Ros中的图像信息是sensor_msgs/Image的格式,而OpenCV 中图像是cv:Mat格式。所以从Ros中获取的图像不能直接用OpenCV进行处理,需要进行格式转化。还好,Ros中提供了进行ROS和OpenCV之间图像信息格式转化的接口CvBridge
代码如下:
#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_COLOR = "Image color window";
static const std::string OPENCV_WINDOW_DEPTH = "Image depth window";
class ImageConverter
{
ros::NodeHandle nh_;
image_transport::ImageTransport it_;
image_transport::Subscriber image_sub_color;
image_transport::Subscriber image_sub_depth;
image_transport::Publisher image_pub_color;
image_transport::Publisher image_pub_depth;
public:
ImageConverter()
: it_(nh_)
{
// Subscrive to input video feed and publish output video feed
image_sub_color = it_.subscribe("/camera/rgb/image_raw", 1, &ImageConverter::imageCb, this);
image_sub_depth = it_.subscribe("/camera/depth/image_raw",1,&ImageConverter::depthCb, this);
image_pub_color = it_.advertise("/image_converter/output_video/color", 1);
image_pub_depth = it_.advertise("/image_converter/output_video/depth", 1);
cv::namedWindow(OPENCV_WINDOW_COLOR);
cv::namedWindow(OPENCV_WINDOW_DEPTH);
}
~ImageConverter()
{
cv::destroyWindow(OPENCV_WINDOW_COLOR);
cv::destroyWindow(OPENCV_WINDOW_DEPTH);
}
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_COLOR, cv_ptr->image);
cv::waitKey(3);
// Output modified video stream
image_pub_color.publish(cv_ptr->toImageMsg());
}
void depthCb(const sensor_msgs::ImageConstPtr &msg)
{
cv_bridge::CvImagePtr cv_ptr;
try
{
cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::TYPE_32FC1);
}
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_DEPTH, cv_ptr->image);
cv::waitKey(3);
// Output modified video stream
image_pub_depth.publish(cv_ptr->toImageMsg());
}
};
int main(int argc, char** argv)
{
ros::init(argc, argv, "image_converter");
ImageConverter ic;
ros::spin();
return 0;
}
编译后可能会出现很多未定义的引用
image_rec_handle.cpp:(.text._ZN14ImageConverterD2Ev[_ZN14ImageConverterD5Ev]+0x35):对‘cv::destroyWindow(cv::String const&)’未定义的
CMakeFiles/image_rec_handle.dir/src/image_rec_handle.cpp.o:在函数‘ImageConverter::imageCb(boost::shared_ptr<sensor_msgs::Image_<st
image_rec_handle.cpp:(.text._ZN14ImageConverter7imageCbERKN5boost10shared_ptrIKN11sensor_msgs6Image_ISaIvEEEEE[_ZN14ImageConverter7
_msgs6Image_ISaIvEEEEE]+0x1bd):对‘cv::imshow(cv::String const&, cv::_InputArray const&)’未定义的引用
image_rec_handle.cpp:(.text._ZN14ImageConverter7imageCbERKN5boost10shared_ptrIKN11sensor_msgs6Image_ISaIvEEEEE[_ZN14ImageConverter7
_msgs6Image_ISaIvEEEEE]+0x1e2):对‘cv::waitKey(int)’未定义的引用
collect2: error: ld returned 1 exit status
这是因为 package.xml 和cmakelist.txt中少了关于opencv的信息。添加后即可编译成功。
另外,深度图有好几种不同的编码方式,我这里摄像头的编码方式是32FC1
在上述代码中, sensor_msgs::image_encodings::TYPE_16UC1
表示将ros数据类型转换cv数据类型的编码方式。一般而言,深度图的编码方式都有8UC, 16UC1, 32FC1
等三种。
参考文献:
https://blog.csdn.net/Jaryblueky/article/details/70895270
https://blog.csdn.net/jchsns007/article/details/78908164
https://www.cnblogs.com/gdut-gordon/p/9151740.html