OpenCV を使用して Web カメラからストリーミングしています。キャプチャされた各フレーム (タイプはcv::Mat
) は、カスタム シグナルを介してノードベースのスロットに転送されますQGraphicsScene
。実際に表示する必要がある単一のタイプのノードがcv::Mat
あり、残りはデータを処理するためのものであるため、データをデータに変換し、それを使用してその表面に描画するビューアーウィジェットを作成しました。cv::Mat
QImage
paintEvent()
ウィジェット自体のコードは次のとおりです。
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
埋め込まれています。QGraphicsScene
QGraphicsProxyWidget
QGraphicsRectItem
使用QPainter
するよりも使用した方が効率的と考えられ、キャプチャーされ変換されたフレームにQLabel
設定されます。私が知る限り、QPixmap
内でOpenGLビューポートを使用することはオプションではありません。シーン内のペイント イベントを処理すると、 およびQGraphicsScene
内のローカル イベントも処理されるようです。ビューアーがその表面にペイントするフレームは、シーンのペイント イベント ハンドラーが呼び出された場合にのみ変更されます (ノードの一部をホバーしたり、ノードを移動したりなど)。QGraphicsItem
QGraphicsProxyWidget
これを修正する方法はありますか?私はこのQLabel+QPixmap
オプションを選択しようとしています (同じ問題または別の問題が発生しないかどうかはわかりませんが) が、まず、現在の方法を維持するためにできることは何もないことを確認したいと思います。物事を行うこと。
編集:QLabel
さて、ウィジェットのペイントイベントの代わりにビューアーを使用するように変更しました。それは魅力のように機能します。ローカルペイントイベントの使用方法を知りたいので、質問はまだ開いています。