点云数据与多相机图像融合实现3D场景的彩色可视化

引言

在现代3D计算机视觉和机器人感知领域,点云数据和图像信息的融合正变得越来越重要。点云数据提供了精确的几何结构,而图像则包含了丰富的颜色和纹理细节。将这两种数据源结合起来,我们能够创建更加逼真和信息丰富的3D场景表示。本文将深入探讨一个结合点云数据和多相机图像的项目,旨在生成高质量的彩色3D点云,从而大幅提升场景的可视化效果。

我们的项目利用了多个开源库,包括Point Cloud Library (PCL)用于点云处理,OpenCV用于图像处理,以及Eigen用于高效的矩阵运算。项目的核心目标是将来自多个相机的2D图像信息精确地映射到3D点云上,最终生成一个色彩丰富、细节清晰的3D场景表示。

数据集的构成包括以下几个关键部分:

  1. 一个存储为PCD格式的点云文件(frame3438.pcd)
  2. 五张来自不同相机的JPEG格式图像(frame3438cam1.jpg 到 frame3438cam5.jpg)
  3. 每个相机的参数矩阵,包括:
    • 内参矩阵(K),描述相机的光学特性
    • 畸变系数(D),用于校正镜头畸变
    • 外参矩阵(t_word_to_cam),描述相机在世界坐标系中的位置和姿态

项目的核心算法实现主要包括以下几个步骤:

  • 点云加载:使用PCL库的io模块加载PCD文件。
  • 图像处理:利用OpenCV加载并预处理图像。
  • 点云投影:将3D点云中的每个点投影到2D图像平面上。
  • 颜色映射:从图像中提取对应的颜色信息,并将其赋给点云中的点。
  • 可视化:使用PCL的可视化模块展示最终的彩色点云。

CMakeList.txt

cmake_minimum_required(VERSION 3.28)
project(UGV_Pt2Pc)set(CMAKE_CXX_STANDARD 11)
set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS TRUE CACHE INTERNAL "")
# Find required packages
find_package(OpenCV REQUIRED)
find_package(PCL REQUIRED)
find_package(Eigen3 REQUIRED)# Include directories
include_directories(${OpenCV_INCLUDE_DIRS}${PCL_INCLUDE_DIRS}${EIGEN3_INCLUDE_DIRS}
)# Add definitions and link directories for PCL
add_definitions(${PCL_DEFINITIONS})
link_directories(${PCL_LIBRARY_DIRS})# Add executable
add_executable(UGV_Pt2Pc main.cpp)# Link libraries
target_link_libraries(UGV_Pt2Pc${OpenCV_LIBS}${PCL_LIBRARIES}
)

 main.cpp

#include <iostream>
#include <boost/thread/thread.hpp>
#include <pcl/common/common_headers.h>
#include <pcl/features/normal_3d.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/icp.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/console/parse.h>
#include <pcl/visualization/cloud_viewer.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core/eigen.hpp>
#include <Eigen/Dense>using namespace cv;
using namespace std;// RGB colour visualisation example
boost::shared_ptr<pcl::visualization::PCLVisualizer> rgbVis(pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr cloud)
{boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));viewer->setBackgroundColor(0, 0, 0);viewer->addPointCloud<pcl::PointXYZRGB>(cloud, "sample cloud");viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "sample cloud");viewer->addCoordinateSystem(1.0);viewer->initCameraParameters();return (viewer);
}void projectPointsToImage(pcl::PointCloud<pcl::PointXYZRGB>::Ptr point_cloud, const Mat& img, const Mat& K, const Mat& D, const Mat& t_word_to_cam)
{Mat camera_par = K * Mat::eye(3, 4, CV_64F);Mat UndistortImage;cv::undistort(img, UndistortImage, K, D, K);int rows = UndistortImage.rows;int cols = UndistortImage.cols;Mat word_h = Mat(4, 1, CV_64FC1);Mat p_result = Mat(3, 1, CV_64FC1);for (int nIndex = 0; nIndex < point_cloud->points.size(); nIndex++){double c_x = point_cloud->points[nIndex].x;double c_y = point_cloud->points[nIndex].y;double c_z = point_cloud->points[nIndex].z;word_h = (Mat_<double>(4, 1) << c_x, c_y, c_z, 1);p_result = camera_par * t_word_to_cam * word_h;double p_w = p_result.at<double>(2, 0);int p_u = (int)((p_result.at<double>(0, 0)) / p_w);int p_v = (int)((p_result.at<double>(1, 0)) / p_w);if(p_u >= 0 && p_u < cols && p_v >= 0 && p_v < rows && p_w > 0){Vec3b color = UndistortImage.at<Vec3b>(p_v, p_u);point_cloud->points[nIndex].r = color[2];point_cloud->points[nIndex].g = color[1];point_cloud->points[nIndex].b = color[0];}}
}int main()
{pcl::PointCloud<pcl::PointXYZRGB>::Ptr point_cloud(new pcl::PointCloud<pcl::PointXYZRGB>);string path = "/home/fairlee/CLionProjects/UGVPoint2Picture/Data/frame3438.pcd";pcl::io::loadPCDFile(path, *point_cloud);vector<string> imgPaths = {"/home/fairlee/CLionProjects/UGVPoint2Picture/Data/frame3438cam1.jpg","/home/fairlee/CLionProjects/UGVPoint2Picture/Data/frame3438cam2.jpg","/home/fairlee/CLionProjects/UGVPoint2Picture/Data/frame3438cam3.jpg","/home/fairlee/CLionProjects/UGVPoint2Picture/Data/frame3438cam4.jpg","/home/fairlee/CLionProjects/UGVPoint2Picture/Data/frame3438cam5.jpg"};vector<Mat> K_matrices = {(Mat_<double>(3, 3) << 7.449480591354508e+02, 0.0, 6.239975192140465e+02, 0.0, 7.477630653570311e+02, 3.718130492325440e+02, 0.0, 0.0, 1.0),(Mat_<double>(3, 3) << 7.496397448476606e+02, 0.0, 6.406747754223233e+02, 0.0, 7.498672914667321e+02, 3.738034702122652e+02, 0.0, 0.0, 1.0),(Mat_<double>(3, 3) << 7.453318932115172e+02, 0.0, 6.353637094339318e+02, 0.0, 7.451280155876273e+02, 3.580752219734694e+02, 0.0, 0.0, 1.0),(Mat_<double>(3, 3) << 7.342274827447166e+02, 0.0, 6.544610847908701e+02, 0.0, 7.343520333235763e+02, 3.620389108671441e+02, 0.0, 0.0, 1.0),(Mat_<double>(3, 3) << 7.476554400662411e+02, 0.0, 6.788461062313610e+02, 0.0, 7.477630653570311e+02, 3.185225546149534e+02, 0.0, 0.0, 1.0)};vector<Mat> D_matrices = {(Mat_<double>(5, 1) << -0.012152688773890, 0.006312744290089, 0.0, 0.0, 0.0),(Mat_<double>(5, 1) << -0.004788988582043, 1.664519226194170e-04, 0.0, 0.0, 0.0),(Mat_<double>(5, 1) << -0.010742962922821, 0.004899856208959, 0.0, 0.0, 0.0),(Mat_<double>(5, 1) << -0.008567792387783, -0.003979577222784, 0.0, 0.0, 0.0),(Mat_<double>(5, 1) << -0.004199529851394, -0.006221124713178, 0.0, 0.0, 0.0)};vector<Mat> t_word_to_cam_matrices = {(Mat_<double>(4, 4) << -0.573083193216839, 0.819337857655761, 0.016159475995802, 0.004020654954081, -0.037263512116764, -0.006355334635993, -0.999285264769970, -5.940790067281352e-04, -0.818649549146101, -0.573275749298479, 0.034173541653635, -0.131669026218482, 0.0, 0.0, 0.0, 1.0),(Mat_<double>(4, 4) << 0.606118826106767, 0.795372432267145, -0.001631756232093, 0.015694798142177, 0.012875614383068, -0.011863195183812, -0.999846729831273, -0.045896562287801, -0.795269883242924, 0.606004916308009, -0.017431414667482, -0.110877525711608, 0.0, 0.0, 0.0, 1.0),(Mat_<double>(4, 4) << -0.945075320161107, -0.325701878485533, 0.027403021245412, 0.012344765860022, -0.014072099115867, -0.043215933241321, -0.998966645659681, -0.063750385501104, 0.326549560172502, -0.944484340508130, 0.036259002827830, -0.129189511868516, 0.0, 0.0, 0.0, 1.0),(Mat_<double>(4, 4) << 0.957103431035445, -0.289410872954947, -0.013941625286710, -0.010506759453144, -0.026517852059621, -0.039578790762524, -0.998864516760867, -0.028600625727241, 0.288530459089372, 0.956386358088211, -0.045555551148511, -0.153290341112109, 0.0, 0.0, 0.0, 1.0),(Mat_<double>(4, 4) << -0.058774247147796, -0.998268213079476, -0.002482463961589, -0.016783534106880, -0.004403582752182, 0.002746003285998, -0.999986533871781, -0.013253349162886, 0.998261587125917, -0.058762523950764, -0.004557350960968, -0.137347689399076, 0.0, 0.0, 0.0, 1.0)};for (int i = 0; i < 5; i++){Mat img = imread(imgPaths[i]);if (img.empty()) {cout << "Failed to load image: " << imgPaths[i] << endl;continue;}if (img.channels() != 3) {cout << "RGB pics needed for image: " << imgPaths[i] << endl;continue;}projectPointsToImage(point_cloud, img, K_matrices[i], D_matrices[i], t_word_to_cam_matrices[i]);}boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer;viewer = rgbVis(point_cloud);while (!viewer->wasStopped()){viewer->spinOnce(100);}return 0;
}

结果 

 注:里面的数据来自MATLAB工具箱标定的数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/56175.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Django学习笔记之Django基础学习

Django笔记 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录…

剧场的客户端形式区别,APP,小程序,H5的不同优势以及推广方案

剧场的客户端形式区别与推广策略 在数字化时代&#xff0c;剧场的线上化成为大势所趋。不同的线上平台如APP、小程序和H5各有千秋&#xff0c;如何选择最适合自己的平台&#xff0c;并制定有效的推广方案&#xff0c;成为了剧场管理者需要考虑的重要问题。 APP&#xff1a;深度…

【AIGC】OpenAI API在快速开发中的实践与应用:优化ChatGPT提示词Prompt加速工程

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;使用最新型号确保最佳实践利用最新模型进行高效任务处理为什么要选择最新模型&#xff1f;结论 &#x1f4af;指令与上下文的分隔最佳实践分隔指令和上下文的重要性使用符…

univer实现excel协同

快速入门 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><script src&q…

无线费控智能水表:智能生活的守护者

在当今智能化日益普及的时代&#xff0c;无线费控智能水表作为一项重要的技术创新&#xff0c;正在逐步改变我们的生活方式。它不仅能够实现远程抄表&#xff0c;自动计费&#xff0c;还能有效监控用水情况&#xff0c;促进水资源的合理利用&#xff0c;是现代城市智慧化管理不…

如何在 cPanel 中使用 PHP-FPM

PHP性能一直是影响网站托管的一个重要问题。PHP是当前网络上使用最广泛的服务器编程语言&#xff0c;远远领先于其他语言。最受欢迎的内容管理系统和电子商务应用程序&#xff0c;如WordPress、Joomla、Drupal、Magento等&#xff0c;都是用PHP编写的。 PHP-FPM加速了在繁忙服务…

24/10/12 算法笔记 NiN

LeNet、AlexNet和VGG都有一个共同的设计模式&#xff1a;通过一系列的卷积层与汇聚层来提取空间结构特征&#xff1b;然后通过全连接层对特征的表征进行处理。 AlexNet和VGG对LeNet的改进主要在于如何扩大和加深这两个模块。 或者&#xff0c;可以想象在这个过程的早期使用全连…

用java来编写web界面

一、ssm框架整体目录架构 二、编写后端代码 1、编写实体层代码 实体层代码就是你的对象 entity package com.cv.entity;public class Apple {private Integer id;private String name;private Integer quantity;private Integer price;private Integer categoryId;public…

C++:STL:vector类常用函数介绍(附加部分重要函数模拟实现)

cplusplus.com/reference/vector/vector/https://cplusplus.com/reference/vector/vector/ vector在实际中非常的重要&#xff0c;在实际中我们熟悉常见的接口就可以&#xff0c;有了string的基础&#xff0c;vector其实大体使用方法上二者是类似的&#xff1a; 这里我们先给…

ScriptableObject基本使用

使用方法 自定义类继承ScriptableObject 可以在类内部增加数据或者数据类&#xff0c;一般用于配置 注意事项 给继承ScriptableObject的类增加CreateAssetMenu特性。 CreateAssetMenu一般默认三个参数 第一个参数是父目录 第二个参数是父目录的子选项 第三个参数是可以…

多态(二)

1.多态的原理 虚函数表 class Base { public:virtual void Func1(){cout << "Func1()" << endl;} private:int _b 1; };b对象是8bytes&#xff0c;除了_b成员&#xff0c;还多一个__vfptr放在对象的前面(注意有些 平台可能会放到对象的最后面&#xf…

微信小程序启动不起来,报错凡是以~/包名/*.js路径的文件,都找不到,试过网上一切方法,最终居然这么解决的,【避坑】命运的齿轮开始转动

app.json "resolveAlias": {"~/*": "/*"},文件代码也没有问题&#xff0c;网上的方法试过来了&#xff0c;大模型AI也问过遍&#xff0c;熬夜到凌晨2点半&#xff0c;最不可思议的是居然是因为微信开发者工具版本的问题&#xff0c;我真的是笑死…

量化之一:均值回归策略

文章目录 均值回归策略理论基础数学公式 关键指标简单移动平均线&#xff08;SMA&#xff09;标准差Z-Score 交易信号实际应用优缺点分析优点缺点 结论 实践backtrader参数&#xff1a;正常情况&#xff1a;异常情况&#xff1a; 均值回归策略 均值回归&#xff08;Mean Rever…

JAVA-数据结构-排序

1.直接插入排序 1.原理&#xff1a;和玩扑克牌一样&#xff0c;从左边第二个牌开始&#xff0c;选中这个&#xff0c;和前面的所有牌比较&#xff0c;插在合适的位置 public static void insertsort(int[] arr){//直接插入排序for (int i 1; i < arr.length; i) {//此循环…

STM32 GPIO

GPIO&#xff08;通用输入输出口&#xff0c;General Purpose Input Output&#xff09;接口的功能是让嵌入式处理器能够通过软件灵活地读出或控制单个物理引脚上的高、低电平&#xff0c;实现内核和外部系统之间的信息交换。 GPIO是嵌入式处理器使用最多的外设&#xff0c;能够…

甲虫身体图像分割系统源码&数据集分享

甲虫身体图像分割系统源码&#xff06;数据集分享 [yolov8-seg-EfficientRepBiPAN&#xff06;yolov8-seg-C2f-FocusedLinearAttention等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challen…

毕设开源 大数据电影数据分析与可视化系统(源码+论文)

文章目录 0 前言1 项目运行效果2 设计概要3 最后 0 前言 &#x1f525;这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师…

简单粗暴理解GNN、GCN、GAT

GNN 思想&#xff1a;近朱者赤近墨者黑 GNN的流程&#xff1a; 聚合&#xff08;把邻居的信息贴到自己身上来&#xff0c;作为它自己特征的补足&#xff09;更新循环&#xff08;为什么要多次&#xff1f;看以下例子&#xff09; GNN能干嘛&#xff1f; 1.结点分类&#xf…

【多线程】多线程(12):多线程环境下使用哈希表

【多线程环境下使用哈希表&#xff08;重点掌握&#xff09;】 可以使用类&#xff1a;“ConcurrentHashMap” ★ConcurrentHashMap对比HashMap和Hashtable的优化点 1.优化了锁的粒度【最核心】 //Hashtable的加锁&#xff0c;就是直接给put&#xff0c;get等方法加上synch…

【网络协议】TCP协议常用机制——延迟应答、捎带应答、面向字节流、异常处理,保姆级详解,建议收藏

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;计算机网络那些事 前几篇文章&#xff0c;博主带大家梳理了一下TCP协议的几个核心机制&#xff0c;比如保证可靠性的 确认应答、超时重传 机制&#xff0c;和提高传输效率的 滑动窗口及其相关优化机…