1,目的
筛选出目标3D对象。
效果如下:
2,原理
- 使用3D对象的体积与直径特征进行筛选。
3,代码解析
3.1,预处理2.5D深度图。
* 参考案例库:select_object_model_3d.hdev
* ************************************************************
* 目的:
* 筛选所需要的3D模型
* 原理:
* 基于3D对象的体积与直径特征进行筛选
* ************************************************************
*
dev_update_off ()
dev_close_window ()
* Load X,Y,Z-Data, scale them to meter and generate a 3D object model
ImagePath := 'time_of_flight/'
* 加载2.5D深度图(带深度信息的图像)
read_image (Image, ImagePath + 'engine_cover_xyz_01')
* 将深度值(Z通道)缩小1000倍(实质是单位:mm->m)
scale_image (Image, Image, .001, .0)
* 长宽放大2倍用于增加细节观察
zoom_image_factor (Image, Image, 2, 2, 'constant')
decompose3 (Image, X, Y, Z)
xyz_to_object_model_3d (X, Y, Z, ObjectModel3DID)
* Compute a mesh (Delauney triangulation) of the model
prepare_object_model_3d (ObjectModel3DID, 'segmentation', 'true', [], [])
释疑解惑*
1,engine_cover_xyz-01.tif
是什么图?
2.5D图
,是通过深度传感器(如结构光相机)获取的二维投影深度图。每个像素存储三维坐标值(X/Y/Z轴),非传统RGB或灰度数据,像素值以浮点型(real
)存储物理空间位置,单位为毫米级精度。
2,zoom_image_factor
对效果的影响?
zoom_image_factor (Image, Image, 2, 2, 'constant')
显示效果:
zoom_image_factor (Image, Image, 1, 1, 'constant')
显示效果:
对比可知:长宽放大2倍可增加细节观察
3,prepare_object_model_3d
算子的作用?
用于优化 3D 对象模型(点云或网格)的核心预处理算子,其主要功能是为后续三维视觉任务(如匹配、分割、测量)提供标准化输入。
核心功能与技术细节
数据规范化
统一不同来源的 3D 数据格式(点云、网格模型等),修复拓扑缺陷(如孔洞填充、噪声过滤)。
关键参数:
GenParamNames
:指定预处理选项(如'max_area_holes'
控制孔洞填充面积阈值)。GenParamValues
:设置参数值(如'sampling'
调节点云采样密度)。
几何特征计算
- 自动生成法向量、曲率等几何属性,为基于形状的分割(
segment_object_model_3d
)或匹配(create_shape_model_3d
)提供基础特征。
- 自动生成法向量、曲率等几何属性,为基于形状的分割(
多分辨率支持
- 支持生成多层级细节模型(LOD),适应不同精度的处理需求,提升算法效率。
工业检测流程
预处理后提升后续算法效率 20%+
例如:
- 修复扫描点云的孔洞(
'max_area_holes'
设为实际缺陷尺寸)。 - 计算法向量辅助钣金件平面分割。
- 关键参数配置指南
参数 | 作用 | 典型值示例 |
---|---|---|
Purpose |
指定预处理目标: - 'shape_based_matching_3d' (匹配) - 'segmentation' (分割) |
'segmentation' |
GenParamNames |
参数名数组: - 'point_coord_ranges' (坐标范围过滤) - 'distance_to' (邻近点距离) |
['sampling','max_area_holes'] |
GenParamValues |
对应参数值: - 采样密度 0.01 (相对模型直径) - 最大孔洞面积 5.0 (mm²) |
[0.02, 10.0] |
与其他算子的协同应用
分割优化:预处理后输入
segment_object_model_3d
,支持基于曲率/颜色的智能分割。距离计算:为
distance_object_model_3d
提供拓扑完整的模型,确保距离精度。位姿调整:配合
rigid_trans_object_model_3d
实现坐标变换前的数据规范化。
注意事项
- 必要性:若不调用该算子,后续操作(如分割)可能因缺失拓扑信息而失败或低效。
- 性能平衡:过高的采样密度(
'sampling'
)会增大内存开销,需根据任务需求权衡。
示例:轴承检测中,通过
prepare_object_model_3d
填充球体表面扫描缺失点,使gen_sphere_object_model_3d
生成的参考模型与实际点云精确对齐212。
作用前:
作用后:
3.2,去除背景,断开连接域
* Prepare the visualization and display the 3D object model
create_pose (0.058, -0.165, 0.660, 345.0, 355.0, 356.0, 'Rp+T', 'gba', 'point', Pose)
*
* Instructions for visualize_object_model_3d
Instructions[0] := 'Rotate: Left button'
Instructions[1] := 'Zoom: Shift + left button'
Instructions[2] := 'Move: Ctrl + left button'
* Configuration
CamParam := [0.01,0,7e-6,7e-6,352,288,710,576]
GenParamName := ['color','disp_pose','alpha','intensity']
GenParamValue := ['green','false',0.8,'none']
*
dev_open_window (0, 0, 710, 576, 'black', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
*
visualize_object_model_3d (WindowHandle, ObjectModel3DID, CamParam, Pose, GenParamName, GenParamValue, 'This scene will be segmented into single objects', [], Instructions, Pose)
*
* Threshold the 3D object Model
MinValue := 0.500
MaxValue := 0.670
* 去除背景,筛选所需要的点云
select_points_object_model_3d (ObjectModel3DID, 'point_coord_z', MinValue, MaxValue, ObjectModel3DIDReduced)
visualize_object_model_3d (WindowHandle, ObjectModel3DIDReduced, CamParam, Pose, GenParamName, GenParamValue, 'Result after thresholding at z=' + (MaxValue * 1e3)$'.3' + 'mm from the camera', [], Instructions, Pose)
*
* Calculate the connected components and the volume and diameter
* of each of the resulting object
GenParamName[0] := 'colored'
GenParamValue[0] := 12
* 断开连接域
connection_object_model_3d (ObjectModel3DIDReduced, 'distance_3d', 0.010, ObjectModel3DIDConnections)
ObjectModel3DIDConnections
如图所示:
3.3,计算特征量:体积与直径
* 计算3D对象的相对于平面的体积
volume_object_model_3d_relative_to_plane (ObjectModel3DIDConnections, [0,0,MaxValue,0,0,0,0], 'signed', 'true', Volume)
* 计算3D对象的最大直径
max_diameter_object_model_3d (ObjectModel3DIDConnections, Diameter)
*
* Display the results
dev_open_window (0, 720, 400, 576, 'black', WindowHandle1)
set_display_font (WindowHandle1, 14, 'mono', 'true', 'false')
Indices := [0:|ObjectModel3DIDConnections| - 1]
disp_message (WindowHandle1, ['Features of the connected components:',' ',' '], 'window', 12, 12, 'white', 'false')
ResultMessage := ' # Max. diameter Volume'
Sequence := [0:|ObjectModel3DIDConnections| - 1]
ResultMessage := [ResultMessage,Sequence$' 3' + ' ' + (Diameter * 1e3)$'7.1f' + ' mm ' + (Volume * 1e3)$'7.3f' + ' dm³']
disp_message (WindowHandle1, ResultMessage, 'window', 50, 12, 'white', 'false')
dev_set_window (WindowHandle)
visualize_object_model_3d (WindowHandle, ObjectModel3DIDConnections, CamParam, Pose, GenParamName, GenParamValue, 'Found ' + |ObjectModel3DIDConnections| + ' connected components', '#' + Indices, Instructions, Pose)
释疑解惑
1,volume_object_model_3d_relative_to_plane
的作用?
volume_object_model_d_relative_to_plane(
: :
ObjectModel3D, // 输入3D模型句柄
Plane, // 参考平面位姿或平面方程
Mode, // 体积计算模式
UseFaceOrientation // 是否考虑面片方向
: Volume // 输出体积值
)
- 算子功能
计算3D对象模型相对于参考平面的体积分布,支持半空间体积分析和方向敏感计算。
参数详解
ObjectModel3D
类型:输入对象
要求:必须为三角化网格或包含多边形集合的3D模型。
注意:若网格非封闭或面片不连续,计算结果受
Mode
和UseFaceOrientation
参数影响。
Plane
定义:标准平面方程参数
[a, b, c, d]
,对应方程ax + by + cz + d = 0
。获取方式
- 通过
fit_primitives_object_model_3d
拟合点云平面; - 手动定义(如
[0, 0, 1, -100]
表示z=100
的平面)。
- 通过
Mode
控制体积计算模式,可选值及含义:
模式 | 计算逻辑 | 应用场景 |
---|---|---|
'signed' |
返回平面以上(正)和以下(负)体积的代数和(例:80 + (-40) = 40 ) |
需要方向信息的平衡分析 |
'unsigned' |
返回平面上下体积绝对值之和(例:` | 80 |
'positive' |
仅计算平面以上体积(正值) | 凸起特征测量(如焊接高度) |
'negative' |
仅计算平面以下体积(自动取绝对值) | 凹陷或容器液位分析 |
UseFaceOrientation
- **
'true'
**:考虑三角面片的法向方向,精确判断面片与平面的相对位置(适用于CAD模型)。
- **
'false'
**:仅根据顶点位置判断面片在平面上/下(适用于点云数据)。
- **
Volume
- 输出:根据
Mode
返回对应的体积值(单位与模型坐标一致)。
- 输出:根据
工业应用示例
注塑件毛刺检测
- 定义分型面平面,使用
'positive'
模式检测凸出异常体积。
- 定义分型面平面,使用
容器液位测量
- 设置液面平面,通过
'negative'
模式计算液体体积。
- 设置液面平面,通过
注意事项
模型质量:网格法向一致性会影响方向敏感模式(
UseFaceOrientation='true'
)的结果精度19。性能优化:对非封闭模型,优先使用
'false'
模式以减少计算开销11。
Plane
效果演示:
3.4,筛选出3D对象
* Select components by their volume and maximal diameter
*
MinVolume := 0.35e-003
MaxVolume := 1.0e-003
MinDiameter := 185.0e-003
MaxDiameter := 300.0e-003
* *** Attention:
* select_object_model_3d uses the plane [0,0,0,0,0,0]
* for the volume calculation! Therefore we have
* to transform the 3d object models, so that the
* reference plane (as defined in the former call to
* volume_object_model_3d_relative_to_plane) coincides to the
* default plane.
hom_mat3d_identity (HomMat3DIdentity)
hom_mat3d_translate (HomMat3DIdentity, 0, 0, -MaxValue, HomMat3DTranslation)
hom_mat3d_invert (HomMat3DTranslation, HomMat3DInvert)
affine_trans_object_model_3d (ObjectModel3DIDConnections, HomMat3DTranslation, ObjectModel3DTranslated)
* Set a label for each part
for Index := 0 to |ObjectModel3DIDConnections| - 1 by 1
set_object_model_3d_attrib_mod (ObjectModel3DTranslated[Index], '&Index', [], Index)
endfor
*
volume_object_model_3d_relative_to_plane (ObjectModel3DTranslated, [0,0,0,0,0,0,0], 'signed', 'true', Volume1)
select_object_model_3d (ObjectModel3DTranslated, ['volume','diameter_object'], 'and', [MinVolume,MinDiameter], [MaxVolume,MaxDiameter], ObjectModel3DSelected)
*
Title := ['Parts selected by using the following features: ',' ' + (MinVolume * 1e3)$'3.1f' + ' dm³ <= volume <= ' + (MaxVolume * 1e3)$'3.1f' + ' dm³','and: ' + (MinDiameter * 1e3)$'.1f' + ' mm <= max. diameter <= ' + (MaxDiameter * 1e3)$'.1f' + ' mm']
* Create the labels
Label := []
for Index := 0 to |ObjectModel3DSelected| - 1 by 1
get_object_model_3d_params (ObjectModel3DSelected[Index], '&Index', FormerIndex)
Label := [Label,'#' + FormerIndex]
endfor
*
if (|ObjectModel3DSelected| > 1)
visualize_object_model_3d (WindowHandle, ObjectModel3DSelected, CamParam, [], GenParamName, GenParamValue, Title, Label, Instructions, Pose)
else
Message := 'No object left after using the following features: '
Message[1] := ' ' + (MinVolume * 1e3)$'3.1f' + ' dm³ <= volume <= ' + (MaxVolume * 1e3)$'3.1f' + ' dm³'
Message[2] := 'and: ' + (MinDiameter * 1e3)$'.1f' + ' mm <= max. diameter <= ' + (MaxDiameter * 1e3)$'.1f' + ' mm'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
endif
*
* Clear the 3d object models
dev_set_window (WindowHandle1)
dev_close_window ()
clear_object_model_3d ([ObjectModel3DID,ObjectModel3DIDReduced,ObjectModel3DSelected,ObjectModel3DTranslated,ObjectModel3DIDConnections])
筛选结果:
4,完整代码。
* 参考案例库:select_object_model_3d.hdev
* ************************************************************
* 目的:
* 筛选所需要的3D模型
* 原理:
* 基于3D对象的体积与直径特征进行筛选
* ************************************************************
*
dev_update_off ()
dev_close_window ()
* Load X,Y,Z-Data, scale them to meter and generate a 3D object model
ImagePath := 'time_of_flight/'
* 加载2.5D深度图(带深度信息的图像)
read_image (Image, ImagePath + 'engine_cover_xyz_01')
* 将深度值(Z通道)缩小1000倍(实质是单位:mm->m)
scale_image (Image, Image, .001, .0)
* 长宽放大2倍用于增加细节观察
zoom_image_factor (Image, Image, 2,2, 'constant')
decompose3 (Image, X, Y, Z)
xyz_to_object_model_3d (X, Y, Z, ObjectModel3DID)
* Compute a mesh (Delauney triangulation) of the model
prepare_object_model_3d (ObjectModel3DID, 'segmentation', 'true', [], [])
*
* Prepare the visualization and display the 3D object model
create_pose (0.058, -0.165, 0.660, 345.0, 355.0, 356.0, 'Rp+T', 'gba', 'point', Pose)
*
* Instructions for visualize_object_model_3d
Instructions[0] := 'Rotate: Left button'
Instructions[1] := 'Zoom: Shift + left button'
Instructions[2] := 'Move: Ctrl + left button'
* Configuration
CamParam := [0.01,0,7e-6,7e-6,352,288,710,576]
GenParamName := ['color','disp_pose','alpha','intensity']
GenParamValue := ['green','false',0.8,'none']
*
dev_open_window (0, 0, 710, 576, 'black', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
*
visualize_object_model_3d (WindowHandle, ObjectModel3DID, CamParam, Pose, GenParamName, GenParamValue, 'This scene will be segmented into single objects', [], Instructions, Pose)
*
* Threshold the 3D object Model
MinValue := 0.500
MaxValue := 0.670
* 去除背景,筛选所需要的点云
select_points_object_model_3d (ObjectModel3DID, 'point_coord_z', MinValue, MaxValue, ObjectModel3DIDReduced)
visualize_object_model_3d (WindowHandle, ObjectModel3DIDReduced, CamParam, Pose, GenParamName, GenParamValue, 'Result after thresholding at z=' + (MaxValue * 1e3)$'.3' + 'mm from the camera', [], Instructions, Pose)
*
* Calculate the connected components and the volume and diameter
* of each of the resulting object
GenParamName[0] := 'colored'
GenParamValue[0] := 12
* 断开连接域
connection_object_model_3d (ObjectModel3DIDReduced, 'distance_3d', 0.010, ObjectModel3DIDConnections)
* gen_plane_object_model_3d ([0,0,MaxValue,0,0,0,0], [-0.5,-0.5,0.5,0.5], [0.5,-0.5,-0.5,0.5],plane01)
* visualize_object_model_3d (WindowHandle, [plane01,ObjectModel3DIDConnections], [], [],\
['color_0','color_'+[1:|ObjectModel3DIDConnections|-1],'alpha_0','disp_pose'], ['orange',gen_tuple_const(|ObjectModel3DIDConnections|-1,'green') ,0.7,'true'], [], [], [], PoseOut)
* 计算3D对象的相对于平面的体积
volume_object_model_3d_relative_to_plane (ObjectModel3DIDConnections, [0,0,MaxValue,0,0,0,0], 'negative', 'true', Volume)
* 计算3D对象的最大直径
max_diameter_object_model_3d (ObjectModel3DIDConnections, Diameter)
*
* Display the results
dev_open_window (0, 720, 400, 576, 'black', WindowHandle1)
set_display_font (WindowHandle1, 14, 'mono', 'true', 'false')
Indices := [0:|ObjectModel3DIDConnections| - 1]
disp_message (WindowHandle1, ['Features of the connected components:',' ',' '], 'window', 12, 12, 'white', 'false')
ResultMessage := ' # Max. diameter Volume'
Sequence := [0:|ObjectModel3DIDConnections| - 1]
ResultMessage := [ResultMessage,Sequence$' 3' + ' ' + (Diameter * 1e3)$'7.1f' + ' mm ' + (Volume * 1e3)$'7.3f' + ' dm³']
disp_message (WindowHandle1, ResultMessage, 'window', 50, 12, 'white', 'false')
dev_set_window (WindowHandle)
visualize_object_model_3d (WindowHandle, ObjectModel3DIDConnections, CamParam, Pose, GenParamName, GenParamValue, 'Found ' + |ObjectModel3DIDConnections| + ' connected components', '#' + Indices, Instructions, Pose)
*
* Select components by their volume and maximal diameter
*
MinVolume := 0.35e-003
MaxVolume := 1.0e-003
MinDiameter := 185.0e-003
MaxDiameter := 300.0e-003
* *** Attention:
* select_object_model_3d uses the plane [0,0,0,0,0,0]
* for the volume calculation! Therefore we have
* to transform the 3d object models, so that the
* reference plane (as defined in the former call to
* volume_object_model_3d_relative_to_plane) coincides to the
* default plane.
hom_mat3d_identity (HomMat3DIdentity)
hom_mat3d_translate (HomMat3DIdentity, 0, 0, -MaxValue, HomMat3DTranslation)
hom_mat3d_invert (HomMat3DTranslation, HomMat3DInvert)
affine_trans_object_model_3d (ObjectModel3DIDConnections, HomMat3DTranslation, ObjectModel3DTranslated)
* Set a label for each part
for Index := 0 to |ObjectModel3DIDConnections| - 1 by 1
set_object_model_3d_attrib_mod (ObjectModel3DTranslated[Index], '&Index', [], Index)
endfor
*
volume_object_model_3d_relative_to_plane (ObjectModel3DTranslated, [0,0,0,0,0,0,0], 'signed', 'true', Volume1)
select_object_model_3d (ObjectModel3DTranslated, ['volume','diameter_object'], 'and', [MinVolume,MinDiameter], [MaxVolume,MaxDiameter], ObjectModel3DSelected)
*
Title := ['Parts selected by using the following features: ',' ' + (MinVolume * 1e3)$'3.1f' + ' dm³ <= volume <= ' + (MaxVolume * 1e3)$'3.1f' + ' dm³','and: ' + (MinDiameter * 1e3)$'.1f' + ' mm <= max. diameter <= ' + (MaxDiameter * 1e3)$'.1f' + ' mm']
* Create the labels
Label := []
for Index := 0 to |ObjectModel3DSelected| - 1 by 1
get_object_model_3d_params (ObjectModel3DSelected[Index], '&Index', FormerIndex)
Label := [Label,'#' + FormerIndex]
endfor
*
if (|ObjectModel3DSelected| > 1)
visualize_object_model_3d (WindowHandle, ObjectModel3DSelected, CamParam, [], GenParamName, GenParamValue, Title, Label, Instructions, Pose)
else
Message := 'No object left after using the following features: '
Message[1] := ' ' + (MinVolume * 1e3)$'3.1f' + ' dm³ <= volume <= ' + (MaxVolume * 1e3)$'3.1f' + ' dm³'
Message[2] := 'and: ' + (MinDiameter * 1e3)$'.1f' + ' mm <= max. diameter <= ' + (MaxDiameter * 1e3)$'.1f' + ' mm'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
endif
*
* Clear the 3d object models
dev_set_window (WindowHandle1)
dev_close_window ()
clear_object_model_3d ([ObjectModel3DID,ObjectModel3DIDReduced,ObjectModel3DSelected,ObjectModel3DTranslated,ObjectModel3DIDConnections])