点云投影至xoy平面生成强度图像

一、备注:

        重新更改过一次的版本,由于新电脑还没来得及装VS 配环境,所以没有测过,后续环境配好了会测一下,做个效果图。先贴上代码吧。按道理应该是没什么问题的,有报错欢迎底下留言!

后续会补上 地面点提取  提取之后 离群点剔除 相关代码

一、算法原理

        就很简单 将点云正射投影至xoy平面,设置固定分辨率,构建格网,求格网内的强度极大值,将强度极大值映射为0~255赋给像素值

 二、代码

// opencv
#include <opencv2/opencv.hpp>   
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
// pcl
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
//lablas
#include <liblas/liblas.hpp>

using namespace std;
using namespace cv;

typedef  pcl::PointCloud<pcl::PointXYZI>::Ptr      pcXYZIPtr;
typedef  pcl::PointCloud<pcl::PointXYZI>           pcXYZI;

/*!
* @brief 读取las格式点云数据函数
* param[in] file_name:las文件  
* param[in] point_cloud:点云指针   
*/
bool readLasFile(const string &file_name, const pcXYZIPtr &point_cloud)
{
	std::ifstream ifs;
	ifs.open(file_name, std::ios::in | std::ios::binary);
	if (ifs.bad())
	{
		cout << "Failed to load las File" << endl;
	}
	liblas::ReaderFactory f;
	liblas::Reader reader = f.CreateWithStream(ifs);
	int number_points = reader.GetHeader().GetPointRecordsCount();//获取las数据点的个数
	point_cloud->width = number_points;
	point_cloud->height = 1;
	point_cloud->is_dense = false;
	point_cloud->resize(point_cloud->width * point_cloud->height);

	liblas::Header const &header = reader.GetHeader();
	int i = 0;
	while (reader.ReadNextPoint())
	{
		point_cloud->points[i].x = reader.GetPoint().GetX();
		point_cloud->points[i].y = reader.GetPoint().GetY();
		point_cloud->points[i].z = reader.GetPoint().GetZ();
		point_cloud->points[i].intensity = reader.GetPoint().GetIntensity();
		
		i++;
	}
	// 检查 强度信息是否存在
	if (point_cloud->points[0].intensity == 0) //check if the intensity exsit
	{
		cout << "Warning! Point cloud intensity may not be imported properly, check the scalar field's name.\n" << endl;
	}
	return 1;
}

/*!
* @brief 点云转强度图像函数
* param[in] cloud:点云指针  
* param[in] resolution:点云转图像分辨率  
* param[out] img: 点云生成的强度图像
*/
cv::Mat pointCloud2imgI(const pcXYZIPtr &cloud, double resolution)
{
	float minx, miny, maxx, maxy, mini, maxi;
	minx = miny = mini = FLT_MAX;
	maxx = maxy = maxi = -FLT_MAX;

	// 获取点云的最大最小 x、y点的坐标
	for (int i = 0; i < cloud->points.size(); i++)
	{
		minx = min(minx, cloud->points[i].x);
		miny = min(miny, cloud->points[i].y);
		maxx = max(maxx, cloud->points[i].x);
		maxy = max(maxy, cloud->points[i].y);
        maxi = max(manxi, cloud->points[i].intensity);
	}

	double lx = maxx - minx;					//点云长度
	double ly = maxy - miny;					//点云宽度
	int rows = round(ly / resolution);			//图像高度
	int clos = round(lx / resolution);			//图像宽度

	cv::Mat img = cv::Mat::zeros(rows, clos, CV_8UC3);

	//强度格网矩阵
	vector<vector<float>> vec_grid_intensity;   

	//格网分配空间 及初始化
	vec_grid_intensity.resize(rows);
	//初始化格网
	for (int i = 0; i < rows; i++)
	{
		vec_grid_intensity[i].resize(clos);
	}

	//依次将点压入所在格网
	for (int i = 0; i < cloud->points.size(); i++)
	{
		int m = (maxy - cloud->points[i].y) / resolution;
		int n = (cloud->points[i].x - minx) / resolution;

		if (m > 0 && m < rows && n > 0 && n < clos)
		{
		    // 将格网中的点云的最大强度值作为格网的强度值
			vec_grid_intensity[m][n] = max(cloud->points[i].intensity, vec_grid_intensity[m][n]);	
		}
	}

	//强度拉伸到0-255之间赋值
	for (int i = 0; i < rows; i++)
	{
		uchar * data = img.ptr<uchar>(i);
		for (int j = 0; j < clos; j++)
		{
			if (vec_grid_intensity[i][j] > 0)
			{
				int pixel = (int)(vec_grid_intensity[i][j]  / maxi * 255);
				//各通道像素赋值
				data[3 * j] = pixel;
				data[3 * j + 1] = pixel;
				data[3 * j + 2] = pixel;
			}
		}
	}
	return img;
}

int main()
{
	const string las_path = "D:/实验/点云/光谷大道.las";
	const double resolution = 0.05;

	pcXYZIPtr cloud(new pcXYZI);

	readLasFile(las_path, cloud);
	Mat cloud_imgI = pointCloud2imgI(cloud, resolution);

	imwrite("cloud_img.jpg", cloud_imgI);
}

三、结果

原始点云

强度图像

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值