C#九点标定矩阵计算
在实现手眼标定的时候,我们通常的做法是机械手移动九次,相机相应的取图九次,之后会得到九个机械手坐标和九个图像坐标,这个时候我们会使用第三方软件输入两组坐标得到一个矩阵,这个矩阵至关重要。那第三方软件是怎么计算的呢?
·
一、目标
在实现手眼标定的时候,我们通常的做法是机械手移动九次,相机相应的取图九次,之后会得到九个机械手坐标和九个图像坐标,这个时候我们会使用第三方软件输入两组坐标得到一个矩阵,这个矩阵至关重要。那第三方软件是怎么计算的呢?
二、求转换矩阵
其中公式的推导用到了最小二乘法和多元线性回归的知识
三、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; }
}
更多推荐
所有评论(0)