参看roswiki:
http://wiki.ros.org/cv_bridge/Tutorials/UsingCvBridgeToConvertBetweenROSImagesAndOpenCVImages
注意其中的源码编译好后,在运行时,要输入视频流
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);
}
其中/camera/image_raw 为图像消息,程序订阅该消息获取图像./image_converter/output_video为程序产生的话题消息.
Demo code如下:
Here is a node that listens to a ROS image message topic, converts the image into a cv::Mat, draws a circle on it and displays the image using OpenCV. The image is then republished over ROS. (这里是一个监听ROS图像消息主题的节点,将图像转换为cv :: Mat,并在其上绘制一个圆圈并使用OpenCV显示图像。 该图像然后通过ROS重新发布。)
In your package.xml and CMakeLists.xml (or when you use catkin_create_pkg), add the following dependencies:
sensor_msgs cv_bridge roscpp std_msgs image_transport
Create a image_converter.cpp file in your /src folder and add the following:
#include /ros.h>
#include /image_transport.h>
#include /cv_bridge.h>
#include /image_encodings.h>
#include /imgproc/imgproc.hpp>
#include /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;
}
Let's break down the above node:
2 #include /image_transport.h>
3
Using image_transport for publishing and subscribing to images in ROS allows you to subscribe to compressed image streams. Remember to include image_transport in your package.xml. (使用image_transport在ROS中发布和订阅图像可以让您订阅压缩的图像流。请记住在package.xml中包含image_transport。)
3 #include /cv_bridge.h>
4 #include /image_encodings.h>
5
Includes the header for CvBridge as well as some useful constants and functions related to image encodings. Remember to include cv_bridge in your package.xml. (包括CvBridge的头文件以及一些与图像编码相关的有用的常量和函数。 记得在你的package.xml中包含cv_bridge。 )
5 #include /imgproc/imgproc.hpp>
6 #include /highgui/highgui.hpp>
7
Includes the headers for OpenCV's image processing and GUI modules. Remember to include opencv2 in your package.xml. (包括OpenCV图像处理和GUI模块的的头文件。 请记住在你的package.xml中包含opencv2。)
12 ros::NodeHandle nh_; 13 image_transport::ImageTransport it_; 14 image_transport::Subscriber image_sub_; 15 image_transport::Publisher image_pub_; 16 17 public: 18 ImageConverter() 19 : it_(nh_) 20 { 21 // Subscrive to input video feed and publish output video feed 22 image_sub_ = it_.subscribe("/camera/image_raw", 1, 23 &ImageConverter::imageCb, this); 24 image_pub_ = it_.advertise("/image_converter/output_video", 1);
Subscribe to an image topic "in" and advertise an image topic "out" using image_transport. ( 订阅图像主题“in”并使用image_transport将图像主题"out"发布出去。)
26 cv::namedWindow(OPENCV_WINDOW); 27 } 28 29 ~ImageConverter() 30 { 31 cv::destroyWindow(OPENCV_WINDOW); 32 }
OpenCV HighGUI calls to create/destroy a display window on start-up/shutdown. (OpenCV HighGUI调用在启动/关闭时创建/销毁显示窗口).
34 void imageCb(const sensor_msgs::ImageConstPtr& msg) 35 { 36 cv_bridge::CvImagePtr cv_ptr; 37 try 38 { 39 cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8); 40 } 41 catch (cv_bridge::Exception& e) 42 { 43 ROS_ERROR("cv_bridge exception: %s", e.what()); 44 return; 45 }
In our subscriber callback, we first convert the ROS image message to a CvImage suitable for working with OpenCV. Since we're going to draw on the image, we need a mutable copy of it, so we use toCvCopy(). sensor_msgs::image_encodings::BGR8 is simply a constant for "bgr8", but less susceptible to typos.
Note that OpenCV expects color images to use BGR channel order.
You should always wrap your calls to toCvCopy() / toCvShared() to catch conversion errors as those functions will not check for the validity of your data.
47 // Draw an example circle on the video stream 48 if (cv_ptr->image.rows > 60 && cv_ptr->image.cols > 60) 49 cv::circle(cv_ptr->image, cv::Point(50, 50), 10, CV_RGB(255,0,0)); 50 51 // Update GUI Window 52
Draw a red circle on the image, then show it in the display window.
53 cv::waitKey(3);
Convert the CvImage to a ROS image message and publish it on the "out" topic.
To run the node, you will need an image stream. Run a camera or play a bag file to generate the image stream. Now you can run this node, remapping "in" to the actual image stream topic.
If you have successfully converted images to OpenCV format, you will see a HighGui window with the name "Image window" and your image+circle displayed.
You can see whether your node is correctly publishing images over ROS using either rostopic or by viewing the images using image_view.