Qt+OpenCV實現(xiàn)目標檢測詳解
一、創(chuàng)建項目&UI設(shè)計
創(chuàng)建項目,UI設(shè)計如下

文件類型判斷
簡單的判斷文件類型
QString file("sample.jpg");
if (file.contains(".jpg") || file.contains(".bmp") || file.contains(".png"))
qDebug()<<"這是圖片。";
推薦使用QMimeDatabase類
QMimeDatabase db;
QMimeType mime = db.mimeTypeForFile("sample.bmp");
if (mime.name().startsWith("image/"))
qDebug()<<"這是圖片。";
| 類型 | 描述 | 示例 |
|---|---|---|
| text | 普通文本 | text/plain, text/html, text/css, text/javascript |
| image | 圖像文件(包含動態(tài)gif) | image/gif, image/png, image/jpeg, image/bmp, image/webp |
| audio | 音頻文件 | audio/wav, audio/mpeg, audio/midi, audio/webm, audio/ogg |
| video | 視頻文件 | video/mp4, video/x-flv, video/webm, video/ogg |
| application | 二進制數(shù)據(jù) | application/xml, application/pdf |
二、代碼與演示
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QFileDialog>
#include <QFile>
#include <opencv2/opencv.hpp>
#include <QMainWindow>
#include <QTimer>
#include <QImage>
#include <QPixmap>
#include <QDateTime>
#include <QMutex>
#include <QMutexLocker>
#include <QMimeDatabase>
#include <iostream>
QPixmap Mat2Image(cv::Mat src);
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
void Init();
~MainWindow();
private slots:
void readFrame(); //自定義信號處理函數(shù)
void on_pushButton_OpenFile_clicked();
void on_pushButton_StartDetect_clicked();
void on_pushButton_StopDetect_clicked();
void on_pushButton_FlushDevice_clicked();
private:
Ui::MainWindow *ui;
QTimer *timer;
QImage *img;
QString mp4_path = NULL;
cv::VideoCapture *capture;
cv::CascadeClassifier *classifier;
std::vector<cv::Rect> bodys;
int display_HeightWidth = 500;
int IsDetect_ok = 0; //用于判斷是否加載了MP4和xml
};
#endif // MAINWINDOW_Hmainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
timer = new QTimer(this);
timer->setInterval(33);
connect(timer,SIGNAL(timeout()),this,SLOT(readFrame()));
ui->pushButton_StartDetect->setEnabled(false);
ui->pushButton_StopDetect->setEnabled(false);
Init();
}
void MainWindow::Init()
{
capture = new cv::VideoCapture();
classifier = new cv::CascadeClassifier;
}
MainWindow::~MainWindow()
{
capture->release();
delete ui;
}
void MainWindow::readFrame()
{
cv::Mat frame, hsv_img, mask_img, gray_src;
capture->read(frame);
if (frame.empty()) return;
// int frame_width = capture->get(cv::CAP_PROP_FRAME_WIDTH);
// int frame_height = capture->get(cv::CAP_PROP_FRAME_HEIGHT);
// if (frame_width / frame_height >= 1){
// cv::resize(frame, frame, cv::Size(display_HeightWidth, (int)(frame_height * display_HeightWidth / frame_width)));
// }else{
// cv::resize(frame, frame, cv::Size((int)(frame_width * display_HeightWidth / frame_height), display_HeightWidth));
// }
//算法一:行人檢測
cv::cvtColor(frame, gray_src, cv::COLOR_BGR2GRAY);
cv::equalizeHist(gray_src, gray_src);
classifier->detectMultiScale(gray_src, bodys, 1.1, 3, 0, cv::Size(30, 30));
for (size_t i = 0; i < bodys.size(); i++){
cv::rectangle(frame, bodys[i], cv::Scalar(0, 0, 255), 2, 8, 0);
}
//算法二:顏色跟蹤
cv::cvtColor(frame, hsv_img, cv::COLOR_BGR2HSV);
cv::inRange(hsv_img, cv::Scalar(35, 43, 46), cv::Scalar(155, 255, 255), mask_img);
cv::Mat kernel = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
morphologyEx(mask_img, mask_img, cv::MORPH_CLOSE, kernel);
erode(mask_img, mask_img, kernel);
GaussianBlur(mask_img, mask_img, cv::Size(3, 3), 0, 0);
if (cv::waitKey(30) == 27) {
ui->textEdit_log->setText("Exit...");
ui->label_raw->clear();
return;
}
cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB);
QImage rawImage = QImage((uchar*)(frame.data),frame.cols,frame.rows,frame.step,QImage::Format_RGB888);
ui->label_raw->setPixmap(QPixmap::fromImage(rawImage)); //顯示源圖像
QImage dstImage = QImage((uchar*)(mask_img.data),mask_img.cols,mask_img.rows,mask_img.step,QImage::Format_Grayscale8);
ui->label_detect->setPixmap(QPixmap::fromImage(dstImage)); //顯示圖像
}
void MainWindow::on_pushButton_OpenFile_clicked()
{
QString filename = QFileDialog::getOpenFileName(this,"打開文件",".","*.mp4 *.avi;;*.png *.jpg *.jpeg *.bmp");
if(!QFile::exists(filename)){
return;
}
ui->statusbar->showMessage(filename);
IsDetect_ok +=1;
if (IsDetect_ok ==2)
ui->pushButton_StartDetect->setEnabled(true);
QMimeDatabase db;
QMimeType mime = db.mimeTypeForFile(filename);
if (mime.name().startsWith("image/")) {
cv::Mat src = cv::imread(filename.toLatin1().data());
if(src.empty()){
ui->statusbar->showMessage("圖像不存在!");
return;
}
cv::Mat temp;
if(src.channels()==4)
cv::cvtColor(src,temp,cv::COLOR_BGRA2RGB);
else if (src.channels()==3)
cv::cvtColor(src,temp,cv::COLOR_BGR2RGB);
else
cv::cvtColor(src,temp,cv::COLOR_GRAY2RGB);
QImage img = QImage((uchar*)temp.data,temp.cols,temp.rows,temp.step,QImage::Format_RGB888);
ui->label_raw->setPixmap(QPixmap::fromImage(img));
ui->label_raw->resize(ui->label_raw->pixmap()->size());
filename.clear();
}else if (mime.name().startsWith("video/")) {
capture->open(filename.toLatin1().data());
if (!capture->isOpened()){
ui->textEdit_log->append("fail to open MP4!");
return;
}
ui->textEdit_log->append(QString::fromUtf8("Open video: %1 succesfully!").arg(filename));
//獲取整個幀數(shù)
long totalFrameNumber = capture->get(CV_CAP_PROP_FRAME_COUNT);
ui->textEdit_log->append(QString::fromUtf8("整個視頻共 %1 幀").arg(totalFrameNumber));
ui->label_raw->resize(QSize(capture->get(CV_CAP_PROP_FRAME_WIDTH), capture->get(CV_CAP_PROP_FRAME_HEIGHT)));
//設(shè)置開始幀()
long frameToStart = 0;
capture->set(CV_CAP_PROP_POS_FRAMES, frameToStart);
ui->textEdit_log->append(QString::fromUtf8("從第 %1 幀開始讀").arg(frameToStart));
//獲取幀率
double rate = capture->get(CV_CAP_PROP_FPS);
ui->textEdit_log->append(QString::fromUtf8("幀率為: %1 ").arg(rate));
}
}
void MainWindow::on_pushButton_StartDetect_clicked()
{
timer->start();
ui->pushButton_StartDetect->setEnabled(false);
ui->pushButton_StopDetect->setEnabled(true);
}
void MainWindow::on_pushButton_StopDetect_clicked()
{
ui->pushButton_StartDetect->setEnabled(true);
ui->pushButton_StopDetect->setEnabled(false);
timer->stop();
}
void MainWindow::on_pushButton_FlushDevice_clicked()
{
QString xmlfilename = QFileDialog::getOpenFileName(this,"打開文件",".","*.xml");
if(!QFile::exists(xmlfilename)){
return;
}
ui->statusbar->showMessage(xmlfilename);
if (!classifier->load(xmlfilename.toLatin1().data())) {
ui->textEdit_log->append("fail to open classifier_path!");
return;
}
IsDetect_ok +=1;
ui->textEdit_log->append(QString::fromUtf8("Open xmlfile: %1 succesfully!").arg(xmlfilename));
if (IsDetect_ok ==2)
ui->pushButton_StartDetect->setEnabled(true);
}演示效果

拓展閱讀
直接在屬性欄目搜索中設(shè)置(如下圖),或者 pushbutton設(shè)置icon和文字

下面是pushbutton設(shè)置icon和文字的四種方法詳解
1.使用系統(tǒng)自帶api
ui->pushButton->setIconSize(QSize(32,32));
ui->pushButton->setIcon(QIcon(":/images/Setting.png"));
ui->pushButton->setText(QString::fromLocal8Bit("系統(tǒng)設(shè)置"));
ui->pushButton->setStyleSheet("QPushButton{border:1px solid blue;background:white;}"
"QPushButton:hover{border:0px;background:blue;}"
"QPushButton:pressed{border:0px;background:red;}");
無法設(shè)置icon和文字之間的距離。
2.如果想讓icon顯示在文字上方可使用QToolButton
ui->toolButton->setIconSize(QSize(32,32));
ui->toolButton->setIcon(QIcon(":/images/Setting.png"));
ui->toolButton->setText(QString::fromLocal8Bit("系統(tǒng)設(shè)置"));
ui->toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
3.在pushbutton上面使用label進行布局
QLabel *iconLabel = new QLabel;
QLabel *textLabel = new QLabel;
iconLabel->setFixedSize(32,32);
iconLabel->setStyleSheet("border:1px solid red;");
textLabel->setStyleSheet("border:1px solid red;");
iconLabel->setPixmap(QPixmap(":/images/Setting.png"));
textLabel->setText(QString::fromLocal8Bit("系統(tǒng)設(shè)置"));
textLabel->setFixedWidth(60);
QHBoxLayout *myLayout = new QHBoxLayout();
myLayout->addSpacing(10);
myLayout->addWidget(iconLabel);
myLayout->addSpacing(30);
myLayout->addWidget(textLabel);
myLayout->addStretch();
ui->pushButton_2->setLayout(myLayout);
ui->pushButton_2->setStyleSheet("QPushButton{border:1px solid blue;background:white;}"
"QPushButton:hover{border:0px;background:blue;}"
"QPushButton:pressed{border:0px;background:red;}");
4.使用圖片,設(shè)置stylesheet即可
以上三種方法,需要設(shè)置,比較麻煩,最好還是找UI設(shè)計按鈕圖片,這樣軟件的適配性也比較好。
到此這篇關(guān)于Qt+OpenCV實現(xiàn)目標檢測詳解的文章就介紹到這了,更多相關(guān)Qt OpenCV目標檢測內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
error LNK2019: 無法解析的外部符號 問題的解決辦法
error LNK2019: 無法解析的外部符號 問題的解決辦法,需要的朋友可以參考一下2013-05-05
C/C++?Qt?Tree與Tab組件實現(xiàn)分頁菜單功能
這篇文章主要介紹了C/C++?Qt?Tree與Tab組件實現(xiàn)分頁菜單功能,實現(xiàn)一個類似于樹形菜單欄的功能,當用戶點擊菜單欄中的選項時則會跳轉(zhuǎn)到不同的頁面上,本文簡單給大家分享實現(xiàn)代碼,感興趣的朋友跟隨小編一起看看吧2021-11-11
C++無鎖數(shù)據(jù)結(jié)構(gòu)實現(xiàn)示例詳解
這篇文章主要為大家介紹了C++無鎖數(shù)據(jù)結(jié)構(gòu)實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12
Visual Studio 2019配置qt開發(fā)環(huán)境的搭建過程
這篇文章主要介紹了Visual Studio 2019配置qt開發(fā)環(huán)境的搭建過程,本文圖文并茂給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03

