Qt+OpenCV利用幀差法實(shí)現(xiàn)車輛識(shí)別
一、目標(biāo)
Qt界面實(shí)現(xiàn) 點(diǎn)擊 線程啟動(dòng)按鈕播放視頻
左邊界面顯示原視頻 右邊界面顯示車輛識(shí)別視頻
結(jié)果展示如下:
初始界面
點(diǎn)擊線程啟動(dòng)后,即可車輛識(shí)別
二、使用Qt界面
設(shè)計(jì)好界面后最好先保存
對(duì)按鈕設(shè)置槽函數(shù)
三、代碼實(shí)現(xiàn)
難點(diǎn)在于:線程同步問(wèn)題
需要使用到connect函數(shù)中的第五個(gè)參數(shù)【第五個(gè)參數(shù) 具體說(shuō)明如下】
1 AutoConnection 為默認(rèn)參數(shù),由發(fā)送信號(hào)決定,如果發(fā)送信號(hào)和接受信號(hào)是同一個(gè)線程,則調(diào)用DirectConnection。如果不在同一個(gè)線程則調(diào)用QueuedConnection;
2 DirectConnection 槽函數(shù)運(yùn)行于信號(hào)發(fā)送者所在的線程,效果上就像是直接在信號(hào)發(fā)送的位置調(diào)用了槽函數(shù)
3 QueuedConnection 槽函數(shù)在控制回到接收者所在線程的事件循環(huán)時(shí)被調(diào)用,槽函數(shù)運(yùn)行于信號(hào)接收者所在線程。發(fā)送信號(hào)后,槽函數(shù)不會(huì)立即被調(diào)用,等到接收者當(dāng)前函數(shù)執(zhí)行完,進(jìn)入事件循環(huán)之后,槽函數(shù)才會(huì)被調(diào)用。多線程下用這個(gè)類型
4 BlockingQueuedConnection 槽函數(shù)的調(diào)用時(shí)機(jī)與Qt::QueuedConnection 一致,不過(guò)在發(fā)送完信號(hào)后,發(fā)送者所在線程會(huì)阻塞,直到槽函數(shù)運(yùn)行完。接收者和發(fā)送者絕對(duì)不能在一個(gè)線程,否則會(huì)死鎖。在多線程間需要同步的場(chǎng)合會(huì)用到這個(gè)
5 UniqueConnection 此類型可通過(guò) “|” 與以上四個(gè)結(jié)合在一起使用。此類型為當(dāng)某個(gè)信號(hào)和槽已經(jīng)連接時(shí),在進(jìn)行重復(fù)連接時(shí)就會(huì)失敗,可避免重復(fù)連接。如果重復(fù)連接,槽函數(shù)會(huì)重復(fù)執(zhí)行
Widget
頭文件導(dǎo)入OpenCV包
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include<opencv2/opencv.hpp> #include"videothread.h" using namespace cv; namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); void paintEvent(QPaintEvent *e); private slots: void on_pushButton_clicked(); public slots: //綁定線程 需要兩幀畫(huà)面 原圖和處理之后的圖 接收由同一個(gè)信號(hào)發(fā)送來(lái)的兩幀畫(huà)面 void ChangeImg(Mat oldimg,Mat newimg); private: Ui::Widget *ui; videothread *pthread; QImage oldimg; QImage newimg; }; #endif // WIDGET_H
源文件 界面實(shí)現(xiàn)
#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); this->pthread = new videothread("D:/00000000000003jieduanshipincailliao/carMove.mp4"); //由于線程同步問(wèn)題 需要使用第五個(gè)參數(shù) connect(this->pthread,SIGNAL(send2UI(Mat,Mat)),this,SLOT(ChangeImg(Mat,Mat)),Qt::BlockingQueuedConnection); } Widget::~Widget() { delete ui; } void Widget::paintEvent(QPaintEvent *e) { ui->label->setPixmap(QPixmap::fromImage(this->oldimg)); ui->label_2->setPixmap(QPixmap::fromImage(this->newimg)); //qDebug()<<"paintEvent"; } void Widget::on_pushButton_clicked() { this->pthread->start(); } void Widget::ChangeImg(Mat oldimg,Mat newimg) { //Mat是BGR 而QImage是RGB 需要轉(zhuǎn)換顏色 cvtColor(oldimg,oldimg,CV_BGR2RGB); cvtColor(newimg,newimg,CV_BGR2RGB); this->oldimg = QImage(oldimg.data,oldimg.cols,oldimg.rows,QImage::Format_RGB888); this->oldimg = this->oldimg.scaled(ui->label->width(),ui->label->height()); this->newimg = QImage(newimg.data,newimg.cols,newimg.rows,QImage::Format_RGB888); this->newimg = this->newimg.scaled(ui->label_2->width(),ui->label_2->height()); //update(); }
VideoThread
頭文件導(dǎo)入OpenCV包
#ifndef VIDEOTHREAD_H #define VIDEOTHREAD_H #include<QThread> #include<opencv2/opencv.hpp> #include<vector> #include<QDebug> #include <QObject> using namespace std; using namespace cv; class videothread : public QThread { Q_OBJECT public: //explicit videothread(QObject *parent = 0); //線程傳參視頻路徑 videothread(char *path); void run(); private: VideoCapture cap; Mat frame;//讀一幀 Mat temp;//保存上一幀 signals: //發(fā)送信號(hào) void send2UI(Mat oldimg,Mat newimg); public slots: }; #endif // VIDEOTHREAD_H
源文件 幀差法 車輛識(shí)別
#include "videothread.h" videothread::videothread(char *path):QThread() { //打開(kāi)一個(gè)視頻 cap.open(path); } void videothread::run() { int count = 0; Mat resFrame,diff; Mat frontGray,afterGray; vector<vector<Point>>contours; Mat element = cv::getStructuringElement(MORPH_RECT,Size(3,3)); Mat element2 = cv::getStructuringElement(MORPH_RECT,Size(20,20)); int x,y,w,h; while (cap.read(frame)) { count++; if(count == 1) { //保存第一幀 temp = frame.clone(); continue; } else { //繪制矩形 使用此幀 resFrame = frame.clone(); //1 灰度處理 目的 RGB三通道轉(zhuǎn)灰度單通道 壓縮到原圖片三分之一大小 cvtColor(temp,frontGray,CV_RGB2GRAY); cvtColor(frame,afterGray,CV_RGB2GRAY); //2 幀差處理 目的 找到幀與幀之間的差異(正在運(yùn)動(dòng)的物體) absdiff(frontGray,afterGray,diff); //3 二值化處理 目的 將灰度圖繼續(xù)識(shí)別轉(zhuǎn)換為黑白分明的圖像 threshold(diff,diff,25,255,CV_THRESH_BINARY); //4 圖像降噪 //4-1 腐蝕處理 目的 去除白色噪點(diǎn) erode(diff,diff,element); //4-2 膨脹 目的 把白色區(qū)域變大 dilate(diff,diff,element2); //5 提取關(guān)鍵點(diǎn) //5-1 查找特征點(diǎn) findContours(diff,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0,0)); //qDebug()<<contours.size(); //5-2 提取關(guān)鍵點(diǎn) vector<vector<Point>>contours_poly(contours.size()); vector<Rect>boundRect(contours.size()); //5-3 確定下四個(gè)點(diǎn)來(lái)用于框選目標(biāo)物體 int num=contours.size(); for(int i = 0;i < num;i++) { approxPolyDP(Mat(contours[i]),contours_poly[i],3,true); //多邊擬合 boundRect[i]=boundingRect(Mat(contours_poly[i])); x=boundRect[i].x; y=boundRect[i].y; w=boundRect[i].width; h=boundRect[i].height; //繪制矩形 rectangle(resFrame,Point(x,y),Point(x+w,y+h),Scalar(0,0,255),2); } } temp = frame.clone(); emit send2UI(frame,resFrame); msleep(1); } }
主入口Qt窗口顯示
#include "widget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }
到此這篇關(guān)于Qt+OpenCV利用幀差法實(shí)現(xiàn)車輛識(shí)別的文章就介紹到這了,更多相關(guān)Qt OpenCV車輛識(shí)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++定時(shí)器實(shí)現(xiàn)和時(shí)間輪介紹
這篇文章主要介紹了C++定時(shí)器實(shí)現(xiàn)和時(shí)間輪介紹,定時(shí)器可以由很多種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn),比如最小堆、紅黑樹(shù)、跳表、甚至數(shù)組都可以,其本質(zhì)都是拿到最小時(shí)間的任務(wù),然后取出該任務(wù)并執(zhí)行,更多相關(guān)內(nèi)容介紹,需要的小伙伴可以參考一下2022-09-09C++?數(shù)據(jù)結(jié)構(gòu)超詳細(xì)講解順序表
程序中經(jīng)常需要將一組數(shù)據(jù)元素作為整體管理和使用,需要?jiǎng)?chuàng)建這種元素組,用變量記錄它們,傳進(jìn)傳出函數(shù)等。一組數(shù)據(jù)中包含的元素個(gè)數(shù)可能發(fā)生變化,順序表則是將元素順序地存放在一塊連續(xù)的存儲(chǔ)區(qū)里,元素間的順序關(guān)系由它們的存儲(chǔ)順序自然表示2022-03-03C語(yǔ)言GetStdHandle函數(shù)使用方法
這篇文章介紹了C語(yǔ)言GetStdHandle函數(shù)的使用方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12C語(yǔ)言實(shí)現(xiàn)自行車存放管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)自行車存放管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08深入分析為Visual Assist設(shè)置快捷鍵的方法
本篇文章是對(duì)為Visual Assist設(shè)置快捷鍵的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05c# 實(shí)現(xiàn)獲取漢字十六進(jìn)制Unicode編碼字符串的實(shí)例
下面小編就為大家?guī)?lái)一篇c# 實(shí)現(xiàn)獲取漢字十六進(jìn)制Unicode編碼字符串的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01C++?this原理與可變參數(shù)及友元函數(shù)友元類分步詳解用法
可變參數(shù)模板(variadic?templates)是C++11新增的強(qiáng)大的特性之一,它對(duì)模板參數(shù)進(jìn)行了高度泛化,能表示0到任意個(gè)數(shù)、任意類型的參數(shù),這篇文章主要介紹了C++?this原理與可變參數(shù)及友元函數(shù)友元類2022-11-11c語(yǔ)言標(biāo)準(zhǔn)庫(kù)中字符轉(zhuǎn)換函數(shù)和數(shù)字轉(zhuǎn)換函數(shù)
這篇文章主要介紹了c標(biāo)準(zhǔn)庫(kù)中字符轉(zhuǎn)換函數(shù)和數(shù)字轉(zhuǎn)換函數(shù),需要的朋友可以參考下2014-04-04