【点云学习】二:获取并保存彩色点云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;
	int count = 0;
	while (count <= 0)
	{
		Sleep(5000);
		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);//深度图到相机三维空间的映射


		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);
		/*char image_name[13];
		sprintf(image_name, "%s%d%s", "C:/Users/Xu_Ruijie/Desktop", count, ".pcd");
		imwrite(image_name, im);*/
		string s = "我来了";
		s += ".pcd";
		pcl::io::savePCDFile(s, *cloud, false);
		std::cerr << "Saved " << cloud->points.size() << " data points." << std::endl;
		viewer.showCloud(cloud);
		
		count++;
		mColorImg.release();
		mDepthImg.release();
		cloud->clear();
		waitKey(10);

	}
	return 0;
}

在基础上加了保存pcd的命令,while那里count可以随便改,注意保存的时候修改一下每次保存的文件名就行了。再贴一个无颜色的点云获取 原始点云获取

余留问题

  1. 我获得原始点云时候,保存了pcd,但是我读不出来,显示pcd::io报错,特别奇怪,就是read那里中止了,希望明天可以解决。【已解决】
    代码直接贴出来了:文件名改成自己的就行,但是这个读出来只是没有颜色的点云,还需进一步完善。
#include<iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
void viewerOneOff(pcl::visualization::PCLVisualizer& viewer) {
    viewer.setBackgroundColor(1.0f, 0.5f, 1.0f);
}

int main(int argc, char** argv) {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

    //*打开点云文件
    if (pcl::io::loadPCDFile<pcl::PointXYZ>("test2.pcd", *cloud) == -1) {
        PCL_ERROR("Couldn't read file rabbit.pcd\n");
        return(-1);
    }
    std::cout << cloud->points.size() << std::endl;
    pcl::visualization::CloudViewer viewer("cloud viewer");
    viewer.showCloud(cloud);
    viewer.runOnVisualizationThreadOnce(viewerOneOff);

    system("pause");
    return 0;
}
  1. pointnet的图片是ply格式的。
  2. 代码有些还不太明白。
  3. 之后就是点云分割和滤波处理了。

还在学习中,欢迎留言。

  • 7
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
在Python中,可以使用不同的库获取彩色点云数据。其中一种常用的库是Open3D。你可以使用Open3D库中的函数来读取彩色点云文件,并将其转换为点云数据结构。 首先,你需要安装Open3D库。可以使用pip命令进行安装,如下所示: ``` pip install open3d ``` 接下来,你可以使用下面的代码来读取彩色点云文件: ```python import open3d as o3d # 读取彩色点云文件 pcd = o3d.io.read_point_cloud("path/to/your/file.ply") # 查看点云信息 print(pcd) ``` 在上面的代码中,你需要将"path/to/your/file.ply"替换为你的彩色点云文件的路径。 通过上述代码,你可以将彩色点云文件读取到一个点云数据结构中,并且可以查看点云的信息。你可以根据需要,对读取到的点云数据进行进一步的处理和操作,例如点云配准、点云分割、点云可视化等。在Open3D库中,还提供了许多函数和方法来进行这些操作。 请注意,上述代码只是一个简单的示例,实际应用中可能需要根据具体的彩色点云文件的格式和数据结构进行相应的调整。此外,在获取彩色点云之前,你可能需要先获取对应的深度图像和RGB图像数据,然后将它们组合成彩色点云。 引用:这里我们将配准好的点云文件直接拿过来用。这两个文件分别是bun001.ply文件和bun002.ply。文件下载地址为python点云拼接样例数据-深度学习文档类资源-CSDN下载。 1 python拼接程序 。 引用:python三维点云研究计划_Coding的叶子的博客-CSDN博客_3d点云 python将按照以下目录持续进行更新……点云格式介绍、点云可视化、点云投影、生成鸟瞰图、生成前视图、点云配准、点云分割、三维目标检测、点云重建、深度学习点云算法……https://blog.csdn.net/suiyingy/article/details/124017716点云配准(一)— ICP方法_Coding的叶子的博客-CSDN博客点云配准——ICP方法介绍https://blog.csdn.net/suiyingy/article/details/124336448更多三维、维感知算法和金融量化分析算法请关注“乐乐感知学堂”微信公众号,并将持续进行更新。 。 引用:点云拼接主要是把不同的点云拼接到一起。通常,为了获得一个完整物体的三维点云,我们可能会在不同的视点进行数据采集,然后把采集的点云数据拼接到一起。 。 <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [python点云拼接](https://blog.csdn.net/suiyingy/article/details/124343913)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值