ROS详解-cv_bridge

cv_bridge是在ROS图像消息和OpenCV图像之间进行转换的一个功能包。

1.Concepts

ROS以自己的sensor_msgs / Image消息格式传递图像,但许多用户希望将图像与OpenCV结合使用。 CvBridge是一个ROS库,提供ROS和OpenCV之间的接口。 可以在vision_opencv stack的cv_bridge包中找到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;
 
}

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的编码。

toCvShare将会返回一个指向ROS消息的cv::Mat const指针防止修改,只要你有返回的CvImage指针的拷贝,ROS消息就不会被释放。如果编码不匹配,ROS将分配一个新的buffer并执行转换,但你还是不能对其进行修改。

图像编码可以是一下任意一种OpenCV支持的图像编码:

  • 8UC[1-4]
  • 8SC[1-4]
  • 16UC[1-4]
  • 16SC[1-4]
  • 32SC[1-4]
  • 32FC[1-4]
  • 64FC[1-4]

vBridge提供了可选的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函数所期望的图像编码格式。

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;
};

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 feed
    image_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 stream
    if (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::imshow(OPENCV_WINDOW, cv_ptr->image);
    cv::waitKey(3);
 
    // Output modified video stream
    image_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 feed
    image_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 stream
    if (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图像,你将在创建的窗口中看到添加圆圈之后的图像。

你可以通过rostopicimage_view查看图像来确认节点是否正确地发布了图像。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋水 墨色

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值