ROS下利用realsense采集RGBD图像合成点云

2023-05-16

摘要:在ROS kinetic下,利用realsense D435深度相机采集校准的RGBD图片,合成点云,在rviz中查看点云,最后保存成pcd文件。

 

一、 各种bug

代码编译成功后,打开rviz添加pointcloud2选项卡,当我订阅合成点云时,可视化失败,选项卡报错:

1)Data size (9394656 bytes) does not match width (640) times height (480) times point_step (32).  Dropping message.

解读:通过  rostopic echo /pointcloud_topic  读取相机节点发布的原始点云的相关数据,可以发现每一帧原始点云的点数量为307200。合成点云的点数量为  9394656 / 32 ,约26万。可以猜测由于某种原因,系统把每一帧合成点云的数据都丢弃了。

原因:我事先给定合成点云的大小为,height = 480,width = 640. 然而在合成点云的过程中,剔除了部分违法值(d=0),由此导致合成点云的点数量与指定的点数量不匹配,合成点云的数据因此被丢弃。

解决方法:采用如下方法给定点云大小, cloud->height = 1; cloud->width = cloud->points.size(); 

 

2)transform xxxxx;

解读:通过  rostopic echo /pointcloud_topic  ,发现原始点云数据具有如下信息,


header: 
  seq: 50114
  stamp: 
    secs: 1528439158
    nsecs: 557543003
  frame_id: "camera_color_optical_frame"  

由此推断,合成点云缺失参考坐标系header.frame_id。点云中点的XYZ属性是相对于某个坐标系来描述的,因此,需要指定点云的参考坐标系。

解决方法:添加点云的header信息, 


pub_pointcloud.header.frame_id = "camera_color_optical_frame"; 
pub_pointcloud.header.stamp = ros::Time::now();  

 

3)将合成的点云存储成pcd文件时遇到如下报错:


[ INFO] [1528442016.931874649]: point cloud size = 0
terminate called after throwing an instance of 'pcl::IOException'
  what():  : [pcl::PCDWriter::writeASCII] Input point cloud has no data!
Aborted (core dumped)  

经过多方查找,摸索了一步trick,分享给大家。真实报错原因仍未查明,期待前辈的指点

高博的源代码如下所示,里面的cloud是pcl的数据类型,

pcl::io::savePCDFile( "./pointcloud.pcd", *cloud );  。

我的源代码如下面所示,先通过 pcl::toROSMsg() 将pcl的数据类型转换成ros的数据类型,再写入pcd中,即可跳过报错。

 

4)相机内参

由于在彩色图和深度图配准的过程中,选用的是彩色图的坐标系,因此在合成点云(像素坐标在变换到相机坐标)时应该选用彩色图的相机内参。

realsense官方提供了一个应用程序可以查看所有视频流的内参。


gordon@gordon-5577:/usr/local/bin$ ./rs-sensor-control   

如下所示

84 : Color #0 (Video Stream: Y16 640x480@ 60Hz)
85 : Color #0 (Video Stream: BGRA8 640x480@ 60Hz)
86 : Color #0 (Video Stream: RGBA8 640x480@ 60Hz)
87 : Color #0 (Video Stream: BGR8 640x480@ 60Hz)
88 : Color #0 (Video Stream: RGB8 640x480@ 60Hz)
89 : Color #0 (Video Stream: YUYV 640x480@ 60Hz)
90 : Color #0 (Video Stream: Y16 640x480@ 30Hz)
91 : Color #0 (Video Stream: BGRA8 640x480@ 30Hz)
92 : Color #0 (Video Stream: RGBA8 640x480@ 30Hz)
93 : Color #0 (Video Stream: BGR8 640x480@ 30Hz)
94 : Color #0 (Video Stream: RGB8 640x480@ 30Hz)
95 : Color #0 (Video Stream: YUYV 640x480@ 30Hz)
96 : Color #0 (Video Stream: Y16 640x480@ 15Hz)
97 : Color #0 (Video Stream: BGRA8 640x480@ 15Hz)
98 : Color #0 (Video Stream: RGBA8 640x480@ 15Hz)
99 : Color #0 (Video Stream: BGR8 640x480@ 15Hz)
100: Color #0 (Video Stream: RGB8 640x480@ 15Hz)
101: Color #0 (Video Stream: YUYV 640x480@ 15Hz)
102: Color #0 (Video Stream: Y16 640x480@ 6Hz)
103: Color #0 (Video Stream: BGRA8 640x480@ 6Hz)
104: Color #0 (Video Stream: RGBA8 640x480@ 6Hz)
105: Color #0 (Video Stream: BGR8 640x480@ 6Hz)
106: Color #0 (Video Stream: RGB8 640x480@ 6Hz)
107: Color #0 (Video Stream: YUYV 640x480@ 6Hz)

 

5)深度图从ROS的数据类型转换为CV的数据类型

 参看链接

 

二、程序代码


#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <sensor_msgs/PointCloud2.h>

// PCL 库
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl_conversions/pcl_conversions.h>
 
// 定义点云类型
typedef pcl::PointCloud<pcl::PointXYZRGB> PointCloud; 

using namespace std;
//namespace enc = sensor_msgs::image_encodings;

// 相机内参
const double camera_factor = 1000;
const double camera_cx = 321.798;
const double camera_cy = 239.607;
const double camera_fx = 615.899;
const double camera_fy = 616.468;

// 全局变量:图像矩阵和点云
cv_bridge::CvImagePtr color_ptr, depth_ptr;
cv::Mat color_pic, depth_pic;

void color_Callback(const sensor_msgs::ImageConstPtr& color_msg)
{
  //cv_bridge::CvImagePtr color_ptr;
  try
  {
    cv::imshow("color_view", cv_bridge::toCvShare(color_msg, sensor_msgs::image_encodings::BGR8)->image);
    color_ptr = cv_bridge::toCvCopy(color_msg, sensor_msgs::image_encodings::BGR8);    

    cv::waitKey(1050); // 不断刷新图像,频率时间为int delay,单位为ms
  }
  catch (cv_bridge::Exception& e )
  {
    ROS_ERROR("Could not convert from '%s' to 'bgr8'.", color_msg->encoding.c_str());
  }
  color_pic = color_ptr->image;

  // output some info about the rgb image in cv format
  cout<<"output some info about the rgb image in cv format"<<endl;
  cout<<"rows of the rgb image = "<<color_pic.rows<<endl; 
  cout<<"cols of the rgb image = "<<color_pic.cols<<endl; 
  cout<<"type of rgb_pic's element = "<<color_pic.type()<<endl; 
}


void depth_Callback(const sensor_msgs::ImageConstPtr& depth_msg)
{
  //cv_bridge::CvImagePtr depth_ptr;
  try
  {
    //cv::imshow("depth_view", cv_bridge::toCvShare(depth_msg, sensor_msgs::image_encodings::TYPE_16UC1)->image);
    //depth_ptr = cv_bridge::toCvCopy(depth_msg, sensor_msgs::image_encodings::TYPE_16UC1); 
    cv::imshow("depth_view", cv_bridge::toCvShare(depth_msg, sensor_msgs::image_encodings::TYPE_32FC1)->image);
    depth_ptr = cv_bridge::toCvCopy(depth_msg, sensor_msgs::image_encodings::TYPE_32FC1); 

    cv::waitKey(1050);
  }
  catch (cv_bridge::Exception& e)
  {
    ROS_ERROR("Could not convert from '%s' to 'mono16'.", depth_msg->encoding.c_str());
  }

  depth_pic = depth_ptr->image;

  // output some info about the depth image in cv format
  cout<<"output some info about the depth image in cv format"<<endl;
  cout<<"rows of the depth image = "<<depth_pic.rows<<endl; 
  cout<<"cols of the depth image = "<<depth_pic.cols<<endl; 
  cout<<"type of depth_pic's element = "<<depth_pic.type()<<endl; 
}
int main(int argc, char **argv)
{
  ros::init(argc, argv, "image_listener");
  ros::NodeHandle nh;
  cv::namedWindow("color_view");
  cv::namedWindow("depth_view");
  cv::startWindowThread();
  image_transport::ImageTransport it(nh);
  image_transport::Subscriber sub = it.subscribe("/camera/color/image_raw", 1, color_Callback);
  image_transport::Subscriber sub1 = it.subscribe("/camera/aligned_depth_to_color/image_raw", 1, depth_Callback);
  ros::Publisher pointcloud_publisher = nh.advertise<sensor_msgs::PointCloud2>("generated_pc", 1);
 // 点云变量
  // 使用智能指针,创建一个空点云。这种指针用完会自动释放。
  PointCloud::Ptr cloud ( new PointCloud );
  sensor_msgs::PointCloud2 pub_pointcloud;

  double sample_rate = 1.0; // 1HZ,1秒发1次 
  ros::Rate naptime(sample_rate); // use to regulate loop rate 

  cout<<"depth value of depth map : "<<endl;

  while (ros::ok()) {
    // 遍历深度图
    for (int m = 0; m < depth_pic.rows; m++){
      for (int n = 0; n < depth_pic.cols; n++){
          // 获取深度图中(m,n)处的值
          float d = depth_pic.ptr<float>(m)[n];//ushort d = depth_pic.ptr<ushort>(m)[n];
          // d 可能没有值,若如此,跳过此点
          if (d == 0)
             continue;
          // d 存在值,则向点云增加一个点
          pcl::PointXYZRGB p;

          // 计算这个点的空间坐标
          p.z = double(d) / camera_factor;
          p.x = (n - camera_cx) * p.z / camera_fx;
          p.y = (m - camera_cy) * p.z / camera_fy;
            
          // 从rgb图像中获取它的颜色
          // rgb是三通道的BGR格式图,所以按下面的顺序获取颜色
          p.b = color_pic.ptr<uchar>(m)[n*3];
          p.g = color_pic.ptr<uchar>(m)[n*3+1];
          p.r = color_pic.ptr<uchar>(m)[n*3+2];
        
          // 把p加入到点云中
          cloud->points.push_back( p );
      }
    }
        

    // 设置并保存点云
    cloud->height = 1;
    cloud->width = cloud->points.size();
    ROS_INFO("point cloud size = %d",cloud->width);
    cloud->is_dense = false;// 转换点云的数据类型并存储成pcd文件
    pcl::toROSMsg(*cloud,pub_pointcloud);
    pub_pointcloud.header.frame_id = "camera_color_optical_frame";
    pub_pointcloud.header.stamp = ros::Time::now();
    pcl::io::savePCDFile("./pointcloud.pcd", pub_pointcloud);
    cout<<"publish point_cloud height = "<<pub_pointcloud.height<<endl;
    cout<<"publish point_cloud width = "<<pub_pointcloud.width<<endl;

    // 发布合成点云和原始点云
    pointcloud_publisher.publish(pub_pointcloud);
    ori_pointcloud_publisher.publish(cloud_msg);
    
    // 清除数据并退出
    cloud->points.clear();

    ros::spinOnce(); //allow data update from callback; 
    naptime.sleep(); // wait for remainder of specified period; 
  }

  cv::destroyWindow("color_view");
  cv::destroyWindow("depth_view");
}  

 

转载于:https://www.cnblogs.com/gdut-gordon/p/9155662.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ROS下利用realsense采集RGBD图像合成点云 的相关文章

  • 第六周总结 & 实验报告(四)

    第六周小结 一 instanceof关键字 在Java中使用instanceof关键字判断一个对象到底是哪个类的实例 xff0c 返回boolean类型 1 instanceof关键字的作用 例 class A public void fu
  • git 下载指定tag版本的源码

    git clone branch x x x https xxx xxx com xxx xxx git 转载于 https www cnblogs com wangjq19920210 p 10695231 html
  • Android yuv转Bitmap

    YuvImage image 61 new YuvImage data ImageFormat NV21 size width size height null if image 61 null ByteArrayOutputStream
  • PCB线宽与电流计算器--在线计算

    http eda365 com article 12 1 html 计算线宽与载流量的关系 xff0c 方便设计 xff1b 单个人建议在有限的空间尽量将大电流线路加宽 转载于 https www cnblogs com brianblog
  • 中国的第一封电子邮件

    Across the Great Wall we can reach every corner in the world 或许你已经忘记 xff0c 那就让我们一同来记起 中国的第一封电子邮件标志着我国进入了互联网时代 xff0c 我似乎也
  • 报Error creating bean with name 'dataSource' defined in class path resource 报错解决办法

    在学习spring boot 的数据库操作的时候 xff0c 报了一串错误 对于初学spring boot的我来说 xff0c 英语水平低 xff0c 看不懂报错的信息 xff0c 给我造成了很大的麻烦 xff0c 花了我一天的时间 xff
  • IntelliJ IDEA 文档无法编辑,变成了只读模式

    因为你 之前 修改了 系统时间 哈哈哈 转载于 https www cnblogs com zongheng14 p 10948236 html
  • Python pip版本升级

    pip版本升级命令 python m pip install upgrade pip 如果报错代码如下 venv C Users ssdy PycharmProjects untitled gt python m pip install u
  • 玩了下opencv的aruco(python版)

    简单的玩了下opencv里头的aruco xff0c 用的手机相机 xff0c 手机装了个 ip摄像头 xff0c 这样视频就可以传到电脑上了 首先是标定 xff0c 我没打印chessboard xff0c 直接在电脑屏幕上显示 xff0
  • 深浅拷贝和赋值的区别

    1 部分语言的深浅拷贝 赋值 软连接 你变他也变 浅拷贝 除了最外层的连接不变外 xff0c 与赋值相同 深拷贝 完全独立 span class token function import span copy a span class to
  • px4的CMakelists.txt阅读

    1 2 3 Copyright c 2017 PX4 Development Team All rights reserved 4 5 Redistribution and use in source and binary forms wi
  • 嵌入式Qt开发环境的搭建详解

    一 嵌入式Qt开发环境的搭建前奏 1 下载arm linux gcc 4 4 3 20100728 tar gz 2 下载qt everywhere opensource src 4 8 5 tar gz xff08 Qt的源码 xff09
  • 百度静态资源库

    http cdn code baidu com 转载于 https www cnblogs com mingl12 p 6373088 html
  • OpenCV 矩形轮廓检测

    转载请注明出处 xff1a http blog csdn net wangyaninglm article details 44151213 xff0c 来自 xff1a shiter编写程序的艺术 基础介绍 OpenCV里提取目标轮廓的函
  • linux更新系统内核,Linux内核升级方法详解

    Linux的内核是系统的核心 xff0c 所以升级内核是Linux系统管理员的一项基本技能 xff0c 所以我就分享了系统运维实务上的一篇文章 xff0c 当然我对源文件稍做了一些内容的增加 xff0c 就是把遇到的问题及解决方案也加上了
  • [ASP.NET] 实现客户端浏览服务端目录的页面

    由于项目需要制作程序发布的网站 xff0c 需要手动选择服务端目录下的文件夹和文件 故制作该页面 xff0c 并打算转为UserControl 页面代码 xff1a AppFileSelect aspx 1 lt 64 Page Langu
  • CSP-S 模拟53

    中下游水准 xff0c 暴力分没拿全 xff0c T1水了 T1 u 两个差分数组水掉 xff08 竖着一个 xff0c 斜着一个 xff09 T2 v 状压 43 记忆化搜索 xff0c 对于sta 61 1 lt lt 30 用hash
  • CSP-S 模拟52

    rank10 T1 平均数 二分答案 xff0c 让所有的数减去这个答案 xff0c 求前缀和 xff0c 然后验证子序列平均数比这个答案小的的个数是否等于K 只需要找前缀和的逆序对个数即可 xff08 归并排序 xff09 T2 涂色游戏
  • 抓取Android崩溃日志

    作为一个测试人员 xff0c 特别是安卓的测试 xff0c 由于系统版本的不同和手机本身各个品牌的优化和硬件的不同 xff0c 会出现各种各样的崩溃 记录崩溃的方式有很多种 xff0c 比如使用录屏工具或文档进行记录 xff0c 但是最简洁
  • oracle给用户赋dblink权限

    create database link 别名 xff08 可任意起 xff09 connect to 需要连接库的用户名identified by 需要连接库的用户名 using 39 DESCRIPTION 61 ADDRESS LIS

随机推荐

  • 前端间隔查询的两种方法:Debounce和Throttle

    Debounce 中文名 xff1a 防抖 在开始操作了之后 xff0c 那么只有在一段 delay 时间段后不再有操作了 xff0c 才执行操作 Throttle 中文名 xff1a 节流 在开始操作之后 xff0c 在 delay ms
  • tcpdump指定IP和端口抓包

    如下指定抓www baidu com 并且80端口的包 保存到test cap 可以在Windows下面用wireshark打开 tcpdump 39 port 80 and host www baidu com 39 w test cap
  • codevs4438 YJQ Runs Upstairs

    Description 学校科技楼一共有 N 层 而神犇YJQ每天都在科技楼 N 楼的机房写代码 这天 他准备从科技楼 1 楼爬到 N 楼 有个 M 连接不同楼层的楼梯 爬每个楼梯需要一定的体力值 楼梯一定是从低处通往高处的 但是由于楼房的
  • linux下如何查看服务器的硬件配置信息

    性能测试时一定要确定测试环境和的硬件配置 软件版本配置 xff0c 保证和线上一致 xff0c 才更接近真实环境 那么linux下如何查看服务器的硬件配置信息 xff1f xff1f 一 查看cpu信息 1 所有信息 lscpu root
  • 转:如何查找别人论文(计算机类文献)中实验的代码?

    最近看计算机类文献 xff0c 想看看别人论文中实验是如何做出来的 xff0c 请问如何查找别人论文中实验的代码 1 如果这论文很老 xff0c 论文里的算法在该领域有举足轻重的地位 那么网上很可能有工具包 例如我做的机器学习方向 xff0
  • Pytorch-属性统计

    引言 本篇介绍Pytorch属性统计的几种方式 统计属性 求值或位置 normmean sumprodmax min argmin argmaxkthvalue topk norm norm 与 normalize norm指的是范数 xf
  • 高性能异步爬虫

    背景 其实爬虫的本质就是client发请求批量获取server的响应数据 xff0c 如果我们有多个url待爬取 xff0c 只用一个线程且采用串行的方式执行 xff0c 那只能等待爬取一个结束后才能继续下一个 xff0c 效率会非常低 需
  • [operator]deepin 卸载自带搜狗输入法后,输入法消失

    解决这个问题我先是升级了官方的im config套件 xff0c 升级后发现并没有什么用 xff0c 然后使用以下方式 xff0c 做个记录 命令行操作 删除搜狗的残留文件 cd config rm rf SogouPY users rm
  • DPK

    一 概念 dpk文件是Delphi的包文件 xff0c 有dpk文件的组件安装比较方便 一般来说 xff0c 支持不同版本Delphi的组件会有不同的dpk文件 xff0c 一般以7结尾的dpk文件是支持Delphi 7的 如果没有支持De
  • TCP/IP协议栈概述及各层包头分析

    一 摘要 对之前几篇博文涉及到的网络通信协议进行分析 xff0c 概述出TCP IP的协议栈模型 xff0c 最后根据实例对各层包头进行分析 二 标准TCP IP协议栈模型 标准TCP IP协议是用于计算机通信的一组协议 xff0c 通常被
  • 2范数和F范数的区别

    2范数和F范数是不同的 2范数表示矩阵或向量的最大奇异值 xff0c max svd X 而 F范数表示矩阵所有元素平方和的开方根 sqrt x i j X x i j 2 转载于 https www cnblogs com yinwei
  • 网络钩子webhook

    网页开发中的网络钩子是一种通过自定义回调函数来增加或更改网页表现的方法 webhook 发布订阅模式 xff0c 与api不同的是 xff0c webhook无需发送请求即可收到监听地址发布的消息 主要用途 xff1a 更新客户端
  • free -g 说明

    free g 说明 xff1a free g 43 buffers cache 说明 xff1a buffer 写缓存 xff0c 表示脏数据写入磁盘之前缓存一段时间 xff0c 可以释放 sync命令可以把buffer强制写入硬盘 cac
  • Google Drive 里的文件下载的方法

    Google Drive 里并不提供创建直接下载链接的选项 xff0c 但是可以通过小小的更改链接形式就能把分享的内容保存到本地 例如 xff0c 一份通过 Google Drive 分享的文件链接形式为 xff1a https drive
  • 关于虚拟机VMware Tools安装中出现的无法自动安装VMCI驱动程序的问题

    问题 解决方法 根据配置文件信息找到所在的虚拟机位置 找到后缀名为vmx的文件 xff0c 右键打开方式中选择使用记事本打开 选择左上角编辑中的查找功能输入图中的查找内容后 xff0c 点击查找下一个 将其原先的TRUE值改为false即可
  • 人脸识别概念杂记

    Gabor特征 xff1a 通过Gabor变换获取的特征 Gabor变换 xff1a 是在20世纪40年代有Gabor提出的一种利用高斯函数作为窗口函数的加窗傅里叶变换 Gabor变换可以有效的获取空间和方向等视觉信息 xff0c 使得原始
  • 大麦盒子(domybox)无法进入系统解决方案!【简单几步】

    大麦无法进入系统解决方案 xff01 简单几步 前提准备 xff1a 电脑一台盒子控制台软件盒子开机并联网并且盒子和电脑处于同一个路由器下的网络 xff01 前提准备 xff1a 电脑一台盒子控制台软件盒子开机并联网并且盒子和电脑处于同一个
  • 常见开发语言擅长领域

    Python xff1a 机器学习 xff0c 数据科学还有Web开发 JavaScript xff1a Web开发 xff08 前端和后端 xff09 和游戏开发 Java xff1a 移动Android应用程序开发 xff0c 企业应用
  • H3C 维护命令

    一 xff1a 基础维护命令 1 dis version 查看版本 2 dis cu 显示实时配置 3 dis this 显示当前视图下的配置 4 dis interface 显示接口 5 dis mac address 显示mac地址表
  • ROS下利用realsense采集RGBD图像合成点云

    摘要 xff1a 在ROS kinetic下 xff0c 利用realsense D435深度相机采集校准的RGBD图片 xff0c 合成点云 xff0c 在rviz中查看点云 xff0c 最后保存成pcd文件 一 各种bug 代码编译成功