行业资讯
📅 2026/8/20 16:09:22
3D拟合测量水杯半径
前言示例采用的素材是2.5D图像该类型图形相对于2D图像多了深度信息。然而相对于3D点云而言2.5D图像是单视角的信息相对残缺。它只能获取物体表面的相对深度轮廓信息无法像3D点云那样提供完整的三维体积数据。维度2D 图像 (二维)2.5D 图像 (伪三维)3D 点云/模型 (真三维)数据结构仅包含平面像素信息X, Y二维平面 相对深度信息X, Y, Z’包含海量离散三维空间坐标X, Y, Z空间信息无深度信息存在透视变形单视角深度轮廓无法获取物体背面或遮挡面全维度空间信息无透视变形支持任意角度旋转核心特点技术成熟数据量小处理极快兼顾深度感知与较低算力成本适合表面形貌分析信息最完整但数据量庞大算法复杂算力要求高典型应用场景传统外观检测如颜色、字符识别、平面尺寸测量、常规OCR、人脸识别、文档扫描工业缺陷检测高反光/透明物体表面的划痕、凹凸检测、游戏开发伪3D场景、数据可视化2.5D立体地图、大屏展示自动驾驶与机器人环境感知、SLAM导航、逆向工程实物扫描建模、精密机械臂抓取、医疗影像重建、BIM建筑模型技术局限性无法区分物体前后空间关系易受光照和背景干扰旋转时会出现“信息盲区”背面细节丢失无法提供真实的三维体积数据硬件设备如3D相机、激光扫描仪成本较高点云处理与深度学习算法的开发门槛高2.5D图像转化为对象2.5D图像观察可见:相对于3D点云对象而言2.5D对象旋转时会其出现“信息盲区”背面细节丢失无法提供真实的三维体积数据。而3D点云在旋转时是可以提供完成的体积信息。如下3D点云1目的。测量水杯的半径如图所示2原理。对3D 点云对象 进行圆柱体拟合获取拟合后的半径。3注意事项。在Halcon中使用fit_primitives_object_model_3d进行圆柱体拟合时输出的primitive_parameter包含以下7个参数‌参数构成‌​ -轴线方向向量‌3个数值(a, b, c)描述圆柱体轴线的空间方向满足归一化条件a² b² c² 1. -轴线上基准点坐标‌3个数值(x0, y0, z0)表示轴线上的一个参考点通常靠近点云的重心. - ‌圆柱半径‌1个数值R单位为点云的原始坐标系单位如毫米数学验证‌圆柱表面点需满足方程(x−xp)2(y−yp)2(z−zp)2−[(x−xp)a(y−yp)b(z−zp)c]2R \sqrt{(x-x_p)^2(y-y_p)^2(z-z_p)^2-[(x-x_p)a(y-y_p)b(z-z_p)c]^2}R(x−xp​)2(y−yp​)2(z−zp​)2−[(x−xp​)a(y−yp​)b(z−zp​)c]2​R其中(x_p, y_p, z_p)为轴线上任意一点在Halcon中使用fit_primitives_object_model_3d对三维点云进行球体拟合时输出的primitive_parameter包含以下4个关键参数参数构成‌‌球心坐标‌包含3个数值(x, y, z)表示拟合球体的中心点在三维空间中的位置‌球体半径‌单个数值R单位为点云的原始坐标系单位如毫米或米参数验证方法‌‌数学验证‌球面点需满足方程(x−x0)2(y−y0)2(z−z0)2R2(x-x_0)^2(y-y_0)^2(z-z_0)^2R^2(x−x0​)2(y−y0​)2(z−z0​)2R2其中(x_0, y_0, z_0)为球心坐标与其他几何体的区别‌‌圆柱体‌输出7个参数轴线方向、基准点、半径68‌平面‌输出4个参数法向量、偏移量4代码。*参考案例库:fit_primitives_object_model_3d.hdev * *********************************************************************** * 将输入的 2.5D 图像拟合成圆柱体并计算显示拟合后的圆柱体半径 * 2.5D 图像在常规二维图像基础上叠加?**高度或深度数据**?形成半三维表达如灰度值隐含高度信息或直接存储深度通道** * 每个像素点除了常规的灰度值/颜色值,还额外记录了该点的Z Axis坐标值 * * 2.5D 图像可分解为三个通道real类型的图像这三个通道分别存储X,Y,Z轴的浮点型物理坐标值图像类型是real。 * * *********************************************************************** dev_update_off () dev_close_window () * Input: 2.5D image * tif图像是HALCON支持的?高精度图像格式专门用于存储包含复杂信息的图像数据如3D深度图、工业相机采集的点云数据等** * 一般由结构光相机3D扫描仪提供 read_image (XYZ, 3d_machine_vision/segmentation/3d_primitives_xyz_02.tif) dev_open_window_fit_image (XYZ, 0, 0, -1, -1, WindowHandle) set_display_font (WindowHandle, 16, mono, true, false) * Access to (x-, y-, z-)coordinates * XYZ图像的三个通道存储的是浮点型物理坐标值图像类型是real。 * 分别存储X Axis,Y Axis,Z Axis浮点型实际物理坐标值 * 调用get_grayval输入目标像素的RowColumn即可读取该像素点对应的浮点型物理坐标值 * x轴的坐标 access_channel (XYZ, X, 1) * y轴的坐标 access_channel (XYZ, Y, 2) * 提取第三通道作为深度 access_channel (XYZ, Z, 3) * Segment cylinder manually threshold (Z, Region, 0.0, 0.83) reduce_domain (X, Region, XTmp) dev_display (Z) dev_set_draw (margin) dev_set_line_width (2) dev_set_color (green) dev_display (Region) disp_message (WindowHandle, Segment cylinder with a simple threshold, window, 12, 12, black, true) disp_continue_message (WindowHandle, black, true) stop () * xyz_to_object_model_3d (XTmp, Y, Z, ObjectModel3DID) * 指定 3D 对象的原始类型拟合算法输出类型 ParFitting : [primitive_type,fitting_algorithm,output_xyz_mapping] ValFitting : [cylinder,least_squares_huber,true] * 对 原始对象进行 3D 拟合 fit_primitives_object_model_3d (ObjectModel3DID, ParFitting, ValFitting, ObjectModel3DOutID) * Clear the object model that is no longer used clear_object_model_3d (ObjectModel3DID) * Display the result of the fitting dev_display (Z) dev_set_draw (fill) dev_display_fitting_results (RegionCylinder, RegionSphere, RegionPlane, RegionNone, ObjectModel3DOutID, WindowHandle, []) dev_update_on () clear_object_model_3d (ObjectModel3DOutID)本地函数dev_display_fitting_results* This procedure displays the results of a fitting operation. * Additionally to the primitive regions, the radius of * cylinders and spheres is displayed. * The colors can be specified with the parameter Colors * in the following manner: * Color[0] is used for objects which could not be fitted * Color[1] is used for cylinders用于圆柱体 * Color[2] is used for spheres用于球体 * Color[3] is used for planes用于平面 * if (Colors []) Colors : [dim gray,forest green,red,slate blue] endif NumNone : 0 * 圆柱体数量 NumCylinders : 0 * 球体数量 NumSpheres : 0 * 平面数量 NumPlanes : 0 for Index : 0 to |ObjectModel3DOutID| - 1 by 1 object_model_3d_to_xyz (XTmp, YTmp, ZTmp, ObjectModel3DOutID[Index], from_xyz_map, [], []) get_domain (XTmp, DomainTmp) * 是否存在原始数据 get_object_model_3d_params (ObjectModel3DOutID[Index], has_primitive_data, ParamValue) if (ParamValue true) get_object_model_3d_params (ObjectModel3DOutID[Index], primitive_parameter, GenParamValuesP) get_object_model_3d_params (ObjectModel3DOutID[Index], primitive_type, ParamValue) if (ParamValue cylinder) if (NumCylinders 0) *-1:表示复制从索引开始剩余的所有对象注意这里是浅复制 copy_obj (DomainTmp, RegionCylinder, 1, -1) * 从拟合的原始数据中获取拟合的圆柱体半径值 * GenParamValuesP7个值分别是 * 圆柱体中心点的 X、Y、Z 坐标圆柱体主轴的单位方向向量圆柱体的半径 RadiusCylinder : GenParamValuesP[6] else concat_obj (RegionCylinder, DomainTmp, RegionCylinder) RadiusCylinder : [RadiusCylinder,GenParamValuesP[6]] endif NumCylinders : NumCylinders 1 elseif (ParamValue sphere) * 球体情况 if (NumSpheres 0) copy_obj (DomainTmp, RegionSphere, 1, -1) RadiusSphere : GenParamValuesP[3] else concat_obj (RegionSphere, DomainTmp, RegionSphere) RadiusSphere : [RadiusSphere,GenParamValuesP[3]] endif NumSpheres : NumSpheres 1 else * 平面情况 if (NumPlanes 0) copy_obj (DomainTmp, RegionPlane, 1, -1) else concat_obj (RegionPlane, DomainTmp, RegionPlane) endif NumPlanes : NumPlanes 1 endif else if (NumNone 0) copy_obj (DomainTmp, RegionNone, 1, -1) else concat_obj (RegionNone, DomainTmp, RegionNone) endif NumNone : NumNone 1 endif endfor * NumColors : |Colors| if (NumNone 0) dev_set_color (Colors[0 % NumColors]) dev_display (RegionNone) endif if (NumCylinders 0) dev_set_color (Colors[1 % NumColors]) dev_display (RegionCylinder) endif if (NumSpheres 0) dev_set_color (Colors[2 % NumColors]) dev_display (RegionSphere) endif if (NumPlanes 0) dev_set_color (Colors[3 % NumColors]) dev_display (RegionPlane) endif disp_message (WindowHandle, 3D Fitting, window, -1, -1, black, true) Message : Cylinders: NumCylinders Message[1] : Spheres: NumSpheres Message[2] : Planes: NumPlanes Message[3] : Undefined: NumNone disp_message (WindowHandle, Message, window, 40, 12, black, true) if (NumCylinders 0) * Display radius for each cylinder area_center (RegionCylinder, Area, Row, Column) for Index : 0 to NumCylinders - 1 by 1 Radius : int(RadiusCylinder[Index] * 1000) disp_message (WindowHandle, Cylinder\nr Radius mm, image, Row[Index], Column[Index], white, false) endfor endif if (NumSpheres 0) * Display radius for each cylinder sphere area_center (RegionSphere, Area, Row, Column) for Index : 0 to NumSpheres - 1 by 1 Radius : int(RadiusSphere[Index] * 1000) disp_message (WindowHandle, Sphere\nr Radius mm, image, Row[Index], Column[Index], white, false) endfor endif return ()