1、双目立体视觉:人眼视差(三角关系推导)
测量越远、精度越差。(双目标定)
步骤:
- 矫正图像对
- 双目标定
- 求视差图
- 形成点云数据
点云数据:空间上每点的坐标。
对比3D和2D:
- 3D更多的是3D点云数据处理。
- 2D更多的是对灰度值的处理。
2、激光三角(原理)传感器
线激光;导轨;限位触发器。
相机 + 激光器 所构成的三角关系:相似三角形原理,比值计算距离。
激光器可分为:直射式,斜射式。
- 相机标定:相机的内外参数
- 光平面标定:相机和激光器的位置关系Pose;
- 移动标定
- 生成物体点云数据;(工作重点就是处理点云)
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中一旦包含了字符类型,将无法带入函数中使用。
第21行:将多余字符删除,然后将字符串转成数字。
第24行和第26行都可以实现,字符转数字。但是本例子中不行,原因未知,待测试。
p := ['11', '12', '13']
tuple_number (p, a)
p := ['11', '12', '13']
b := number (p)
后面就是检查整数,然后通过长度规律切片。
需要注意一下正则匹配。
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)