点云学习二:获取并保存彩色点云PCD文件

点云学习二:获得彩色点云PCD文件

上一篇博客讲的是如何用Kinect+opencv获得RGB-D图像和深度图像。这篇主要介绍pcd文件。整合了几篇不错的博客,方便自己理解。

PCD文件

点云数据是指在一个三维坐标系中的一组向量的集合。这些向量通常以X,Y,Z三维坐标的形式表示,一般主要代表一个物体的外表面几何形状,除此之外点云数据还可以附带RGB信息,即每个坐标点的颜色信息,或者是其他的信息。
PCL这个开源库专门处理pcd格式的文件,它实现了点云获取、滤波、分割、配准、检索、特征提取、识别、追踪、曲面重建、可视化等。

# .PCD v0.7 - Point Cloud Data file format
VERSION 0.7
FIELDS x y z rgba       RGB三个值通过位运算合一起
SIZE 4 4 4 4            以字节为单位指定每个数据所占用的内存。
TYPE F F F U            指定每个数据的数据类型。
                        I:可表示int8,int16,int32。
                        U:可表示uint8,unit16,uint32。
                        F:表示float(上图所用的为浮点类型)。
COUNT 1 1 1 1           指定每个维度有多少元素,xyz数据通常只有一个元素。
WIDTH 181550            指定数据点的宽度,它包含两个含义:
                        1.可指定点云总个数(与POINTS相同),用于无组织的数据。
                        2.可指定有组织点云数据的宽度(连续点的总数)。
HEIGHT 1                指定数据点的高度,它包含两个含义:
                        1.可指定有组织的点云数据的高度(总行数)。
                        2.对未组织的数据,它被设置为1。
VIEWPOINT 0 0 0 1 0 0 0 采集数据时的视点(由平移tx,ty,tz和四元数qw,qx,qy,qz组成)。
POINTS 181550           指定点云总个数。
DATA ascii              数据类型
1.3159573 0.89465034 1.7700001 4287533445
1.3135536 0.88792604 1.7680001 4287270020
1.3126484 0.88222772 1.7680001 4287402374
1.3117549 0.87654412 1.7680001 4287402887
1.3153214 0.87383044 1.774 4287270785
1.3174117 0.87011409 1.7780001 4287467650
1.3172878 0.86492777 1.779 4287335811

数据解说摘自

这个是我用Kinect显示出的彩色点云数据的一部分,图就是下面这个灯。
在这里插入图片描述

保存彩色点云

再来说是如何获得的,代码如下:来源

#include <Kinect.h>
#include <opencv2\opencv.hpp>
#include <pcl/visualization/cloud_viewer.h> 
#include <pcl/visualization/pcl_visualizer.h>
#include <opencv2/highgui/highgui.hpp>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>

using namespace cv;
using namespace std;


IKinectSensor* pSensor;
ICoordinateMapper* pMapper;
const int iDWidth = 512, iDHeight = 424;//深度图尺寸
const int iCWidth = 1920, iCHeight = 1080;//彩色图尺寸
CameraSpacePoint depth2xyz[iDWidth * iDHeight];
ColorSpacePoint depth2rgb[iCWidth * iCHeight];


void viewerOneOff(pcl::visualization::PCLVisualizer& viewer)
{
	viewer.setBackgroundColor(1.0, 1.0, 1.0);//设置背景颜色 
}


//启动Kinect
bool initKinect()
{
	if (FAILED(GetDefaultKinectSensor(&pSensor))) return false;
	if (pSensor)
	{
		pSensor->get_CoordinateMapper(&pMapper);
		pSensor->Open();
		cout << "已打开相机" << endl;
		return true;
	}
	else return false;
}
//获取深度帧
Mat DepthData()
{
	IDepthFrameSource* pFrameSource = nullptr;
	pSensor->get_DepthFrameSource(&pFrameSource);
	IDepthFrameReader* pFrameReader = nullptr;
	pFrameSource->OpenReader(&pFrameReader);
	IDepthFrame* pFrame = nullptr;
	Mat mDepthImg(iDHeight, iDWidth, CV_16UC1);
	while (true)
	{
		if (pFrameReader->AcquireLatestFrame(&pFrame) == S_OK)
		{

			pFrame->CopyFrameDataToArray(iDWidth * iDHeight, reinterpret_cast<UINT16*>(mDepthImg.data));
			cout << "已获取深度帧" << endl;
			pFrame->Release();
			return mDepthImg;
			break;
		}
	}
}
//获取彩色帧
Mat RGBData()
{
	IColorFrameSource* pFrameSource = nullptr;
	pSensor->get_ColorFrameSource(&pFrameSource);
	IColorFrameReader* pFrameReader = nullptr;
	pFrameSource->OpenReader(&pFrameReader);
	IColorFrame* pFrame = nullptr;
	Mat mColorImg(iCHeight, iCWidth, CV_8UC4);
	while (true)
	{
		if (pFrameReader->AcquireLatestFrame(&pFrame) == S_OK)
		{

			pFrame->CopyConvertedFrameDataToArray(iCWidth * iCHeight * 4, mColorImg.data, ColorImageFormat_Bgra);
			cout << "已获取彩色帧" << endl;
			pFrame->Release();
			return mColorImg;
			break;
		}
	}
}


int main()
{
	initKinect();
	pcl::visualization::CloudViewer viewer("Cloud Viewer");
	viewer.runOnVisualizationThreadOnce(viewerOneOff);
	pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGBA>);
	Mat mColorImg;
	Mat mDepthImg;
	while (cv::waitKey(30) != VK_ESCAPE)
	{
		mColorImg = RGBData();
		mDepthImg = DepthData();
		imshow("RGB", mColorImg);
		pMapper->MapDepthFrameToColorSpace(iDHeight * iDWidth, reinterpret_cast<UINT16*>(mDepthImg.data), iDHeight* iDWidth, depth2rgb);//深度图到颜色的映射
		pMapper->MapDepthFrameToCameraSpace(iDHeight * iDWidth, reinterpret_cast<UINT16*>(mDepthImg.data), iDHeight* iDWidth, depth2xyz);//深度图到相机三维空间的映射
		//for (int i = 0; i < iDWidth*iDHeight; i++)
		//{
		//	cout << i << ":  " << "X=" << depth2rgb[i].X << ";  Y=" << depth2rgb[i].Y<<endl;
		//}

		float maxX = depth2xyz[0].X, maxY = depth2xyz[0].Y, maxZ = depth2xyz[0].Z;
		float minX = depth2xyz[0].X, minY = depth2xyz[0].Y, minZ = depth2xyz[0].Z;
		for (size_t i = 0; i < iDWidth; i++)
		{
			for (size_t j = 0; j < iDHeight; j++)
			{
				pcl::PointXYZRGBA pointTemp;
				if (depth2xyz[i + j * iDWidth].Z > 0.5 && depth2rgb[i + j * iDWidth].X < 1920 && depth2rgb[i + j * iDWidth].X>0 && depth2rgb[i + j * iDWidth].Y < 1080 && depth2rgb[i + j * iDWidth].Y>0)
				{
					pointTemp.x = -depth2xyz[i + j * iDWidth].X;
					if (depth2xyz[i + j * iDWidth].X > maxX) maxX = -depth2xyz[i + j * iDWidth].X;
					if (depth2xyz[i + j * iDWidth].X < minX) minX = -depth2xyz[i + j * iDWidth].X;
					pointTemp.y = depth2xyz[i + j * iDWidth].Y;
					if (depth2xyz[i + j * iDWidth].Y > maxY) maxY = depth2xyz[i + j * iDWidth].Y;
					if (depth2xyz[i + j * iDWidth].Y < minY) minY = depth2xyz[i + j * iDWidth].Y;
					pointTemp.z = depth2xyz[i + j * iDWidth].Z;
					if (depth2xyz[i + j * iDWidth].Z != 0.0)
					{
						if (depth2xyz[i + j * iDWidth].Z > maxZ) maxZ = depth2xyz[i + j * iDWidth].Z;
						if (depth2xyz[i + j * iDWidth].Z < minZ) minZ = depth2xyz[i + j * iDWidth].Z;
					}
					pointTemp.b = mColorImg.at<cv::Vec4b>(depth2rgb[i + j * iDWidth].Y, depth2rgb[i + j * iDWidth].X)[0];
					pointTemp.g = mColorImg.at<cv::Vec4b>(depth2rgb[i + j * iDWidth].Y, depth2rgb[i + j * iDWidth].X)[1];
					pointTemp.r = mColorImg.at<cv::Vec4b>(depth2rgb[i + j * iDWidth].Y, depth2rgb[i + j * iDWidth].X)[2];
					pointTemp.a = mColorImg.at<cv::Vec4b>(depth2rgb[i + j * iDWidth].Y, depth2rgb[i + j * iDWidth].X)[3];
					cloud->push_back(pointTemp);
				}

			}

		}
		pcl::io::savePCDFileASCII("deng.pcd", *cloud);
		/*string s = "我来了";
		s += ".pcd";
		pcl::io::savePCDFile(s, *cloud, false);
		std::cerr << "Saved " << cloud->points.size() << " data points." << std::endl;*/
		viewer.showCloud(cloud);
		mColorImg.release();
		mDepthImg.release();
		cloud->clear();
		waitKey(10);

	}

	return 0;
}

在基础上加了保存pcd的命令,但是我觉得不够严谨,因为这个代码是实时的。再贴一个无颜色的点云获取 原始点云获取

余留问题

  1. 我获得原始点云时候,保存了pcd,但是我读不出来,显示pcd::io报错,特别奇怪,就是read那里中止了,希望明天可以解决。
  2. pointnet的图片是ply格式的,要试着改一下实时。
  3. 代码有些还不太明白。
  4. 之后就是点云分割和滤波处理了。

还在学习中,欢迎留言。

猜你喜欢

转载自blog.csdn.net/weixin_45709940/article/details/107967333