Qt+OpenCV實(shí)現(xiàn)目標(biāo)檢測詳解
一、創(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 | 二進(jìn)制數(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_H
mainwindow.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進(jìn)行布局
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實(shí)現(xiàn)目標(biāo)檢測詳解的文章就介紹到這了,更多相關(guān)Qt OpenCV目標(biāo)檢測內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
error LNK2019: 無法解析的外部符號 問題的解決辦法
error LNK2019: 無法解析的外部符號 問題的解決辦法,需要的朋友可以參考一下2013-05-05C/C++?Qt?Tree與Tab組件實(shí)現(xiàn)分頁菜單功能
這篇文章主要介紹了C/C++?Qt?Tree與Tab組件實(shí)現(xiàn)分頁菜單功能,實(shí)現(xiàn)一個類似于樹形菜單欄的功能,當(dāng)用戶點(diǎn)擊菜單欄中的選項時則會跳轉(zhuǎn)到不同的頁面上,本文簡單給大家分享實(shí)現(xiàn)代碼,感興趣的朋友跟隨小編一起看看吧2021-11-11C++無鎖數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)示例詳解
這篇文章主要為大家介紹了C++無鎖數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12C語言 詳細(xì)解析時間復(fù)雜度與空間復(fù)雜度
算法復(fù)雜度分為時間復(fù)雜度和空間復(fù)雜度。其作用: 時間復(fù)雜度是度量算法執(zhí)行的時間長短;而空間復(fù)雜度是度量算法所需存儲空間的大小2022-04-04Visual Studio 2019配置qt開發(fā)環(huán)境的搭建過程
這篇文章主要介紹了Visual Studio 2019配置qt開發(fā)環(huán)境的搭建過程,本文圖文并茂給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03