原文作者: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为:

单点激光测距原理

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

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


图: 单点激光测距示意图

由几何知识可作相似三角形,激光头、摄像头与目标物体组成的三角形,相似于摄像头、成像点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的激光三角测量

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

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

一般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)图像。参考下图:

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

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

激光三角测量(sheet of light)halcon示例详解 Reconstruct_Connection_Rod_Calib.hdev 三维重建的更多相关文章

  1. 在java poi导入Excel通用工具类示例详解

    转: 在java poi导入Excel通用工具类示例详解 更新时间:2017年09月10日 14:21:36   作者:daochuwenziyao   我要评论   这篇文章主要给大家介绍了关于在j ...

  2. jquery移除、绑定、触发元素事件使用示例详解

    这篇文章主要介绍了jquery移除.绑定.触发元素事件使用示例详解,需要的朋友可以参考下. unbind(type [,data]) //data是要移除的函数 $('#btn').unbind(&q ...

  3. gcc与g++的编译链接的示例详解

    一.编译方式的示例详解 1. 编译C代码 代码如下:main.c /*!  ************************************************************** ...

  4. 史上最易懂——ReactNative分组列表SectionList使用详情及示例详解

    React Native系列 <逻辑性最强的React Native环境搭建与调试> <ReactNative开发工具有这一篇足矣> <解决React Native un ...

  5. Spring Boot 2.x 快速入门(下)HelloWorld示例详解

    上篇 Spring Boot 2.x 快速入门(上)HelloWorld示例 进行了Sprint Boot的快速入门,以实际的示例代码来练手,总比光看书要强很多嘛,最好的就是边看.边写.边记.边展示. ...

  6. VS2010 Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)

    步骤如下: 1. Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)" title="VS2010 Chart控件(一)Chart控件在ASP.NE ...

  7. socket编程的同步、异步与阻塞、非阻塞示例详解

     socket编程的同步.异步与阻塞.非阻塞示例详解之一  分类: 架构设计与优化 简介图 1. 基本 Linux I/O 模型的简单矩阵 每个 I/O 模型都有自己的使用模式,它们对于特定的应用程序 ...

  8. String.format()【示例详解】

    String.format()[示例详解] 整理者:Vashon 前言: String.format 作为文本处理工具,为我们提供强大而丰富的字符串格式化功能,为了不止步于简单调用 String.fo ...

  9. SpringBoot与PageHelper的整合示例详解

    SpringBoot与PageHelper的整合示例详解 1.PageHelper简介 PageHelper官网地址: https://pagehelper.github.io/ 摘要: com.gi ...

随机推荐

  1. 常见ASP脚本攻击及防范技巧

    由于ASP的方便易用,越来越多的网站后台程序都使用ASP脚本语言.但是, 由于ASP本身存在一些安全漏洞,稍不小心就会给黑客提供可乘之机.事实上,安全不仅是网管的事,编程人员也必须在某些安全细节上注意 ...

  2. 从零开始一起学习SLAM | 用四元数插值来对齐IMU和图像帧

    视觉 Vs. IMU 小白:师兄,好久没见到你了啊,我最近在看IMU(Inertial Measurement Unit,惯性导航单元)相关的东西,正好有问题求助啊 师兄:又遇到啥问题啦? 小白:是这 ...

  3. Day 02--选题与设计(二)

    1.今天我们主要设计了一下我们微信小程序可以实现的功能,客户操作的基本流程,研究了墨刀这个工具的使用方法并试着将想法转化为原型设计项目.我们给自己的系统起名为“天天好餐”.我们认为食堂订送餐与网络上的 ...

  4. 类spring ioc 泛型保留

    类spring ioc 泛型保留 什么是泛型擦除 Java并不会传递泛型类,举个直观的栗子: @Component public class BaseProvider<T> { publi ...

  5. c11标准

    在编译器vs13及其以上可以使用 编译器对语言的一种优化 1.变量初始化 int a=0,a(10),a{10};定义a的值的三种方式 2.nullptr 相当于c的null 有类型 更加的安全 3. ...

  6. 《Java 8 in Action》Chapter 7:并行数据处理与性能

    在Java 7之前,并行处理数据集合非常麻烦.第一,你得明确地把包含数据的数据结构分成若干子部分.第二,你要给每个子部分分配一个独立的线程.第三,你需要在恰当的时候对它们进行同步来避免不希望出现的竞争 ...

  7. Demo小细节-2

    今天在牛客的题海中再次找虐,题目如下: public class B { public static B t1 = new B(); public static B t2 = new B(); { S ...

  8. ‎CocosBuilder 学习笔记(2) .ccbi 文件结构分析

    ccbi总体结构 CCBReader按字节读取.ccbi内容,每个字节8位二进制. .ccbi总体结构分为4个部分: Header 第0-3字节:ibcc .ccbi文件的标志.readHeader方 ...

  9. 再谈C#装箱和拆箱操作

    1. 使用非泛型集合时引发的装箱和拆箱操作 看下面的一段代码: 1 2 3 4 5 6 7 8 var array = new ArrayList(); array.Add(1); array.Add ...

  10. SPSS数据分析方法不知道如何选择

      一提到数学,高等数学,线性代数,概率论与数理统计,数值分析,空间解析几何这些数学课程,头疼呀.作为文科生,遇见这些课程时,通常都是各种寻求帮助,班上有位宅男数学很厉害,各种被女生‘围观’,这数学为 ...