halcon 入门教程(九)激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 模型三维重建

 

原文作者:aircraft

原文链接:https://www.cnblogs.com/DOMLX/p/11555100.html

 

有兴趣可以多看其他的halcon教程

 halcon 学习教程目录

 

前言:最近公司项目用到halcon的3d模板匹配,三维重建,相机标定,所以最近都在研究这些,现在分享一下对激光三角测量示例的个人理解。

 

完整的激光三角测量视频教程:https://www.bilibili.com/video/BV1cJ411M7DE

demo是calibrate_sheet_of_light_calplate.hdev,其中包括了相机标定过程已经激光标定过程

 

 

1.Reconstruct_Connection_Rod_Calib.hdev

先看一下这个halcon示例做了些什么:

通过一道激光照射过一个零件,留下了一个个片截图,后面用于测量其深度信息。

 

 

 

 

而示例就是用光片模型的重建,对所有的connection_rod系列图片进行处理,重建出原模型的图像:

 

 

 

 

 

 

也可以看片光x,y,z的信息:

 

 

 

 

 

 

 

最后我们可以调用halcon的算子visualize_object_model_3d (WindowHandle, ObjectModel3DID, CameraParam1, PoseIn, 'color', 'blue', 'Reconstructed Connection Rod', '', Instructions, PoseOut) 将3d零件模型重建

 

 

 

 

 

 

模型可以通过鼠标随意移动,就跟我上篇博客 opengl导入3d模型并且显示一样OpenGl读取导入3D模型并且添加鼠标移动旋转显示

 2.激光三角测量

激光三角测距法作为低成本的激光雷达设计方案,可获得高精度、高性价比的应用效果,并成为室内服务机器人导航的首选方案,本文将对激光雷达核心组件进行介绍并重点阐述基于激光三角测距法的激光雷达原理。

激光雷达四大核心组件

激光雷达主要由激光器、接收器、信号处理单元和旋转机构这四大核心组件构成。

激光器:激光器是激光雷达中的激光发射机构。在工作过程中,它会以脉冲的方式点亮。以思岚科技的RPLIDAR A3系列雷达为例,每秒钟,它会点亮和熄灭16000次。

接收器:激光器发射的激光照射到障碍物以后,通过障碍物的反射,反射光线会经由镜头组汇聚到接收器上。

信号处理单元:信号处理单元负责控制激光器的发射,以及接收器收到的信号的处理。根据这些信息计算出目标物体的距离信息。

旋转机构:以上3个组件构成了测量的核心部件。旋转机构负责将上述核心部件以稳定的转速旋转起来,从而实现对所在平面的扫描,并产生实时的平面图信息。

 

激光三角测距法原理

目前激光雷达的测量原理主要有脉冲法、相干法和三角法3种,脉冲法和相干光法对激光雷达的硬件要求高,但测量精度比激光三角法要高得多,故多用于军事领域。而激光三角测距法因其成本低,精度满足大部分商用及民用要求,故得到了广泛关注。

激光三角测距法主要是通过一束激光以一定的入射角度照射被测目标,激光在目标表面发生反射和散射,在另一角度利用透镜对反射激光汇聚成像,光斑成像在CCD(Charge-coupled Device,感光耦合组件)位置传感器上。当被测物体沿激光方向发生移动时,位置传感器上的光斑将产生移动,其位移大小对应被测物体的移动距离,因此可通过算法设计,由光斑位移距离计算出被测物体与基线的距离值。由于入射光和反射光构成一个三角形,对光斑位移的计算运用了几何三角定理,故该测量法被称为激光三角测距法。

按入射光束与被测物体表面法线的角度关系,激光三角测距法可分为斜射式和直射式两种。

1、直射式激光三角测距法

直射式激光三角测距原理

如图1所示,当激光光束垂直入射被测物体表面,即入射光线与被测物体表面法线共线时,为直射式激光三角法。

 

2、斜射式激光三角测距法

当光路系统中,激光入射光束与被测物体表面法线夹角小于90°时,该入射方式即为斜射式。如图2所示的光路图为激光三角法斜射式光路图。

由激光器发射的激光与物体表面法线成一定角度入射到被测物体表面,反(散)射光经B处的透镜汇聚成像,最后被光敏单元采集。

斜射式激光三角测距原理

由图2可知入射光AO与基线AB的夹角为α,AB为激光器中心与CCD中心的距离,BF为透镜的焦距f,D为被测物体距离基线无穷远处时反射光线在光敏单元上成像的极限位置。DE为光斑在光敏单元上偏离极限位置的位移,记为x。当系统的光路确定后,α、AB与f均为已知参数。由光路图中的几何关系可知△ABO∽△DEB,则有边长关系:

激光三角测距原理则易知激光三角测距原理

在确定系统的光路时,可将CCD位置传感器的一个轴与基线AB平行(假设为y轴),则由通过算法得到的激光光点像素坐标为(Px,Py)可得到x的值为:

激光三角测距原理

其中CellSize是光敏单元上单个像素的尺寸,DeviationValue是通过像素点计算的投影距离和实际投影距离x的偏差量。当被测物体与基线AB产生相对位移时,x改变为x,由以上条件可得被测物体运动距离y为:

激光三角测距原理

 

单点激光测距原理

单点激光测距原理图如下图2-6所示,

 


图2-6: 单点激光测距示意图

由几何知识可作相似三角形,激光头、摄像头与目标物体组成的三角形,相似于摄像头、成像


                f/x=q/s  ==>  q=fs/x                              

 

可分为两部分计算:

        X=x1+x2= f/tan⁡β + pixelSize* position

 

其中pixelSize是像素单位大小, position是成像的像素坐标相对于成像中心的位置。

最后,可求得距离d:

                     d=q/sin⁡β 

 

3.代码注解

 

看注释就好了,慢慢看,结合示例跑一下就能大概理解了,示例在halcon的激光三角测量

 

如果在看的过程中对某个算子不理解,参数有疑问,可以直接双击那个算子

 

,打开帮助手册,去看每个算子的参数信息,以及用法介绍:

 

 

 

 

 

一般dev_update_off放在开始,如果原来的程序有残留一些窗口什么的就可以关闭,dev_update_on放在程序结束

dev_update_window:定义 程序执行打开和关闭期间,图像对象是否在图形窗口中显示;在单步模式下,该规则无效,单个算子调用以后,对象总是显示在图形窗口上;在测量一系列算子的运行时间的时候,应该设置为OFF,以减少HDevelop中GUI更新的运行时间的影响

dev_update_pc:在程序执行期间,控制程序计数器的更新

dev_update_var:在程序执行期间控制变量窗口的更新或关闭,则每当程序修改变量时,更改变量窗口(图标和控件变量)的内容。 dev_update_time:控制是否显示算子的执行时间

* 关闭窗口更新(提升执行效率)
dev_update_off ()

* 读取初始片光轮廓图像
read_image (ProfileImage, 'sheet_of_light/connection_rod_001')


* 关闭所有图形窗口并重新打开适配图像尺寸的窗口
dev_close_window ()

* 打开适配图像尺寸的新窗口(最大尺寸1024x768)
dev_open_window_fit_image (ProfileImage, 0, 0, 1024, 768, WindowHandle1)

* 设置显示字体为等宽14号字
set_display_font (WindowHandle1, 14, 'mono', 'true', 'false')

* 设置绘制模式为轮廓显示
dev_set_draw ('margin')

* 设置轮廓线宽为3像素
dev_set_line_width (3)

* 设置默认显示颜色为绿色
dev_set_color ('green')

* 恢复默认颜色查找表
dev_set_lut ('default')

* 设置计算校准测量所需的姿势和相机参数

* 内部相机参数(需根据实际标定结果替换)
CamParam := [0.0126514,640.275,-2.07143e+007,3.18867e+011,-0.0895689,0.0231197,6.00051e-006,6e-006,387.036,120.112,752,240]

* 相机坐标系位姿参数
CamPose := [-0.00164029,1.91372e-006,0.300135,0.575347,0.587877,180.026,0]

* 片光平面位姿参数
LightplanePose := [0.00270989,-0.00548841,0.00843714,66.9928,359.72,0.659384,0]

* 运动平台位姿参数(通常设置为零位)
MovementPose := [7.86235e-008,0.000120112,1.9745e-006,0,0,0,0]

* 创建矩形ROI区域(y1=120,x1=75,y2=195,x2=710)
gen_rectangle1 (ProfileRegion, 120, 75, 195, 710)

* 创建片光三维重建模型(关键参数配置)
create_sheet_of_light_model (ProfileRegion, ['min_gray','num_profiles','ambiguity_solving'], [70,290,'first'], SheetOfLightModelID)

* 配置模型参数:启用XYZ标定
set_sheet_of_light_param (SheetOfLightModelID, 'calibration', 'xyz')

* 设置物理单位为毫米
set_sheet_of_light_param (SheetOfLightModelID, 'scale', 'mm')

* 注入相机内参矩阵
set_sheet_of_light_param (SheetOfLightModelID, 'camera_parameter', CamParam)

* 设置相机外参位姿
set_sheet_of_light_param (SheetOfLightModelID, 'camera_pose', CamPose)

* 配置片光平面位姿
set_sheet_of_light_param (SheetOfLightModelID, 'lightplane_pose', LightplanePose)

* 设置运动平台位姿参数
set_sheet_of_light_param (SheetOfLightModelID, 'movement_pose', MovementPose)

* 连续采集并处理290帧轮廓图像
for Index := 1 to 290 by 1
    * 读取序列图像(文件名格式:connection_rod_001~290)
    read_image (ProfileImage, 'sheet_of_light/connection_rod_' + Index$'.3')
    
    * 显示原始图像和ROI区域
    dev_display (ProfileImage)
    dev_display (ProfileRegion)
    
    * 执行片光轮廓测量(核心处理)
    measure_profile_sheet_of_light (ProfileImage, SheetOfLightModelID, [])
    
    * 显示采集进度提示
    disp_message (WindowHandle1, '采集轮廓图像', 'window', -1, -1, 'black', 'true')
endfor

* 获取视差图数据
get_sheet_of_light_result (Disparity, SheetOfLightModelID, 'disparity')

* 获取X坐标图数据(单位:mm)
get_sheet_of_light_result (X, SheetOfLightModelID, 'x')

* 获取Y坐标图数据
get_sheet_of_light_result (Y, SheetOfLightModelID, 'y')

* 获取Z坐标图数据
get_sheet_of_light_result (Z, SheetOfLightModelID, 'z')

* 生成三维点云模型
get_sheet_of_light_result_object_model_3d (SheetOfLightModelID, ObjectModel3DID)

* 释放片光模型内存
clear_sheet_of_light_model (SheetOfLightModelID)

* 配置视差图显示窗口
get_image_size (Disparity, Width, Height)
dev_set_window_extents (0, 0, Width, Height)

* 使用温度计颜色映射显示视差图
dev_set_lut ('temperature')
dev_clear_window ()
dev_display (Disparity)

* 添加视差图标题
disp_message (WindowHandle1, '重建片光生产的视差图像', 'window', -1, -1, 'black', 'true')

* 显示继续操作提示
disp_continue_message (WindowHandle1, 'black', 'true')
stop ()

* 准备Z坐标显示窗口
dev_close_window ()
dev_open_window (Height + 10, 0, Width * .5, Height * .5, 'black', WindowHandle3)

* 设置Z坐标窗口字体
set_display_font (WindowHandle3, 16, 'mono', 'true', 'false')

* 显示Z坐标数据
dev_display (Z)
disp_message (WindowHandle3, '标定的 Z 坐标', 'window', -1, -1, 'black', 'true')

* 准备Y坐标显示窗口
dev_open_window ((Height + 10) * .5, 0, Width * .5, Height * .5, 'black', WindowHandle2)

* 设置Y坐标窗口字体
set_display_font (WindowHandle2, 16, 'mono', 'true', 'false')

* 显示Y坐标数据
dev_display (Y)
disp_message (WindowHandle2, '标定的 Y 坐标', 'window', -1, -1, 'black', 'true')

* 准备X坐标显示窗口
dev_open_window (0, 0, Width * .5, Height * .5, 'black', WindowHandle1)

* 恢复默认颜色表并显示X坐标
dev_set_lut ('default')
dev_display (X)

* 设置X坐标窗口字体
set_display_font (WindowHandle1, 16, 'mono', 'true', 'false')

* 添加X坐标标题
disp_message (WindowHandle1, '标定的 X 坐标', 'window', -1, -1, 'black', 'true')

* 再次显示继续提示
disp_continue_message (WindowHandle3, 'black', 'true')
stop ()

* 配置三维可视化参数
CameraParam1 := [0.012,0,6e-006,6e-006,376,240,752,480]

* 定义三维视图操作提示
Instructions[0] := '旋转: Left 鼠标左键'
Instructions[1] := '缩放: Shift + 鼠标左键'
Instructions[2] := '移动Move: Ctrl + 鼠标左键'

* 设置初始观察视角
PoseIn := [0,-10,300,-30,0,-30,0]

* 清理旧窗口并创建新三维可视化窗口
dev_close_window ()
dev_open_window (0, 0, CameraParam1[6], CameraParam1[7], 'black', WindowHandle)

* 设置三维窗口字体
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')

* 交互式显示三维点云模型
visualize_object_model_3d (WindowHandle, ObjectModel3DID, CameraParam1, PoseIn, 'color', 'blue', '重建', '', Instructions, PoseOut)

* 清理三维模型资源
clear_object_model_3d (ObjectModel3DID)

 

这上面有提到一个视差图像:

Disparity(视差)怎么理解?
        在研究双目深度图估计时,经常会使用D=B×f/d(D:Depth,B:Baseline,f:focal,d:disparity)这个公式,从视差推理出深度,那么这里的d到底怎么理解?
        现在,伸出你左右手的食指,放在离眼睛不同距离的位置上。先闭上左眼看两只手指,再闭上右眼观察两只手指,可以发现,左右眼看到的东西是不一样的,其次,**距离眼睛近的物体移动的距离(视差)更大,距离眼睛远的物体移动的距离(视差)更小。**将同一空间物理点在不同图像中的映像点对应起来,这个差别,我们称作视差(Disparity)图像。参考下图:

 

 


        公式不难发现,视差与深度成反比,关系如下:

 

 



        有了视差disparity,就可以推断出深度图。深度图像也称为距离图像,是指将相机到场景中各点的距离(深度)值作为像素值的图像。深度图获取方法有很多,例如:激光雷达深度成像法、计算机立体视觉成像、坐标测量机法、莫尔条纹法、结构光法等。
        举个例子:(Kinect相机)

 

 

 

 

 

参考博客:Disparity(视差)简单解释  链接: https://blog.csdn.net/weixin_40367126/article/details/90753760

参考博客:HALCON例子:激光三角ReconstructConnectionRodCalib 链接: https://weibo.com/ttarticle/p/show?id=2309404407678905483355

 

若有兴趣交流分享技术,可关注本人公众号,里面会不定期的分享各种编程教程,和共享源码,诸如研究分享关于c/c++,python,前端,后端,opencv,halcon,opengl,机器学习深度学习之类有关于基础编程,图像处理和机器视觉开发的知识

posted @ 2019-09-20 09:54  aircraft  阅读(12288)  评论(0)    收藏  举报