ROS系列:八、图像消息和OpenCV图像之间进行转换-cv_bridge
cv_bridge是在ROS图像消息和OpenCV图像之间进行转换的一个功能包。
(一)在ROS图像和OpenCV图像之间转换(C ++)
1.Concepts(概念)
ROS以自己的sensor_msgs / Image消息格式传递图像,但许多用户希望将图像与OpenCV结合使用。 CvBridge是一个ROS库,提供ROS和OpenCV之间的接口。 可以在vision_opencv stack的cv_bridge包中找到CvBridge。
在本教程中,您将学习如何编写使用CvBridge将ROS映像转换为OpenCVcv :: Mat格式的节点。
您还将学习如何将OpenCV图像转换为ROS格式以通过ROS发布。
1.1 从C-Turtle或更早版本编写的代码迁移过来
关于OpenCV,在ROS Diamondback中有很大的api变化,虽然后向兼容维护了一阵,但从hydro开始有些已经被移除了,如sensor_msgs/CvBridge。关于迁移的问题见链接。
2.把ROS图像转换成OpenCV图像
CvBridge定义了一个包含OpenCV图像及其编码、ROS头文件(header)的Cvimage类型。CvImage包含sensor_msgs / Image的信息,因此我们可以在者两者之间转换。CvImage 的class 如下:
namespace cv_bridge {class CvImage
{
public:std_msgs::Header header;std::string encoding;cv::Mat image;
};typedef boost::shared_ptr<CvImage> CvImagePtr;
typedef boost::shared_ptr<CvImage const> CvImageConstPtr;}
将ROS sensor_msgs / Image消息转换为CvImage时,CvBridge会识别两个不同的用例:
1.我们想要就地修改数据。 我们必须复制ROS消息数据。
2.我们不会修改数据。 我们可以安全地共享ROS消息所拥有的数据,而不是复制
CvBridge提供以下用于转换为CvImage的函数:
// Case 1: Always copy, returning a mutable CvImage
CvImagePtr toCvCopy(const sensor_msgs::ImageConstPtr& source,const std::string& encoding = std::string());
CvImagePtr toCvCopy(const sensor_msgs::Image& source,const std::string& encoding = std::string());// Case 2: Share if possible, returning a const CvImage
CvImageConstPtr toCvShare(const sensor_msgs::ImageConstPtr& source,const std::string& encoding = std::string());
CvImageConstPtr toCvShare(const sensor_msgs::Image& source,const boost::shared_ptr<void const>& tracked_object,const std::string& encoding = std::string());
函数的输入是一个图像指针,以及一个可选的编码参数用于规定目标CvImage的编码。
即使源和目标编码匹配,toCvCopy也会从ROS消息创建图像数据的副本。 但是,您可以自由修改返回的CvImage
toCvShare将会返回一个指向ROS消息的cv::Mat const指针防止修改,只要你有返回的CvImage指针的拷贝,ROS消息就不会被释放。如果编码不匹配,ROS将分配一个新的buffer并执行转换,但你还是不能对其进行修改。
注:当你有一个包含sensor_msgs/Image的其他消息类型的指针时,使用toCvShare的第二种重载方法将更为方便。
如果没有给定编码信息,目标图像的编码将与源图像一样,在这种情况下toCvShare能保证不会对数据进行拷贝。图像编码可以是一下任意一种OpenCV支持的图像编码:
- 8UC[1-4]
- 8SC[1-4]
- 16UC[1-4]
- 16SC[1-4]
- 32SC[1-4]
- 32FC[1-4]
- 64FC[1-4]
对于某些常用的编码,CvBridge提供了可选的color或pixel depth的转换,要想使用这个特性,需要将编码指定为一下格式之一:
mono8: CV_8UC1, grayscale image
mono16: CV_16UC1, 16-bit grayscale image
bgr8: CV_8UC3, color image with blue-green-red color order
rgb8: CV_8UC3, color image with red-green-blue color order
bgra8: CV_8UC4, BGR color image with an alpha channel
rgba8: CV_8UC4, RGB color image with an alpha channel
其中mono8和bgr8是大多数OpenCV函数所期望的图像编码格式。
最后,CvBridge也可以识别OpenCV中8UC1类型的Bayer pattern编码,CvBridge将不会对Bayer pattern进行转换,一般是由image_proc进行转换的。CvBridge可以识别一下以下集中Bayer编码:
bayer_rggb8
bayer_bggr8
bayer_gbrg8
bayer_grbg8
3.将OpenCV图像转换为ROS图像消息
要转换CvImage为ROS图像消息,可以使用toImageMsg()成员函数:
class CvImage
{sensor_msgs::ImagePtr toImageMsg() const;// Overload mainly intended for aggregate messages that contain// a sensor_msgs::Image as a member.void toImageMsg(sensor_msgs::Image& ros_image) const;
};
如果CvImage是你自己创建的,不要忘了填充header和编码字段。对于自己创建CvImage的例子,可以参考图像教程
4.ROS节点示例
这里展示一个监听ROS图像消息话题的节点,并将该图像转换为cv::Mat格式,然后使用OpenCV在图像上画一个圆并进行显示。最后该图像将在ROS中重新发布
在你的package.xml和CMakeLists.xml(或者在你使用catkin_create_pkg时)添加一下依赖:
sensor_msgs
cv_bridge
roscpp
std_msgs
image_transport
在你的功能包src下面创建一个image_converter.cpp,t添加以下代码:
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>static const std::string OPENCV_WINDOW = "Image window";class ImageConverter
{ros::NodeHandle nh_;image_transport::ImageTransport it_;image_transport::Subscriber image_sub_;image_transport::Publisher image_pub_;public:ImageConverter(): it_(nh_){// Subscrive to input video feed and publish output video feedimage_sub_ = it_.subscribe("/camera/image_raw", 1,&ImageConverter::imageCb, this);image_pub_ = it_.advertise("/image_converter/output_video", 1);cv::namedWindow(OPENCV_WINDOW);}~ImageConverter(){cv::destroyWindow(OPENCV_WINDOW);}void imageCb(const sensor_msgs::ImageConstPtr& msg){cv_bridge::CvImagePtr cv_ptr;try{cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);}catch (cv_bridge::Exception& e){ROS_ERROR("cv_bridge exception: %s", e.what());return;}// Draw an example circle on the video streamif (cv_ptr->image.rows > 60 && cv_ptr->image.cols > 60)cv::circle(cv_ptr->image, cv::Point(50, 50), 10, CV_RGB(255,0,0));// Update GUI Windowcv::imshow(OPENCV_WINDOW, cv_ptr->image);cv::waitKey(3);// Output modified video streamimage_pub_.publish(cv_ptr->toImageMsg());}
};int main(int argc, char** argv)
{ros::init(argc, argv, "image_converter");ImageConverter ic;ros::spin();return 0;
}
接下来我们对代码进行一个分解:
#include <image_transport/image_transport.h>
使用在ROS中发布和订阅图像image_transport允许您订阅压缩图像流。 请记住在package.xml中添加image_transport的依赖配置。
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
包含CvBridge的头文件以及image encodings(包含了很多有用的常量和函数),记得在package.xml中添加cv_bridge的依赖配置。
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp
包含OpenCV的图像处理和GUI模块头文件,记得在package.xml中include opencv2的依赖。
ros::NodeHandle nh_;image_transport::ImageTransport it_;image_transport::Subscriber image_sub_;image_transport::Publisher image_pub_;public:ImageConverter(): it_(nh_){// Subscrive to input video feed and publish output video feedimage_sub_ = it_.subscribe("/camera/image_raw", 1,&ImageConverter::imageCb, this);image_pub_ = it_.advertise("/image_converter/output_video", 1);
用image_transport订阅一个图像主题“in”和发布一个图像主题“out”。
cv::namedWindow(OPENCV_WINDOW);}~ImageConverter(){cv::destroyWindow(OPENCV_WINDOW);}
在初始化和析构时调用OpenCV HighGUI来创建及销毁窗口。
void imageCb(const sensor_msgs::ImageConstPtr& msg){cv_bridge::CvImagePtr cv_ptr;try{cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);}catch (cv_bridge::Exception& e){ROS_ERROR("cv_bridge exception: %s", e.what());return;}
在我们的回调函数中,首先将ROS图像消息转换为了CvImage以在OpenCV中使用。因为我们需要在图像中画圆,所以需要一个图像的拷贝,应使用toCvCopy()。sensor_msgs::image_encodings::BGR8是”bgr8”字符串常量。
注意:penCV期望彩色图像使用BGR通道顺序。
我们应该调用toCvCopy()/toCvShared()时来捕获异常错误,因为这些函数不会校验数据的有效性。
// Draw an example circle on the video streamif (cv_ptr->image.rows > 60 && cv_ptr->image.cols > 60)cv::circle(cv_ptr->image, cv::Point(50, 50), 10, CV_RGB(255,0,0));// Update GUI Window
在图像中画一个红色的圆圈并进行显示。
cv::waitKey(3);
将CvImage转换为ROS图像消息并将其发布到“out”话题上。
要运行节点,您需要一个图像流。运行一个摄像头或播放bag文件以生成图像流。 现在,您可以运行此节点,将“in”重新映射(remapping)到实际的图像流主题。
如果你成功地转换为OpenCV图像,你将在创建的窗口中看到添加圆圈之后的图像。
你可以通过rostopic或image_view查看图像来确认节点是否正确地发布了图像。
5.共享图像数据的例子
在上节中我们创建了图像的拷贝,但共享图像也很容易:
namespace enc = sensor_msgs::image_encodings;void imageCb(const sensor_msgs::ImageConstPtr& msg)
{cv_bridge::CvImageConstPtr cv_ptr;try{cv_ptr = cv_bridge::toCvShare(msg, enc::BGR8);}catch (cv_bridge::Exception& e){ROS_ERROR("cv_bridge exception: %s", e.what());return;}// Process cv_ptr->image using OpenCV
}
如果输入图像的编码是”bgr8”,cv_ptr将会是图像数据的一个别名而非拷贝。如果输入图像不是”bgr8”编码但是可转换为”bgr8”编码(如”mono8”),CvBridge将会为cv_ptr分配一个新的buffer并执行转换。如果没有异常捕获语句的话一行代码就能共享图像了,但可能输入图像的编码无法转换为目标编码从而导致节点崩溃。例如,当输入图像是从一个Bayer pattern摄像机的image_raw话题接收的,CvBridge将会抛出异常,因为不支持Bayer到color的自动转换。
一个稍微更复杂的例子:
namespace enc = sensor_msgs::image_encodings;void imageCb(const sensor_msgs::ImageConstPtr& msg)
{cv_bridge::CvImageConstPtr cv_ptr;try{if (enc::isColor(msg->encoding))cv_ptr = cv_bridge::toCvShare(msg, enc::BGR8);elsecv_ptr = cv_bridge::toCvShare(msg, enc::MONO8);}catch (cv_bridge::Exception& e){ROS_ERROR("cv_bridge exception: %s", e.what());return;}// Process cv_ptr->image using OpenCV
}
在这个例子中,如果可以的话我们将使用color的编码,不行的话就是用monochrome类型的编码,如果输入图像是”bgr8”或”mono8”编码,将不会进行拷贝。
ROS系列:八、图像消息和OpenCV图像之间进行转换-cv_bridge相关推荐
- 三维视觉基础之世界坐标系、相机坐标系、图像坐标系和像素坐标系之间的转换关系
三维视觉基础之世界坐标系.相机坐标系.图像坐标系和像素坐标系之间的转换关系 一.各坐标系介绍 二.世界坐标系和相机坐标系之间的转换 三.相机坐标系和图像坐标系之间的转换 四.图像坐标系和像素坐标系之间 ...
- 相机成像---世界坐标系、相机坐标系、图像坐标系和像素坐标系之间的转换关系
新学期第一天开始写的这篇文章,看看我啥时候能把他发出去.假期当然是啥也没干了,之前还信誓旦旦说回家一定能学习,学个毛线.开始学习啦,去年年末把环境配置好了之后,实验发现他不准,用的D435i摄像头是红 ...
- 世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换
世界坐标系.相机坐标系.图像坐标系.像素坐标系之间的转换 图像处理.立体视觉等方向常常涉及到四个坐标系:世界坐标系.相机坐标系.图像坐标系.像素坐标系.例如下图: 构建世界坐标系只是为了更好的描述相机 ...
- pythonopencv图像形态_python+opencv图像形态学处理详细解释(膨胀、腐蚀、开闭运算、礼帽和黑猫)...
python+opencv图像形态学处理 本篇博客主要是关于形态学中的腐蚀.膨胀.开运算.闭运算.礼帽和黑帽的函数用法. 内容会比较,为方便查阅.代码的解释会写在代码中. 用于测试的图像原图: 一.腐 ...
- 计算机视觉:相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换(转载)
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/chentravelling/article/details/53558096 0.前言 最近整理了& ...
- 【自动驾驶】16.计算机视觉:相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换
本篇博客为转载,我对其中的细节添加了一些说明. 原文链接:https://blog.csdn.net/chentravelling/article/details/53558096 0.前言 最近整理 ...
- 二 八 十 十六 进制之间快速转换
一. 十进制与二进制之间的转换 (1) 十进制转换为二进制,分为整数部分和小数部分 ① 整数部分 方法:除2取余法,即每次将整数部分除以2,余数为该位权上的数,而商继续除以2,余数又为上一个位权上的数 ...
- android utf-8 转 gbk编码,【字符编码系列】GBK,UTF-8,UTF-16之间的转换
写在前面的话 本文属于 字符编码系列文章之一,更多请前往 字符编码系列. 大纲 不同编码转换的理论基础 UTF-16转UTF-8 UTF-16转GBK UTF-16和UTF-8之间的转换 UTF-16 ...
- python opencv 图像叠加,python opencv图像叠加/图像融合/mask掩模
目录python 一.图像叠加 能够经过OpenCV函数cv.add()或简单地经过numpy操做添加两个图像,res = img1 + img2.两个图像应该具备相同的深度和类型,或者第二个图像能够 ...
- cv_bridge用于ROS图像和OpenCV图像的转换
ROS是机器人领域中比较受到关注的一种系统,它的应用比较方便而且有许多的工具比如传感器驱动包可以直接使用.但是ROS对于传感器数据有自己的格式和规范.而在OpenCV中,图像是以Mat矩阵的形式存储的 ...
最新文章
- uniapp富文本兼容视频实现方案
- R语言构建ElasticNet回归模型实战:基于mtcars数据集
- 功能之前,感叹号有什么作用?
- micropython解释器原理_了解一下 MicroPython 的项目整体架构
- 全球与中国Z型斗式提升机市场运营战略分析及未来趋势创新建议报告2022-2027年版
- Git for Windows之推送本地版本库到远程仓库
- 排序算法之选择法排序(C/C++)
- python好用的内置库_第42p,time库,Python中优秀的内置库
- 树——一种数据结构(二)
- js 控制 head 元素 隐藏与显示
- ATP-EMTP谁懂啊,急!!
- 感性电路电流计算_电工初学者会正确计算负载功率吗?一篇文章彻底教会你
- ECshop二次开发细节
- 【Redis踩坑日记】Redis由于目标计算机积极拒绝,无法连接
- Disastrous Downtime
- PostgreSQL 透明加密(TDE,FDE) - 块级加密
- ListView分页(带图片)显示用法案例。。。下
- office online server2016详细安装步骤及问题总结
- 《神经网络与深度学习》邱希鹏 学习笔记 (1)
- kingcms php 列表页bug,kingcms最新版sql注入漏洞
热门文章
- FeHelper ( 浏览器插件 )
- 解决Win10系统关机自动重启问题
- 单片机高效c语言编程,飞思卡尔单片机高效C语言编程(中文).pdf
- c语言笔试面试大全,C语言基础笔试题
- 法兰克焊接机器人编程入门_焊接机器人编程入门基本常识
- (十一)GDBdebug调试技术——malloc()和free()发生故障
- zmodem transfer canceled by remote side 段错误(吐核)
- 过来领你的Bug之“缺陷分析“篇
- 黑客帝国之八种超级武器
- active控件和java脚本_Active控件问题小结(附解决办法)