3D点云基础知识(二)-bilibili视频资源整理(二)鞋点胶点云轮廓提取

资料来源:超人视觉免费启蒙三维课程入门(第六节)3D鞋点胶的点云边界(轮廓)提取

相似案例:Halcon三维测量(3):鞋底涂胶+边缘提取

Halcon学习方法强调:从案例当中学习:最重要是思路和算子的用法、为我们所用。不要机械式套用。

视觉:

  1. 机器视觉(2D、3D):
    1. 2D:
      1. 识别定位(对位贴合)(深度学习)
      2. 测量
      3. 缺陷(外观检测)(深度学习)
      4. 符号需求(一维码、二维码、三维码、OCR)
      5. 视觉+运动控制板卡+机器人
    2. 3D:
      1. 鞋点胶
      2. 无序抓取:在Halcon【实例程序】中【方法】【多目立体视觉】locate_pipe_joints-stereo.hdev案例中。
      3. 点云数据+深度学习
        1. 工具:Halcon、VisionPro、LabView、OpenCV、Sherlock、Evsion、Insight、Matlab、(Emgucv+C#)
        2. 推荐:Halcon===>>>>   OpenCV  ====>>>>    源码自己编写
        3. 语言主流:C#+halcon、C+++QT+halcon、C+++MFC+halcon
  2. 计算机视觉:
    1. 室外:(深度学习)
    2. 工业:

视觉项目思路:(算法+软件框架)

1、需求分析:2D还是3D的?

2、项目评估仿真:

3、合同

4、方案设计:(硬件方案、软件方案)点云直接买现成的,因为精度更高。

5、精度和速度,考虑硬件方案:

6、概要设计

7、详细设计

8、编码

9、测试调试

10、交付

11、维护


鞋点胶边界检测思路:

1、点的法向量重建:K邻域、体素。法向量非常重要:

2、当前教程:(不是通用、不太灵活的方法)(初学者)

1)获取点云切平面

2)切平面与点云的交线

3)交线在点云上的起点、终点求出来

4)起点、终点就是外边界。

起点、终点如何求?

将交平面转化为一个2D图像求XLD轮廓。XLD上的起点、终点可求。

激光三角成像:线轮廓+移动


第一步:读入点云(鞋)的文件。

第二步:分割出鞋子的点云集合。(去除噪声等。)

第三步:仿射变换到与长轴和短轴平行的位置。(3D一样可以仿射变换):方便切平面的定义。

第四步:定义切平面,求鞋的3D点云集合跟切平面的点云交集。

第五步:把交集的点云坐标映射成2D的XLD轮廓,求每段轮廓起点、终点坐标。

第六步:把得到的每段XLD的起点、终点坐标又映射转换成3D点云坐标。

第七步:显示鞋的点云集合以及鞋的外边界的点云集合。




资料来源:超人视觉免费启蒙三维课程入门(第七节)3D鞋点胶的点云边界提取

超人视觉免费启蒙三维课程入门第八节(3D鞋点胶的点云边界提取)

第八节还有一个链接

第一步:加载并显示扫描生成的点云数据。

dev_close_window ()
dev_update_off ()
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
* 1、读取点云文件
read_object_model_3d ('./2.om3', 'mm', [], [], ObjectModel3D, Status)
visualize_object_model_3d (WindowHandle, ObjectModel3D, [], [], [], [], [], [], [], PoseOut)

visualize_object_model_3d参数的详解:visualize_object_model_3d (窗口句柄, 3D模型, [内参], [外参], [参数名], [参数名对应的值], [标题信息], [模型信息], [窗口提示信息:比如旋转、放大、缩小], PoseOut)

  • 相机的内外参数
  • 参数名和参数名对应的值:对应下面的:GenParamNameGenParamValue:定义了:显示的颜色,透明度。可以定义显示参数。
  • poseOut:输出点云的姿态。相对于坐标系的平移和旋转。

双击【变量窗口】中的ObjectModel3D变量可以打开【三维对象模型检查】。

 点击勾选【Display Models】,会打开【显示三维对象模型】,在显示窗口左下方状态栏中可以显示模型的姿态信息。(7个数字:偏移X,偏移Y,偏移Z,偏转x,偏转y,偏转z,旋转类型(旋转顺序));

在【显示三维对象模型】窗口上面工具栏可以【插入代码】:

插入代码如下:

CamParam := ['area_scan_division',0.06,0,8.5e-006,8.5e-006,468,161,936,323]
Pose := [-899.05,-1306.69,750249,3.85575,13.3872,36.4233,0]
GenParamName := ['colored','alpha','color_0']
GenParamValue := [12,0.9,'cyan']
disp_object_model_3d (200000, ObjectModel3D, CamParam, Pose, GenParamName, GenParamValue)

这里的这个显示函数为disp_object_model_3d,相比于visualize_object_model_3d的交互式显示不同。看F1帮助文档的描述:

visualize_object_model_3d — Interactively display 3D object models

disp_object_model_3d — Display 3D object models.

一个交互式显示,可以点击旋转,缩放,一个只是展示。

插入的代码:

  • 其中会把内参(相机配置参数)和外参(当前的姿态信息)输出。同时对显示进行定义:GenParamNameGenParamValue:定义了:显示的颜色,透明度。
  • 如果曾经求解过法向量,那么就可以点击【显示三维对象模型的法向量】显示法向量,如果没有求过,不会显示。
  • 【显示三维对象模型的坐标系】:在halcon中红颜色代表的是X轴方向,绿颜色代表的是Y轴方向,蓝颜色代表的是Z轴方向。

halcon中可以用create_pose — Create a 3D pose.来创建一个姿态

在【显示三维对象模型】中:【Base Parameter】有点云的中心点、直径、外接矩形框。


在视频中作者特别强调了:【案例教程中】【方法】【三维对象处理】中【moments_object_model_3d.hdev】这个教程。显示方法。 

前面英文就说如果点云有山脊状走势,那么山脊更适合做X轴方向,我们原来的坐标系就需要转到以山脊走向为X轴的坐标系统下。

选坐标轴的一个原则是:沿着数据方差最大的方向作为主轴。

In this example the color encodes the value of the z-component of the data。对z轴高度信息颜色编码。

x-axis in red, the y-axis in green and the z-axis in blue.

 第32行和第33行:显示参数列表。

GenParamName := ['lut','color_attrib','light_position','disp_pose','alpha']
GenParamValue := ['color1','coord_z','0.0 0.0 -0.3 1.0','true',0.9]

 根据z轴坐标的高度不同,颜色不同。disp_pose显示坐标系:true。

 第39行和第40行:创建姿态。

create_pose (-0.0005, -0.0005, 0.04, 280, 0, 20, 'Rp+T', 'gba', 'point', DispPose1)
create_pose (0, -0.0005, 0.04, 280, 0, 20, 'Rp+T', 'gba', 'point', DispPose2)

 此外,在第四步中会介绍提到的两种3D点云模型刚体变换:一、放射变换:affine_trans_object_model_3d和二、刚体变换:rigid_trans_object_model_3d

 第二步:去噪声

通过connection_object_model_3d基于某种特征(三角网格(需要计算生成三角网格)、距离、)来将连通域断开,以此来实现:区域切割。独立集合对象。

关于connection_object_model_3d算子,作者推荐核心案例教程:【方法】【三维对象处理】【connection_object_model_3d.hdev】

通过分割完成后,用get_object_model_3d_params来计算每个连通域的点云个数。

connection_object_model_3d (ObjectModel3D, 'distance_3d', 1000, ObjectModel3DConnected)
get_object_model_3d_params (ObjectModel3DConnected, 'num_points', GenParamValue)

第三步:滤波筛选

关于点云筛选的两个案例:【select_points_object_model_3d_by_density.hdev】和【select_object_model_3d.hdev】代表了点云筛选的两种方法。

*3、滤波筛选:
select_object_model_3d (ObjectModel3DConnected, 'num_points', 'and', 120000, 200000, ObjectModel3DSelected)
visualize_object_model_3d (WindowHandle, ObjectModel3DSelected[1], [], PoseOut, ['lut','color_attrib','disp_pose'], ['color1','coord_z','true'], [], [], [], PoseOut2)

第四步:将鞋点云集合变换到原始坐标系下主轴-X、Y、Z轴

所谓主轴:用最小外接长方体将点云囊括,长轴与X轴重合,短轴与Y轴重合,高度与Z轴重合。重合移动肯定会有一个姿态关系:pose。

moments_object_model_3d (ObjectModel3DSelected, 'principal_axes', Pose)第二个参数意思求主轴,第三个参数输出pose姿态。moments_object_model_3d 用来求矩,还有两个参数分别是一阶矩,二阶矩

然后将姿态反变换:求姿态的反变换:这样变换就可以将长轴作为X轴,变换就涉及刚体变换(仿射变换)。变换就需要用到矩阵和姿态。

点云模型刚体变换

rigid_trans_object_model_3d:刚体变换算子。既可以平移,也可以旋转。

* 4、将鞋点云集合变换到原始坐标系下主轴-X、Y、Z轴
* 第二个参数意思求主轴,第三个参数,输出pose姿态。
moments_object_model_3d (ObjectModel3DSelected[1], 'principal_axes',PoseOut1)
pose_invert (PoseOut1, PoseInvert)

* 这样变换就可以将长轴作为X轴,变换就涉及刚体变换(仿射变换)。变换就需要用到矩阵和姿态。
* rigid_trans_object_model_3d (ObjectModel3DSelected[1], PoseInvert, ObjectModel3DRigidTrans)
* visualize_object_model_3d (WindowHandle, ObjectModel3DRigidTrans, [], PoseInvert, [], [], [], [], [], PoseOut)

仿射变换一样可以达到同样的效果。 放射变换需要的是一个矩阵。

将姿态变换为矩阵:pose_to_hom_mat3d

仿射变换:affine_trans_object_model_3d

* 用仿射变换也可以实现这个变换:
pose_to_hom_mat3d (PoseInvert, HomMat3D)   \\ 将姿态变换为矩阵
affine_trans_object_model_3d (ObjectModel3DSelected[1], HomMat3D, ObjectModel3DAffineTrans)
visualize_object_model_3d (WindowHandle, ObjectModel3DAffineTrans, [], PoseInvert, ['lut','color_attrib','disp_pose'], ['color1','coord_z','true'], [], [], [], PoseOut3)

moments_object_model_3d 确定主轴X轴方向,这样做的原因是为了方便沿着x轴做切平面的时候,方便分割。这就是确定长轴的原因。

标准位置的好处:做切平面与鞋面垂直。与轴平行,沿轴切,不会乱。整齐。


第五步:如果鞋子还是没有转正:那么就需要求一个最小外接box。

推荐案例【smallest_bounding_box_object_model_3d.hdev】中的smallest_bounding_box_object_model_3d算子完成。

求box之前可以做一个三角曲面重建:使得点云更加圆滑。

三角曲面重建。将无序点云三角化。内部算子实际使用的是贪婪投影三角法。将有向点云投影到一个二维平面内,平面内三角化。根据平面内的三角拓扑关系,生成一个三角网格曲面模型。如果使用膨胀腐蚀,就会使网格变大变小。

*三角曲面重建。将无序点云三角化。内部算子实际使用的是贪婪投影三角法。将有向点云投影到一个二维平面内,平面内三角化。根据平面内的三角拓扑关系,生成一个三角网格曲面模型。如果使用膨胀腐蚀,就会使网格变大变小。
triangulate_object_model_3d (ObjectModel3DAffineTrans, 'greedy', [], [], TriangulatedObjectModel3D, Information)
* 三角曲面重建需要点时间。如果点数太多的话,可以简化点云:
* 三角曲面重建比较适用于表面连续比较光滑的曲面,或者点云密度比较均匀的情况。速度会比较快。否则会出现因点云不连续导致的奇形怪状。甚至悬空点。
visualize_object_model_3d (WindowHandle, TriangulatedObjectModel3D, [], PoseOut3, ['lut','color_attrib','disp_pose'], ['color1','coord_z','true'], [], [], [], PoseOut4)

* 三角曲面重建需要点时间。如果点数太多的话,可以简化点云
* 三角曲面重建比较适用于表面连续比较光滑的曲面,或者点云密度比较均匀的情况。速度会比较快。否则会出现因点云不连续导致的奇形怪状。甚至悬空点。

求最小外接box:

* 最小外接box
smallest_bounding_box_object_model_3d (TriangulatedObjectModel3D, 'oriented', Pose, Length1, Length2, Length3)
gen_box_object_model_3d (Pose, Length1, Length2, Length3, ObjectModel3D1)
pose_invert (Pose, PoseInvert1)
rigid_trans_object_model_3d (TriangulatedObjectModel3D, PoseInvert1, ObjectModel3DRigidTrans)
visualize_object_model_3d (WindowHandle, ObjectModel3DRigidTrans, [], [], ['lut','color_attrib','disp_pose'], ['color1','coord_z','true'], [], [], [], PoseOut5)
* 联合显示:
visualize_object_model_3d (WindowHandle, [ObjectModel3DRigidTrans,ObjectModel3D1], [], [], ['color_0','color_1','alpha_1', 'disp_pose'], ['green','gray',0.5,'true'], 'RectBOX', [], [], PoseOut2)

特别注意联合显示时的操作:要注意将外面图像设置透明度。




超人视觉免费启蒙三维课程入门第九讲-求切平面

第六步:在box中做切平面,求与轮廓的交线。

在X轴,做切平面,每次沿X轴移动指定均匀长度。切平面与点云有一个点云交集,把点云交集映射到二维平面上形成一个XLD二维的轮廓交线,交线的两端(起点、终点)就是我们需要的轮廓点。

做切平面需要给出切平面的姿态。

一段段的做切割:肯定要引入一个循环问题:

推荐案例:inspect_3d_surface_intersections.hdev,

*5、求切平面交线点云
for Index1 := 0 to 50 by 1
    CutPlanePose := Pose
    CutPlanePose[0]:=Pose[0]-Length1/2+(Index1)*40+3   // pose中的参数值:第一个为沿着x轴的平移。
    CutPlanePose[3]:=0
    CutPlanePose[4]:=90       // pose第五个值为绕着y轴旋转90度,立起来。
    CutPlanePose[5]:=0
    * 产生平面,去看一下切平面的情况。第一个参数是姿态pose,第二、第三个参数是限定大小。
    gen_plane_object_model_3d (CutPlanePose, [-1, -1, 1, 1]*1, [-1, 1, 1, -1]*1,IntersectionPlane)
*     visualize_object_model_3d (WindowHandle, [ObjectModel3DRigidTrans,IntersectionPlane], [], Pose,  ['color_0','color_1','alpha_1', 'disp_pose'], ['green','gray',0.5,'true'], [], [], [], PoseOut)
    visualize_object_model_3d (WindowHandle, [aim_object,IntersectionPlane], [], Pose,  ['disp_pose'], ['true'], [], [], [], PoseOut)

    * 得到XLD交线。
    intersect_plane_object_model_3d (IntersectionPlane, CutPlanePose, ObjectModel3DIntersection)
    visualize_object_model_3d (WindowHandle, ObjectModel3DIntersection, [], [], [], [], [], [], [], PoseOut7)
    
    * 然后求起点、终点。先变换到2维XLD。
    pose_invert (CutPlanePose,PoseInvert2)
    *确定投影平面在前面
    get_object_model_3d_params (ObjectModel3DIntersection, 'diameter_axis_aligned_bounding_box', Diameter)
    PoseInvert2[2]:=PoseInvert2[2]+Diameter  // 切平面往上抬升。沿着z轴往上升高一个直径大小。凸显效果哦。
    // 基于长轴x轴切割,投影在yoz投影面上。
    * 用平行于投影平面的相机(1:1的比例)
    Scale:=1
    CamParam:=[0, 0, 1.0 /Scale, 1.0/Scale, 0, 0, 500, 500]
    project_object_model_3d (IntersectionXld, ObjectModel3DIntersection, CamParam, PoseInvert2, 'data', 'lines')
    * XLD有可能是多段的。
    count_obj (IntersectionXld, Number)
    
    * 点按照由上到下
    Rows:=[]
    Columns:=[]
    Row:=[]
    Column:=[]
    for I := 1 to Number by 1
        select_obj (IntersectionXld, EdgeContour,I)
        get_contour_xld (EdgeContour, Row1, Colum)  // 获得XLD关键点坐标。
        Rows:=[Rows, Row]
        Columns:=[Columns, Column]
    endfor
    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, Row[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]]
    
    dev_display (Intersection)
    
    gen_cross_contour_xld (StartXP, StartRow, StartColumn, 6, 0.795296)
    gen_cross_contour_xld (EndXP, EndRow, EndColumn, 6, 0.785398)
    
    * 转成点云的坐标
    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)
    
*     dev_display (Intersection)
    
    visualize_object_model_3d (WindowHandle, [StartPoint, EndPoint], [], [], [], [], [], [], [], PoseOut6)
    * 所有对点的边界点集合
    objectsOut:=[objectOut, StartPoint]
    objectsOut:=[objectOut, EndPoint]
    
    * 显示时的颜色
    Index_S:=0+Index1*2
    Index_E:=0+Index1*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

* 显示外边界模型点云。
visualize_object_model_3d (WindowHandle, [objectsOut,ObjectModel3DRigidTrans], [], [], ['colorsOut','color_88'], ['colorvaluesOut','red'], [], [], [], PoseOut2)

* 二维显示
dev_open_window (0, 0, 512, 512, 'black', WindowHandle1)
dev_set_color ('red')
gen_cross_contour_xld (Start, all_x, all_y, 3, 0.785398)


基于当前的算法稳定不好,而且有些边缘处理粗糙。最好的做法是基于法向量求解。

  • 7
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值