ROS image_transport
此外上面提到过FPS这个参数,自然少不了介绍图像的压缩。一般使用的时候直接会使用没有压缩的图像,但是在需要传输的时候,这一些大图像非常占用带宽,所以对图像进行压缩也就是必然的选择了。
ROS中已有的图像压缩的包有image_transport,它提供了一系列的类以及节点允许用户自己选择特定的传输策略,同时将传输的数据统一为sensors_msgs/Image。但是它本身并不完成数据的压缩工作,本身只完成对原始数据的传输,真正的数据压缩由继承自它的插件们来完成,关于插件的问题下面再说。这一些插件构成的集合是image_transport_plugins(http://wiki.ros.org/image_transport_plugins), 内部含有对图片的JPEG/PNG格式的压缩以及对视频数据的Theroa编码,这是一个免费但是有损的编码方式。视频编码没用过就不多说了,但是视频同样也可以逐帧通过图片压缩进行传输,当然效率上的问题没有与直接对视频编码进行比较因而也不好推荐。
这一些插件可以通过apt-get安装
在具有image_transport的插件的基础上,我们才可以选择采用哪种插件进行图像的压缩,当然实际是image_transport来选择。
通过使用rqt_reconfigure工具可以动态调节压缩比,直观显示采用具体哪一种类型或者压缩比。
当然也可以直接使用rqt将各类插件集中在一起。
下面显示了不同的JPEG压缩率下的不同图像
上图使用了uvc_camera,内部已经使用了image_transport的类,所以在驱动相机之后,自然提供了压缩的一些选择。但是如果没有提供压缩的数据呢?我想对于某一些相机的驱动,应该是只提供原始数据的吧,因此,对于此类驱动,我们可以继续使用image_transport来进行数据的压缩。Image_transport 提供了republish节点,方便我们直接做处理:选择压缩格式,进行数据的重发。
在使用republish之前,需要将image_transport完全安装,如下所示。
否则无法使用republish.
对于wiki上的例子,(http://wiki.ros.org/image_transport),Nodes部分的代码是有问题的。
这样肯定没法使用啊。
但上面大概说明了republish的用法,对于视频或者图像输入,in_transport 表示接受的数据的传输形式,out_transport 表示重发数据的传输形式。in:=之后必须为原始图像的topic,out:=为重发的topic的基本名称。
wiki给出了目前可以使用的三种数据格式,如下所示。
如果in_transport 设置为 raw,即订阅原始数据;设置为compressed,则订阅压缩数据;若设置为theora,则订阅视频的theora编码的数据。如果out_transport 设置为raw,则重只发原始数据;若为compressed,则只重发压缩数据;设置为theora,则只重发theora编码的视频数据。
但是如果out_transport 缺省,则重发全部的插件提供的数据,即包括原始数据、压缩数据、深度压缩数据以及theora编码的视频数据。
如果相机本身没有提供深度数据,则订阅深度数据失败,即没有深度数据。
下面是一个具体的例子,in_transport设置为 raw,out_transport 设置为raw,通过比较左右两图发现,右图多的一个节点就是/republish_name
下图则是设置out_transport缺省的情况,发现将原来所有的节点全部重发。
此外,我们也可以自行使用image_transport作为基类来编写自己的插件,实现满足自己需求的要求。这方面的代码在wiki上已经给出。
(http://wiki.ros.org/image_transport/Tutorials/WritingNewTransport)
由于这个部分同时涉及到了pluginlib的使用,因而需要先看pluginlib的部分。
此外,我们在自定义使用image_transport时常打算自己设定压缩的比率,但是目前image_transport没有开放参数的接口。观察transport_hints.h 的代码,我们发现只有image_transport 一个参数可以调,即选择插件的选项。
关于图像压缩的部分就暂时到这里为止。
上面我们注意到,image_transport涉及到在ROS中使用OpenCV,因而也就简单介绍一下。对于上面的图像压缩,使用OpenCV同样可以做到,CV的知识就借助其他的书籍来学习了,入门可以看《OpenCV3编程入门》。OpenCV放在ROS中使用,主要由vision_opencv这个stack提供帮助。它包括了cv_bridge以及image_geometry。
cv_bridge主要提供的帮助是将OpenCV的图像数据与ROS的image消息进行转换。OpenCV提供了图像的数据可以作为ROS中的image消息的data部分,而其他的部分,需要由用户自行定义。
ROS的sensor_msgs/Image消息如下所示。其中的data数据可以由OpenCV的图像数据进行填充。当然,data数据也就可以变成OpenCV的Mat数据格式。
关于cv_bridge的使用基本没有很大的难度,使用image_transport的subscriber与publisher进行ROS节点之间的图像收发,在需要使用OpenCV的时候使用cv_bridge将消息转化为Mat类型,由此进行OpenCV的处理,处理结束之后如果还需要处理之后的数据,则再利用cv_bridge将Mat转化为sensor_msgs/Image即可。所以,cv_bridge就如他的名字一样,是bridge,为OpenCV的使用搭建桥梁,桥上面运输的就是关键的图像像素数据。
关于cv_bridge的使用,wiki上的详细的教程见此处(http://wiki.ros.org/cv_bridge/Tutorials/UsingCvBridgeToConvertBetweenROSImagesAndOpenCVImages)
当然,由于sensor_msgs/Image的data需要的数据是uint8类型的,对于opencv中提供的众多数据类型,在进行数据的使用(拷贝或是引用)时,需要指明编码的格式,防止出现图片编码的混乱。具体的使用细节还是根据现场的情况进行分析及时调试即可。
说完cv_bridge,那么vision_opencv中的image_geometry是干什么的呢?
image_geometry借助sensor_msgs/CameraInfo的参数简化对图像的几何描述,包含了C++与python的库。这么说的话就感觉和没说差不多啊,所以我们看一下头文件的位置就明白了,如下图所示。
image_geometry中包含的两个头文件 pinhole_camera_model.h和stereo_camera_model.h,由此我们便从名字上得知,它的主要功能在于对单目相机以及双目相机进行建立模型。建立模型干嘛?干什么就是用户的事情了,但是模型建立之后,便可以简化对图像的几何描述,这也就是上面的意思了吧。
wiki推荐使用这个库,原文写到“Although CameraInfo contains all the information required to rectify a raw image and project points onto it, it is highly recommended that you use this library, since performing these operations correctly over the space of all camera options can be non-trivial.”。总之用image_geometry可以让你对在相机空间进行操作感到不那么繁琐。wiki提供了在图中标注TF例子(http://wiki.ros.org/image_geometry/Tutorials/ProjectTfFrameToImage)但是这个例子对于理解image_geometry感觉不是很有帮助啊,而且需要你事先了解TF的内容。所以为了了解image_geometry,还是得从源码入手。
(http://docs.ros.org/api/image_geometry/html/c++/classimage__geometry_1_1PinholeCameraModel.html)。我个人不喜欢看源码,因为不会看....但是通过查看函数的功能,大概还是猜的出来整个头文件想要干嘛。通过查看源码,我个人的理解是:image_transport就是一个比sensor_msgs/CameraInfo更加详细、更加通用,为我们在不同的分辨率下得到相机的各类物理参数(如x,y坐标的光学中心,x,y坐标的焦距等等等)的工具。
此外,各种与CV、AR相关的C/C++资料可以查看(http://blog.exbot.net/archives/957)
视觉以及图像处理、3D重构等工具以及网站(http://blog.exbot.net/archives/949)