1 引言
  小博在前两次已经介绍过ROS的安装使用以及基础的基础知识了,我的研究方向是计算机视觉,所以我的大部分文章基本都是视觉.所以本节将结合视觉和ROS写一篇博客,来为大家详细讲解一下,并附上教程.
 通常我们在机器人项目中都会涉及到进程间通讯,亦或是好多人老是问我python 怎么调用C++,其实我认为他很有可能是遇到了进程间通讯的问题,或是图像检测使用python做的,无法将检测到的结果发给打的大程序框架.其实ROS很好的解决了进程间通信的问题,他将每一个进程可以看做一个节点,本节就新建两个节点,一个用来发布一张图像信息,另一个节点用来接收图像.具体图像处理算法可因各位具体情况而定,博客其他章节使用算法也比较多,可多多参考.

2 ROS节点
首先参考我的这篇博客,保证你的环境是正常的,可以打出hello world消息才能继续往下走.
https://blog.csdn.net/xiao__run/article/details/84675245
这时候我们可以看到我们的文件夹情况
在这里插入图片描述

src文件里是我们的每一个项目,当你做完(一)上面的步骤之后,已经有一个了,接下来我们创建一个关于图像的,我们这里同样使用opencv,后面我们才使用caffe,tensorflow.

cd ROS /src    //ROS位置里的src目录下
catkin_create_pkg tag_detector image_transport  cv_bridge  //catkin_create_pkg包名与后面两个是图像转换依赖
cd .. 
catkin_make 
source ./devel/setup.bash

如果编译没错我们再进入下一步

进入cd tag_detector/src文件,开始我们的代码,先写一个发布图像的节点

nano image_raw.cpp

填入以下代码

#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
 
int main(int argc, char** argv)
{
  ros::init(argc, argv, "image_publisher");

  ros::NodeHandle nh;

  image_transport::ImageTransport it(nh);
 //在camera/image话题上发布图像,这里第一个参数是话题的名称,第二个是缓冲区的大小
  image_transport::Publisher pub = it.advertise("camera/image", 1);
  cv::Mat image = cv::imread("/home/lenovo/darknet/000079.jpg");
//
/算法                               
/算法     
/
  cv::imshow("image",image);
  ROS_INFO("Hello ROS!");
  sensor_msgs::ImagePtr msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", image).toImageMsg();
 //将opencv格式的图像转化为ROS所支持的消息类型,从而发布到相应的话题上。
  ros::Rate loop_rate(5);
	cv::waitKey(0);
  while (nh.ok())
 {
    pub.publish(msg);
    ros::spinOnce();
    loop_rate.sleep();
  }
}

接下来新建另一个节点,接收这张图片.

nano listen_image.cpp

复制如下代码

#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/opencv.hpp>
#include <cv_bridge/cv_bridge.h>
 
void imageCallback(const sensor_msgs::ImageConstPtr& msg)
{
  try
  {
    cv::imshow("view", cv_bridge::toCvShare(msg, "bgr8")->image);
  }
  catch (cv_bridge::Exception& e)
  {
    ROS_ERROR("Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str());
  }
}
 
int main(int argc, char **argv)
{
  ros::init(argc, argv, "listen_image");
  ros::NodeHandle nh;
  cv::namedWindow("view");
  cv::startWindowThread();
  image_transport::ImageTransport it(nh);
  image_transport::Subscriber sub = it.subscribe("camera/image", 1, imageCallback);
  ros::spin();
  cv::destroyWindow("view");
}

接下来我们配置ROS/src/tag_detectorcmakelixt.txt东西,打开,复制以下几段,其实就是opencv的依赖,不会cmake 的同学可以百度稍微学习下.

find_package(OpenCV REQUIRED)
include_directories(${catkin_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS})

#build my_publisher and my_subscriber
add_executable(tag_detector_pub src/image_raw.cpp)
add_executable(tag_detector_listen src/listen_image.cpp)
target_link_libraries(tag_detector_pub  ${OpenCV_LIBS})
target_link_libraries(tag_detector_pub ${catkin_LIBRARIES})

target_link_libraries(tag_detector_listen  ${OpenCV_LIBS})
target_link_libraries(tag_detector_listen ${catkin_LIBRARIES})

接下来我们编译一下,记住是在你的ROS路径下

catkin_make

不报错证明编译通过,接下来你就可以运行了.
还是一样,跟运行小乌龟程序一样三步走,记住是在三个不同命令窗口哈.

roscore
rosrun tag_detector tag_detector_pub 
rosrun tag_detector tag_detector_listen 

运行之后你可以通过rqt查看你的节点情况.
当然你可以将你的算法加入到我的图像传输中标记的算法模块里.
3 视频的发布与订阅
原理基本一样,只是代码稍微有点变换,我这里使用的是双目摄像头,结果图如下:

在这里插入图片描述

代码我直接粘贴啦,各位自取消息发布

#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
#include <std_msgs/String.h>
using namespace cv;
int main(int argc, char** argv)
{
	// ROS节点初始化 
	ros::init(argc, argv, "image_publisher"); 
	ros::NodeHandle n; 
	ros::Time time = ros::Time::now(); 
	ros::Rate loop_rate(5); // 定义节点句柄 
	image_transport::ImageTransport it(n); 
	image_transport::Publisher pub = it.advertise("video_image", 1); 
	sensor_msgs::ImagePtr msg; // opencv准备读取视频 
	cv::VideoCapture video; 
	video.open(1);
	
	if( !video.isOpened() ) 
	{
		ROS_INFO("Read Video failed!\n"); 
		return 0; 
	} 
	cv::Mat frame;
	int count = 0;
	 while(1)
 	{ 
		video >> frame; 
		if( frame.empty() ) 
			break;
			 count++; 
			msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", frame).toImageMsg(); 			
			pub.publish(msg); 
			ROS_INFO( "read the %dth frame successfully!", count ); 
			loop_rate.sleep();
		 ros::spinOnce(); 
	} 
	video.release(); 
return 0;

}

消息订阅

#include<ros/ros.h> 
#include<cv_bridge/cv_bridge.h> 
#include<sensor_msgs/image_encodings.h> 
#include<image_transport/image_transport.h> 
#include<opencv2/opencv.hpp> 
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp> 
#include<stdio.h> 
#include<math.h> 
#include<vector> 
void imageCalllback(const sensor_msgs::ImageConstPtr& msg) 
{
    ROS_INFO("Received \n");
    try
   {
	cv::imshow( "video", cv_bridge::toCvShare(msg, "bgr8")->image ); 
	cv::waitKey(30); 
    }
    catch( cv_bridge::Exception& e )
    {
	  ROS_ERROR( "Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str() );
    }
} 

int main(int argc, char** argv) 
{
	 ros::init(argc, argv, "image_listener"); 
	 ros::NodeHandle n; cv::namedWindow("video");
	 cv::startWindowThread();
	 image_transport::ImageTransport it(n);
	 image_transport::Subscriber sub = it.subscribe( "video_image", 1, imageCalllback );
	 ros::spin();
     cv::destroyWindow("video");
 return 0;
}