用c++ PCL库和Opencv库实现将点云数据转化成图片形式

用c++ PCL库和Opencv库实现将点云数据转化成图片形式

自己的毕业设计与点云相关,现在想要将得到的点云切割数据转化为图片形式,然后进行opencv的图像处理,但是苦于找了很多资料,没有很详细的内容介绍,于是自己用c++,写了一套程序。

参考连接

链接: http://ronny.rest/tutorials/module/pointclouds_01/point_cloud_mpl/

链接: https://blog.csdn.net/learning_tortosie/article/details/88828388

图像和点云坐标

先要理解好图像和点云坐标的关系是完成整个流程关键的基础

用c++ PCL库和Opencv库实现将点云数据转化成图片形式_第1张图片

蓝色坐标轴就是图像的坐标系,黄色坐标指的是点云的坐标系。

在这里注意:
1.图像坐标系中的对应坐标轴始终为正值
2.图像坐标系的原点是在图像的左上角点
3.图像坐标系坐标值是int整数型

4.点云坐标原点是相机点
5.至于点云坐标系中的x轴y轴z轴指向要看你的鸟瞰视图视哪一个方向的,以我距离,我的是以上图片的坐标系。

鸟瞰图和坐标系的关系

用c++ PCL库和Opencv库实现将点云数据转化成图片形式_第2张图片
用c++ PCL库和Opencv库实现将点云数据转化成图片形式_第3张图片

如上如所看,我的坐标系以及款选点云框与坐标系之间的关系:
**在这里规定:
x_img表示图像坐标系中,x轴坐标
y_img表示图像坐标系中,y轴坐标
x_max表示图像的x轴大小,用于设置图像大小
y_max表示图像y轴大小,用于设置图像大小
pixel_values表示在图像坐标系中对应坐标的函数值
**

设置款选点云的矩形框

	float side_range [] = { -1500,800 };
	float fwd_range[] = { -500 ,500 };
	float height_range[] = { -2,2};//y轴相关

	//记录筛选出来的点云下标
	vectorindices;

	//获取用矩形框款住想要的点云 利用循环每一个点云,筛选出属于规定框中的点云
	for (int i = 0; i < cloud->points.size(); i++) {
		if ((cloud->points[i].x > fwd_range[0] && cloud->points[i].x < 		fwd_range[1]) && (cloud->points[i].z > side_range[0] && cloud-	>points[i].z < side_range[1]))
		{
			indices.push_back(i);
		}
	};

将点云的厚度信息经过比例转化成255对应值,赋值到img图像对应的坐标值中

	//将点云的厚度信息经过比例转化成255对应值,赋值到img图像对应的坐标值中
	for (int i = 0; i < indices.size(); i++) {
		pixel_values[i]=scale_to_255(pixel_values[i], height_range[0], height_range[1]);
	}
	//将a值缩放到0-255之间,放回的类型是整型int
	int scale_to_255(int pixel_value, int min, int max) {
		return int((((pixel_value - min) / float(max - min)) * 255));
	}

源代码

注释比较清晰,欢迎大家一起交流,本人小白,不断摸索,有不足之处欢迎提供建议

#include 
#include 
#include   
#include 
#include
using namespace std;

//将a值缩放到0-255之间,放回的类型是整型int
int scale_to_255(int pixel_value, int min, int max) {
	return int((((pixel_value - min) / float(max - min)) * 255));
}

void use_pcdTopicture_main(pcl::PointCloud< pcl::PointXYZRGB>::Ptr cloud, float res, float side_range_left, float side_range_right, float fwd_range_behind , float fwd_range_front, float height_range_min,float height_range_max) {
	/*初始化 
	cloud        表示点云地址
	res          表示分辨率
	side_range   left - most to right - most
	fwd_range    back - most to forward - most
	height_range bottom - most to upper - most*/
	res = 1.0;
	//获取点云的最值
	pcl::PointXYZRGB min, max;
	pcl::getMinMax3D(*cloud, min, max);
	//将点云的最值设置为框住点云的边界,自动设置边框大小,目的就是构建图片大小。
	//在cloudcompare中绿色坐标轴代表y,红色坐标轴代表x,蓝色坐标轴代表z,因此我们想要的是水平面也就是XOZ面
	//根据双目成像原理我认为点云的原点就是相机的位置。,所以我认为款选的是要固定的
	float side_range [] = { -1500,800 };
	float fwd_range[] = { -500 ,500 };
	float height_range[] = { -2,2};//y轴相关
	//记录筛选出来的点云下标
	vectorindices;

	//获取用矩形框款住想要的点云 利用循环每一个点云,筛选出属于规定框中的点云
	for (int i = 0; i < cloud->points.size(); i++) {
		if ((cloud->points[i].x > fwd_range[0] && cloud->points[i].x < fwd_range[1]) && (cloud->points[i].z > side_range[0] && cloud->points[i].z < side_range[1]))
		{
			indices.push_back(i);
		}
	};

	//在img图像中坐标
	vectorx_img;
	vectory_img;
	//将点云的值映射到像素位置中,分辨率为1的话则,将点云的值原封不动的映射到图像中
	for (int i = 0; i < indices.size(); i++) {
		x_img.push_back(-cloud->points[i].z/res);
		y_img.push_back(-cloud->points[i].x / res);

	}
	//平移图像数据到点云的最左上角
	for (int i = 0; i < indices.size(); i++) {
		x_img[i]-=int(floor(side_range[0]/res));
		y_img[i] += int(ceil(fwd_range[1] / res));

	}
	//将厚度信息的值转化为255值,并且填充到对应的img中对应的坐标中
	vectorpixel_values;
	//先筛选符合厚度条件的点云
	for (int i = 0; i < indices.size(); i++) {
		if (cloud->points[i].y > height_range[0] && cloud->points[i].y < height_range[1])
		{
			pixel_values.push_back(cloud->points[i].y);
		}
	}
	//将点云的厚度信息经过比例转化成255对应值,赋值到img图像对应的坐标值中
	for (int i = 0; i < indices.size(); i++) {
		pixel_values[i]=scale_to_255(pixel_values[i], height_range[0], height_range[1]);
	}

	//创建图像大小,取决于我们所定义的框选矩形和分辨率
	int x_max = 1 + int((side_range[1] - side_range[0]) / res);
	int y_max = 1 + int((fwd_range[1] - fwd_range[0]) / res);
	//利用opencv创建一个Mat类型来存储图像的信息
	cv::Mat im = cv::Mat::zeros(x_max, y_max, CV_8U);
	//im[x_img, y_img]=pixel_values;
	//创建一个循环,遍历x_img或者y_img的点,给Mat类型的图像,对应的x_img,y_img坐标赋值pixel_values值
	for (int i = 0; i < x_img.size(); i++) {
		im.at(x_img[i], y_img[i]) = pixel_values[i];
	}
	//数据图片打印信息
	cout << "图像中x轴最小点坐标值为x_img min:"<< *min_element(x_img.begin(), x_img.end()) << endl;
	cout << "图像中x轴最大点坐标值为x_img max:" << *max_element(x_img.begin(), x_img.end()) << endl;
	cout << "图像中y轴最小点坐标值为y_img min:" << *min_element(y_img.begin(), y_img.end()) << endl;
	cout << "图像中y轴最大点坐标值为y_img max:" << *max_element(y_img.begin(), y_img.end()) << endl;
	
	

	//可视化
	cvNamedWindow("img_result");
	cv::imshow("img_result", im);

	//取反
	cv::Mat im_reverse;
	im_reverse = 255 - im;
	cvNamedWindow("img_reverse_result");
	cv::imshow("img_reverse_result", im_reverse);
	cvvWaitKey();

	//将图片保存
	std::vectorparam;
	param.push_back(CV_IMWRITE_PXM_BINARY);
	cv::imwrite("img_reverse_result.bmp", im_reverse, param);
	cout << "save img" << endl;
	
}

如果复制本人代码,希望能够引出引用,尊重本人成果

你可能感兴趣的:(计算机视觉,opencv,图像处理)