本文翻译自 xx大学的机器人课程,以及个人使用的Ros进行图像处理时的一些问题总结:

1. ROS 中表示图像

1.1 查看图像

ROS中最基本的图像表示方式为sensor_mags/Image 类型,可以使用RVIZ对该topic所对应的图像画面进行查看,RVIZ中的Camera display功能;或者更简便的,可以使用模块image_view :

具体命令为: rosrun image_view image_view image:=topic_name

例如, 如果想要查看 Turtlebot‘s KInect sensor 捕捉的图像,可以使用命令:

rosrun image_view image_view image:=/camera/rgb/image_color compressed

rosrun image_view image_view image:=/camera/rgb/image_mono compressed

1.2. 转换图像

大家可能已经知道,在ROS中订阅其他电脑上发出的某个topic,在传输的的时候是会占用一定的网络带宽的, 例如,在我的电脑上, 订阅  /camera/rgb/image color 话题,每秒钟会消耗掉2.5 megabytes;

之所以会出现如上的状况,是因为我们传输的都是未压缩的视频或图像数据。 当然,ROS也提供了对应的转换方法,可以将topic中的图像转换成对应的压缩格式,这种压缩方式基本只会降低图像或者视频的大小,而并不会损失掉一些图像的细节,同时,ROS将该模块都统一打包,因此我们并不需要关心具体的压缩或者解压过程。

关于image transport的最简单的例子如下:

#include <ros/ros.h>
#include <image_transport/image_transport.h>void callback(const sensor_msgs::ImageConstPtr& msg) {ROS_INFO("Got image.");
}
int main(int argc, char **argv) {ros::init(argc, argv, "nodeName");ros::NodeHandle nh;image_transport::ImageTransport it(nh);image_transport::Subscriber sub = it.subscribe(topicName, queueSize, callback);ros::spin();
}

如果使用以上代码,必须进行对在package.xml 和CMakeLists.txt 中添加依赖库:image_transport.

注意,在上面的代码中我们使用的topicName依然是原先的topic内容,但是代码在执行的时候 会比之前的那种直接subscribe一个topic的方法多一层判断,会先调用参数∼image transport判断是否需要订阅压缩图像;

关于 ∼image transport的几种情况:

1. 如果对参数 ∼image transport不进行任何的说明或者是赋值,那么最后的结果 跟没使用这个模块是一样的效果, ROS最终会follow的topic依然是未压缩的图像;

2. 如果参数 ∼image transport设置成compressed的类型,每副图像都会以JPEG或者PNG的形式进行压缩,而后在callback之前,也就是接收到数据之后进行解压缩decompression;

3. 如果参数 ∼image transport设置成theora,视频流将会被压缩成为更小的格式,这种方式比compressed更高效一点,因为它会推算连续帧中的相似性。

使用Image_transport的另一个方法或者好处是,我们可以仅仅通过命令实现压缩或者改变压缩的方式,如下:

<launch><node name="view" pkg="J5" type="view" output="screen"><param name="image_transport" value="theora" /></node>
</launch> 

上面的讲解中Image_transport前的~表示这是一个node的private变量,因此使用时一般是加载node之间,作为参数出现。

1.3 OpenCV

OpenCV是什么这里就不介绍了,ROS中其实已经整合了OpenCV,并且可以在ROS代码中进行使用;

1.3.1 编译使用opencv

如果要在ROS代码中使用Opencv,需要额外地包含OPencv的库,对应的包含方法如下:

find_package(OpenCV_REQUIRED)
target_link_libraries(your executable-name ${OpenCV_LIBS}) ​

同时还需要包含另一个包cv_bridge, 主要是用于在ROS图像与OpenCV图像之间做一个转换;

1.3.2 转换成cv::Mat的格式:

cv_bridge的一个好处是将sensor_msgs::Image类型的消息转换成为cv::Mat的形式;例如,我们可以在callback函数中进行如下设置:

#include <cv_bridge/cv_bridge.h>
#include <opencv/cv.h>
...
cv_bridge::CvImagePtr cvImagePtr;
try {cvImagePtr = cv_bridge::toCvCopy(msg);
} catch (cv_bridge::Exception &e) {ROS_ERROR("cv_bridge exception: %s", e.what());
}

cvImagePtr 是cv_bridge的图像数据表达,我们可以直接使用cvImagePtr->image 来获得cv::Mat;

1.4  图像访问

一张图像其实就是一个二维数组,对cv::Mat 格式的图像,可以通过rows 和 cols 进行数据访问:

cv::Mat &Mat = cv::ImagePtr->image;
int width = mat.cols;
int height = mat.rows;  

除了检查图像的size,最主要的是我们需要对获取来的图像中的数值进行访问, OPencv中cv::Mat 可以用at进行单个像素的数值访问,cv::Mat中图像的存储可以有很多种形式,例如单通道的灰色图像以单字节的形式存储,而三通道的彩色图像,每个像素的位置存放的都是一个1*3的数组, 不仅如此,cv::Mat中还可以存储float或者double型的数据。

以Turtlebot 的/camera/rgb/image mono 为例,这是一个单通道Mono8的图像,每一个像素中存储的是一个无符号字符 unsigned char, 对这种类型数据的访问为:

cv::Mat &mat = cvImagePtr->image; ROS_INFO("image[%d,%d] = %d", i, j, (int) mat.at(i, j));

这样输出的数据中都是从0 到 255的数字,代表了不同的像素值, 0为black, 255 为white;

而话题 /camera/rgb/image color 传输的确实bgr8的图像,每个像素中存放的是三个无符号char,分别代表了red,green,blue,这种形式的图像一般通过cv::Vec3b 的形式进行访问;

cv::Mat &mat = cvImagePtr->image;
cv::Vec3b pixel = mat.at(i,j);
ROS_INFO("image[%d,%d] = (r=%d,g=%d,b=%d)", i, j, pixel[2], pixel[1], pixel[0]);  

1.5 图像显示

opencv的另一个好处是可以很方便地显示图像,这里用一段代码举例:

#include <opencv/highgui.h>
cvNamedWindow("windowName", CV_WINDOW_AUTOSIZE);
cvStartWindowThread();
cv::imshow("windowName", mat);
cvDestroyWindow("windowName");

这样的显示方法 对比 直接在ROS中进行图像显示 的一个好处就是: 在图像显示之前,可以对图像进行编辑, 例如我们可以通过如下代码,将一副彩色图像中的某个像素值变成0 ,也就是三个通道的数值都变成黑色:

cv::Vec3b &pixel = mat.at<cv::Vec3b>(i,j);
pixel[0] = 0;
pixel[1] = 0;
pixel[2] = 0;

结束。

上面的教程相对是比较基础的,接下来是我自己的一些总结:

1. 首先是压缩图像部分,这部分 分为发布压缩图像订阅/查看压缩图像

发布:

将一个正常的图像topic转换成压缩图像的形式,这里用compressed形式进行举例,可以在launch文件中直接进行设置:

 <param name="image_transport" type="string" value="compressed" />

也是同样放在一个node中作为参数出现;

订阅/显示:

如果要是查看一个压缩图像,上面说道可以用ros自己的模块image_view进行显示,但是如果要访问一个压缩图像,则需要在image_view后面进行参数添加:

rosrun image_view image_view image:=/camera/rgb/image_color  ∼image transport = compressed  

使用:

上面从Ros的sensor_msg形式转换成opencv的cv::Mat 都是针对与原图像,这里主要说以下针对压缩图像的转换,具体代码如下:

  ros::NodeHandle nodeHandler;ros::Subscriber encoder_sub = nodeHandler.subscribe("/odom", 10, &ImageGrabber::GrabOdom, &igb);ros::Subscriber image_sub = nodeHandler.subscribe("/usb_cam_left/image_raw/compressed", 1, &ImageGrabber::GrabImage, &igb);ros::spin();

上面是main函数的部分,接下来是回调函数:

void ImageGrabber::GrabImage(const sensor_msgs::CompressedImageConstPtr &msgRGB) {cv::Mat image;try{image = cv::imdecode(cv::Mat(msgRGB->data),1);}catch(cv_bridge::Exception& e){ROS_ERROR("Could not convert to image! ");}cout << "get image data" << endl;if(!image.empty() && finishedCurTrack){/* DO SOMETHING*/}
}

另外,如果是SLAM中,我们经常使用到双目,这是后就需要对双目图像进行压缩和转换,压缩部分与单目一样,但是在订阅的时候,因为SLAM双目跟踪的特殊性质,需要对双目采集的图像进行一个同步,具体如下:

    ros::NodeHandle nh;message_filters::Subscriber<sensor_msgs::CompressedImage> left_sub(nh, "/left_cam/image_raw/compressed", 1);message_filters::Subscriber<sensor_msgs::CompressedImage> right_sub(nh, "/right_cam/image_raw/compressed", 1);typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::CompressedImage, sensor_msgs::CompressedImage> sync_pol;message_filters::Synchronizer<sync_pol> sync(sync_pol(10), left_sub,right_sub);sync.registerCallback(boost::bind(&ImageGrabber::GrabStereo,&igb,_1,_2));ros::spin();

这里需要注意在 message_filters中订阅的是sensor_msgs::CompressedImage类型的消息, 而在接下来的回调函数中使用的是指针类型的消息:

void ImageGrabber::GrabStereo(const sensor_msgs::CompressedImageConstPtr& msgLeft,const sensor_msgs::CompressedImageConstPtr& msgRight)
{cv::Mat left_img;try{left_img = cv::imdecode(cv::Mat(msgLeft->data),1);}catch (cv_bridge::Exception& e){ROS_ERROR("cv_bridge exception: %s", e.what());return;}cv::Mat right_img;try{right_img = cv::imdecode(cv::Mat(msgRight->data),1);}catch (cv_bridge::Exception& e){ROS_ERROR("cv_bridge exception: %s", e.what());return;}/*DO SOMETHING*/
}

ROS 图像相关的命令与应用相关推荐

  1. 2.ROS机器视觉——ROS图像(imgmsg)与opencv(cv2)对接

    参考:古月学院和ROS机器人开发实践 目标:实现ROS系统读取摄像头的图像,ROS读取的图像数据转化为opencv中的图像,opencv对接受的图像进行处理,最后返回给ROS系统可视化输出. 安装op ...

  2. ROS基本概念 文件系统 创建ROS软件包 ROS中的一些命令

    ROS基本概念 文件系统 创建ROS软件包 ROS中的一些命令 ROS是什么 ROS文件系统 文件系统工具:rospack.roscd.rosls 创建ROS 软件包 catkin是什么 创建和构建一 ...

  3. ROS入门之使用命令行工具控制小海龟移动

    前面的文章主要是说明一下ROS入门需要了解的基本概念,这篇文章则是要说明一下如何使用命令行工具. 2.1 命令行工具的使用 ROS有很多常用命令:rostopic.rosservice.rosnode ...

  4. linux图像界面和命令界面切换:

    linux图像界面和命令界面切换: 步骤: 1.首先要保证服务器能正常正常,如连通网关和dns: ping www.baidu.com 2.centos7安装图形界面然后通过yum查询需要安装哪些包, ...

  5. 【ROS基础】Linux命令行

    系列文章目录 [ROS基础]Linux 命令行 [ROS基础].launch 文件语法记录 [ROS基础]CMakeLists.txt 文件语法记录 [ROS基础]Package.xml 文件语法记录 ...

  6. 使用Python进行ros图像的发送

    使用Python进行ros图像的发送 这里首先要完成ros和Pycharm联合编程的设置,具体可以参考qt和pycharm联合ros编程的设置 之后如果用到处理图像的这块的话,就需要下面cv_brid ...

  7. 最详细的SQL注入相关的命令整理

    最详细的SQL注入相关的命令整理   QUOTE: 1.   用^转义字符来写ASP(一句话***)文件的方法: ?   http://192.168.1.5/display.asp?keyno=18 ...

  8. 一款图像相关软件PhoXo

    一款图像相关软件PhoXo SkySeraph May 22nd 2011  HQU Email:zgzhaobo@gmail.com    QQ:452728574 Latest Modified ...

  9. 环境变量PATH 、mv 命令 、cp 命令和 查看文档相关的命令

    2019独角兽企业重金招聘Python工程师标准>>> 环境变量PATH which 命令 which+命令名 //查找某个命令的绝对路径 如:查找rm命令的绝对路径 which的查 ...

最新文章

  1. 运用jieba库分词
  2. 华人世界——客家足迹行
  3. 请妥善保管自己的QQ等网络帐号
  4. c语言funcode空格消失的函数,01北科大暑期计算机实践FunCode游戏设计+C++课程设计 - 海底世界 - 图文...
  5. pagefile.sys解析
  6. ES6学习笔记之Promise
  7. 千万PV级别WEB站点架构设计
  8. Java面向对象抽象类案例分析
  9. python 全栈开发,Day79(Django的用户认证组件,分页器)
  10. LeetCode Algorithm 589. N 叉树的前序遍历
  11. 【289】◀▶ Python I/O 读写文本文件
  12. LeetCode 2116. 判断一个括号字符串是否有效(栈)
  13. php-php异步网络通信引擎-服务发现-消息队列 案例
  14. Java语言程序设计课程设计
  15. 在线3D大脑建模网站分享
  16. CPU的内部架构和工作原理(好文)
  17. 基于Vue的图片裁剪 vue-cropper
  18. 一个广告净化大师拦截视频网站片头广告的实现
  19. M3800的故事——Ipad mini2·电源1
  20. 7-139 手机话费 (10 分)

热门文章

  1. opencv库skimage 实现Canny边缘探测算法
  2. flashtorch:卷积神经网络的可视化
  3. solrcloud 7.5在k8s上的部署安装和使用教程
  4. python机器学习案例系列教程——k均值聚类、k中心点聚类
  5. 【Proteus仿真8086】简单IO接口实验——读取开关状态控制灯的亮灭
  6. vivado和modelsim联合仿真实现分频器——2的n次方分频
  7. 十六进制的形式在屏幕中间显示二进制byte类型数据
  8. Flink官方文档学习(三):Standalone Cluster 集群部署
  9. 如何选择梯度下降法中的学习速率α(Gradient Descent Learning Rate Alpha)
  10. Go语言学习之11 日志收集系统kafka库实战