如何为Intel RealSense D455+PCL生成的OBJ网格添加纹理?
给OrganizedFastMesh生成的网格添加纹理(Intel RealSense D455 + PCL)
你的核心问题是当前仅使用了PointXYZ类型的点云,没有携带**纹理坐标(UV)**和彩色数据,导致生成的OBJ文件缺少纹理信息。以下是可行的实现方案:
关键步骤
- 改用带RGB的点云类型:使用
PointXYZRGB或PointXYZRGBA,从RealSense同步获取对齐后的深度和彩色帧,将每个3D点与对应的彩色像素绑定。 - 添加纹理坐标:根据点云的行列索引计算UV坐标(OBJ的UV原点在左下角,需注意Y轴反转)。
- 关联纹理图片:保存彩色帧为纹理图片,在OBJ中引用该图片并绑定UV坐标。
修改后的完整代码
#include <pcl/io/obj_io.h> #include <pcl/surface/organized_fast_mesh.h> #include <pcl/point_types.h> #include <librealsense2/rs.hpp> #include <opencv2/opencv.hpp> int main() { // 初始化RealSense管道,配置彩色和深度流 rs2::pipeline pipe; rs2::config cfg; cfg.enable_stream(RS2_STREAM_COLOR, 848, 480, RS2_FORMAT_RGB8, 30); cfg.enable_stream(RS2_STREAM_DEPTH, 848, 480, RS2_FORMAT_Z16, 30); pipe.start(cfg); // 对齐深度帧到彩色帧,确保点云与彩色像素一一对应 rs2::align align(RS2_STREAM_COLOR); auto aligned_frames = align.process(pipe.wait_for_frames()); auto color_frame = aligned_frames.get_color_frame(); auto depth_frame = aligned_frames.get_depth_frame(); int width = color_frame.get_width(); int height = color_frame.get_height(); int total_points = width * height; // 创建带RGB信息的有序点云 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>); cloud->width = width; cloud->height = height; cloud->resize(total_points); // 获取彩色相机内参,用于像素转3D坐标 rs2::video_stream_profile color_profile = color_frame.get_profile().as<rs2::video_stream_profile>(); rs2::intrinsics intrin = color_profile.get_intrinsics(); // 填充点云的XYZ和RGB数据 const uint8_t* color_data = reinterpret_cast<const uint8_t*>(color_frame.get_data()); int color_stride = color_frame.get_stride_in_bytes(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int idx = y * width + x; float depth = depth_frame.get_distance(x, y); if (depth <= 0.0f) continue; // 跳过无效深度点 // 将像素坐标转换为3D空间坐标 rs2::point3d world_pt = rs2::deproject_pixel_to_point(intrin, {static_cast<float>(x), static_cast<float>(y)}, depth); cloud->at(idx).x = world_pt.x; cloud->at(idx).y = world_pt.y; cloud->at(idx).z = world_pt.z; // 提取对应像素的RGB值 int color_idx = y * color_stride + x * 3; cloud->at(idx).r = color_data[color_idx]; cloud->at(idx).g = color_data[color_idx + 1]; cloud->at(idx).b = color_data[color_idx + 2]; } } // 使用OrganizedFastMesh重建网格 pcl::OrganizedFastMesh<pcl::PointXYZRGB>::Ptr mesh_generator(new pcl::OrganizedFastMesh<pcl::PointXYZRGB>); pcl::PolygonMesh output_mesh; mesh_generator->setTriangulationType(pcl::OrganizedFastMesh<pcl::PointXYZRGB>::TRIANGLE_RIGHT_CUT); mesh_generator->setInputCloud(cloud); mesh_generator->reconstruct(output_mesh); // 1. 保存彩色帧为纹理图片 cv::Mat color_mat(cv::Size(width, height), CV_8UC3, (void*)color_frame.get_data(), cv::Mat::AUTO_STEP); cv::cvtColor(color_mat, color_mat, cv::COLOR_RGB2BGR); // OpenCV默认BGR格式,转换后保存 cv::imwrite("texture.jpg", color_mat); // 2. 为每个顶点添加纹理坐标(UV) output_mesh.tex_coords.resize(total_points); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int idx = y * width + x; // OBJ的UV坐标规则:u范围0-1(x/宽度),v范围0-1(1 - y/高度,因为OBJ原点在左下角) output_mesh.tex_coords[idx].u = static_cast<float>(x) / width; output_mesh.tex_coords[idx].v = 1.0f - static_cast<float>(y) / height; } } // 3. 保存带纹理的OBJ文件,自动生成MTL文件关联纹理 pcl::io::saveOBJFile("Mesh.obj", output_mesh, "texture.jpg"); pipe.stop(); return 0; }
注意事项
- 确保已安装
librealsense2和opencv库,编译时链接对应依赖 - 帧对齐是关键:如果深度和彩色帧未对齐,3D点会对应错误的彩色像素,导致纹理错位
- 若PCL版本较旧,
saveOBJFile可能无法自动生成MTL文件,此时需要手动创建MTL文件并在OBJ头部添加引用(如mtllib Mesh.mtl)
内容的提问来源于stack exchange,提问作者Amayes
相关产品推荐
相关产品推荐

