原文作者:aircraft
原文链接:https://www.cnblogs.com/DOMLX/p/11555100.html
前言:最近项目用到halcon的3d模板匹配,三维重建,相机标定,所以最近都在研究这些,现在分享一下对激光三角测量示例的个人理解。
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为:
3.代码注解
看注释就好了,慢慢看,结合示例跑一下就能大概理解了,示例在halcon的激光三角测量
* 首先,创建一个片光模型,并设置合适的参数,接下来连续采集一系列轮廓图像。 * 最后,从模型中检索视觉差图像,分数图像,标定坐标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, 0, 0, 1024, 768, WindowHandle1) //打开一个新窗体 set_display_font (WindowHandle1, 14, 'mono', 'true', 'false')//设置字体 dev_set_draw ('margin') //设置轮廓 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] // * * 创建模型以处理配置文件图像并设置模型所需的参数 gen_rectangle1 (ProfileRegion, 120, 75, 195, 710) //创建矩形 * 创建一个基于 3D 测量的片光模型 create_sheet_of_light_model (ProfileRegion, ['min_gray','num_profiles','ambiguity_solving'], [70,290,'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 := 1 to 290 by 1 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', -1, -1, '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 (0, 0, Width, Height) //调整大小 dev_set_lut ('temperature') // set_display_font (WindowHandle1, 16, 'mono', 'true', 'false') //设置字体 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) //打开窗体3 set_display_font (WindowHandle3, 16, 'mono', 'true', 'false')//设置字体 dev_display (Z) //显示Z信息 disp_message (WindowHandle3, '标定的 Z 坐标', 'window', -1, -1, 'black', 'true') //显示信息 * * 显示Y坐标 dev_open_window ((Height + 10) * .5, 0, Width * .5, Height * .5, 'black', WindowHandle2) //打开窗体2 set_display_font (WindowHandle2, 16, 'mono', 'true', 'false')//设置字体 dev_display (Y)//显示Z信息 disp_message (WindowHandle2, '标定的 Y 坐标', 'window', -1, -1, 'black', 'true') * * 显示X坐标 dev_open_window (0, 0, Width * .5, Height * .5, 'black', WindowHandle1) //打开窗体1 dev_display (X)//显示Z信息 dev_set_lut ('default') set_display_font (WindowHandle1, 16, 'mono', 'true', 'false')//设置字体 disp_message (WindowHandle1, '标定的 X 坐标', 'window', -1, -1, 'black', 'true') //显示信息 disp_continue_message (WindowHandle3, 'black', 'true') //显示暂停信息 stop () //暂停 * * Display the 3d object model 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 () //关闭窗体2 dev_close_window () //关闭窗体3 dev_close_window () //关闭窗体12 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