一、目标    

         在实现手眼标定的时候,我们通常的做法是机械手移动九次,相机相应的取图九次,之后会得到九个机械手坐标和九个图像坐标,这个时候我们会使用第三方软件输入两组坐标得到一个矩阵,这个矩阵至关重要。那第三方软件是怎么计算的呢?

二、求转换矩阵

        其中公式的推导用到了最小二乘法和多元线性回归的知识

三、C#编程

        3.1 有关矩阵的类

public class Matrix
{
    public int row;
    public int column;
    public double[,] arr;
    public Matrix()
    {
        row = 0; column = 0;
        arr = new double[row, column];
    }
    public Matrix(int row1, int column1)
    {
        row = row1;
        column = column1;
        arr = new double[row, column];
    }
    
    public Matrix(int row1, int column1, double[,] arr1)
    {
        row = row1;
        column = column1;
        arr = arr1;
    }
   
    public static Matrix operator +(Matrix A, Matrix B)
    {
        Matrix C = new Matrix(A.row, B.column);
        if (A.row == B.row && A.column == B.column)
        {
            for (int i = 0; i < A.row; i++)
                for (int j = 0; j < A.column; j++)
                    C.arr[i, j] = A.arr[i, j] + B.arr[i, j];
        }
        return C;
    }
    public static Matrix operator -(Matrix A, Matrix B)
    {
        Matrix C = new Matrix(A.row, B.column);
        if (A.row == B.row && A.column == B.column)
        {
            for (int i = 0; i < A.row; i++)
                for (int j = 0; j < A.column; j++)
                    C.arr[i, j] = A.arr[i, j] - B.arr[i, j];
        }
        return C;
    }
    public static Matrix operator *(Matrix A, Matrix B)
    {
        Matrix C = new Matrix(A.row, B.column);
        if (A.column == B.row)
        {
            for (int i = 0; i < A.row; i++)
                for (int j = 0; j < B.column; j++)
                {
                    double temp = 0;
                    for (int k = 0; k < A.column; k++)
                        temp += A.arr[i, k] * B.arr[k, j];
                    C.arr[i, j] = temp;
                }
        }
        return C;
    }
    public Matrix transposs(Matrix A)
    {
        Matrix B = new Matrix(A.column, A.row);
        for (int i = 0; i < A.column; i++)
            for (int j = 0; j < A.row; j++)
                B.arr[i, j] = A.arr[j, i];
        return B;
    }
    //逆矩阵
    public double[,] InverseMatrix(double[,] matrix)
    {
        int n = matrix.GetLength(0);
        double[,] result = new double[n, n];
        double[,] temp = new double[n, 2 * n];

        //将矩阵和单位矩阵拼接成一个2n* n的矩阵
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                temp[i, j] = matrix[i, j];
                temp[i, j + n] = i == j ? 1 : 0;
            }
        }
        //高斯 - 约旦消元法
        for (int i = 0; i < n; i++)
        {
            double tempValue = temp[i, i];
            for (int j = i; j < 2 * n; j++)
            {
                temp[i, j] /= tempValue;
            }
            for (int j = 0; j < n; j++)
            {
                if (j != i)
                {
                    tempValue = temp[j, i];
                    for (int k = i; k < 2 * n; k++)
                    {
                        temp[j, k] -= tempValue * temp[i, k];
                    }
                }
            }
        }
        //取出逆矩阵
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                result[i, j] = temp[i, j + n];
            }
        }

        return result;
    }

    public (Matrix L, Matrix U) LUDecompose()
    {
        int n = row;
        Matrix L = new Matrix(n, n);
        Matrix U = new Matrix(n, n);

        for (int i = 0; i < n; i++)
        {
            // Compute elements of U
            for (int k = i; k < n; k++)
            {
                double sum = 0;
                for (int j = 0; j < i; j++)
                    sum += L.arr[i, j] * U.arr[j, k];
                U.arr[i, k] = this.arr[i, k] - sum;
            }

            // Compute elements of L
            for (int k = i; k < n; k++)
            {
                if (i == k)
                    L.arr[i, i] = 1;
                else
                {
                    double sum = 0;
                    for (int j = 0; j < i; j++)
                        sum += L.arr[k, j] * U.arr[j, i];
                    L.arr[k, i] = (this.arr[k, i] - sum) / U.arr[i, i];
                }
            }
        }

        return (L,U);
    }
    public Matrix Inverse()
    {
        (Matrix L, Matrix U) = LUDecompose();
        int n = row;
        Matrix inv = new Matrix(n, n);

        // Compute inverse using L and U
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                double sum = 0;
                for (int k = 0; k <= Math.Min(i, j); k++)
                    sum += L.arr[i, k] * ((i == k) ? 1 : inv.arr[k, j]);
                inv.arr[i, j] = sum;
            }
        }

        for (int i = n - 1; i >= 0; i--)
        {
            for (int j = n - 1; j >= 0; j--)
            {
                double sum = 0;
                for (int k = j; k < n; k++)
                    sum += U.arr[i, k] * inv.arr[k, j];
                inv.arr[i, j] = (j >= i) ? sum / U.arr[i, i] : ((i == j) ? 1 : 0);
            }
        }

        return inv;
    }
    public Matrix Inverse(Matrix matrix)
    {
        matrix.arr = InverseMatrix(matrix.arr);
        return matrix;
    }
}

        3.2 计算

注意:其中返回的矩形需要转置才是我们一般在第三方软件见到的矩阵

public Matrix Canculate(List<DataSource> datas)
{
    //矩阵A,像素坐标
    Matrix matrixA = new Matrix(datas.Count, 3);
    for (int i = 0; i < datas.Count; i++)
    {
        matrixA.arr[i, 0] = datas[i].PixelX;
        matrixA.arr[i, 1] = datas[i].PixelY;
        matrixA.arr[i, 2] = 1;
    }
    //矩阵B,实际坐标
    Matrix matrixB = new Matrix(datas.Count, 2);
    for (int i = 0; i < datas.Count; i++)
    {
        matrixB.arr[i, 0] = datas[i].RealX;
        matrixB.arr[i, 1] = datas[i].RealY;
    }
    return (matrixA.transposs(matrixA) * matrixA).Inverse() * matrixA.transposs(matrixA) * matrixB;
}

        3.3 输入参数List<DataSource> datas 中DataSource

public class DataSource
{
    public double PixelX { get; set; }
    public double PixelY { get; set; }
    public double RealX { get; set; }
    public double RealY { get; set; }
}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐