您的位置:首页 > 运维架构

ROS中利用opencv3完成四个视频流拼接成一副图像显示,并添加track条进行参数调节

2017-04-28 11:38 1191 查看
        ROS开发过程中,经常会调试摄像头。我使用的双目在调试过程中可能需要同时查看其左边摄像头的图像,右边摄像头的图像,RGB图像和depth图像。而利用RVIZ或者image_view同时查看这几幅图像并不方便。这几幅图像不在同一个窗口显示,同时查看起来不太容易。又用于涉及到自动曝光等动态参数的调试,调用rqt_reconfigure来调试也比较麻烦。

        因此我通过opencv来同时显示这四帧图像,之前搜了很多用opencv同时显示几幅图像的,讲得都不是很明白,因此写一篇博客来总结一下。本文是用opencv3来实现显示的,opencv2与3的差别较大,可能会出错。

        废话不多说直接上代码:#include<ros/ros.h> //ros标准库头文件
#include<iostream> //C++标准输入输出库
#include <stdio.h>
/*
cv_bridge中包含CvBridge库
*/
#include<cv_bridge/cv_bridge.h>
/*
ROS图象类型的编码函数
*/
#include<sensor_msgs/image_encodings.h>
/*
image_transport 头文件用来在ROS系统中的话题上发布和订阅图象消息
*/
#include<image_transport/image_transport.h>
//OpenCV2标准头文件
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include <dynamic_reconfigure/server.h>

using namespace cv;
static const std::string OPENCV_WINDOW = "color/image";//该变量是定义显示的窗口名称
static const std::string imagetopic = "/camera/color/image";//ROS系统中订阅topic,通过topic来获取图像数据,一共有4个topic
static const std::string ir1topic = "/camera/lc/image";
static const std::string depthtopic = "/camera/depth/image";
static const std::string ir2topic = "/camera/rc/image";
int auto_exposure_state=0;//定义自动曝光是否开启的变量
int colorwidth,colorheight;//定义显示图像的宽和高
cv::Mat A,B,C,D,ptr_color,ptr_depth,ptr_ir1,ptr_ir2,sumMat,test1;//定义一些重要的全局cv::Mat矩阵
//sumMat是最终拼接的总的图像,ABCD分别是sumMat图像中的4个区域
class ImageConverter //这是ROS系统中关于图像显示的常规的设置,定义类
{
ros::NodeHandle nh_;//ROS句柄
image_transport::ImageTransport it_;
image_transport::Subscriber image_sub1_;
image_transport::Subscriber image_sub2_;
image_transport::Subscriber image_sub3_;
image_transport::Subscriber image_sub4_;

public:
ImageConverter()
: it_(nh_)//构造函数
{
// Subscrive to input video feed and publish output video feed
image_sub1_ = it_.subscribe(imagetopic, 1,&ImageConverter::imageCb, this);//订阅TOPIC,回调函数为imageCb
image_sub2_ = it_.subscribe(depthtopic, 1,&ImageConverter::depthCb, this);//每个订阅的topic都有回调函数,接收到数据则进入回调函数处理
image_sub3_ = it_.subscribe(ir1topic, 1,&ImageConverter::ir1Cb, this);
image_sub4_ = it_.subscribe(ir2topic, 1,&ImageConverter::ir2Cb, this);
cv::namedWindow(OPENCV_WINDOW);//创建显示窗口,名称为之前定义的变量
cv::createTrackbar("Auto_exposure",OPENCV_WINDOW,&auto_exposure_state,1,track_change);//在刚创的窗口创建滑动条,用于调节自动曝光

}

~ImageConverter()//析构函数
{
cv::destroyWindow(OPENCV_WINDOW);//关掉显示窗口
}
static void track_change(int position,void* userdata){ //这是滑动条滑动后的回调函数,滑动后在此进行处理

if(position==0){
system("rosrun dynamic_reconfigure dynparam set /camera/driver r200_lr_auto_exposure_enabled 0");
}
else{
system("rosrun dynamic_reconfigure dynparam set /camera/driver r200_lr_auto_exposure_enabled 1");
}

}

void imageCb(const sensor_msgs::ImageConstPtr& msg) //Cbtopic的回调函数,接收到RGB摄像头数据后进入此回调函数
{
cv_bridge::CvImagePtr cv_ptr;// 声明一个CvImage指针的实例
try
{
cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);//将ROS消息中的图象信息提取,生成新cv类型的图象,复制给CvImage指针
}
catch (cv_bridge::Exception& e)
{
ROS_ERROR("cv_bridge exception: %s", e.what());//异常处理
return;
}

A=(cv::Mat)cv_ptr->image;//将topic得到的数据赋给A矩阵
cvtColor(A,A,CV_BGR2GRAY);//A矩阵转化成单通道灰度图(由于四个MAT拼成一个大MAT,必须保持格式一致,否则MAT大小对不齐会出现数组越界)
mergeImage(A,1);//将A拼到图像上
}

void depthCb(const sensor_msgs::ImageConstPtr& msg)
{
cv_bridge::CvImagePtr cv_ptr;// 声明一个CvImage指针的实例
try
{
cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::TYPE_16UC1);//将ROS消息中的图象信息提取,生成新cv类型的图象,复制给CvImage指针
}
catch (cv_bridge::Exception& e)
{
ROS_ERROR("cv_bridge exception: %s", e.what());//异常处理
return;
}
cv_ptr->image.convertTo(B,CV_8UC1,255.0 / 4500);
mergeImage(B,2);
}

void ir1Cb(const sensor_msgs::ImageConstPtr& msg)
{
cv_bridge::CvImagePtr cv_ptr;// 声明一个CvImage指针的实例
try
{
cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::TYPE_8UC1);//将ROS消息中的图象信息提取,生成新cv类型的图象,复制给CvImage指针
}
catch (cv_bridge::Exception& e)
{
ROS_ERROR("cv_bridge exception: %s", e.what());//异常处理
return;
}
C=(cv::Mat)cv_ptr->image;
mergeImage(C,3);
}
void ir2Cb(const sensor_msgs::ImageConstPtr& msg)
{
cv_bridge::CvImagePtr cv_ptr;// 声明一个CvImage指针的实例
try
{
cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::TYPE_8UC1);//将ROS消息中的图象信息提取,生成新cv类型的图象,复制给CvImage指针
}
catch (cv_bridge::Exception& e)
{
ROS_ERROR("cv_bridge exception: %s", e.what());//异常处理
return;
}
D=(cv::Mat)cv_ptr->image;
mergeImage(D,4);
}

/*
这是图象处理的主要函数,一般会把图像处理的主要程序写在这个函数中。这里的例子只是一个彩色图象到灰度图象的转化
*/
void mergeImage(cv::Mat img,int classy)
{
switch (classy) {
case 1:
img.convertTo(ptr_color,CV_8UC1);//将A矩阵单通道格式付给ptr_color
break;
case 2:
img.convertTo(ptr_depth,CV_8UC1);
break;
case 3:
img.convertTo(ptr_ir1,CV_8UC1);
break;
case 4:
img.convertTo(ptr_ir2,CV_8UC1);
break;
default:
break;
}
image_process(sumMat);//显示sumMat
}
void image_process(cv::Mat img)
{

cv::imshow(OPENCV_WINDOW, img);
cv::waitKey(10);

}

};

int main(int argc, char** argv)
{
ros::init(argc, argv, "realcam_dnew_
4000
node");
ros::param::get("/camera/driver/r200_lr_auto_exposure_enabled",auto_exposure_state);
ros::param::get("/camera/driver/color_width",colorwidth);//得到一副图像的宽
ros::param::get("/camera/driver/color_height",colorheight);//得到一副图像的高
sumMat=cv::Mat::zeros(colorheight*2,colorwidth*2,CV_8UC1);//初始化sumMat,2倍的宽,2倍的高,单通道灰度图像
ptr_color = sumMat(cv::Rect(0,0,colorwidth,colorheight));//ptr_color即为sumMat的左上角部分
ptr_depth = sumMat(cv::Rect(colorwidth,0,colorwidth,colorheight));//ptr_depth为sumMat的右上角
ptr_ir1=sumMat(cv::Rect(0,colorheight,colorwidth,colorheight));
ptr_ir2=sumMat(cv::Rect(colorwidth,colorheight,colorwidth,colorheight));

ImageConverter ic;
ros::spin();
return 0;
}
如是,则实现了四副图像拼接成一副图像的操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ros opencv 视频流 C++
相关文章推荐