Halcon实战:基于surface_fusion的多相机3D表面重建技术详解
一、引言
在工业机器视觉领域,多视图立体视觉(MVS)是实现三维重建的核心技术之一。它通过从不同视角拍摄的多张二维图像,计算像素间的视差,进而恢复出场景的三维结构。本案例详细展示了如何使用Halcon的surface_fusion方法,对多相机采集的图像序列进行3D表面重建。
surface_fusion方法是Halcon提供的一种高级3D重建技术,它建立在surface_pairwise(成对匹配)的基础上,通过融合来自多个相机对的重建结果,生成一个更完整、更精确的三维表面模型。这种方法特别适用于需要高精度、高完整性3D模型的场景,如零部件检测、逆向工程和质量控制。
二、核心知识点铺垫
1. 多相机系统与相机模型
一个典型的多相机3D重建系统由多个固定在不同位置的相机组成。在进行重建前,必须通过相机标定过程获取每个相机的内参(如焦距、主点)和外参(如位置、姿态)。这些参数被保存在相机设置模型(.csm文件)中,供重建算法使用。
2. 视差计算(Disparity Calculation)
视差是指同一物理点在不同相机图像上的投影位置差异。它是三维重建的基础。Halcon提供了多种视差计算方法,如binocular_disparity,可以通过设置不同的匹配算法(如NCC)、窗口大小和过滤选项来优化视差图的质量。
3.surface_pairwise与surface_fusion
surface_pairwise:该方法首先对每一对相机拍摄的图像进行立体匹配,计算出视差图,然后通过三角测量原理,将视差图转换为稀疏的三维点云。surface_fusion:该方法以surface_pairwise生成的多组稀疏点云为输入,通过一种融合算法,将这些点云合并并优化,最终生成一个连续、光滑的三维表面模型。
4. 关键参数
Resolution:定义了重建后3D模型的体素(Voxel)大小。分辨率越高,模型越精细,但计算量和内存消耗也越大。BoundingBox:定义了3D重建的空间范围。只有在该范围内的点才会被重建,合理设置可以显著减少计算量。SurfaceTolerance:表面容差,用于控制表面重建的平滑程度和精度。
三、核心算子列表
| 算子名 | 核心功能 |
|---|---|
read_camera_setup_model | 读取相机设置模型文件(.csm),获取相机内外参。 |
create_stereo_model | 创建一个多视图立体模型,并指定重建方法(如’surface_fusion’)。 |
set_stereo_model_param | 设置立体模型的各种参数,如视差计算方法、分辨率、边界框等。 |
set_stereo_model_image_pairs | 定义用于立体匹配的相机图像对。 |
reconstruct_surface_stereo | 执行3D表面重建,生成最终的3D物体模型。 |
get_stereo_model_object_model_3d | 获取重建过程中生成的中间结果(如’surface_pairwise’的点云)。 |
visualize_object_model_3d | 可视化显示3D物体模型,支持旋转、缩放和平移交互。 |
clear_stereo_model | 清除立体模型,释放内存。 |
clear_object_model_3d | 清除3D物体模型,释放内存。 |
四、完整代码+中文注释(// 格式)
// 【示例说明】本示例演示如何使用 'surface_fusion' 方法从多个相机的图像中重建多个物体的3D模型。 // 核心流程:加载相机模型 -> 创建立体模型 -> 设置参数 -> 循环重建并显示结果。 dev_close_window () // 关闭当前窗口 dev_update_off () // 关闭窗口更新,提高运行效率 dev_open_window (0, 0, 512, 512, 'black', WindowHandle) // 打开一个新窗口 dev_resize_window_fit_size (0, 0, 1024, 600, -1, -1) // 调整窗口大小以适应显示 set_display_font (WindowHandle, 14, 'mono', 'true', 'false') // 设置显示字体 // 定义交互说明信息 Instructions := 'Rotate: Left button' Instructions[1] := 'Zoom: Shift + left button' Instructions[2] := 'Move: Ctrl + left button' // 显示介绍信息 Message := 'This example reconstructs several 3D objects using the method \'surface_fusion\'.' Message[2] := ' ' Message[3] := 'The \'surface_fusion\' method uses the results of the method \'surface_pairwise\' as' Message[4] := 'input for the fusion algorithm. Therefore, the pairwise parameters have to be' Message[5] := 'configured as well.' Message[6] := ' ' Message[7] := 'For all reconstructions, the same parameter settings are used. ' Message[8] := 'It is possible to tweak the parameters to optimally fit one particular object.' Message[9] := 'This will improve the reconstruction results even further.' dev_disp_text (Message, 'window', 12, 12, 'white', 'box', 'false') // 显示多行文本 dev_disp_text ('Press Run (F5) to continue', 'window', 'bottom', 'right', 'black', [], []) // 显示底部提示 stop () // 暂停,等待用户按键 // 【重建分辨率选择】 // 为了演示目的,使用相对较低的分辨率,以减少运行时间。 // 如果追求更高精度,可以将此参数设置为false。 FastReconstruction := true // 根据分辨率选择设置参数 if (FastReconstruction) Resolution := 0.0012 // 设置重建分辨率为1.2毫米 Info := ', coarse resolution' // 记录分辨率信息 else Resolution := 0.0006 // 设置重建分辨率为0.6毫米 Info := ', fine resolution' // 记录分辨率信息 endif SurfaceTolerance := 2 * Resolution // 设置表面容差为分辨率的两倍 // 【加载相机模型】 read_camera_setup_model ('cam_setup_model.csm', CameraSetupModelID) // 读取相机设置模型文件 // 获取相机数量 get_camera_setup_param (CameraSetupModelID, 'general', 'num_cameras', NumCameras) // 【创建立体模型】 // 使用 'surface_fusion' 方法创建一个多视图立体模型 create_stereo_model (CameraSetupModelID, 'surface_fusion', [], [], StereoModelID) clear_camera_setup_model (CameraSetupModelID) // 清除相机设置模型,释放内存 // 【配置立体模型参数】 // 设置图像校正的插值方法为双线性插值 set_stereo_model_param (StereoModelID, 'rectif_interpolation', 'bilinear') // 定义用于立体匹配的相机图像对(这里使用相机0与相机1、相机0与相机2的组合) set_stereo_model_image_pairs (StereoModelID, [0,0], [1,2]) // 设置视差计算方法为 'binocular' set_stereo_model_param (StereoModelID, 'disparity_method', 'binocular') // 设置双目匹配算法为归一化互相关(NCC) set_stereo_model_param (StereoModelID, 'binocular_method', 'ncc') // 设置匹配窗口大小为11x11 set_stereo_model_param (StereoModelID, 'binocular_mask_width', 11) set_stereo_model_param (StereoModelID, 'binocular_mask_height', 11) // 启用左右一致性检查以提高匹配的鲁棒性 set_stereo_model_param (StereoModelID, 'binocular_filter', 'left_right_check') // 使用插值方法计算亚像素级视差,提高精度 set_stereo_model_param (StereoModelID, 'binocular_sub_disparity', 'interpolation') // 【循环处理多个物体数据集】 NumObjects := 5 // 物体总数 for I := 1 to NumObjects by 1 // 读取当前物体的所有相机图像 read_image (Images, '3d_machine_vision/multi_view/engine_part_cam_' + [0:2] + '_0' + I) // 将图像拼接起来以便显示 tile_images (Images, TiledImage, 2, 'vertical') // 【设置重建边界框】 // 根据不同物体设置不同的3D重建空间范围 if (I == 1) BoundingBox := [-0.134,-0.043,-0.005,-0.022,0.067,0.042] elseif (I == 2) BoundingBox := [-0.135,-0.039,-0.005,-0.02,0.075,0.035] elseif (I == 3 or I == 4) BoundingBox := [-0.14,-0.048,-0.005,-0.018,0.088,0.040] elseif (I == 5) BoundingBox := [-0.147,-0.077,-0.005,-0.02,0.088,0.04] endif set_stereo_model_param (StereoModelID, 'bounding_box', BoundingBox) // 启用持久化模式,以便获取 'surface_pairwise' 的中间结果 set_stereo_model_param (StereoModelID, 'persistence', 1) // 设置点云网格化方法为 'isosurface',生成连续的表面 set_stereo_model_param (StereoModelID, 'point_meshing', 'isosurface') // 设置重建分辨率 set_stereo_model_param (StereoModelID, 'resolution', Resolution) // 设置表面容差 set_stereo_model_param (StereoModelID, 'surface_tolerance', SurfaceTolerance) // 设置结果的颜色属性为 'median'(中值颜色) set_stereo_model_param (StereoModelID, 'color', 'median') // 如果是快速重建,增加平滑程度以减少噪点 if (FastReconstruction) set_stereo_model_param (StereoModelID, 'smoothing', 1.5) endif // 显示当前处理的图像 dev_resize_window_fit_image (TiledImage, 0, 0, -1, -1) get_part (WindowHandle, Row1, Column1, Row2, Column2) dev_clear_window () dev_display (TiledImage) dev_disp_text ('Reconstruct scene from 3 different views. Please wait...', 'window', 12, 12, 'black', [], []) // 【执行3D重建】 count_seconds (S1) // 记录开始时间 reconstruct_surface_stereo (Images, StereoModelID, OM3DFusion) // 执行表面融合重建 count_seconds (S2) // 记录结束时间 // 获取 'surface_pairwise' 方法生成的中间3D模型(点云) get_stereo_model_object_model_3d (StereoModelID, 'm3d_pairwise', OM3DPairwise) // 创建一个可视化用的位姿(Pose) create_pose (0.026, -0.07, 1.9, 330, 345, 300, 'Rp+T', 'gba', 'point', VisPose) // 【可视化显示结果】 // 1. 显示 'surface_pairwise' 的中间结果(橙色点云) Title := 'Intermediate result (reconstructed using \'surface_pairwise\'' + Info + ') (' + I + '/' + NumObjects + ')' visualize_object_model_3d (WindowHandle, OM3DPairwise, [], VisPose, ['color','point_size'], ['orange',1], Title, [], Instructions, VisPose) // 2. 显示 'surface_fusion' 的融合结果 Title := 'Reconstructed object model using \'surface_fusion\'' + Info + ' (' + I + '/' + NumObjects + ')' visualize_object_model_3d (WindowHandle, OM3DFusion, [], VisPose, [], [], Title, [], Instructions, VisPose) // 3. 显示最终的、带颜色和三角化的融合结果,并显示重建时间 Title := 'Final result (colored and triangulated' + Info + ') (' + I + '/' + NumObjects + ')\nReconstruction time: ' + (S2 - S1)$'.2' + ' s (Resolution ' + (Resolution * 1000) + ' mm)' visualize_object_model_3d (WindowHandle, OM3DFusion, [], VisPose, 'color_attrib', 'red', Title, [], Instructions, VisPose) // 清理当前物体的3D模型,释放内存 clear_object_model_3d (OM3DPairwise) clear_object_model_3d (OM3DFusion) endfor // 清理立体模型,释放内存 clear_stereo_model (StereoModelID)五、核心算子深度剖析
1.create_stereo_model
功能
创建一个多视图立体视觉模型,是进行3D重建的入口。该算子会根据指定的相机设置模型和重建方法,初始化内部数据结构。
参数说明
| 参数名 | 含义 | 示例值 |
|---|---|---|
CameraSetupModelID | 输入相机设置模型的句柄,包含了所有相机的内外参数。 | CameraSetupModelID |
Method | 指定3D重建的方法。 | 'surface_fusion' |
GenParamName | 可选的通用参数名列表。 | [] |
GenParamValue | 可选的通用参数值列表。 | [] |
StereoModelID | 输出新创建的立体模型的句柄。 | StereoModelID |
2.set_stereo_model_param
功能
设置立体模型的各种参数,以控制重建过程的各个方面。这是优化重建效果的关键。
常用参数说明
| 参数名 | 含义 | 常用取值 |
|---|---|---|
'disparity_method' | 视差计算方法。 | 'binocular' |
'binocular_method' | 双目匹配算法。 | 'ncc','sad' |
'binocular_mask_width' | 匹配窗口宽度。 | 5, 7, 9, 11 |
'binocular_mask_height' | 匹配窗口高度。 | 5, 7, 9, 11 |
'bounding_box' | 3D重建的空间范围。 | [XMin, YMin, ZMin, XMax, YMax, ZMax] |
'resolution' | 3D模型的体素分辨率。 | 0.001(1mm) |
'surface_tolerance' | 表面重建的容差。 | 2 * Resolution |
'color' | 输出3D模型的颜色属性。 | 'median','nearest' |
3.reconstruct_surface_stereo
功能
执行3D表面重建。该算子是整个流程的核心,它会使用之前设置好的所有参数和相机模型,对输入的多张图像进行处理,最终生成一个三维物体模型。
参数说明
| 参数名 | 含义 | 示例值 |
|---|---|---|
Images | 输入的多张相机图像。 | Images |
StereoModelID | 立体模型的句柄。 | StereoModelID |
ObjectModel3D | 输出的重建结果,是一个3D物体模型句柄。 | OM3DFusion |
4.get_stereo_model_object_model_3d
功能
获取在reconstruct_surface_stereo执行过程中生成的中间或附加的3D物体模型。
参数说明
| 参数名 | 含义 | 示例值 |
|---|---|---|
StereoModelID | 立体模型的句柄。 | StereoModelID |
ObjectName | 要获取的3D物体模型的名称。 | 'm3d_pairwise' |
ObjectModel3D | 输出获取到的3D物体模型句柄。 | OM3DPairwise |
六、全流程解析
步骤1:环境初始化与参数设置
代码首先关闭了不必要的窗口更新,打开了一个新的显示窗口,并设置了字体。然后定义了一个布尔变量FastReconstruction来选择不同的重建分辨率,这直接影响了重建的速度和精度。
步骤2:加载相机模型
通过read_camera_setup_model读取相机配置文件(.csm),该文件包含了进行三维重建所必需的相机内外参数。
步骤3:创建并配置立体模型
使用create_stereo_model创建了一个基于'surface_fusion'方法的立体模型。接着,通过一系列set_stereo_model_param调用,详细配置了视差计算、图像对选择、重建分辨率、边界框等关键参数。
步骤4:循环处理多个物体
代码对5个不同的物体进行了循环处理:
- 读取图像:读取当前物体的所有相机视图图像。
- 设置边界框:根据物体的大小和位置,设置合适的3D重建空间范围。
- 执行重建:调用
reconstruct_surface_stereo进行3D表面融合重建,并记录重建时间。 - 获取中间结果:使用
get_stereo_model_object_model_3d获取'surface_pairwise'方法生成的中间点云结果。 - 可视化结果:使用
visualize_object_model_3d分别显示了中间的点云结果、最终的融合表面模型以及带有颜色和三角化的最终模型,方便用户进行观察和比较。 - 资源清理:在每次循环结束后,清理当前物体的3D模型,释放内存。
步骤5:资源释放
最后,在所有物体处理完毕后,清理立体模型,释放所有相关资源。
七、实战优化建议
1. 分辨率与精度的权衡
- 高精度需求:如果应用场景(如精密零件检测)对模型精度要求极高,应将
FastReconstruction设为false,使用Resolution := 0.0006或更小的分辨率。 - 实时性需求:如果需要快速得到重建结果(如在线检测),则应使用较高的分辨率(如
0.0012),并可以考虑启用smoothing参数来减少噪点。
2. 边界框(BoundingBox)的优化
- 精确测量:在设置
BoundingBox前,可以先用较低分辨率对物体进行一次快速重建,获取其大致的空间范围,然后在此基础上稍微扩大一点作为精确重建的边界框。 - 避免冗余:边界框不应设置过大,否则会包含大量空的空间,增加计算量和内存使用。
3. 视差计算参数调优
- 匹配窗口大小:对于纹理丰富的表面,可以使用较小的窗口(如5x5或7x7)以提高细节;对于纹理较少或重复纹理的表面,应使用较大的窗口(如11x11或15x15)以提高匹配的鲁棒性。
- 匹配算法选择:
'ncc'(归一化互相关)对光照变化不敏感,适用于大多数场景;'sad'(绝对差之和)计算速度更快,但对光照变化较为敏感。
4. 表面后处理
重建得到的3D模型可以通过Halcon的其他算子进行后处理,例如:
smooth_object_model_3d:对表面进行平滑处理。reduce_object_model_3d:对点云进行下采样,减少数据量。compute_object_model_3d_metrics:计算3D模型的体积、表面积等度量。
八、总结
本案例详细介绍了如何使用Halcon的surface_fusion方法进行多相机3D表面重建。通过对代码的逐行解析和核心算子的深入剖析,我们理解了多视图立体视觉重建的完整流程,包括相机模型加载、立体模型创建与配置、三维重建执行以及结果可视化。
surface_fusion方法通过融合多个相机对的重建结果,能够生成比传统成对匹配方法更完整、更精确的3D表面模型,是工业三维检测和质量控制领域的强大工具。掌握其参数调优方法和实战技巧,对于成功应用该技术至关重要。