赞
踩
最近学习了一下拟合平面的原理,看了这篇文章最小二乘拟合平面(C++版) - 知乎
讲到了以下几种方法,我这里在halcon中对其一一实现。
1,直接求解法
2.使用拉格朗日乘子法
3 SVD分解法
1.各方法对比
在halcon中其实有对应的算子直接实现拟合平面Ax+By+C=D
如fit_primitives_object_model_3d
我这里取了一张点云图,对其中一小块点云进行平面拟合测试
取红色圈内一部分数据测试
直接使用halcon算子 fit_primitives_object_model_3d得到的结果
[0.376856, -0.602116, -0.703873, -0.553981]
使用拉格朗日乘子的那个方法得到的结果
[0.376856, -0.602116, -0.703873, -0.553981]
第一个直接求解法得到的结果
[0.376656, -0.601768, -0.704277, -0.554283]
用SVD方法求解的结果
[-0.376856, 0.602116, 0.703873, 0.553981]
结果都一样,除了那个直接求解法的,没有做去质心处理,可能有点细微的差别
2.halcon代码
- read_image (XYZ, '3d_machine_vision/segmentation/3d_primitives_xyz_01.tif')
-
- access_channel (XYZ, X, 1)
- access_channel (XYZ, Y, 2)
- access_channel (XYZ, Z, 3)
-
- gen_ellipse (ROI_0, 84.5473, 95.7705, rad(-35.9506), 10.9232, 8.60448)
- reduce_domain (Z, ROI_0, ImageReduced)
- xyz_to_object_model_3d (X, Y, ImageReduced, ObjectModel3D)
-
-
- *直接使用halcon拟合平面算子处理
- fit_primitives_object_model_3d (ObjectModel3D, 'primitive_type', 'plane', ObjectModel3DOut)
- get_object_model_3d_params (ObjectModel3DOut, 'primitive_parameter', Result1)
- get_object_model_3d_params (ObjectModel3DOut, 'primitive_rms', GenParamValue1)
-
-
-
- *获取截取的3d模型x、y、z的坐标值
- get_object_model_3d_params (ObjectModel3D, 'point_coord_x', pX)
- get_object_model_3d_params (ObjectModel3D, 'point_coord_y', pY)
- get_object_model_3d_params (ObjectModel3D, 'point_coord_z', pZ)
-
-
- *测试用拉格朗日乘子法
- Num:=|pX|
-
- *求均值
- XM:=mean(pX)
- YM:=mean(pY)
- ZM:=mean(pZ)
-
- *去质心
- DX:=pX-XM
- DY:=pY-YM
- DZ:=pZ-ZM
-
- *求矩阵各个位置的值
- MA11 := sum(DX * DX)
- MA22 := sum(DY * DY)
- MA33 := sum(DZ * DZ)
- MA12 := sum(DX * DY)
- MA13 := sum(DX * DZ)
- MA23 := sum(DY * DZ)
- create_matrix (3, 3, [MA11,MA12,MA13,MA12,MA22,MA23,MA13,MA23,MA33], MatrixID)
-
- *实对称矩阵,求特征值和特征向量
- eigenvalues_symmetric_matrix (MatrixID, 'true', EigenvaluesID, EigenvectorsID)
-
- *特征值按小到大排列,所以平面法向量是第一列特征向量
- get_value_matrix (EigenvectorsID, 0, 0, NX)
- get_value_matrix (EigenvectorsID, 1, 0, NY)
- get_value_matrix (EigenvectorsID, 2, 0, NZ)
-
- *算C 平面方程NX*X+NY*Y+NZ*Z=C
- C := NX * XM + NY * YM + NZ * ZM
- Result2:=[NX,NY,NZ,C]
-
-
- *对应使用直接求解法
- *算矩阵各个位置的值
- MB11:=sum(pX*pX)
- MB12:=sum(pX*pY)
- MB13:=sum(pX)
- MB22:=sum(pY*pY)
- MB23:=sum(pY)
- MB33:=|pX|
- MC1:=sum(pX*pZ)
- MC2:=sum(pY*pZ)
- MC3:=sum(pZ)
-
- create_matrix (3, 3, [MB11,MB12,MB13,MB12,MB22,MB23,MB13,MB23,MB33], MB)
- create_matrix (3, 1, [MC1,MC2,MC3], MC)
- solve_matrix (MB, 'general', 0, MC, MatrixResultID)
- get_full_matrix (MatrixResultID, Values)
- *要求a^2+b^2+c^2=1 求解真正的a、c
- dd:=Values[0]*Values[0]+Values[1]*Values[1]+1
- a:=Values[0]/sqrt(dd)
- b:=Values[1]/sqrt(dd)
- c:=-1/sqrt(dd)
- *因为这里的平面方程为a*x+b*y+c*z=d 与文章中方程A*x+B*y+C*z+D=0中d相差个负号,所以
- d:=-Values[2]/sqrt(dd)
- Result3:=[a,b,c,d]
-
- *SVD分解法
- create_matrix (3, Num, [DX,DY,DZ], A)
- transpose_matrix_mod (A)
- svd_matrix (A, 'full', 'both', U, S, V)
-
- get_full_matrix (V, VValues)
- get_value_matrix (V, 0, 2, Value1)
- get_value_matrix (V, 1, 2, Value2)
- get_value_matrix (V, 2, 2, Value3)
-
- Value4:=Value1*XM+Value2*YM+Value3*ZM
- Result4:=[Value1,Value2,Value3,Value4]
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
那个求各个位置的值,可以直接用矩阵相乘好了,简写成
- *求特征向量法
- create_matrix(3,Num,[DX,DY,DZ],B)
- mult_matrix (B, B, 'ABT', MatrixMultID)
- eigenvalues_symmetric_matrix (MatrixMultID, 'true', EigenvaluesID1, EigenvectorsID1)
- get_full_matrix (EigenvectorsID1, Values3)
- aa:=Values3[0]
- bb:=Values3[3]
- cc:=Values3[6]
- dd:=aa*XM+bb*YM+cc*ZM
- Result5:=[aa,bb,cc,dd]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。