忽然想起opencv,一直想作人脸识别,但是理论基础太水,只能慢慢来,去年学习了一会,而后公司让我去搞app和网络,就一直搁着,如今学习qml,忽然想能不能在qml里面使用opencv,因此就有了这篇文章。算法
在QML中,可视化的基础组件是Item,不可视化的就是QtObject,它们对应C++中的QQuickItem和QObject类,扩展QML组件一个继续基于QML中的Item扩张,还有就是继承QQuickItem,咱们想把opencv加到QML中,那么只有继承QQuickItem了。
怎么使用,那还要看QML新的渲染机制,Qt5的QML渲染基于OpenGL,其场景的渲染在单独的线程进行,咱们须要须要QQuickItem返回可以描述场景的对象,就是QSGNode。实现QQuick的updatePaintNode函数就OK了,咱们在updatePaintNode,描述怎么渲染。markdown
OpenCVcapture继承QOjbect,其是图像捕获的基类,OpenCVcamera是OpenCVcapture子类,完成从摄像头捕获数据。OpenCVaction类封装了opencv图像算法操做。OpenCVshowFrame继承QQuickItem,实现可视化。网络
#include <QApplication> #include <QQmlApplicationEngine> #include <QtQml/qqml.h> #include "opencvcamera.h" #include "opencvshowframe.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); qmlRegisterType<OpenCVcamera>("OpenCV", 1, 0, "OpenCVcamera"); qmlRegisterType<OpenCVshowFrame>("OpenCV", 1, 0, "OpenCVshowFrame"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }
import QtQuick 2.4 import QtQuick.Controls 1.3 import QtQuick.Window 2.2 import QtQuick.Dialogs 1.2 import OpenCV 1.0 ApplicationWindow { title: qsTr("Hello World") width: 640 height: 480 visible: true menuBar: MenuBar { Menu { title: qsTr("&File") MenuItem { text: qsTr("&Open") onTriggered: { //messageDialog.show(qsTr("Open OpenCV triggered")); opencvCamera.m_run = true } } MenuItem { text: qsTr("&Close") onTriggered: { //messageDialog.show(qsTr("Open OpenCV triggered")); opencvCamera.m_run = false } } MenuItem { text: qsTr("E&xit") onTriggered: Qt.quit(); } } } OpenCVcamera { id:opencvCamera m_cameraId: 1 m_run: false //width: 320 //height: 240 } OpenCVshowFrame { anchors.centerIn: parent id:opencvShowFrame m_capture: opencvCamera m_frameRate: 33 m_run: true width: 480 height: 320 } MessageDialog { id: messageDialog title: qsTr("May I have your attention, please?") function show(caption) { messageDialog.text = caption; messageDialog.open(); } } }
效果
我封装了轮廓扫描的算法操做。app
QSGNode* OpenCVshowFrame::updatePaintNode(QSGNode *old, UpdatePaintNodeData *) { QSGSimpleTextureNode *texture = static_cast<QSGSimpleTextureNode*>(old); if (texture == NULL) { texture = new QSGSimpleTextureNode(); } QImage img; IplImage *iplImage = NULL; IplImage *out = NULL; if (m_capture) { iplImage = static_cast<OpenCVcapture*>(m_capture)->getFrame(); } if (iplImage != NULL) { out = doActions(iplImage); uchar *imgData = (uchar *)out->imageData; //qDebug() << out->depth << out->nChannels; img = QImage(imgData, out->width, out->height, QImage::Format_RGB888); } else { img = QImage(boundingRect().size().toSize(), QImage::Format_RGB888); } QSGTexture *t = window()->createTextureFromImage(img.scaled(boundingRect().size().toSize())); if (t) { QSGTexture *tt = texture->texture(); if (tt) { tt->deleteLater(); } texture->setRect(boundingRect()); texture->setTexture(t); } if (out) { cvReleaseImage(&out); } return texture; }
使用了QSGSimpleTextureNode,而后咱们将opencv的图像,做为一个QSGTexture,而后返回给渲染的线程进行场景的渲染。函数
这里还要说下,Qt的QImage,不支持单通道的灰度图,咱们须要转换成RGB才能正确的显示。学习