希望你做得好! 我是从昨天开始就如何使用opencv实现多线程视频处理程序而努力的。
我理解线程是如何工作的,如何使用简单的互斥锁等......但是当涉及到实现时,我完全迷失了。
我的目标是使用Qt创建一个界面,并显示两个标签,一个显示原始视频,另一个显示已处理的标签,每个标签都由一个帖子处理。
现在我只是试图通过线程来显示图像,但我真的很挣扎。
以下是我迄今所做的事情:
CaptureThread继承自QThread的类: 它应该处理凸轮捕获的开始等...
#ifndef CAPTURETHREAD_H
#define CAPTURETHREAD_H
#include <QThread>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/videoio.hpp"
#include <QTimer>
class CaptureThread : public QThread
{
Q_OBJECT
public:
explicit CaptureThread(QObject *parent);
protected:
void run();
signals:
void frameCaptured(cv::Mat);
public slots:
void captureFrame();
private:
QTimer* tmrTimer;
cv::VideoCapture capWebam;
cv::Mat capturedFrame;
};
#endif // CAPTURETHREAD_H
这是它的实施:
#include "capturethread.h"
#include <QDebug>
CaptureThread::CaptureThread(QObject* parent):QThread(parent)
{
capWebam.open(0);
}
void CaptureThread::run()
{
tmrTimer = new QTimer(this);
QObject::connect(tmrTimer, SIGNAL(timeout()), this, SLOT(captureFrame()));
tmrTimer->start(10);
exec();
}
void CaptureThread::captureFrame()
{
if(capWebam.isOpened()){
capWebam.read(capturedFrame);
emit frameCaptured(capturedFrame);
}
}
MainWindow用于显示相机Feed ...
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/videoio.hpp"
#include <capturethread.h>
#include <QTimer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void pricessFrameAndUpdateGUI(cv::Mat matOriginal);
private slots:
void on_button_clicked();
private:
Ui::MainWindow *ui;
QImage toGrayscale(QImage image);
cv::VideoCapture capWebcam;
cv::Mat matOriginal;
cv::Mat matProcessed;
QImage qimgOriginal;
QImage qimgProcessed;
QTimer* tmrTimer;
CaptureThread* cpThread;
};
#endif // MAINWINDOW_H
及其实施:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtCore>
#include <cv.h>
#include <QColor>
#include <opencv/highgui.h>
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{
ui->setupUi(this);
cpThread = new CaptureThread(this);
QObject::connect(cpThread, SIGNAL(frameCaptured(cv::Mat)),this, SLOT(pricessFrameAndUpdateGUI(cv::Mat)));
cpThread->start();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::pricessFrameAndUpdateGUI(cv::Mat matOriginal)
{
cv::Canny(matOriginal, matProcessed, 100, 300);
cv::cvtColor(matOriginal, matOriginal, CV_BGR2RGB);
QImage qimgOriginal((uchar*)matOriginal.data, matOriginal.cols, matOriginal.rows, matOriginal.step, QImage::Format_RGB888);
QImage qimgProcessed((uchar*)matProcessed.data, matProcessed.cols, matProcessed.rows, matProcessed.step,QImage::Format_Indexed8);
ui->original->setPixmap(QPixmap::fromImage(qimgOriginal));
ui->modified->setPixmap(QPixmap::fromImage(qimgProcessed));
}
编译并执行程序后,我收到此错误:
Starting /media/wassim/BLAZER/Workspace/CPP/build-firstCV-Desktop_Qt_5_3_GCC_64bit-Debug/firstCV...
VIDEOIO ERROR: V4L/V4L2: VIDIOC_S_CROP
QObject: Cannot create children for a parent that is in a different thread.
(Parent is CaptureThread(0xc02be0), parent's thread is QThread(0xae82c0), current thread is CaptureThread(0xc02be0)
The program has unexpectedly finished.
/media/wassim/BLAZER/Workspace/CPP/build-firstCV-Desktop_Qt_5_3_GCC_64bit-Debug/firstCV crashed
谢谢你们的帮助!
答案 0 :(得分:2)
您看到的错误是由QTimer传递给另一个线程中的父级引起的。 CaptureThread存在于UI线程中。 QTimer是在另一个线程中创建的(它在run()方法中)。
最简单的解决方案:将QTimer(和启动调用)的实例化移动到ctor中:
tmrTimer = new QTimer(this);
QObject::connect(tmrTimer, SIGNAL(timeout()),
this, SLOT(captureFrame()));
tmrTimer->start(40);
这应该有效。但它不会像它应该的那样工作。 timeout()信号将在CaptureThread所在的线程中对消息进行排队,这是UI线程。所以一切都将在UI线程中完成,而不仅仅是后期处理。最快的解决方案:
CaptureThread::CaptureThread() : QObject()
{
capWebam.open(0);
QThread* t = new QThread();
moveToThread(t);
t->start();
tmrTimer = new QTimer;
QObject::connect(tmrTimer, SIGNAL(timeout()),
this, SLOT(captureFrame()));
tmrTimer->start(40);
}
CaptureThread被移动到新的QThread(它不是QThread的子类)。此外,将后处理移动到此线程。这只是概念,然后您必须处理清理,注册元类型等...
编辑:好的,只是一个快速的测试代码(在Mac OS上测试过),可能会被破坏并需要优化,我没有检查内存清理等等...(另外注意你是如何做的)在代码中隐藏matOriginal,你没有将类成员传递给QImage,但看起来是本地实例):的main.cpp
#include <QApplication>
#include <QLabel>
#include <QTimer>
#include <QThread>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "src.h"
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
cv::VideoCapture vc;
if (!vc.open(0))
return 1;
QTimer t;
QThread th;
CaptureHandler handler(&vc);
handler.moveToThread(&th);
th.start();
MainWidget w1;
w1.resize(100, 100);
w1.show();
MainWidget w2;
w2.resize(100, 100);
w2.show();
QObject::connect(&t, SIGNAL(timeout()),
&handler, SLOT(handleFrame()));
QObject::connect(&handler, SIGNAL(frameReady(QImage)),
&w1, SLOT(onFrame(QImage)));
QObject::connect(&handler, SIGNAL(framePpReady(QImage)),
&w2, SLOT(onFrame(QImage)));
t.start(20);
return a.exec();
}
src.h
#ifndef SRC_H
#define SRC_H
#include <QObject>
#include <QImage>
#include <QLabel>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
class CaptureHandler : public QObject
{
Q_OBJECT
public:
CaptureHandler(cv::VideoCapture* vc);
signals:
void frameReady(QImage frame);
void framePpReady(QImage frame);
public slots:
void handleFrame();
private:
cv::VideoCapture* vc;
};
class MainWidget : public QLabel
{
Q_OBJECT
public slots:
void onFrame(QImage frame);
};
#endif // SRC_H
src.cpp
#include <QObject>
#include <QImage>
#include <QLabel>
#include "src.h"
void cleanup_mat(void* info)
{
delete (cv::Mat*)info;
}
CaptureHandler::CaptureHandler(cv::VideoCapture* vc) : QObject(), vc(vc) {}
void CaptureHandler::handleFrame() {
cv::Mat* original = new cv::Mat;
if (!vc->read(*original))
return;
cv::Mat* processed = new cv::Mat;
cv::Canny(*original, *processed, 100, 300);
cv::cvtColor(*original, *original, CV_BGR2RGB);
QImage qimgOriginal((uchar*)original->data,
original->cols,
original->rows,
original->step,
QImage::Format_RGB888, cleanup_mat, original);
QImage qimgProcessed((uchar*)processed->data,
processed->cols,
processed->rows,
processed->step,
QImage::Format_Indexed8, cleanup_mat, processed);
emit frameReady(qimgOriginal);
emit framePpReady(qimgProcessed);
}
void MainWidget::onFrame(QImage frame) {
setPixmap(QPixmap::fromImage(frame));
}
拍摄: - )