filecapture.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #ifndef FILECAPTURE_H #define FILECAPTURE_H #include <QObject> #include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp> using namespace cv; class FileCapture : public QObject { Q_OBJECT VideoCapture *videoCapture; QString url; bool stopVideo; public: explicit FileCapture(QObject *parent = nullptr); void setUrl(QString &value); signals: void newFrameCaptured(Mat frame); public slots: bool openVideo(); }; #endif // FILECAPTURE_H | cs |
frame.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #ifndef FRAME_H #define FRAME_H #include <QObject> #include <QQuickPaintedItem> #include <QImage> #include <QPainter> #include <QDebug> #include <opencv2/core.hpp> #include <opencv2/core/utility.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp> using namespace cv; class Frame : public QQuickPaintedItem { Q_OBJECT // passing frame as Qimage and writh with setFrame function and so on.. Q_PROPERTY( QImage frame READ getFrame WRITE setFrame NOTIFY frameChanged ) Mat rawFrame; QImage frame; public: Frame(QQuickItem *parent = nullptr ); void paint(QPainter *painter); Mat getRawFrame() const; QImage getFrame() const; void setFrame(const QImage &value); Q_INVOKABLE void setRawFrame(const Mat &value); Q_INVOKABLE void openImage(QString url); signals: void frameChanged(); public slots: void convert2QImage(); }; #endif // FRAME_H | cs |
threadmanager.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #ifndef THREADMANAGER_H #define THREADMANAGER_H #include <QObject> #include <QThread> #include "filecapture.h" class threadManager : public QObject { Q_OBJECT QThread thread; FileCapture capture; public: explicit threadManager(QObject *parent = nullptr); Q_INVOKABLE void runCapture(QString url); signals: void updateView(Mat frame); public slots: void receiveFrame(Mat frame); }; #endif // THREADMANAGER_H | cs |
filecapture.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include "filecapture.h" void FileCapture::setUrl(QString &value) { value.remove("file://"); url = value; } bool FileCapture::openVideo() { Mat rawFrame; videoCapture = new VideoCapture; videoCapture->open( url.toStdString() ); if(!videoCapture->isOpened()){ return false; } while(videoCapture->read(rawFrame) && !stopVideo){ emit(newFrameCaptured(rawFrame)); } return true; } FileCapture::FileCapture(QObject *parent) : QObject(parent) { stopVideo = false; } | cs |
frame.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | #include "frame.h" Mat Frame::getRawFrame() const { qDebug() <<__func__; return rawFrame; } void Frame::setRawFrame(const Mat &value) { qDebug() <<__func__; rawFrame = value; convert2QImage(); } QImage Frame::getFrame() const { qDebug() <<__func__; return frame; } void Frame::setFrame(const QImage &value) { qDebug() <<__func__; frame = value; Frame::update(); emit( frameChanged() ); } void Frame::openImage(QString url) { qDebug() <<__func__; url.remove("file://"); rawFrame = imread(url.toStdString()); convert2QImage(); } void Frame::convert2QImage() { qDebug() <<__func__; Mat tempMat; // this may be bgr to rgb cvtColor( rawFrame, tempMat, COLOR_RGB2BGR ); // constructor with the buffer and width, height, byte per line, format QImage tempImage( (uchar*)tempMat.data, tempMat.cols, tempMat.rows, tempMat.step, QImage::Format_RGB888); frame = tempImage; //// in my opinion this disconnect mamory sharing with tempImage so we can chaenge tempImage without effecting on frame frame.detach(); Frame::update(); emit(frameChanged()); } Frame::Frame(QQuickItem *parent) : QQuickPaintedItem (parent) { qDebug() <<__func__; } void Frame::paint(QPainter *painter) { qDebug() <<__func__; frame.scaled(1280,720, Qt::IgnoreAspectRatio, Qt::FastTransformation); painter->drawImage(0, 0, frame, 0, -1, -1, Qt::AutoColor ); } | cs |
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #include <QGuiApplication> #include <QQmlApplicationEngine> // include thease to expose my thread to qml #include <QQmlContext> #include <QQmlComponent> //include frame because we want to render something from // Frame object otherwise we just connect signal and slot to the object #include <frame.h> //I didn't registered video related objects //Since I just wanna connect signal and slot from them #include "threadmanager.h" int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; threadManager videoThread; // register my class qmlRegisterType<Frame>("com.app.frame", 1, 0, "Frame"); //register object so Mat can be transfered throgh signal and slot qRegisterMetaType<cv::Mat>("Mat"); // pass my context to qml as named videoThread( any class can be passed this way too ) engine.rootContext()->setContextProperty("videoThread", &videoThread); const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); } | cs |
threadmanager.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include "threadmanager.h" threadManager::threadManager(QObject *parent) : QObject(parent) { } void threadManager::runCapture(QString url) { capture.setUrl( url ); connect( &thread , &QThread::started, &capture, &FileCapture::openVideo ); connect( &thread , &QThread::finished, &capture, &FileCapture::deleteLater); connect( &capture, &FileCapture::newFrameCaptured, this, &threadManager::receiveFrame); capture.moveToThread(&thread); thread.start(); } void threadManager::receiveFrame(Mat frame) { emit(updateView(frame)); } | cs |
home.qml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import QtQuick 2.0 import QtQuick.Controls 2.12 Page { anchors.fill:parent Rectangle{ id: bar width: parent.width height: parent.height * 0.1 color: 'orange' Label{ text : "Welcome to the Qt OpenCV app" color : "white" anchors.centerIn: parent } } Button{ id : imageButton text:'Show Image' anchors.top: bar.bottom anchors.topMargin: 20 anchors.horizontalCenter: parent.horizontalCenter onClicked: loader.push("qrc:/showImage"); } Button{ text:'Show Video' anchors.top: imageButton.bottom anchors.topMargin: 20 anchors.horizontalCenter: parent.horizontalCenter onClicked: loader.push("qrc:/showVideo"); } } | cs |
main.qml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 2.12 Window { visible: true width: 1024 height: 720 title: qsTr("app") StackView{ id: loader anchors.fill: parent initialItem: 'qrc:/home' } } | cs |
showImage.qml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | import QtQuick 2.0 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import QtQuick.Dialogs 1.2 import com.app.frame 1.0 Page { anchors.fill:parent Rectangle{ id: bar width: parent.width height: parent.height * 0.1 color: 'orange' Label{ text : "Show Image" color : "white" anchors.centerIn: parent } } ColumnLayout{ id: imageContainer width: 640 height: 480 anchors.top:bar.bottom anchors.topMargin: 20 anchors.horizontalCenter: parent.horizontalCenter Image{ id : picture source: "qrc:/logo" Layout.preferredWidth : imageContainer.width Layout.preferredHeight: imageContainer.height fillMode: Image.PreserveAspectFit } Frame{ id : selectedImage Layout.preferredWidth: imageContainer.width Layout.preferredHeight: imageContainer.height visible: false } } RowLayout{ anchors.top: imageContainer.bottom anchors.topMargin: 10 anchors.horizontalCenter: parent.horizontalCenter width: parent.width * 0.6 spacing: width * 0.2 Button{ text : 'Open Image' Layout.preferredWidth: parent.width * 0.4 onClicked: imageDialog.open() } Button{ text : 'Go Back' Layout.preferredWidth: parent.width * 0.4 onClicked: loader.pop() } } FileDialog{ id : imageDialog title : 'Choose Image' folder : shortcuts.pictures onAccepted:{ selectedImage.openImage(imageDialog.fileUrl); picture.visible = false; selectedImage.visible = true; } } } | cs |
showVideo.qml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | import QtQuick 2.0 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import QtQuick.Dialogs 1.2 import com.app.frame 1.0 Page { anchors.fill:parent Connections{ // name of class reference defined in main.cpp target: videoThread // updateView signal should be referred as onUpdateView such as a slot name // frame is a name of Mat object from updateView signal // name of parameter should be the same with it's definition onUpdateView : selectedImage.setRawFrame(frame) } Rectangle{ id: bar width: parent.width height: parent.height * 0.1 color: 'orange' Label{ text : "Show Video" color : "white" anchors.centerIn: parent } } ColumnLayout{ id: imageContainer width: 640 height: 480 anchors.top:bar.bottom anchors.topMargin: 20 anchors.horizontalCenter: parent.horizontalCenter Image{ id : picture source: "qrc:/logo" Layout.preferredWidth : imageContainer.width Layout.preferredHeight: imageContainer.height fillMode: Image.PreserveAspectFit } Frame{ id : selectedImage Layout.preferredWidth: imageContainer.width Layout.preferredHeight: imageContainer.height visible: false } } RowLayout{ anchors.top: imageContainer.bottom anchors.topMargin: 10 anchors.horizontalCenter: parent.horizontalCenter width: parent.width * 0.6 spacing: width * 0.2 Button{ text : 'Open Video' Layout.preferredWidth: parent.width * 0.4 onClicked: videoDialog.open() } Button{ text : 'Go Back' Layout.preferredWidth: parent.width * 0.4 onClicked: loader.pop() } } FileDialog{ id : videoDialog title : 'Choose Video' folder : shortcuts.movies onAccepted:{ picture.visible = false; selectedImage.visible = true; videoThread.runCapture(videoDialog.fileUrl); } } } | cs |
app.pro
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | QT += quick CONFIG += c++11 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Refer to the documentation for the # deprecated API to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ filecapture.cpp \ frame.cpp \ main.cpp \ threadmanager.cpp RESOURCES += qml.qrc INCLUDEPATH += /usr/local/include/opencv LIBS += -L/usr/local/lib \ -lopencv_core \ -lopencv_imgproc \ -lopencv_imgcodecs \ -lopencv_videoio \ -lopencv_flann \ -lopencv_highgui \ -lopencv_features2d \ -lopencv_photo \ -lopencv_video \ -lopencv_calib3d \ -lopencv_objdetect \ -lopencv_stitching \ -lopencv_dnn \ -lopencv_ml # Additional import path used to resolve QML modules in Qt Creator's code model QML_IMPORT_PATH = # Additional import path used to resolve QML modules just for Qt Quick Designer QML_DESIGNER_IMPORT_PATH = # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target HEADERS += \ filecapture.h \ frame.h \ threadmanager.h | cs |
'QT' 카테고리의 다른 글
QT Mouse Event Label example (0) | 2019.06.21 |
---|---|
QT invokeMethod 예제 (0) | 2019.03.22 |
qt msvc-version.conf 설정 (0) | 2019.03.18 |
커스텀 위젯 만들기 노트 (0) | 2019.03.17 |
Qt 동적 라이브러리 만들기 및 사용하기 (0) | 2019.03.16 |