三维重建_彩色图和深度图转点云文件、ply和pcd相互转换、点云合并

目录

1 彩色图 + 深度图 = 点云

2 ply转pcd

3 pcd转ply

4 点云合并


1 彩色图 + 深度图 = 点云

// C++ 标准库
#include <iostream>
#include <string>
using namespace std;

// OpenCV 库
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

// PCL 库
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>

// 定义点云类型
typedef pcl::PointXYZRGBA PointT;
typedef pcl::PointCloud<PointT> PointCloud;

// 相机内参
const double camera_factor = 1000;
const double camera_cx = 325.5;
const double camera_cy = 253.5;
const double camera_fx = 518.0;
const double camera_fy = 519.0;

// 主函数 
int main(int argc, char ** argv)
{
	// 图像矩阵
	cv::Mat rgb, depth;
	// 使用cv::imread()来读取图像
	// rgb 图像是8UC3的彩色图像
	// depth 是16UC1的单通道图像,注意flags设置-1,表示读取原始数据不做任何修改
	rgb = cv::imread("C:\\Users\\Administrator\\Desktop\\color.png");
	depth = cv::imread("C:\\Users\\Administrator\\Desktop\\depth.png", -1);

	// 点云变量
	// 使用智能指针,创建一个空点云。这种指针用完会自动释放。
	PointCloud::Ptr cloud(new PointCloud);
	// 遍历深度图
	for (int m = 0; m < depth.rows; m++)
		for (int n = 0; n < depth.cols; n++)
		{
			// 获取深度图中(m,n)处的值
			ushort d = depth.ptr<ushort>(m)[n];
			// d 可能没有值,若如此,跳过此点
			if (d == 0)
				continue;
			// d 存在值,则向点云增加一个点
			PointT p;

			// 计算这个点的空间坐标
			p.z = double(d) / camera_factor;
			p.x = (n - camera_cx) * p.z / camera_fx;
			p.y = (m - camera_cy) * p.z / camera_fy;

			// 从rgb图像中获取它的颜色
			// rgb是三通道的BGR格式图,所以按下面的顺序获取颜色
			p.b = rgb.ptr<uchar>(m)[n * 3];
			p.g = rgb.ptr<uchar>(m)[n * 3 + 1];
			p.r = rgb.ptr<uchar>(m)[n * 3 + 2];

			// 把p加入到点云中
			cloud->points.push_back(p);
		}
	// 设置并保存点云
	cloud->height = 1;
	cloud->width = cloud->points.size();
	cout << "point cloud size = " << cloud->points.size() << endl;
	cloud->is_dense = false;
	pcl::io::savePLYFile("C:\\Users\\Administrator\\Desktop\\ply.ply", *cloud);   //将点云数据保存为ply文件
	pcl::io::savePCDFile("C:\\Users\\Administrator\\Desktop\\pcd.pcd", *cloud);   //将点云数据保存为pcd文件
	// 清除数据并退出
	cloud->points.clear();
	cout << "Point cloud saved." << endl;
	return 0;
}

2 ply转pcd

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>
#include <pcl/console/time.h>
#include <pcl/io/vtk_lib_io.h>
#include <pcl/io/vtk_io.h>
#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <pcl/visualization/cloud_viewer.h>  
#include <pcl/conversions.h>
using namespace pcl;
using namespace pcl::io;
using namespace pcl::console;
 
int main()
{
	pcl::PCLPointCloud2 point_cloud2;
	pcl::PLYReader reader;
	reader.read("reconstructed_2_1.ply", point_cloud2);
	pcl::PointCloud<pcl::PointXYZ> point_cloud;
	pcl::fromPCLPointCloud2(point_cloud2, point_cloud);
	pcl::PCDWriter writer;
	writer.writeASCII("reconstructed_2_1.pcd", point_cloud);
	cout << "Done!" << endl;
	return 0;
}

3 pcd转ply

#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include<pcl/PCLPointCloud2.h>
#include<iostream>
#include<string>
 
using namespace pcl;
using namespace pcl::io;
using namespace std;
 
int PCDtoPLYconvertor(string & input_filename, string& output_filename)
{
	pcl::PCLPointCloud2 cloud;
	if (loadPCDFile(input_filename, cloud) < 0)
	{
		cout << "Error: cannot load the PCD file!!!" << endl;
		return -1;
	}
	PLYWriter writer;
	writer.write(output_filename, cloud, Eigen::Vector4f::Zero(), Eigen::Quaternionf::Identity(), true, true);
	return 0;
 
}
 
int main()
{
	string input_filename = "./reconstructed_1_reconstructed_2_1.pcd";
	string output_filename = "./reconstructed_1_reconstructed_2_1.ply";
	PCDtoPLYconvertor(input_filename, output_filename);
	cout << "Done!" << endl;
	return 0;
}

4 点云合并

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <string>
 
using namespace std;  // 可以加入 std 的命名空间
 
int main(int argc, char** argv)
{
	string ReviseName;
	cout << "是否已经修改输出文件的名称和K值?请输入Y或N。" << endl;
	cin >> ReviseName;
	if (ReviseName != "Y")
	{
		return (-1);//跳出整个程序
	}
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);	// 总点
 
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud1(new pcl::PointCloud<pcl::PointXYZ>);	// 点云1
	pcl::PCDReader reader;
	reader.read<pcl::PointXYZ>("reconstructed_1.pcd", *cloud1);//读取pcd文件,用指针传递给cloud。
 
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud2(new pcl::PointCloud<pcl::PointXYZ>);	// 点云2
	reader.read<pcl::PointXYZ>("reconstructed_2_1.pcd", *cloud2);//读取pcd文件,用指针传递给cloud。
 
 
	//拷贝点云数据
 
	*cloud = *cloud1;
	*cloud += *cloud2;
 
	//输出时所用离群点的名字
	string name_out1 = "reconstructed_1_";   //因为string变量自身就带着隐含的双引号了,所以不用特意加双引号
	string name_out2 = "reconstructed_2_1.pcd";
	string name_out = name_out1; name_out += name_out2; 
	cout << name_out << endl;
 
	pcl::PCDWriter writer;
	writer.write<pcl::PointXYZ>(name_out, *cloud, false);//滤波后内点(主体点)
	cout << "点云合并完成!" << endl;
 
	return(0);
}

参考:

  • vs2019+opencv配置方法:https://blog.csdn.net/y18771025420/article/details/110373449
  • vs2019+pcl配置方法:https://blog.csdn.net/y18771025420/article/details/110517524
  • 参考文章:https://blog.csdn.net/stq054188/article/details/106408454
     

猜你喜欢

转载自blog.csdn.net/shyjhyp11/article/details/115056068