当前位置:   article > 正文

点云转二维图_3d点云图转换为2d图

3d点云图转换为2d图

开发过程中,有将三维点云转换为二维图片的需求。介绍2个转换的方式:

一、通过三维平面投影到二维图片上,这种方式相对准确。

假设有一个相机坐标系下的三维点(x,y,),则它在图像平面上的投影坐标(u,v )可通过以下公式计算得到:

u= (fx *X +cx*Z) / Z

v= (fy *Y +cy*Z) / Z

其中,fx、fy、cx、y表示相机的内部参数,1表示单位矩阵的最后一个元素.

相机内参矩阵K:

fx 0 cx

0 fy cy

0 0 1

  1. pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);   
  2.     double fx = 4810;
  3. double fy = 4807.4;
  4. double cx = 0;
  5. double cy = 0;
  6. double minValue = std::min(min.x, min.y);
  7. minValue = -minValue;        //整体平移,防止出现负数
  8. // Convert point cloud to depth image
  9. cv::Mat depth_image(cloud->width(), cloud->height() , CV_32FCI);
  10. float* depth_data = (float*)depth_image.data;
  11. for (int i = 0; i < cloud->points.size(); i++) {
  12. pcl::PointXYZRGB point = cloud->points[i];
  13. int u = std::round((point.x+ minValue) / fabs(point.z) * fx + cx);
  14. int v = std::round((point.y+ minValue) / fabs(point.z) * fy + cy);
  15. if (u >= 0 && u < depth_image.cols && v >= 0 && v < depth_image.rows) {
  16. depth_data[v * depth_image.cols + u] = fabs(point.z);
  17. }
  18. }
  19. double min_depth , max_depth ;
  20. cv::minMaxLoc(depth_image, &min_depth, &max_depth);
  21. cv::Mat normalized_depth_image;
  22. //z轴颜色归一至0-255
  23. cv::normalize(depth_image, normalized_depth_image, 0, 255, cv::NORM_MINMAX, CV_32FC1);
  24. // 将归一化后的深度图像数据类型转换为CV_8UC1类型
  25. cv::Mat depth_image_8u;
  26. normalized_depth_image.convertTo(depth_image_8u, CV_8UC1);
  27. cv::Mat colorDepthImage; // 上色后的深度图像
  28. // 将灰度深度图映射为热度图
  29. cv::applyColorMap(depth_image_8u, colorDepthImage, cv::COLORMAP_JET);
  30. cv::imshow("Depth Image", colorDepthImage);

注意:以上的点云是针对有序的点云数据,如果点云是无序的(即height为1),图片的大小可用点云最值代替pcl::getMinMax3D(*cloud, min, max)不再赘述。

二、根据点云位置点直接对应到二维图片,可能会失真(不得不用才使用)

点云根据点云最大最小或者点云宽高在图片像素上遍历。

  1.    //获取点云最值
  2. pcl::PointXYZRGB min;//用于存放三个轴的最小值
  3. pcl::PointXYZRGB max;//用于存放三个轴的最大值
  4. pcl::getMinMax3D(*cloud, min, max);
  5. for (auto& point : cloud->points) {//转为正数
  6. point.x -= min.x;
  7. point.y -= min.y;
  8. point.z -= min.z;
  9. }
  10. pcl::getMinMax3D(*cloud, min, max);
  11. int Prow = ceil(max.x - min.x) ;//向上取整
  12. int Pcol = ceil(max.y - min.y) ;
  13. cv::Mat image1(Prow,Pcol, CV_8UC1);//注意当前为单通道,灰色
  14.     //cv::Mat image(image1.rows, image1.cols, CV_8UC3,
  15. //cv::Scalar(255, 255, 255)); 转为三通道
  16. //初始化图像像素为255
  17. for (int i = 0; i < image.rows; i++)
  18. {
  19. for (int j = 0; j < image.cols; j++)
  20. {
  21. image.at<uchar>(j,i) = 255;
  22. }
  23. }
  24. //根据点云高度对图像进行赋值
  25. for (int i = 0; i < cloud1->points.size(); i++)
  26. {
  27. int image_i, image_j;
  28. image_i = cloud1->points[i].y;
  29. image_j =cloud1->points[i].x;
  30. //根据点云高度,进行0-255转换
  31. image1.at<uchar>(image_i, image_j) = uchar((cloud1->points[i].z - min.z) * 255 / (max.z - min.z));
  32.        
  33.         //cv::Vec3b pixel;
  34. //pixel[0] = cloud->points[i].b; // blue
  35. //pixel[1] = cloud->points[i].g; // green
  36. //pixel[2] = cloud->points[i].r; // red
  37. //image.at<cv::Vec3b>(image_i, image_j) = pixel;
  38. }
  39. cv::Mat color_image;
  40. cv::applyColorMap(image1, color_image, cv::COLORMAP_JET);    //伪彩图
  41. imshow("Point Cloud Image", color_image);

注意:图片格式类型。

总结:图片处理生成需要多了解图片的一些原理,比如深度值是点云z值最值跨度,是二维图像的灰度值等。


更新:有时候会出现点云和图片不一致导致图片只有轮廓的情况,这时我们需要对点云值和图片大小进行缩放,使得所有信息能够全部显示。

  1.     float scale = 0.1; //缩小
  2.     pcl::getMinMax3D(*inputCloud, min, max);
  3. int Prow = ceil(max.x - min.x) ;//向上取整
  4. int Pcol = ceil(max.y - min.y) ;
  5. cv::Mat image(Pcol * scale, Prow * scale, CV_8UC3, cv::Scalar(0, 0, 0));
  6. //初始化图像像素为255
  7. for (int i = 0; i < image.rows; i++)
  8. {
  9. for (int j = 0; j < image.cols; j++)
  10. {
  11. image.at<uchar>(i, j) = 0;
  12. }
  13. }
  14. for(int index = 0; index < inputCloud->points.size(); ++index)
  15. {
  16. inputCloud->points[index].x -= topLeft.x;
  17. inputCloud->points[index].y -= topLeft.y;
  18. inputCloud->points[index].z -= topLeft.z;
  19. int image_i, image_j;
  20. image_i = inputCloud->points[index].x * scale;
  21. image_j = inputCloud->points[index].y * scale;
  22. cv::Vec3b pixel;
  23. pixel[0] = inputCloud->points[index].b; // blue
  24. pixel[1] = inputCloud->points[index].g; // green
  25. pixel[2] = inputCloud->points[index].r; // red
  26. if (image_j< image.rows && image_i < image.cols)
  27. {
  28. image.at<cv::Vec3b>(image_j, image_i) = pixel;
  29. }
  30. }
  31. cv::imwrite("MyCloud.jpg", image);

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/96212?site
推荐阅读
相关标签
  

闽ICP备14008679号