利用Qt Creator 如何在ROS 项目中从一个界面调用另一个界面?

一、系统配置:

Ubuntu14.04 ROS indigo ,Qt 5.9.1 Creator,已安插件ros_qtc_plugin,可以直接建一个包含Qt界面的ROS package,不太明白?没关系,那就看我上一篇博客<利用Qt Creator 如何在ROS 项目中从一个界面调用另一个界面?>怎么用的.

二、基本思路:

要想实现这个目标非常简单,就是将ROS 发出图片消息和Qt显示图片结合起来,大致可分为三步,每一步都有相关文章,我就是做了一个结合,毕竟QT-ROS这方面资料太少,分享出来大家共同进步!在下也是刚接触,有不对之处,欢迎大家指正!

step1:利用opencv将图片转化为ros可以接受的消息 ,参考链接

step2:在qt下可以打开图片,利用opencv显示在界面上,参考链接

step3:根据子线程和主线程通信,将消息通过信号与槽的机制传到qt界面显示,参考链接

结合以上文章,下面到了揉合阶段,如果你看到这里,大致明白了怎么回事,那么你就不要往下看了,自己去调,去改,那样自己做出来会蛮有成就感的。

三、程序实现:

1.根据step1 链接建了两个普通package:image_node_a和image_node_b ,注意配置CMakeLists 文件,没什么问题,不想多说,注意将image_noe_a中载入图片文件的路径改为自己的,千万不要包含中文!!!此步完成证明发消息没问题了!

cv::Mat image = cv::imread("/home/sun/Dragon.png", CV_LOAD_IMAGE_COLOR);
//chage the directory to your own filepath 

2.根据step2的链接建了个包含qt界面的package gui_subsrciber

catkin_create_qt_pkg gui_subscriber roscpp
在main_window.hpp文件中添加opencv需要的相关头文件,在public中添加displayMat(cv::Mat),并在private中提前声明

public:    
         void displayMat(cv::Mat image);
private:
	Ui::MainWindowDesign ui;
  QNode qnode;
  cv::Mat image;
之后在main_window.cpp中实现,注意提前在main_window.ui 中提前添加一个label用于显示图片

void MainWindow::displayMat(cv::Mat image)
{
  cv::Mat rgb;
      QImage img;
      if(image.channels()==3)
      {
          //cvt Mat BGR 2 QImage RGB
          cv::cvtColor(image,rgb,CV_BGR2RGB);
          img =QImage((const unsigned char*)(rgb.data),
                      rgb.cols,rgb.rows,
                      rgb.cols*rgb.channels(),
                      QImage::Format_RGB888);
      }
      else
      {
          img =QImage((const unsigned char*)(image.data),
                      image.cols,image.rows,
                      image.cols*image.channels(),
                      QImage::Format_RGB888);
      }
      ui.label_4->setPixmap(QPixmap::fromImage(img));//label_4就是你添加的label的对象名
      ui.label_4->resize(ui.label_4->pixmap()->size());
运行,没什么问题!见下图!


3.到现在为止还是ROS的ROS,QT的归qt,没什么联系,那么现在这一步就重要了,在gui_subscriber package的qnode文件中建一个订阅image_node_a的节点,就是将image_node_b的内容在gui_subscriber中再实现一遍,先保证在这个package中能正常接收到image_node_a发的图片,没什么很大的区别,现在qnode.hpp文件中声明回调函数,private添加订阅者声明

pubiic:
     ...
     void myCallback_img(const sensor_msgs::ImageConstPtr& msg);
     ...
private:
    int init_argc;
    char** init_argv;
  image_transport::Subscriber image_sub;
之后在qnode.cpp文件中实现回调函数就OK了,另外字啊qnode.cpp文件的两个init()和run()函数中分别添加以下句柄

 image_transport::ImageTransport it(n);
  image_transport::Subscriber image_sub;
  image_sub = it.subscribe("node_a",1,&QNode::myCallback_img,this);
然后修改CMakeLists文件和package.xml文件中的build和run depend啊!CMakeLists中按照image_node_b里面需要添加的拷贝过来就可以了, 千万注意顺序!!!看gui_subscriber可以订阅到了!


4.最后一步,这才是核心!根据step3中传送自定义消息的方法,将qnode中接收到的消息给main_window显示啊!

(1) 在回调函数中,结束时要将imge以信号的形式发出去,你就要在qnode.hpp中定义一个信号

public:
    ...
    void myCallback_img(const sensor_msgs::ImageConstPtr& msg);
    cv::Mat img;//发送的图片type
    ...
Q_SIGNALS:
	void loggingUpdated();
  void rosShutdown();
  void imageSignal(cv::Mat);//定义发送图片的信号
(2) 在回调函数最后添加Q_EMIT 如下:

void QNode::myCallback_img(const sensor_msgs::ImageConstPtr &msg)
{
  cv_bridge::CvImagePtr cv_ptr;
  try
  {   /*change to CVImage*/
  cv_ptr = cv_bridge::toCvCopy(msg, enc::BGR8);
  //cv::imshow("gui_subscriber listener from node_a",cv_ptr->image);
  img = cv_ptr->image;//呼应public中的img 啊!
  Q_EMIT imageSignal(img)  //将信号发出去
  cv::waitKey(30);
  }
...
 }
(3) 回main_window.hpp中,将之前的displayMat改为Q_SLOTS用于接收qnode发来的imageSignal

public Q_SLOTS:
          void displayMat(cv::Mat image);
(4) 最后的最后在main_window.cpp的实现函数中添加信号和槽的连接,ok了就!

//Be sure register the message type
  qRegisterMetaType<cv::Mat>("cv::Mat");
  ...
  //Next is the key siganl and slot
  QObject::connect(&qnode,SIGNAL(imageSignal(cv::Mat)),this,SLOT(displayMat(cv::Mat)));
编译,有问题,那就查 头文件是否包含,CMakeLists文件修改好没,依赖库有没有添加,基本就没别的问题了!大功告成!先运行image_node_a,再运行gui_subscriber,直接就会显示下面界面!

有什么 问题欢迎留言交流!源码见github

猜你喜欢

转载自blog.csdn.net/qq_30460905/article/details/79080993