文章目录
坐标转换对比
需求:
图像坐标转机械手坐标
CCD→机械手坐标、模组坐标
方法:
Halcon转化
OpenCV转化
测试过程
1:生成变化矩阵
csharp
double[] RobotX, RobotY, CCDX, CCDY;
CCDX = new double[] { 100, 200, 200, 100, 150 };
CCDY = new double[] { 100, 100, 200, 200, 150 };
RobotX = new double[] { 0, 2, 2, 0, 1 };
RobotY = new double[] { 0, 0, 2, 2, 1 };
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"CCD{i + 1}数据:[{CCDX[i]},{CCDY[i]}]---RobotX{i + 1}数据:[{RobotX[i]},{RobotY[i]}]");
}
Stopwatch sw = Stopwatch.StartNew();
// 1:Halcon计算仿射变换矩阵
HOperatorSet.VectorToHomMat2d(CCDX, CCDY, RobotX, RobotY, out HTuple hv_HomMat2D);
Console.WriteLine($"Halcon耗时:{sw.ElapsedTicks}纳秒");
Mat matCCD = new Mat(CCDX.Length, 2, OpenCvSharp.MatType.CV_64F);
Mat matRobot = new Mat(RobotX.Length, 2, OpenCvSharp.MatType.CV_64F);
Mat mat2D = new Mat();
for (int i = 0; i < RobotX.Length; i++)
{
matCCD.Set<double>(i, 0, CCDX[i]);
matCCD.Set<double>(i, 1, CCDY[i]);
matRobot.Set<double>(i, 0, RobotX[i]);
matRobot.Set<double>(i, 1, RobotY[i]);
}
sw = Stopwatch.StartNew();
mat2D = OpenCvSharp.Cv2.EstimateAffine2D(matCCD, matRobot);
Console.WriteLine($"Opencv耗时:{sw.ElapsedTicks}纳秒");
StringBuilder sb = new StringBuilder();
sb.Append("[");
sb.Append(mat2D.Get<double>(0, 0).ToString());
sb.Append(",");
sb.Append(mat2D.Get<double>(0, 1).ToString());
sb.Append(",");
sb.Append(mat2D.Get<double>(0, 2).ToString());
sb.Append(",");
sb.Append(mat2D.Get<double>(1, 0).ToString());
sb.Append(",");
sb.Append(mat2D.Get<double>(1, 1).ToString());
sb.Append(",");
sb.Append(mat2D.Get<double>(1, 2).ToString());
sb.Append(",");
sb.Append(mat2D.Get<double>(2, 0).ToString());
sb.Append(",");
sb.Append(mat2D.Get<double>(2, 1).ToString());
sb.Append(",");
sb.Append(mat2D.Get<double>(2, 2).ToString());
sb.Append("]");
//打印仿射变换矩阵
Console.WriteLine("HALCON 矩阵输出 Matrix: " + hv_HomMat2D.ToString());
Console.WriteLine("OOpcv4 矩阵输出 Matrix: " + sb.ToString());
Console.WriteLine("***********");
2:测试数据
csharp
//测试
HTuple rr, cc;
HOperatorSet.AffineTransPoint2d(hv_HomMat2D, CCDX[0], CCDY[0], out rr, out cc);
Console.WriteLine($"Halcon测试点1图像({CCDX[0]}, {CCDY[0]})转为物理: ({rr}, {cc})");
double[] src = new double[] { CCDX[0], CCDY[0], 0 };
double[] C = hv_HomMat2D.ToDArr();
double[] PS = new double[3];
PS[0] = src[0] * C[0] + src[1] * C[1] + C[2];
PS[1] = src[0] * C[3] + src[1] * C[4] + C[5];
Console.WriteLine($"公式来测试点1图像({CCDX[0]}, {CCDY[0]})转为物理: ({PS[0]}, {PS[1]})");
Console.WriteLine("***********");
HOperatorSet.AffineTransPoint2d(hv_HomMat2D, CCDX[1], CCDY[1], out rr, out cc);
Console.WriteLine($"Halcon测试点2图像({CCDX[1]}, {CCDY[1]})转为物理: ({rr}, {cc})");
src = new double[] { CCDX[1], CCDY[1], 0 };
PS = new double[3];
PS[0] = src[0] * C[0] + src[1] * C[1] + C[2];
PS[1] = src[0] * C[3] + src[1] * C[4] + C[5];
Console.WriteLine($"公式来测试点2图像({CCDX[1]}, {CCDY[1]})转为物理: ({PS[0]}, {PS[1]})");
Console.WriteLine("***********");
HOperatorSet.AffineTransPoint2d(hv_HomMat2D, CCDX[2], CCDY[2], out rr, out cc);
Console.WriteLine($"Halcon测试点3图像({CCDX[2]}, {CCDY[2]})转为物理: ({rr}, {cc})");
src = new double[] { CCDX[2], CCDY[2], 0 };
PS = new double[3];
PS[0] = src[0] * C[0] + src[1] * C[1] + C[2];
PS[1] = src[0] * C[3] + src[1] * C[4] + C[5];
Console.WriteLine($"公式来测试点3图像({CCDX[2]}, {CCDY[2]})转为物理: ({PS[0]}, {PS[1]})");
结果显示

输出矩阵都是一样的。
测试速度,还是halcon厉害
小结:
1:转化矩阵生成时,先写像素坐标,在写机械手坐标。
2:使用时,
方法1:
机械坐标X=像素X矩阵0+像素Y 矩阵1+矩阵2;
机械坐标Y=像素X矩阵3+像素Y 矩阵4+矩阵5;
方法2:
Halcon算子 HOperatorSet.AffineTransPoint2d(矩阵,像素坐标,out 机械坐标)。
3:
矩阵a11和a12是X轴的缩放和旋转。
矩阵a21和a22是Y轴的缩放和旋转。
a13是X方向的平移量;a23是Y方向的平移量。
结尾:
二维仿射变换矩阵=转、缩放、平移和剪切。
利用最小二乘法和可能的 RANSAC 算法,通过一组对应的点来估计仿射变换矩阵。它的实现涉及线性代数和优化技术。