0

我正在使用 OpenCV 从网络摄像头进行流式传输。每个捕获的帧(类型是cv::Mat)通过自定义信号传输到基于节点的插槽中QGraphicsScene。由于我有一个实际需要显示的单一类型的节点,cv::Mat而其余的只是用于处理数据,我创建了一个查看器小部件,该小部件将cv::Mat数据转换为QImage数据,然后使用paintEvent()在其表面上绘制它:

基于节点的 QGraphicsScene - 内部绘制事件

这是小部件本身的代码:

qcvn_node_viewer.hpp

#ifndef QCVN_NODE_VIEWER_HPP
#define QCVN_NODE_VIEWER_HPP

#include <QWidget>
#include <QImage>
#include <QSize>
#include <QPaintEvent>
#include <opencv2/core.hpp>

class QCVN_Node_Viewer : public QWidget
{
    Q_OBJECT
    QImage output;

  public:
    explicit QCVN_Node_Viewer(QWidget *parent = 0);
    ~QCVN_Node_Viewer();

    QSize sizeHint() const;
    QSize minimumSizeHint() const;

    // Source: http://stackoverflow.com/a/17137998/1559401
    static QImage Mat2QImage(cv::Mat const& frame);
    static cv::Mat QImage2Mat(QImage const& src);

  protected:
    void paintEvent(QPaintEvent *event);

  signals:
    // Nodes connect to sendFrame(cv::Mat) signal
    void sendFrame(cv::Mat);

  public slots:
    void receiveFrame(cv::Mat frame);
};

#endif // QCVN_NODE_VIEWER_HPP

qcvn_node_viewer.cpp

#include "qcvn_node_viewer.hpp"
#include <opencv2/imgproc.hpp>
#include <QPainter>

QCVN_Node_Viewer::QCVN_Node_Viewer(QWidget *parent) :
  QWidget(parent)
{
  qRegisterMetaType<cv::Mat>("cv::Mat");
}

QCVN_Node_Viewer::~QCVN_Node_Viewer()
{
}

QSize QCVN_Node_Viewer::sizeHint() const
{
  return output.size();
}

QSize QCVN_Node_Viewer::minimumSizeHint() const
{
  return output.size();
}

QImage QCVN_Node_Viewer::Mat2QImage(cv::Mat const& frame)
{
     cv::Mat temp;
     cvtColor(frame, temp,CV_BGR2RGB);
     QImage dest((const uchar *) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);
     dest.bits(); // enforce deep copy
     return dest;
}

cv::Mat QCVN_Node_Viewer::QImage2Mat(QImage const& frame)
{
     cv::Mat tmp(frame.height(),frame.width(),CV_8UC3,(uchar*)frame.bits(),frame.bytesPerLine());
     cv::Mat result; // deep copy just in case (my lack of knowledge with open cv)
     cvtColor(tmp, result,CV_BGR2RGB);
     return result;
}

void QCVN_Node_Viewer::paintEvent(QPaintEvent *event)
{
  QPainter painter(this);
  painter.drawImage(QPoint(0,0), output);
  painter.end();
}

void QCVN_Node_Viewer::receiveFrame(cv::Mat frame)
{
  if(frame.empty()) return;

  // Pass along the received frame
  emit sendFrame(frame);

  // Generate
  // http://stackoverflow.com/questions/17127762/cvmat-to-qimage-and-back
  // Applications crashes sometimes! Conversion seems to be incorrect
  output = Mat2QImage(frame);
  output.bits();
  setFixedSize(output.width(), output.height());

  repaint();
}

正如您从上面的屏幕截图中看到的那样,QWidget它嵌入在一个QGraphicsSceneusing 中QGraphicsProxyWidget,以及QGraphicsRectItem我用于在场景中选择/移动节点的一个。

使用QPainter被认为比使用更有效,QLabel并将其设置QPixmap为捕获和转换的帧。QGraphicsScene据我所知,在 a 内使用 OpenGL 视口不是一种选择。处理场景中的绘制事件似乎也处理了QGraphicsItems 和QGraphicsProxyWidgets 内部的本地事件。查看器在其表面上绘制的帧在调用场景的绘制事件处理程序时才会更改(悬停我的一些节点,移动它们等)。

有没有办法来解决这个问题?我即将选择这个QLabel+QPixmap选项(即使我不确定它是否会遇到相同或不同的问题)但首先我想确保我无能为力来保持我目前的方式的做事。


编辑:好的,所以我将查看器更改为使用QLabel而不是小部件的绘制事件,它就像一个魅力。不过,这个问题仍然悬而未决,因为我想知道如何使用本地绘画事件。

4

0 回答 0