一、简介
这个是从B站上看到的一个项目,虽然很简单,但是对于我们这种自学3D的初学者来说是一个很好的案例,切平面法是比较简单的一种方法,后期我们在看一种法向量法,let us go!
友情提示:IT Blog 上的那位朋友,你不用照搬过去,你可以改一下,至少吧图片上我的那个名称去掉,还有我自己写的都是自己理解的,很多东西都是有误的。
二、思路
1、读入点云文件
2、筛选其中的那个鞋子模型,将周围的那些点都删掉
3、坐标位姿转换 ,求3D模型的矩,然后通过逆姿态将坐标移动产品的中心坐标系位置
4、模型三角化,并将这个模型放到最小外接box 中
5、从最小外接box中再次获取位姿,在做一次刚体变化,主要是为了将最小外接box的中心作为新的坐标系中心,然后我们做切片的时候切的就是这个box定义的x 轴的位姿。显示最小外接box 和这个产品模型。
6、开始做切片;我们是按照上面第5步中的坐标 逐步对x 轴进行切片
细节:a、生成切片的平面,平行与yOz 的平面
b、求这个模型与切片平面的交线,生成一个轮廓,
轮廓线的 row 对于的是交线模型的Y轴 column 对应的是交线模型的Z轴
c、对这个轮廓做映射,这一步很重要
d、拿到每段轮廓的第一个点和最后一个点的坐标(这两个点的坐标就是轮廓)
e、将每段轮廓的首尾连个点生成 三维的位姿,主要是看这个生成的和求出的是不是一直的,这一步可以没有
7、将所有的每个切片的首尾点放到数组中,集合起来的坐标就是我们想要的大概轮廓
三、核心解释
1、算子解释:
project_object_model_3d
把一个3D目标模型的边缘投影到图像坐标中。
project_object_model_3d 将 3D 对象模型投影到图像坐标系中,并在 ModelContours 中返回投影轮廓。首先,使用给定的 Pose 将它们转换为相机坐标系。然后,根据相机内部参数CamParam将这些坐标投影到图像坐标系中。 相机内部参数 CamParam 描述了相机的投影特性。 Pose 描述了世界坐标系相对于相机坐标系的位置和方向。 有一些通用参数可以选择性地用于影响投影。如果需要,可以分别使用 GenParamName 和 GenParamValue 指定这些参数及其对应的值。 GenParamName 的以下值是可能的: project_object_model_3d( : ModelContours : ObjectModel3D, CamParam, Pose, GenParamName, GenParamValue : )*====================================================
CamParam
(input_control) 相机内参
Pose
(input_control) 姿态,是一个7 个数的矩阵(3*3)
GenParamName
Default value: []
List of values: ‘
data
‘,如果“data”设置为“面”,则投影 3D 对象模型的面。面由它们在 ModelContours 中的边界线表示。如果“data”设置为“线”,则投影 3D 对象模型的 3D 线。如果“data”设置为“点”,则投影 3D 对象模型的点。‘false’, ‘hidden_surface_removal’, ‘min_face_angle’,
‘point_orientation’
:
此参数以弧度为单位指定十字的方向。因此,该参数仅在选择 3D 对象模型的点进行投影并且“point_shape”设置为“cross”(见上文)时才有效。 建议值:0、0.39、0.79 默认值:0.79‘
point_shape
‘,此参数指定点在输出轮廓 ModelContours 中的表示方式,因此,此参数仅在选择 3D 对象模型的点进行投影时才有效。 如果 'point_shape' 设置为 'circle',则点由圆形表示,而 如果 'point_shape' 设置为 'cross',则点由十字表示。在这两种情况下,点的大小(即圆圈的大小或十字的大小)都可以由通用参数“point_size”指定(见下文)。十字的方向可以由通用参数
‘point_size’
:
此参数指定输出轮廓 ModelContours 中点表示的大小,即圆的大小或十字的大小,具体取决于所选的“point_shape”。因此,此参数仅在选择 3D 对象模型的点进行投影时才有效(见上文)。大小必须以像素为单位。如果 'point_size' 设置为 0,则每个点由包含单个轮廓点的轮廓表示。 建议值:0、2、4 默认值:4‘true’, ‘union_adjacent_contours’
GenParamValue
Default value: []
Suggested values: 0.17, 0.26, 0.35, 0.52, ‘true’, ‘false’, ‘auto’, ‘points’, ‘faces’, ‘lines’, ‘circle’, ‘cross’, 1, 2, 3, 4, 0.785398
相机的内参详解:
CameraParameters := [0.00367057,-809.403,2.20647e-006,2.2e-006,1136.84,1064.02,2592,1944]
第一个参数:焦距(m)
第二个参数:Kappa(-1/m^2)
第三个参数:单个像素的宽(m)
第四个参数:单个像素的高(m)
第五个参数:中心点x坐标(像素)
第六个参数:中心点y坐标
第七个参数:像素宽
第八个参数:像素高
相机外参:
CameraPose := [0.0290517,-0.0118443,0.242762,0.3944,0.507229,287.921,0]
前三个参数是平移,后三个参数是旋转角度,第七个参数是表示这个是一个(3*3)的矩阵
2、过程解释
帅选模型:
用矩来显示3D点云模型在坐标系下的位置:
*3 将鞋子的点云集合变换到原始坐标系下 的主轴 x y Z
moments_object_model_3d (ObjectModel3DSelected, 'principal_axes', pose)
* 将这个姿态反变化,让坐标系在鞋子点云的中心上
pose_invert (pose, PoseInvert)
然后将这个矩产品模型中心通过刚体变换或者是仿射变换作为我们新的坐标系;
三角化
*4、三角化 三维重建 表面比较光滑的 密度一样的
triangulate_object_model_3d (ObjectModel3DAffineTrans, 'greedy', [], [], TriangulatedObjectModel3D, Information)
最小BOX化,并加坐标系中心放到这个BOX的中心上
smallest_bounding_box_object_model_3d (TriangulatedObjectModel3D, 'oriented', PoseOutbox, Length1, Length2, Length3)
pose_invert (PoseOutbox, PoseInvertBox)
rigid_trans_object_model_3d (TriangulatedObjectModel3D, PoseInvertBox, TransObjectModel3D)
visualize_object_model_3d (WindowHandle, TransObjectModel3D, [], [], ['lut','color_attrib','disp_pose'], ['color1','coord_z','true'], ['最小外接立方体-鞋子点云'], [], [], PoseOutcube)
* 将box 和 鞋子的点云模型都显示一下,为的是将点云模型的坐标系和立方体的坐标 做一个标准位置
smallest_bounding_box_object_model_3d (TransObjectModel3D, 'oriented', PoseBox,Length1, Length2, Length3)
gen_box_object_model_3d (PoseBox, Length1, Length2, Length3, PoseBoxOriented)
visualize_object_model_3d (WindowHandle,[TransObjectModel3D,PoseBoxOriented], [],[], ['color_0','color_1','alpha_1','disp_pose'], ['green','gray',0.5,'true'],'RectBOX', [], [], Pose)
生产平面:
CutPlanePose:=PoseBox
CutPlanePose[0]:=PoseBox[0]-Length1/2+(Index)*3+3
CutPlanePose[3]:=0
CutPlanePose[4]:=90
CutPlanePose[5]:=0
* 生成一个平面
gen_plane_object_model_3d (CutPlanePose,[-1,-1,1,1] * 90, [-1,1,1,-1] * 90, ObjectModel3D1)
求交线:
*求这个平面和 三角化模型的焦点
intersect_plane_object_model_3d (TransObjectModel3D, CutPlanePose, ObjectModel3DIntersection)
get_object_model_3d_params (ObjectModel3DIntersection, 'num_points', GenParamValue1)
* 显示我们通过切平面得到的交线模型
* visualize_object_model_3d (WindowHandle, ObjectModel3DIntersection, [], [], [], [], [], [], [], PoseOut2)
* 通过投影得到轮廓 轮廓线的 row 对于的是交线模型的Y轴 column 对应的是交线模型的Z轴
pose_invert (CutPlanePose, PoseInvertXLD)
get_object_model_3d_params (ObjectModel3DIntersection, 'diameter_axis_aligned_bounding_box', Diameter)
PoseInvertXLD[2]:=PoseInvertXLD[2]+Diameter
切面得到的轮廓:
四、显示
*1读入鞋点云文件数据集合
read_object_model_3d ('2020-01-14-16832.om3', 'm', [], [], ObjectModel3D, Status)
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
* 显示读入的点云文件
visualize_object_model_3d (WindowHandle, ObjectModel3D, [], [], ['lut','color_attrib','disp_pose','alpha'], ['color1','coord_z','true',0.5], ['鞋子点云'], [], [], PoseOut)
*2 开始筛选其中的那个鞋子模型,将周围的那些点都删掉
connection_object_model_3d (ObjectModel3D, 'distance_3d', 1, ObjectModel3DConnected)
* 参考案例:
*返回三维对象模型的属性。 得到属性 num_points 然后用点来筛选出模型
get_object_model_3d_params (ObjectModel3DConnected, 'num_points', GenParamValue)
select_object_model_3d (ObjectModel3DConnected, 'num_points', 'and', 200000, 2e7, ObjectModel3DSelected)
* 显示筛选之后的3d模型显示 select3D object
visualize_object_model_3d (WindowHandle, ObjectModel3DSelected, [], [], ['lut','color_attrib','disp_pose'], ['color1','coord_z','true'], [], [], [], PoseOut1)
*3 将鞋子的点云集合变换到原始坐标系下 的主轴 x y Z
moments_object_model_3d (ObjectModel3DSelected, 'principal_axes', pose)
* 将这个姿态反变化,让坐标系在鞋子点云的中心上
pose_invert (pose, PoseInvert)
* 点云的刚体变换
*rigid_trans_object_model_3d (ObjectModel3DSelected, PoseInvert, ObjectModel3DRigidTrans)
*visualize_object_model_3d (WindowHandle, ObjectModel3DRigidTrans, [], [], ['lut','color_attrib','disp_pose'], ['color1','coord_z','true'], ['刚体变换之后的鞋子点云'], [], [], PoseOut)
* 用放射变换来实现
pose_to_hom_mat3d (PoseInvert, HomMat3D)
affine_trans_object_model_3d (ObjectModel3DSelected, HomMat3D, ObjectModel3DAffineTrans)
visualize_object_model_3d (WindowHandle, ObjectModel3DAffineTrans, [], [], ['lut','color_attrib','disp_pose'], ['color1','coord_z','true'], ['刚体变换之后的鞋子点云'], [], [], PoseOut1)
* 坐标系中显示 红色是X轴,绿色的是Y轴 蓝色的是Z轴
*4、三角化 三维重建 表面比较光滑的 密度一样的
triangulate_object_model_3d (ObjectModel3DAffineTrans, 'greedy', [], [], TriangulatedObjectModel3D, Information)
visualize_object_model_3d (WindowHandle, TriangulatedObjectModel3D, [], [], ['lut','color_attrib','disp_pose'], ['color1','coord_z','true'], ['三角化鞋子点云'], [], [], PoseOut3)
* 5、求这个鞋子电源的最小外接立方体
smallest_bounding_box_object_model_3d (TriangulatedObjectModel3D, 'oriented', PoseOutbox, Length1, Length2, Length3)
pose_invert (PoseOutbox, PoseInvertBox)
rigid_trans_object_model_3d (TriangulatedObjectModel3D, PoseInvertBox, TransObjectModel3D)
visualize_object_model_3d (WindowHandle, TransObjectModel3D, [], [], ['lut','color_attrib','disp_pose'], ['color1','coord_z','true'], ['最小外接立方体-鞋子点云'], [], [], PoseOutcube)
* 将box 和 鞋子的点云模型都显示一下,为的是将点云模型的坐标系和立方体的坐标 做一个标准位置
smallest_bounding_box_object_model_3d (TransObjectModel3D, 'oriented', PoseBox,Length1, Length2, Length3)
gen_box_object_model_3d (PoseBox, Length1, Length2, Length3, PoseBoxOriented)
visualize_object_model_3d (WindowHandle,[TransObjectModel3D,PoseBoxOriented], [],[], ['color_0','color_1','alpha_1','disp_pose'], ['green','gray',0.5,'true'],'RectBOX', [], [], Pose)
objectsOut:=[]
Index_S:=[]
Index_E:=[]
color_S:=[]
color_E:=[]
colorsOut:=[]
colorvaluesOut:=[]
all_x:=[]
all_y:=[]
* 6 做切平面
for Index := 0 to 60 by 1
CutPlanePose:=PoseBox
CutPlanePose[0]:=PoseBox[0]-Length1/2+(Index)*3+3
CutPlanePose[3]:=0
CutPlanePose[4]:=90
CutPlanePose[5]:=0
* 生成一个平面
gen_plane_object_model_3d (CutPlanePose,[-1,-1,1,1] * 90, [-1,1,1,-1] * 90, ObjectModel3D1)
* 显示这个切平面
*visualize_object_model_3d (WindowHandle, [TransObjectModel3D,ObjectModel3D1], [], Pose, ['color_0','color_1','alpha_1','disp_pose'], ['green','gray',0.5,'true'], [], [], [], PoseOut1)
*求这个平面和 三角化模型的焦点
intersect_plane_object_model_3d (TransObjectModel3D, CutPlanePose, ObjectModel3DIntersection)
get_object_model_3d_params (ObjectModel3DIntersection, 'num_points', GenParamValue1)
* 显示我们通过切平面得到的交线模型
* visualize_object_model_3d (WindowHandle, ObjectModel3DIntersection, [], [], [], [], [], [], [], PoseOut2)
* 通过投影得到轮廓 轮廓线的 row 对于的是交线模型的Y轴 column 对应的是交线模型的Z轴
pose_invert (CutPlanePose, PoseInvertXLD)
get_object_model_3d_params (ObjectModel3DIntersection, 'diameter_axis_aligned_bounding_box', Diameter)
PoseInvertXLD[2]:=PoseInvertXLD[2]+Diameter
* 用平行于投影平面的相机(1:1的比例)
Scale:=1
CamParam := [0,0,1.0 / Scale,1.0 / Scale,0,0,500,500]
project_object_model_3d (IntersectionXld, ObjectModel3DIntersection, CamParam, PoseInvertXLD, 'data', 'lines')
count_obj (IntersectionXld, Number)
* 将所有的轮廓的的点都放到数组当中
Rows:=[]
Columns:=[]
Row:=[]
Column:=[]
for I:=1 to Number by 1
select_obj (IntersectionXld, EdgeContour, I)
get_contour_xld(EdgeContour, Row,Column)
Rows:=[Rows,Row]
Columns:=[Columns,Column]
endfor
* 将点按照 Row 来排序,拿到第一个点和最后一个点
tuple_sort_index (Rows, Indices)
tuple_length (Rows, Length)
OrderRow:=[]
OrderColumn:=[]
if(Length>=1)
for Row_Index:=0 to Length-1 by 1
OrderRow:=[OrderRow,Rows[Indices[Row_Index]]]
OrderColumn:=[OrderColumn,Columns[[Row_Index]]]
endfor
endif
gen_contour_polygon_xld (Intersection, OrderRow, OrderColumn)
tuple_sort_index (OrderRow, Indices)
tuple_length(OrderRow,Length)
*起点(xld)
StartRow:=OrderRow[Indices[0]]
StartColumn:=OrderColumn[Indices[0]]
*终点(xld)
EndRow:=OrderRow[Indices[Length-1]]
EndColumn:=OrderColumn[Indices[Length-1]]
gen_cross_contour_xld (startCross, StartRow, StartColumn, 60, 0.785398)
gen_cross_contour_xld (endCross, EndRow, EndColumn, 60, 0.785398)
dev_display(Intersection)
*转成点云的坐标 简单的来说就是将平面 row column 转换成三维空间中的 x,y,z
StartPose:=[CutPlanePose[0],StartRow,-StartColumn, 0,0,0,0]
EndPose :=[CutPlanePose[0],EndRow,-EndColumn, 0,0,0,0]
gen_sphere_object_model_3d (StartPose, 2, StartPoint)
gen_sphere_object_model_3d (EndPose , 2, EndPoint )
* visualize_object_model_3d (WindowHandle, [StartPoint,EndPoint], [], [], ['color_0','color_1','alpha_1'], ['green','gray',0.5], [], [], [], PoseOut4)
*所有对点的边界点集合
objectsOut := [objectsOut,StartPoint]
objectsOut := [objectsOut,EndPoint ]
*显示时的颜色
Index_S:= 0+Index*2
Index_E:= 0+Index*2+1
color_S:='color_'+Index_S
color_E:='color_'+Index_E
colorsOut := [colorsOut,color_S]
colorsOut := [colorsOut,color_E]
colorvaluesOut := [colorvaluesOut,'blue']
colorvaluesOut := [colorvaluesOut,'blue']
all_x:=[all_x,CutPlanePose[0]]
all_y:=[all_y,StartRow]
all_x:=[all_x,CutPlanePose[0]]
all_y:=[all_y,EndRow]
endfor
stop()
*显示外边界模型点云
visualize_object_model_3d (WindowHandle,[objectsOut,TriangulatedObjectModel3D], [],[],[colorsOut,'color_88'],[colorvaluesOut,'red'], [], '', [], Pose)
*2二维显示
dev_open_window (0, 0, 512, 512, 'black', WindowHandle1)
dev_set_color('red')
gen_cross_contour_xld(Start,all_x,all_y, 3, 0.885398)