3D点云数据集制作实录【LiDAR】

在过去的两年里,我一直在和机器人打交道。 今年早些时候,我不再只关注相机,而是决定开始使用激光雷达。 因此,经过大量研究后,我选择了 32 束 RoboSense 设备。
在这里插入图片描述

推荐:用 NSDT编辑器 快速搭建可编程3D场景

我不得不花一些时间来设置它,特别是创建一个合适的支架,也可以携带相机。 经过一番尝试,激光雷达终于准备好了,我宣布我爱上了这种数据。

我项目的下一步是开始开发一个系统,使用 LiDAR 点云检测和跟踪 3D 对象。 应用程序多种多样,但包括检测固定物体(建筑物、交通标志等)以创建 3D 地图,以及检测移动物体(行人、汽车等)以避免碰撞。

在开发上述任何应用程序之前,我首先需要学习如何有效地将点云数据加载到 TensorFlow(我用于深度学习的工具)中。 目前,我的数据集由 12,200 个点云图像对组成。 该图像用作背景来了解激光雷达正在观察什么。 我还对所有点云进行了预处理,以仅显示大约在相机视野内的数据,而不是原始的 360° 视图。
在这里插入图片描述

尝试将数据加载到 TensorFlow 比我预想的更具挑战性。 首先,点云存储为 PCD(点云数据)文件,这是一种用于存储 3D 点云数据的文件格式。 TensorFlow 无法直接处理这种类型的文件,因此需要进行转换。 Open3D 库是一个易于使用的点云操作工具。 使用此工具,我可以轻松加载 PCD 文件并将点提取为 X、Y 和 Z 坐标的 NumPy 数组。 另一个工具 NSDT 3DConvert用于可视化PCD点云并确认在 Google Colab 上正确提取了点:
在这里插入图片描述

https://3dconvert.nsdt.cloud

有了新工具,我将 12,200 个 PCD 和 12,200 个 JPG 上传到我的 Google Drive,并将其连接到 Google Colab。 然后,我创建了一些代码来加载 PCD、提取点并将它们放入 NumPy 数组中,这是 TensorFlow 可以轻松处理的结构。 我自信地运行了代码,并惊恐地看到,等待几分钟后,Colab 抱怨在转换点云时内存不足。 坏消息,因为我计划收集和处理比目前更多的数据。

幸运的是,这是处理大型数据集时的常见问题,而 TensorFlow 等工具具有处理此类情况的功能。 所需的解决方案是 Dataset API,它提供了创建高效输入管道的方法。 引用API的文档:数据集的使用遵循一个常见的模式:

  • 根据你的输入数据创建源数据集。
  • 应用数据集转换来预处理数据。
  • 迭代数据集并处理元素。
  • 迭代以流式传输的方式进行,因此完整的数据集不需要装入内存。

因此,本质上,Dataset API 将允许我创建一个管道,并且数据将根据 TensorFlow 中的训练循环的请求分部分加载,从而避免内存不足。 因此,我回顾了如何使用 API,并创建了一些代码来构建数据管道。 按照上述模式的步骤 1,代码首先加载所有 PCD 和图像的 URL 列表,然后在步骤 2 中,加载 PCD 并将其转换为 NumPy 中的点,然后加载图像并对其进行标准化。 但这时候我又遇到了麻烦。

为了提高效率,Dataset API 中的所有内容(显然还有所有 TensorFlow API)都作为图中的张量运行。 Dataset API 提供了从不同格式加载数据的函数,但没有用于 PCD 的函数。 在研究了不同的可能解决方案后,我决定不再将数据作为多个 PCD 和 JPEG 文件并让 TensorFlow 加载并预处理它们,而是离线预处理所有数据,并将其打包到 HDF5 文件中 。

HDF5 是一种开源文件格式,支持大型、复杂、异构数据。 我显然已经验证了 Dataset API 支持这种类型的文件。 使用这种格式的主要优点除了可以很好地使用 TensorFlow 之外,还在于我可以将所有数据打包到一个结构良好的大文件中,以便我可以轻松移动。 我创建了一个简单的 Python 脚本来加载所有 PCD、提取点,并将它们与相应的上下文文件一起打包到一个漂亮的 HDF5 文件中。

def generate_hdf5_dataset_with_padding(path, run_name, hdf5_filename):

	# Build main path
	path = join(path, run_name)
	
	# Get files
	jpgs = sorted(glob.glob(path+"/jpg/*.jpg"))
	pcds = sorted(glob.glob(path+"/pcd/*.pcd"))

	# Open HDF5 file in write mode
	with h5py.File(hdf5_filename, 'w') as f:
		
		images = []
		point_clouds = []
		
		# Determine the size of largest point cloud for padding
		max_size = 0

		for i, jpg in enumerate(jpgs):

			base_name = jpg[jpg.rfind("/")+1:jpg.find(".jpg")]

			# Load the image
			image = cv2.cvtColor(cv2.imread(jpgs[i]), cv2.COLOR_BGR2RGB) 
			images.append(image)

		
			# Load the point cloud
			cloud = o3d.io.read_point_cloud(pcds[i])
			points= np.asarray(cloud.points)
			point_clouds.append(points)
			
			# Keep track of largest size
			if points.shape[0] > max_size:
				max_size = points.shape[0]
			
			if ((i+1) % 1000 == 0):
				print("Processed ",(i+1)," pairs of files.")
				
		print("Max size ", max_size)
		print("Padding ...")

		# Pad the point clouds with 0s
		padded_point_clouds = []
		for points in point_clouds:
			pad_amount = max_size - points.shape[0]
			
			points_padded = np.pad(points, ((0, pad_amount),(0, 0)), 'constant', constant_values=(0, 0))
			padded_point_clouds.append(points_padded)

		# Create an images and a point clouds dataset in the file
		f.create_dataset("images", data = np.asarray(images))
		f.create_dataset("point_clouds", data = np.asarray(padded_point_clouds))
		
	print("Done!")

将 HDF5 文件(约 18 GB)加载到我的 Drive 中后,我返回 Colab 并添加相应的数据集 API 代码。 本质上,该模式的第 1 步从 HDF5 文件加载图像和点并创建相应的对,第 2 步从点云中随机选择一些点(我将在后面的文章中解释原因),并对图像进行归一化, 步骤 3 已准备好根据请求很好地提供数据。

def resize_and_format_data(points, image):

  # Sample a random number of points
  idxs = tf.range(tf.shape(points)[0])
  ridxs = tf.random.shuffle(idxs)[:SAMPLE_SIZE]
  points = tf.gather(points, ridxs)

  # Normalize pixels in the input image
  image = tf.cast(image, dtype=tf.float32)
  image = image/127.5
  image -= 1
  
  return points, image

def get_training_dataset(hdf5_path):
  # Get the point clouds
  x_train = tfio.IODataset.from_hdf5(hdf5_path, dataset='/point_clouds')
  # Get the images
  y_train = tfio.IODataset.from_hdf5(hdf5_path, dataset='/images')
  # Zip them to create pairs
  training_dataset = tf.data.Dataset.zip((x_train,y_train))
  # Apply the data transformations
  training_dataset = training_dataset.map(resize_and_format_data)
  
  # Shuffle, prepare batches, etc ...
  training_dataset = training_dataset.shuffle(100, reshuffle_each_iteration=True)
  training_dataset = training_dataset.batch(BATCH_SIZE)
  training_dataset = training_dataset.repeat()
  training_dataset = training_dataset.prefetch(-1)

  # Return dataset
  return training_dataset

我使用非常基本的训练代码尝试了数据管道,效果非常好。 不再出现内存不足错误。 我不确定这是否是提供数据的最有效方法,但它确实成功了,特别是,创建管道是点云数据操作的第一个很好的练习。 接下来,使用点云训练第一个 TensorFlow 模型。


原文链接:制作3D点云数据集 — BimAnt

猜你喜欢

转载自blog.csdn.net/shebao3333/article/details/133301550
今日推荐