原文作者:aircraft

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

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

1.Reconstruct_Connection_Rod_Calib.hdev

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

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

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

 2.激光三角测量

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

激光雷达四大核心组件

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

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

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

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

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

激光三角测距法原理

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

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

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

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

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

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

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

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP则易知激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

单点激光测距原理

单点激光测距原理图如下图2-6所示,
激光头Laser与摄像头在同一水平线(称为基准线)上,其距离为s,摄像头焦距为f,激光头与基准线的夹角为β。

假设目标物体Object在点状激光器的照射下,反射回摄像头成像平面的位置为点P。

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP
图: 单点激光测距示意图

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

设 PP′=x,q、d如图所示,则由相似三角形可得:

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

可分为两部分计算:

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

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

最后,可求得距离d:

                     d=q/sin⁡β 

3.代码注解

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

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

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

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

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

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

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

* 首先,创建一个片光模型,并设置合适的参数,接下来连续采集一系列轮廓图像。

* 最后,从模型中检索视觉差图像,分数图像,标定坐标X,Y和Z以及测量得到的3D对象模型并显示。

*

dev_update_off () //暂停熟悉

read_image (ProfileImage, 'sheet_of_light/connection_rod_001') //读取图像

dev_close_window () //关闭窗体

dev_open_window_fit_image (ProfileImage, , , , , WindowHandle1) //打开一个新窗体

set_display_font (WindowHandle1, , 'mono', 'true', 'false')//设置字体

dev_set_draw ('margin') //设置轮廓

dev_set_line_width () //设置线宽

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-,387.036,120.112,,]

CamPose := [-0.00164029,1.91372e-006,0.300135,0.575347,0.587877,180.026,] //相机坐标

LightplanePose := [0.00270989,-0.00548841,0.00843714,66.9928,359.72,0.659384,] //片光平面坐标

MovementPose := [7.86235e-008,0.000120112,1.9745e-006,,,,] //

*

* 创建模型以处理配置文件图像并设置模型所需的参数

gen_rectangle1 (ProfileRegion, , , , ) //创建矩形

* 创建一个基于 3D 测量的片光模型

create_sheet_of_light_model (ProfileRegion, ['min_gray','num_profiles','ambiguity_solving'], [,,'first'], SheetOfLightModelID)

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) //移动姿态,移动过程中通常为大地坐标

*

* 连续的图像测量轮廓

for Index :=  to  by

read_image (ProfileImage, 'sheet_of_light/connection_rod_' + Index$'.3') //读取图像

dev_display (ProfileImage) //显示图像

dev_display (ProfileRegion) //显示区域

measure_profile_sheet_of_light (ProfileImage, SheetOfLightModelID, []) //对输入和存储的轮廓图像进行片光技术处理

disp_message (WindowHandle1, '采集轮廓图像', 'window', -, -, 'black', 'true') //显示信息

endfor

* 获取片光图像

get_sheet_of_light_result (Disparity, SheetOfLightModelID, 'disparity') //返回片光深度距离

get_sheet_of_light_result (X, SheetOfLightModelID, 'x') //返回片光x数据

get_sheet_of_light_result (Y, SheetOfLightModelID, 'y') //返回片光y数据

get_sheet_of_light_result (Z, SheetOfLightModelID, 'z') //返回片光z数据

get_sheet_of_light_result_object_model_3d (SheetOfLightModelID, ObjectModel3DID) //返回片光3D模型数据

clear_sheet_of_light_model (SheetOfLightModelID) //清除指定片光模型

*

* 显示视差图像

get_image_size (Disparity, Width, Height) //获取图像大小

dev_set_window_extents (, , Width, Height) //调整大小

dev_set_lut ('temperature') //

set_display_font (WindowHandle1, , 'mono', 'true', 'false') //设置字体

dev_clear_window () //清除窗体

dev_display (Disparity)

disp_message (WindowHandle1, '重建片光生产的视差图像', 'window', -, -, 'black', 'true') //显示信息

disp_continue_message (WindowHandle1, 'black', 'true') //显示暂停信息

stop () //暂停

*

* 显示Z坐标

dev_close_window () //关闭窗体

dev_open_window (Height + , , Width * ., Height * ., 'black', WindowHandle3) //打开窗体3

set_display_font (WindowHandle3, , 'mono', 'true', 'false')//设置字体

dev_display (Z) //显示Z信息

disp_message (WindowHandle3, '标定的 Z 坐标', 'window', -, -, 'black', 'true') //显示信息

*

* 显示Y坐标

dev_open_window ((Height + ) * ., , Width * ., Height * ., 'black', WindowHandle2) //打开窗体2

set_display_font (WindowHandle2, , 'mono', 'true', 'false')//设置字体

dev_display (Y)//显示Z信息

disp_message (WindowHandle2, '标定的 Y 坐标', 'window', -, -, 'black', 'true')

*

* 显示X坐标

dev_open_window (, , Width * ., Height * ., 'black', WindowHandle1) //打开窗体1

dev_display (X)//显示Z信息

dev_set_lut ('default')

set_display_font (WindowHandle1, , 'mono', 'true', 'false')//设置字体

disp_message (WindowHandle1, '标定的 X 坐标', 'window', -, -, 'black', 'true') //显示信息

disp_continue_message (WindowHandle3, 'black', 'true') //显示暂停信息

stop () //暂停

*

* Display the 3d object model

CameraParam1 := [0.012,,6e-,6e-,,,,] //相机内部参数

Instructions[] := '旋转: Left 鼠标左键'

Instructions[] := '缩放: Shift + 鼠标左键'

Instructions[] := '移动Move: Ctrl + 鼠标左键'

PoseIn := [,-,,-,,-,]

dev_close_window () //关闭窗体2

dev_close_window () //关闭窗体3

dev_close_window () //关闭窗体12

dev_open_window (, , CameraParam1[], CameraParam1[], 'black', WindowHandle) //打开新窗体

set_display_font (WindowHandle, , '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)图像。参考下图:

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

参考博客: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,机器学习深度学习之类有关于基础编程,图像处理和机器视觉开发的知识

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建-LMLPHP

05-11 16:12