如何将ROS发出的图片消息在Qt Ceator的界面显示出来?

一、系统配置:

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

  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
当然可以!以下是一个示例代码,展示了如何使用Qt编写一个回调函数来接收ROS发布的图像消息,并将其显示Qt界面上: ```cpp #include <ros/ros.h> #include <sensor_msgs/Image.h> #include <QApplication> #include <QLabel> #include <QImage> #include <QPixmap> class ImageSubscriber : public QObject { Q_OBJECT public: ImageSubscriber(QWidget* parent = nullptr) : QObject(parent), label_(new QLabel(parent)) { // 创建ROS节点和图像订阅者 ros::NodeHandle nh; image_sub_ = nh.subscribe("image_topic", 1, &ImageSubscriber::imageCallback, this); } public slots: void imageCallback(const sensor_msgs::ImageConstPtr& msg) { // 将ROS图像消息转换为Qt图像 QImage image(msg->data.data(), msg->width, msg->height, QImage::Format_RGB888); // 在Qt界面上显示图像 QPixmap pixmap = QPixmap::fromImage(image); label_->setPixmap(pixmap.scaled(label_->size(), Qt::KeepAspectRatio)); label_->show(); } private: QLabel* label_; ros::Subscriber image_sub_; }; int main(int argc, char** argv) { // 初始化ROS节点 ros::init(argc, argv, "image_subscriber_node"); // 创建Qt应用程序 QApplication app(argc, argv); // 创建主窗口 QWidget* mainWindow = new QWidget(); mainWindow->resize(800, 600); // 创建图像订阅者 ImageSubscriber imageSubscriber(mainWindow); // 显示主窗口 mainWindow->show(); // 运行Qt事件循环 return app.exec(); } #include "main.moc" ``` 请注意,上述代码中的 "image_topic" 应替换为您实际使用的ROS图像话题。 希望这可以帮助到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值