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

一、备注:

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

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

一、算法原理

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

 二、代码

// opencv
#include    
#include 
#include 
// pcl
#include 
#include 
//lablas
#include 

using namespace std;
using namespace cv;

typedef  pcl::PointCloud::Ptr      pcXYZIPtr;
typedef  pcl::PointCloud           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> 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(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);
}

三、结果

原始点云

点云投影至xoy平面生成强度图像_第1张图片

强度图像

点云投影至xoy平面生成强度图像_第2张图片

你可能感兴趣的:(点云数据处理,C++,c++)