1、双目立体视觉:人眼视差(三角关系推导)

测量越远、精度越差。(双目标定)

步骤:

  1. 矫正图像对
  2. 双目标定
  3. 求视差图
  4. 形成点云数据

点云数据:空间上每点的坐标。

对比3D和2D:

  • 3D更多的是3D点云数据处理。
  • 2D更多的是对灰度值的处理。

2、激光三角(原理)传感器

线激光;导轨;限位触发器。

相机  +  激光器   所构成的三角关系:相似三角形原理,比值计算距离。

激光器可分为:直射式,斜射式。

  1. 相机标定:相机的内外参数
  2. 光平面标定:相机和激光器的位置关系Pose;
  3. 移动标定
  4. 生成物体点云数据;(工作重点就是处理点云)

3、结构光加双目(单目)

(纹理光)


4、TOF(time of Fly)飞行时间

采集到的为深度信息;形成深度图,距离图。




超人视觉免费启蒙三维课程入门第三节(配合3D实战设备获取点云并且halcon读取显示曲面重建保存等)

点云数据处理流程

halcon中:

1、读取点云数据的函数:

read_object_model_3d (, 'm', [], [], ObjectModel3D, Status)

halcon:支持多种点云格式:默认的为om3。如果格式不支持,需要转格式:

当前手中为csv格式,记录了XYZ。

dev_update_off ()

Filename := './1.csv' // 点云数据的名称,.txt、.csv、.asc等格式的都可以

NumColumns := 5 //如果点云的每行数据有3个数字就写3 (只有xyz 的数据)

count_seconds (Then)
open_file (Filename, 'input', FileHandle)

VecOutLine.clear()
repeat
    fread_line (FileHandle, VecOutLine.at(VecOutLine.length()), IsEOF)
until (IsEOF)
convert_vector_to_tuple (VecOutLine, P)
S := P[354540]
stop()

P1 := split(P, '\n')
P2 := split(P1, ',')

P3 := number(regexp_replace(P2,'^\\s*(.+?)\\s*\n*$', '$1'))

// tuple_number负责字符转数字,tuple_string负责数字转字符。
// tuple_number (P2, P3)

// P4 := number(P2)
// convert_vector_to_tuple({P2},P4)


IndexIsString := find(type_elem(P3),H_TYPE_STRING)
if (IndexIsString > -1)
     throw ('could not convert "' + P3[IndexIsString] + '" to a number')
endif

X := P3[[1:NumColumns:|P3|-1]]
Y := P3[[2:NumColumns:|P3|-1]]
Z := P3[[3:NumColumns:|P3|-1]]
stop()


close_file (FileHandle)
count_seconds (Now)
DurationSeconds := Now - Then
Msg := 'opening file ' + Filename + ' in ' + DurationSeconds + 's'
dev_inspect_ctrl (Msg)

gen_object_model_3d_from_points (X, Y, Z, ObjectModel3D)

write_object_model_3d (ObjectModel3D, 'om3', 'E:/vincent/Halcon/1.om3', [], [])

dev_get_window (WindowHandle)
visualize_object_model_3d (WindowHandle, ObjectModel3D, [], [], ['lut','color_attrib','disp_pose'], ['color1','coord_z','true'], 'title:点云卡车', 'label:标签', '提示信息', PoseOut)

// read_object_model_3d

数据预处理、清洗等操作: 

第12行:at作用类似构建一个伪二维数组;

第14行:将向量转为数组类型,便于切割。

第18行和第19行:数据分割,以\n为分割符切割操作;以,为分隔符,将内部数组展开。

通过观察变量窗口,可以发现:将鼠标指向VecOutLine时,显示数目为354541个数量,此时最后一个变量S为空,所以总数为354540个点。得到此数对于衡量下面的P1,P2,P3和衡量X,Y,Z个数至关重要,因为需要衡量X,Y,Z是否转数字成功。一个点都不能少,否则X中一旦包含了字符类型,将无法带入函数中使用。

3D点云处理opencv 3d点云入门_halcon

第21行:将多余字符删除,然后将字符串转成数字。

第24行和第26行都可以实现,字符转数字。但是本例子中不行,原因未知,待测试。

p := ['11', '12', '13']
tuple_number (p, a)


p := ['11', '12', '13']
b := number (p)

3D点云处理opencv 3d点云入门_halcon_02

后面就是检查整数,然后通过长度规律切片。

需要注意一下正则匹配。 

2、显示点云数据:

dev_open_window (0, 0, 710, 576, 'black', WindowHandle)
visualize_object_model_3d (WindowHandle, ObjectModel3DID, CamParam, Pose, GenParamName, GenParamValue, 'This scene will be segmented into single objects', [], Instructions, Pose)

3、 点云三维重建-三角网格算法。拓扑结构

点云的点都是孤立的,需要寻找其中的相互关系建立拓扑结构。

散点: ——>>曲面重建;

三角曲面重建:

triangulate_object_model_3d (ObjectModel3D, 'greedy', [], [], TriangulatedObjectModel3D, Information)

3D重建需要一段时间,halcon下面可以看到进度条。所以,可以用于效果显示。

* 1、点云文件读取
read_object_model_3d ('E:/vincent/Halcon/1.om3', 'm', [], [], ObjectModel3D, Status)

* 2、获取3D点云数据参数
get_object_model_3d_params (ObjectModel3D, 'num_points', GenParamValue)
get_object_model_3d_params (ObjectModel3D, 'point_coord_z', GenParamValue1)

* 3、显示点云数据
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)

* 4、显示三角网格曲面重建
triangulate_object_model_3d (ObjectModel3D, 'greedy', [], [], TriangulatedObjectModel3D, Information)
visualize_object_model_3d (WindowHandle, TriangulatedObjectModel3D, [], [], [], [], [], [], [], PoseOut)

* 5、保存三角曲面重建
write_object_model_3d (TriangulatedObjectModel3D, 'om3', 'E:/vincent/Halcon/1三角网格曲面重建.om3', [], [])




测量电池高度的思路:

拟合曲面:最小二乘,点云特征匹配。点云拼接。

1、获取纽扣电池上表面的点云集合。

2、平台背景的点云集合。去噪:高斯平滑、体素特征平滑,Z坐标不一致筛选。

3、电池点云Z坐标。

4、得到平台背景Z坐标。

5、求电池点云Z坐标的均值a。

6、平台背景点云z坐标的均值b。

7、a-b得到高度。


得到关于z轴的坐标信息。

get_object_model_3d_params (ObjectModel3D, 'point_coord_z', GenParamValue)

得到整个点云关于Z轴的高度信息,在变量GenParamValue中会把所有点的高度信息保存,然后在【变量窗口】中将鼠标移动过去停留就会显示最大最小值,以及平均值。右键选择【像函数一样绘图】通过统计我们大概可以可以看到点云中点的分布情况,同时对于特别突兀的点也可以筛选出来。比如说最大值和最小值情况。

halcon点云筛选(两个重要函数)

1、select_points_object_model_3d:筛选孤立散点的特征值(点的x y z坐标,法向量xyz)针对点的特征筛选select_points_object_model_3d (ObjectModel3D, 'point_coord_z', -418, 14000, ObjectModel3DThresholded)。可以依据第二个参数来筛选我们需要的特征,阈值范围通过后面两个参数设置。这个算子中的Example例程一定要仔细看看。

2、 select_object_model_3d:根据点云连通域筛选。经过connection_object_model_3d连通之后筛选。

点云的连通集合断开

connection_object_model_3d (ObjectModel3DThresholded, 'distance_3d', 500, ObjectModel3DConnected)

connection_object_model_3d:连通域分析:通过连通域分析来将物体表面大概位置拆分开来,

特别强调:通过connection_object_model_3d连通域分析之后得到点云,再通过get_object_model_3d_params (ObjectModel3DConnected, 'num_points', GenParamValue1)读取参数可以发现,被分为了九个区域(GenParamValue1长度为9),我们只要从中选择匹配我们的需要的区域即可。如何挑选,有时是根据点云的点数,有时是根据高度,反正测试参数,哪个最稳定

我们可以通过select_object_model_3d再一次筛选连通域,直到我们需要的集群被选中为止。

dev_update_off ()
* 1、读入点云数据(文件中)
read_object_model_3d ('E:/vincent/Halcon/1.om3', 'm', [], [], ObjectModel3D, Status)
dev_close_window ()

dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
* visualize_object_model_3d (WindowHandle, ObjectModel3D, [], [], ['lut','color_attrib','disp_pose'], ['color1','coord_z', 'true'], [], [], [], PoseOut)

* 2、通过高度初次筛选点云数据
get_object_model_3d_params (ObjectModel3D, 'point_coord_z', GenParamValue)
select_points_object_model_3d (ObjectModel3D, 'point_coord_z', 1600, 4000, ObjectModel3DThresholded)
* visualize_object_model_3d (WindowHandle, ObjectModel3DThresholded, [], PoseOut, ['lut','color_attrib','disp_pose'], ['color1','coord_z', 'true'], [], [], [], PoseOut1)

* 3、通过连通域分析将目标区域分割,进一步缩小范围,得到目标物体点云
connection_object_model_3d (ObjectModel3DThresholded, 'distance_3d', 200, ObjectModel3DConnected)
* 计算每个连通域内的点数,通过点数来锁定目标的点云群。
get_object_model_3d_params (ObjectModel3DConnected, 'num_points', GenParamValue1)
* 筛选
select_object_model_3d (ObjectModel3DConnected, 'num_points', 'and', 10000, 20000, ObjectModel3DSelected)

visualize_object_model_3d (WindowHandle, ObjectModel3DSelected, [], [], [], [], [], [], [], PoseOut)

* 这个方法肯定不稳定,需要更加稳定的方法。

* 4、按照教程上是得到电池上点云的高度:
get_object_model_3d_params (ObjectModel3DSelected, 'point_coord_z', GenParamValue2)

* 5、计算平均值:以此估计高度
* halcon中设计数值计算的都是用tuple。
tuple_mean (GenParamValue2, Mean)
* 下面这个也是求均值。
ave:= mean(GenParamValue2)

* 原教程:将电池和背景的点云连通域分割以后,分别求解两个部分的平均高度,然后做差得到厚度值。

* 其实:拟合平面精度更高一些。
Param[0]:='Shift +left button Zoom'
Param[1]:='Ctrl +left button Move'
Param[2]:='left button Rotat'

visualize_object_model_3d (WindowHandle, ObjectModel3D, [], [], ['lut','color_attrib', 'disp_pose'], ['color1','coord_z','true'], '电池点云的高度为' + ave +'mm', 'Battery Object', Param, PoseOut1)