当前位置: 首页 > news >正文

PCL将深度图转化为点云并存储为pcd文件

最近又开始折腾点云了,下面记录一点基础知识。
(1)深度相机采集的depth 数据如何转换为点云pcd
一般3D相机都会采集到depth 数据,以记录深度相机拍摄到的深度距离Z值。要将深度图转化成三维空间点云数据,首先需要相机的内参数据。
示例如下:

#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/icp.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/registration/ndt.h>#include <windows.h>// 定义点云类型(不带颜色)
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloud;//---------相机内参---------------
const double camera_factor = 1000;//单位米
const double camera_fx = 611.716003; ;
const double camera_fy = 612.044861;
const double camera_cx = 631.656372; 
const double camera_cy = 401.639801; 
bool CreateDirectorySimple(const std::string& dir) 
{return CreateDirectoryA(dir.c_str(), NULL) || GetLastError() == ERROR_ALREADY_EXISTS;
}std::vector<std::string> FindAllPngDepthImages(const std::string& image_dir) 
{std::vector<std::string> png_files;WIN32_FIND_DATAA find_data;HANDLE hFind = INVALID_HANDLE_VALUE;std::string pattern = image_dir + "*.png";hFind = FindFirstFileA(pattern.c_str(), &find_data);if (hFind == INVALID_HANDLE_VALUE) {std::cerr << "无法打开目录或未找到 PNG 文件: " << image_dir << std::endl;return png_files;}do {std::string filename = find_data.cFileName;// 排除目录if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)continue;// 添加 PNG 文件路径png_files.push_back(image_dir + filename);} while (FindNextFileA(hFind, &find_data) != 0);FindClose(hFind);return png_files;
}bool ProcessDepthImage(const std::string& depth_path, const std::string& pcd_path) 
{// 读取深度图像std::cout << "找到 " << depth_path << std::endl;cv::Mat depth = cv::imread(depth_path, cv::IMREAD_UNCHANGED);if (depth.empty()) {std::cerr << "无法加载深度图像: " << depth_path << std::endl;return false;}// 检查深度图像类型if (depth.type() != CV_16UC1 && depth.type() != CV_32FC1) {std::cerr << "深度图像类型不支持 (仅支持 CV_16UC1 和 CV_32FC1): " << depth_path << std::endl;return false;}// 创建点云对象PointCloud::Ptr cloud(new PointCloud);// 定义圆柱体过滤参数const double target_z = 0.97; // 目标距离1米const double z_tolerance = 0.5;// 深度容忍范围 ±0.05米const double radius = 0.65;//    // 圆柱体半径0.5米(直径1米)// 遍历每个像素for (int m = 0; m < depth.rows; m++){for (int n = 0; n < depth.cols; n++) {// 获取深度值unsigned short d = depth.ptr<unsigned short>(m)[n];if (d == 0)continue; // 无效深度值,跳过// 计算空间坐标(单位:米)double z = double(d) / camera_factor;double x = (n - camera_cx) * z / camera_fx;double y = (m - camera_cy) * z / camera_fy;// --------过滤条件:提取位于指定ROI范围内的点云数据if (x <- 0.65)continue;if (sqrtf((z - target_z)*(z - target_z)+ (y-0.034) * (y - 0.034) ) > (radius * radius))//圆柱体过滤continue;// 创建点PointT p;p.x =  (x);p.y =  (y);p.z =  (z);			// 添加到点云cloud->points.push_back(p);}}// 设置点云属性cloud->height = 1;cloud->width = static_cast<uint32_t>(cloud->points.size());cloud->is_dense = false;std::cout << "点云大小 = " << cloud->points.size() << std::endl;if(cloud->points.size() == 0)  		return false;// 保存 PCD 文件//if (pcl::io::savePCDFileASCII(pcd_path, *cloud) == -1)//以ASCII 码形式吸入pcdif (pcl::io::savePCDFileBinary(pcd_path, *cloud) == -1)//以二进制形式写入pcd{PCL_ERROR("无法保存 PCD 文件: %s\n", pcd_path.c_str());return false;}std::cout << "已保存 PCD 文件: " << pcd_path << ",包含 " << cloud->points.size() << " 个点。" <<std::endl;return true;
}
int main()
{
// depth图像目录和固定输出 PCD 目录
std::string image_dir = "F:/Data/depth/";      //深度图数据路径
std::string pcd_dir = "F:/Data/pcd12/";     // 输出的pcdl文件路径示例
int index = 0 ;
// 创建固定输出目录(不检查是否存在)
CreateDirectorySimple(pcd_dir);// 查找所有 PNG 深度图
std::vector<std::string> depth_images = FindAllPngDepthImages(image_dir);
std::cout << "找到 " << depth_images.size() << " 个 PNG 深度图。" << std::endl;// 处理每个深度图
for (const auto& depth_path : depth_images) 
{index = index + 1;std::cout << "已经处理了: " << index << std::endl;//if (index % 2 != 1)//continue;// 提取文件名(不含路径)size_t pos = depth_path.find_last_of("/\\");std::string filename = (pos == std::string::npos) ? depth_path : depth_path.substr(pos + 1);// 提取基名(去除扩展名)size_t dot = filename.find_last_of('.');std::string base = (dot == std::string::npos) ? filename : filename.substr(0, dot);// 定义 PCD 文件路径std::string pcd_path = pcd_dir + base + ".pcd";// 处理并保存 PCDbool success = ProcessDepthImage(depth_path, pcd_path);if (!success) {std::cerr << "处理深度图失败: " << depth_path << std::endl;}}return 0;
}

(2)为什么用pcl写点云数据到pcd文件后用记事本打开乱码
如果写入pcd 的数据是按照ASCII码写的,其一定可以用文本文件打开,如果用二进制类型写的打开就是乱码。
上面的代码中的语句
1)if(pcl::io::savePCDFileASCII(pcd_path, *cloud) == -1)//以ASCII 码形式吸入pcd,写速度慢,文件大,但可以用文本文件查看点云坐标;
2)if (pcl::io::savePCDFileBinary(pcd_path, *cloud) == -1)//以二进制形式写入pcd,写速度快,文件小。

好了,先这样吧,pcl 博大精深,后面继续~


http://www.mrgr.cn/news/47967.html

相关文章:

  • 人工智能-Python网络编程-HTTP
  • 买卖预测工具
  • 03、Spring 声明式事务
  • 【已解决】图片png转ico格式
  • AtCoder Beginner Contest 386
  • OpenCV-Python实战(11)——边缘检测
  • Verdin AM62使用CODESYS
  • 【Java SE 题库】递归的魅力之--> 汉诺塔问题
  • 初阶数据结构(2):空间复杂度和复杂度算法题
  • Alluxio在数据索引和模型分发中的核心价值与应用
  • vue3 + vite + cesium项目
  • ARM在嵌入式开发中的作用有哪些?
  • 攻防世界1
  • 51单片机数码管循环显示0~f
  • F开头的词根词缀:ful
  • 关于不建议使用北京新网数码信息技术公司的服务器和虚拟机的说明(重要说明)
  • PSD18C-LF-T7 高功率TVS射线管芯片IC
  • AcWing算法提高课 1.2.2 最长上升子序列模型(二)
  • 云原生后端
  • uni-app关闭底部系统导航栏的控制按钮BUG
  • Pura 70系列和Pocket 2已支持升级尝鲜鸿蒙NEXT,报名教程在这里
  • 进程的理解
  • 单例模式和读者写者问题
  • 找不到xinput1_3.dll怎么解决,快来试试这个几个方法
  • Java获取当前年月日
  • 活动队列