Corner-case 数据闭环-点云数据和图像数据

程序处理点云

 流行的开源库主要有 PCL 和 Open3D
   open3d的点云基本操作: 可视化、降采样、法向量、裁剪和绘制点云
   点云三维坐标和颜色是分开的,分别是points和colors

Python点云数据处理(三)滤波与RANSAC分割

 并依据 RANSAC 在ROS中实现对地面点云的分割
 分割出地面点云以减少对障碍物聚类的影响。
   引入PCL点云库,PCL点云库中有标准的RANSAC算法接口,我们可以通过调用它实现更加快速,稳定滤除地面点云。
   
  地面应是多数点通过的,因此在上述点云图像中随机选取三个点确定一个平面,设置一个tolerance,
  计算其他所有点距该平面的距离。
    若距离小于tolerance的点认为是inliners点,否则为outliners点,
	inliners中点数量最多对应的平面认为是best fit。 

代码实现

 import open3d as o3d
 
 pcd = o3d.io.read_point_cloud("../test_data/fragment.pcd")
 plane_model, inliers = pcd.segment_plane(distance_threshold=0.01,
                                          ransac_n=3,
                                          num_iterations=1000)
 
 # 模型参数
 [a, b, c, d] = plane_model
 print(f"Plane equation: {a:.2f}x + {b:.2f}y + {c:.2f}z + {d:.2f} = 0")
 #显示
 inlier_cloud = pcd.select_by_index(inliers)
 inlier_cloud.paint_uniform_color([1.0, 0, 0]) # inliers为红色
 outlier_cloud = pcd.select_by_index(inliers, invert=True)
 
 o3d.visualization.draw_geometries([inlier_cloud, outlier_cloud],
                                   zoom=0.8,
                                   front=[-0.4999, -0.1659, -0.8499],
                                   lookat=[2.1813, 2.0619, 2.0999],
                                   up=[0.1204, -0.9852, 0.1215])	

C++ PCL常用函数

 PCL常用函数
   1. 删除无效点(nan点)         ——pcl::removeNaNFromPointCloud
   2. 判断单个点是否是无效点    ——pcl::isFinite
   3. 求点的极值                ——pcl::getMinMax3D
   4. 点云与点云ptr类型互相转换      inliers_ptr cloud_ptr
   5. 点云拷贝                  ——pcl::copyPointCloud
   6. 点云的插入与删除          ——insert、push_back和erase
   7. 指定点云的颜色显示        ——PointCloudColorHandlerCustom
   8. PointCloud和PCLPointCloud2类型互相转换——toPCLPointCloud2和fromPCLPointCloud2
   9. 提取已知索引之外的点云    —— pcl::ExtractIndices
   10. 计算质心                  ——pcl::compute3DCentroid
   11. 计算两个向量之间的夹角    ——pcl::getAngle3D    

读写

 点云
   # 读取文件
   pcd = o3d.io.read_point_cloud(path)  # path为文件路径
   o3d.visualization.draw_geometries([inlier_cloud, outlier_cloud],width=600,height=600)
   # 保存文件
    o3d.io.write_point_cloud(path, pcd)  # path为文件路径
    o3d.io.write_point_cloud(path, inlier_cloud) 
    o3d.io.write_point_cloud(path, outlier_cloud) 
    o3d.visualization.draw_geometries([inlier_cloud, outlier_cloud],width=600,height=600)
 图片
    img = o3d.io.read_image("y7.png")
    o3d.io.write_image("天使.jpg", img)
    o3d.visualization.draw_geometries()
    print(img)
	
	pcl_viewer in_pcd_road.pcd

地面点云剔除方法

   deep_cluster(深度图像的快速分割)
   基于角度和高度的地面点剔除算法
   地面平面拟合(Ground Plane Fitting)
点云分割,分离出障碍物点云  
  
 GLFW 是配合 OpenGL 使用的轻量级工具程序库,
      缩写自 Graphics Library Framework(图形库框架
	  
 前窗口DISPLAY环境变量的值。echo $DISPLAY  返回值是空。
   解决:把DISPLAY的值改成 :0.0 即可 export DISPLAY=:0.0
 Docker默认是不提供对GUI的支持的
 
Bounding Boxes边界框
    点云如何实现聚类,并使用PCL库函数实现点云聚类,
	下面就需要使用边界框将点云框出来 :查找聚类点云各维度的最小值最大值,作为边界框的参数

基于深度图的点云聚类方法

 基于深度图的点云聚类方法
    1.扫描线补偿     车辆左侧的黑色车辆就造成了点云缺失
    2.地面点移除
    3.深度图生成     深度图指的是将点云的数据转为平面数据形式进行显示,每个像素可以存储该点的距离、intensity等值,
	              这种形式与kdtree或者octree不同的是,深度图有利于快速查找得到某一点的相邻点,
				  并且这些点是具有一定顺序关系的,而不是依靠距离度量来查找相邻
				  
				  地面点障碍物快速分割聚类
    4.邻域搜索与阈值设计
	   尝试用聚类算法进行点云分割
	   
	   
  点云聚类方法可以被大致总结为四种类型,
      基于3D欧式空间的方法,
	  使用超栅格或者超点来聚类点云的方法,
	  在深度图上的改进单通道连通域标记方法,
	  和在深度图上的的改进两通道连通域标记方法	 

模型

01.语义分割
    模型之DeepLabv3+	
        语义分割(Semantic Segmentation)和实例分割(Instance Segmentation)
    数据 Cityscapes	
        Cityscapes数据集,即城市景观数据集,这是一个新的大规模数据集,其中包含一组不同的立体视频序列,记录在50个不同城市的街道场景中,
    	除了一组较大的20000弱注释帧外,还包含5000帧的高质量像素级注释
    	Cityscapes数据集包含2975张图片。包含了街景图片和对应的标签。大小为113MB
    	全部有二十个类:
         person, bird, cat, cow, dog, horse, sheep, aeroplane, bicycle, boat, bus, car, motorbike, train,
    	 bottle, chair, dining table, potted plant, sofa, tv / monitor
	Overlap   阈值
02.目标检测
    Object detector--- proposals 进行 计算 IoUs ,设置阈值

3D数据

 点云是在同一空间参考系下表达目标空间分布和目标表面特性的海量点集合
  对于点云数据的处理,主要涉及点云滤波、点云配准、点云分类、点云语义分割、点云目标识别等。
  点云滤波,就是滤掉噪声。原始采集的点云数据往往包含大量散列点、孤立点 
  3D空间里面,坐标原点到底在哪儿,以及xyz三个轴在哪儿	 

3D数据表示

3D数据的不同表示类型
   点云(Point clouds)
       paint_uniform_color 给所有的点上一个统一的颜色,颜色是在RGB空间得[0,1]范围内得值
   	point = numpy.asarray(pcd.points)  # 将点转换为numpy数组
   	print(o3d.np.asarray(pcd.points))#输出点的三维坐标
   	
   	numpy转open3D需要借助Vector3dVector函数,这样可以直接赋值与open3d.PointCloud.points,
   	点数,法向量和颜色的转换  pcd.points   pcd.normals  pcd.colors
   	   单位法向量  normals
   	   切向量      tangent plane
   	   
   体素网格(Voxel grids) 
   	 素是体积元素(Volume Pixel) 体素是3D空间的像素。量化的,大小固定的点云。每个单元都是固定大小和离散坐标 通常是一个立方体
   	栅格地图(Occupancy Grid Map)
   	八叉树地图(Octomap)
   多边形网格(Polygon meshes)	
       mesh是面片的集

代码示例

# -*-coding:utf-8 -*-

import os
import open3d as o3d
import numpy as np
import matplotlib.pyplot as plt


## 读取文件
cloud_file_path="/data/cloud/20220304/pcd/1638783331.199959993.pcd"
pcd = o3d.io.read_point_cloud(cloud_file_path)

## 点云预处理
# 分别为剔除非数点和无穷值点
pcd_new = o3d.geometry.PointCloud.remove_non_finite_points(
                        pcd, remove_nan = True, remove_infinite = False)
#pcd_new = o3d.geometry.PointCloud.remove_radius_outlier(pcd, knn, radius)

##ransac
# distance_threshold为距离阈值参数,ransac_n为RANSAC迭代的点数,num_iterations为最大迭代次数
dis = 0.01
rnn =3
n=1000
pane_model, inliers = pcd.segment_plane(distance_threshold=dis, ransac_n=rnn, num_iterations=n)

# RANSAC分割后的内部点云(拟合平面点)
pcd_in = pcd.select_by_index(inliers)

# RANSAC分割后的外部点云(拟合平面之外的点)
pcd_out = pcd.select_by_index(inliers, invert=True) 
print(pcd_in)
print(pcd_out)
out_path = "/data/cloud/20220304/out_1638783331.199.pcd"
o3d.io.write_point_cloud(out_path, pcd_out)

#聚类
with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:
    # np.array 将点云从oepn3d形式转换为矩阵形式#
    labels = np.array(pcd_out.cluster_dbscan(eps=0.02, min_points=20, print_progress=True))
	
max_label = labels.max()
print(f"point cloud has {max_label + 1} clusters")

colors = plt.get_cmap("tab20")(labels / (max_label if max_label > 0 else 1))
colors[labels < 0] = 0
pcd_out.colors = o3d.utility.Vector3dVector(colors[:, :3])
# 将点云转换成open3d中的数据形式并用pcd来保存,以方便用open3d处理
new_out_path = "/data/cloud/new_out_path_1638783331.199.pcd"
o3d.io.write_point_cloud(new_out_path, pcd_out)


# 打印聚类非0的点云下标,点云数
print(np.nonzero(labels), '  type: ', type(np.nonzero(labels)), ' size: ', len(np.array(np.nonzero(labels)[0])))

zero_index = np.where(labels == 0)  # 提取分类为0的聚类点云下标
zero_pcd = pcd_out.select_by_index(np.array(zero_index)[0])  # 根据下标提取点云点
print(zero_pcd)
print('zero_index: ', zero_index, " size: ", len(np.array(zero_index)[0]))
min = labels.min()
max = labels.max()
for label in range(min, max+1):
    label_index = np.where(labels == label)  # 提取分类为label的聚类点云下标
    label_pcd = pcd_out.select_by_index(np.array(label_index)[0])  # 根据下标提取点云点
    print('label: ', str(label), '点云数:', len(label_pcd.points))
    # 分别按分类写入文件
    o3d.io.write_point_cloud("/data/cloud/20220304/out" + str(label) + ".pcd", label_pcd)

附录概念

Fast Range Image-Based Segmentation of Sparse 3D Laser Scans for Online Operation
# 雷达采集到的未经任何处理的点云数据转化成深度图,
     行数取决于雷达的线数,列数取决于雷达旋转360°采集的点数,每个像素存储点到传感器的欧式距离。
	  该方法仅仅只用了一个参数来进行点云分割的处理
	  
A Fast Segmentation Method of Sparse Point Clouds
候选目标框(Proposal-based methods)的算法
无候选目标框的算法(Proposal-free methods)
    mean-shift等聚类(clustering)方法来将同一个instance的点聚集(group)到一起

	华为智能汽车解决方案  HI (HUAWEI Intelligent Automotive Solution)	

参考:

https://blog.csdn.net/QLeelq/article/details/121999763?spm=1001.2014.3001.5502
 【点云处理技术之PCL】随机采样一致算法(Random sample consensus,RANSAC)https://blog.csdn.net/QLeelq/article/details/122079778?spm=1001.2014.3001.5502
 https://github.com/AbangLZU/plane_fit_ground_filter
 https://www.cityscapes-dataset.com/
 CODA: A Real-World Road Corner Case Dataset for Object Detection in Autonomous Driving
 https://github.com/AbangLZU
      http://www.open3d.org/docs/release/tutorial/geometry/pointcloud.html
posted @ 2022-04-21 15:08  辰令  阅读(569)  评论(0编辑  收藏  举报