问题描述
我正在尝试在线程内使用 OpenCV 库处理一些图像,因为处理操作需要一些时间才能完成.
I am trying to process some image using OpenCV Library inside a thread, because the process operation takes some time before it's done.
所以问题是 QThread 总是向 QMainWindow 中的 Slot 返回一个 Null QImage.
So the problem is QThread always returning a Null QImage to the Slot in QMainWindow.
我收到此异常错误:
Exception thrown at 0x00007FFE01962F6D (Qt5Guid.dll) in QtWidgetsApplication1.exe: 0xC0000005: Access violation reading location 0x0000022CAB6EE080.
此文件中出现错误:
qtwidgetsapplication1.cpp 此文件用于 QMainWindow
qtwidgetsapplication1.cpp this file is for QMainWindow
#include "qtwidgetsapplication1.h"
#include "stdafx.h"
QtWidgetsApplication1::QtWidgetsApplication1(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
connect(ui.addItem_btn, SIGNAL(clicked()), this, SLOT(addItem_btn_OnClick())); // Add Item to the List
dftThread = new DetectFaceThread(this);
connect(dftThread, &DetectFaceThread::detectedFace, this, &QtWidgetsApplication1::onDetectedFace);
connect(dftThread, &DetectFaceThread::finished, dftThread, &QObject::deleteLater);
}
QtWidgetsApplication1::~QtWidgetsApplication1()
{
}
void QtWidgetsApplication1::addItem_btn_OnClick()
{
dftThread->start();
}
void QtWidgetsApplication1::onDetectedFace(const QImage& face)
{
if (face.isNull())
{
QMessageBox::warning(this, QString("Detection Error"), QString("Face not detected!"));
return;
}
ui.imgDisplay_label->setPixmap(QPixmap::fromImage(face));
}
这是我的代码:
DetectFaceThread.h
#pragma once
#include <qthread.h>
#include <QtWidgets/qmessagebox.h>
#include <qmutex.h>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>
class DetectFaceThread :
public QThread
{
Q_OBJECT
public:
DetectFaceThread(QWidget* parent = nullptr);
~DetectFaceThread();
void run() override;
signals:
void detectedFace(const QImage &face);
};
DetectFaceThread.cpp
#include "DetectFaceThread.h"
DetectFaceThread::DetectFaceThread(QWidget* parent)
{
}
DetectFaceThread::~DetectFaceThread()
{
QMessageBox::information(nullptr, QString("Thread Info"), QString("Thread successfully destroyed"));
}
void DetectFaceThread::run()
{
QMutex mutex;
mutex.lock();
std::string img_path = "res/paper.jpg";
cv::Mat img = cv::imread(img_path);
if (img.empty())
{
QMessageBox::warning(nullptr, QString("Load Error"), QString("Image not found!"));
return;
}
cv::cvtColor(img, img, cv::ColorConversionCodes::COLOR_BGR2RGB);
float w = 800, h = 1000;
cv::Point2f src[4] = { {383, 445}, {885, 521}, {89, 1125}, {921, 1270} };
cv::Point2f dst[4] = { {0.0f, 0.0f}, {w, 0.0f}, {0.0f, h}, {w, h} };
cv::Mat matrix = getPerspectiveTransform(src, dst);
cv::Mat img_warp;
cv::warpPerspective(img, img_warp, matrix, cv::Size(w, h));
QImage qimage(img_warp.data, img_warp.cols, img_warp.rows, img_warp.step, QImage::Format::Format_RGB888);
mutex.unlock();
emit detectedFace(qimage);
}
最后应用程序就终止了,有人可以帮助我吗.
And in the end the application just terminates, can any one help me please.
更新:我尝试了您的解决方案,但它引发了相同的异常错误.
Update: I tried your solution but it throws the same Exception error.
connect(dftThread, &DetectFaceThread::detectedFace, this, &QtWidgetsApplication1::onDetectedFace, Qt::QueuedConnection);
推荐答案
我认为问题在于在 DetectFaceThread 线程中创建对象图像.当run()函数被执行时,run()中的所有数据都会被销毁.我建议在主线程中创建一个对象图像并在 DetectFace 中执行图像处理.并使用 movetothread,而不是运行覆盖方法.
I think the problem is in creating an object image in the DetectFaceThread thread. When the run () function is executed, all data in run () will be destroyed.I suggest creating an object image in the main thread and performing image processing in DetectFace. And use movetothread, but not the run override method.
工作示例
---------------MainWindow.h-------------
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>
#include <QThread>
#include <detectface.h>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QThread thread;
DetectFace detect;
private:
Ui::MainWindow *ui;
public slots:
void showResult();
private slots:
void on_pushButton_clicked();
};
#endif // MAINWINDOW_H
---------------MainWindow.cpp-------------
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&thread,&QThread::started,&detect,&DetectFace::detectFace);
connect(&detect,&DetectFace::endDetectFace,&thread, &QThread::quit);
connect(&thread, &QThread::finished, this, &MainWindow::showResult);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::showResult()
{
cv::Mat *image = detect.getImage();
QImage qimage = QImage((uchar*) image->data, image->cols, image->rows, image->step, QImage::Format_RGB888);
ui->label->setPixmap(QPixmap::fromImage(qimage,Qt::AutoColor));
}
void MainWindow::on_pushButton_clicked()
{
while(thread.isRunning())
{
thread.quit();
}
detect.moveToThread(&thread); //transfer object img in thread
thread.start();
}
---------------DetectFace.h--------------
#ifndef DETECTFACE_H
#define DETECTFACE_H
#include <QObject>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>
#include <QMessageBox>
class DetectFace : public QObject
{
Q_OBJECT
cv::Mat img;
cv::Mat img_warp;
std::string img_path ;
public:
DetectFace();
cv::Mat* getImage();
void detectFace();
signals:
void endDetectFace();
};
#endif // DETECTFACE_H
---------------DetectFace.cpp--------------
#include "detectface.h"
DetectFace::DetectFace()
{
img_path = "res/paper.jpg";
}
cv::Mat *DetectFace::getImage()
{
return &img_warp;
}
void DetectFace::detectFace()
{
img = cv::imread(img_path);
if (img.empty())
{
QMessageBox::warning(nullptr, QString("Load Error"), QString("Image not found!"));
return;
}
cv::cvtColor(img, img, cv::ColorConversionCodes::COLOR_BGR2RGB);
float w = 800, h = 1000;
cv::Point2f src[4] = { {383, 445}, {885, 521}, {89, 1125}, {921, 1270} };
cv::Point2f dst[4] = { {0.0f, 0.0f}, {w, 0.0f}, {0.0f, h}, {w, h} };
cv::Mat matrix = cv::getPerspectiveTransform(src, dst);
cv::warpPerspective(img, img_warp, matrix, cv::Size(w, h));
emit endDetectFace();
}
-----------------main cpp------------
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
这篇关于QT C++ 如何从 QThread 返回 QImage 并将其显示在 QMainWindow 中的 QLabel 上?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!