基于Qt和Opencv實現(xiàn)二維碼解析
本文詳細(xì)講解了如何利用 Qt 和 OpenCV 實現(xiàn)一個可從視頻和圖片中檢測二維碼的軟件。代碼實現(xiàn)了視頻解碼、多線程處理和界面更新等功能,是一個典型的跨線程圖像處理項目。以下分模塊對代碼進(jìn)行解析。


一、項目的整體結(jié)構(gòu)
項目分為以下幾部分:
主窗口 (MainWindow) :負(fù)責(zé)界面的加載、初始化和用戶交互。
工作線程 (mThread):處理耗時的圖像處理任務(wù)(如二維碼識別)。
二維碼檢測邏輯:使用 OpenCV 進(jìn)行二維碼檢測,支持圖片和視頻兩種數(shù)據(jù)來源。
多線程通信:通過信號與槽機(jī)制,在主線程和工作線程之間傳遞狀態(tài)與數(shù)據(jù)。
二、主窗口功能解析
1. 初始化界面和變量
MainWindow 類的構(gòu)造函數(shù)調(diào)用了 initializeUI() 和 initializeVariable(),分別完成了界面的樣式加載和核心變量的初始化。
void MainWindow::initializeVariable()
{
m_tip = nullptr;
m_lamp[0] = QImage(":/Img/e.png");
m_lamp[1] = QImage(":/Img/i.png");
m_lamp[2] = QImage(":/Img/w.png");
mthread = new mThread(); // 創(chuàng)建工作線程
m_Threadrun = false;
// 線程信號與主窗口槽函數(shù)的連接
connect(mthread, SIGNAL(RuningState(bool)), this, SLOT(onRespondThreadRuningState(bool)));
connect(mthread, SIGNAL(errors(QString)), this, SLOT(onRespondThreaderrors(QString)));
connect(mthread, SIGNAL(infors(QString)), this, SLOT(onRespondThreadinfors(QString)));
connect(mthread, SIGNAL(warings(QString)), this, SLOT(onRespondThreadwarings(QString)));
connect(mthread, &mThread::imageProcessed, this, &MainWindow::processImage);
}
2. 啟動和停止線程
用戶點擊按鈕后,調(diào)用 on_btn_Start_Stop_clicked,判斷當(dāng)前線程狀態(tài)以啟動或停止工作線程。
void MainWindow::on_btn_Start_Stop_clicked()
{
m_Threadrun ? mthread->stop() : mthread->start(); // 根據(jù)當(dāng)前狀態(tài)啟動或停止線程
}
3. 文件選擇
QFileDialog 被用來讓用戶選擇視頻或圖像文件,并將這些參數(shù)傳遞到線程處理。
void MainWindow::on_btn_Loadfile_clicked()
{
QString fileName = QFileDialog::getOpenFileName(nullptr, tc("選擇視頻文件"), "", tc("視頻文件(*.mp4)"));
mthread->setFunId(0); // 設(shè)置功能 ID:0 表示處理視頻
if (!fileName.isEmpty())
mthread->setThreadParams(fileName); // 傳遞參數(shù)到線程
}
void MainWindow::on_btn_Loadimages_clicked()
{
QStringList fileNames = QFileDialog::getOpenFileNames(nullptr, tc("選擇圖像文件"), "", tc("圖片文件(*.jpg *.bmp *.png)"));
mthread->setFunId(1); // 設(shè)置功能 ID:1 表示處理圖片
if (!fileNames.isEmpty())
mthread->setThreadParams(fileNames);
}
三、工作線程實現(xiàn)
mThread 類繼承自 QThread,用于處理耗時的二維碼檢測任務(wù)。其主要功能包括:
根據(jù)功能 ID 分別處理視頻或圖片。
在每幀中調(diào)用 OpenCV 的 QRCodeDetector 進(jìn)行二維碼檢測。
通過信號將處理后的圖像和數(shù)據(jù)傳遞回主線程。
1. 核心線程邏輯
線程的運行邏輯集中在 run() 方法中。getFunId() 決定了是處理視頻還是圖片,分別調(diào)用 anayVideo() 或 anayImages()。
void mThread::run()
{
m_isRun = true;
emit RuningState(true); // 通知主線程:線程開始運行
emit infors(tc("線程啟動"));
switch (getFunId()) {
case 0:
anayVideo(); // 處理視頻
break;
case 1:
anayImages(); // 處理圖片
break;
default:
break;
}
emit RuningState(false); // 通知主線程:線程結(jié)束運行
emit infors(tc("線程退出"));
}
2. 視頻處理
在 anayVideo() 中,使用 OpenCV 的 VideoCapture 解碼視頻逐幀處理。每一幀調(diào)用 delectDecoded() 檢測二維碼,并通過信號將結(jié)果傳回主線程。
void mThread::anayVideo()
{
cv::VideoCapture cap;
if (!cap.open(m_Params.toString().toLocal8Bit().data()) || !cap.isOpened())
{
emit errors(tc("視頻未打開"));
m_isRun = false;
}
else
{
cv::Mat frame;
int frameCount = cap.get(cv::CAP_PROP_FRAME_COUNT);
while ((frameCount--) > 0 && m_isRun) // 幀循環(huán)
{
cap >> frame; // 讀取一幀
if (frame.empty())
break;
QString msg;
delectDecoded(frame, msg); // 檢測二維碼
emit imageProcessed(MatToQImage(frame), msg); // 發(fā)射處理信號
cv::waitKey(50);
}
cap.release();
}
}
3. 圖片處理
圖片處理邏輯與視頻類似,只是直接從文件路徑中讀取。
void mThread::anayImages()
{
QStringList files = m_Params.toStringList();
for (auto file : files)
{
cv::Mat frame = cv::imread(file.toStdString().c_str());
if (frame.empty() && !m_isRun)
break;
QString msg;
delectDecoded(frame, msg);
emit imageProcessed(MatToQImage(frame), msg); // 發(fā)射信號
cv::waitKey(1000);
}
}
四、二維碼檢測實現(xiàn)
1. 使用 OpenCV 進(jìn)行檢測
在 delectDecoded() 方法中,利用 OpenCV 的 QRCodeDetector 類進(jìn)行二維碼檢測和解碼,并將結(jié)果繪制到圖像中。
int mThread::delectDecoded(cv::Mat &image, QString &code)
{
cv::Mat bbox, rectifiedImage;
std::string data = qrDecoder.detectAndDecode(image, bbox, rectifiedImage);
??????? if (data.length() > 0)
{
code = QString::fromStdString(data); // 將結(jié)果返回
std::vector<cv::Point> points;
for (int i = 0; i < bbox.cols; i++)
{
points.push_back(cv::Point(static_cast<int>(bbox.at<cv::Point2f>(0, i).x), static_cast<int>(bbox.at<cv::Point2f>(0, i).y)));
}
for (size_t i = 0; i < points.size(); i++)
{
cv::line(image, points[i], points[(i + 1) % points.size()], cv::Scalar(0, 255, 0), 3); // 繪制綠色邊框
}
int minY = points[0].y;
for (const auto &point : points) {
minY = std::min(minY, point.y);
}
cv::putText(image, data, cv::Point(points[0].x, minY - 10), cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 255, 0), 2); // 顯示二維碼信息
}
else
{
code = tc("未檢測到二維碼!");
}
return 0;
}2. Mat 轉(zhuǎn) QImage
為了在 Qt 界面中顯示 OpenCV 的圖像,MatToQImage() 將 OpenCV 的 cv::Mat 轉(zhuǎn)換為 Qt 的 QImage。
五、多線程與信號槽
在本項目中,多線程通過信號與槽實現(xiàn)以下功能:
更新主界面狀態(tài):線程的運行狀態(tài)(如啟動和停止)通過 RuningState 信號通知主線程。
實時更新圖像和檢測結(jié)果:imageProcessed 信號傳遞處理后的圖像和二維碼信息,更新界面。
connect(mthread, &mThread::imageProcessed, this, &MainWindow::processImage);
???????void MainWindow::processImage(const QImage &image, const QString &msg)
{
ui->lab_disp->setPixmap(QPixmap::fromImage(image).scaled(image.width() / 2, image.height() / 2)); // 顯示縮放后的圖像
ui->lab_disData->setText(msg); // 顯示檢測到的信息
}以上就是基于Qt和Opencv實現(xiàn)二維碼解析的詳細(xì)內(nèi)容,更多關(guān)于Qt Opencv二維碼解析的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語言實現(xiàn)職工工資管理系統(tǒng)的示例代碼
這篇文章主要為大家詳細(xì)介紹了C語言如何實現(xiàn)職工工資管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-08-08
C語言實現(xiàn)的統(tǒng)計素數(shù)并求和代碼分享
這篇文章主要介紹了C語言實現(xiàn)的統(tǒng)計素數(shù)并求和代碼分享,來自PAT平臺(浙江大學(xué)計算機(jī)程序設(shè)計能力考試系統(tǒng))的一個題目,需要的朋友可以參考下2014-08-08
C/C++ Zlib庫封裝MyZip壓縮類的詳細(xì)過程
在軟件開發(fā)中,文件的壓縮和解壓縮是一項常見的任務(wù),而ZIP是一種被廣泛應(yīng)用的壓縮格式,本文將聚焦于一個簡化的C++實現(xiàn),通過分析代碼,我們將深入了解其設(shè)計和實現(xiàn)細(xì)節(jié),感興趣的朋友一起看看吧2023-11-11

