Qt+OpenCV利用幀差法實現車輛識別
一、目標
Qt界面實現 點擊 線程啟動按鈕播放視頻
左邊界面顯示原視頻 右邊界面顯示車輛識別視頻
結果展示如下:
初始界面
點擊線程啟動後,即可車輛識別
二、使用Qt界面
設計好界面後最好先保存
對按鈕設置槽函數
三、代碼實現
難點在於:線程同步問題
需要使用到connect函數中的第五個參數【第五個參數 具體說明如下】
1 AutoConnection 為默認參數,由發送信號決定,如果發送信號和接受信號是同一個線程,則調用DirectConnection。如果不在同一個線程則調用QueuedConnection;
2 DirectConnection 槽函數運行於信號發送者所在的線程,效果上就像是直接在信號發送的位置調用瞭槽函數
3 QueuedConnection 槽函數在控制回到接收者所在線程的事件循環時被調用,槽函數運行於信號接收者所在線程。發送信號後,槽函數不會立即被調用,等到接收者當前函數執行完,進入事件循環之後,槽函數才會被調用。多線程下用這個類型
4 BlockingQueuedConnection 槽函數的調用時機與Qt::QueuedConnection 一致,不過在發送完信號後,發送者所在線程會阻塞,直到槽函數運行完。接收者和發送者絕對不能在一個線程,否則會死鎖。在多線程間需要同步的場合會用到這個
5 UniqueConnection 此類型可通過 “|” 與以上四個結合在一起使用。此類型為當某個信號和槽已經連接時,在進行重復連接時就會失敗,可避免重復連接。如果重復連接,槽函數會重復執行
Widget
頭文件導入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: //綁定線程 需要兩幀畫面 原圖和處理之後的圖 接收由同一個信號發送來的兩幀畫面 void ChangeImg(Mat oldimg,Mat newimg); private: Ui::Widget *ui; videothread *pthread; QImage oldimg; QImage newimg; }; #endif // WIDGET_H
源文件 界面實現
#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"); //由於線程同步問題 需要使用第五個參數 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 需要轉換顏色 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
頭文件導入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: //發送信號 void send2UI(Mat oldimg,Mat newimg); public slots: }; #endif // VIDEOTHREAD_H
源文件 幀差法 車輛識別
#include "videothread.h" videothread::videothread(char *path):QThread() { //打開一個視頻 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三通道轉灰度單通道 壓縮到原圖片三分之一大小 cvtColor(temp,frontGray,CV_RGB2GRAY); cvtColor(frame,afterGray,CV_RGB2GRAY); //2 幀差處理 目的 找到幀與幀之間的差異(正在運動的物體) absdiff(frontGray,afterGray,diff); //3 二值化處理 目的 將灰度圖繼續識別轉換為黑白分明的圖像 threshold(diff,diff,25,255,CV_THRESH_BINARY); //4 圖像降噪 //4-1 腐蝕處理 目的 去除白色噪點 erode(diff,diff,element); //4-2 膨脹 目的 把白色區域變大 dilate(diff,diff,element2); //5 提取關鍵點 //5-1 查找特征點 findContours(diff,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0,0)); //qDebug()<<contours.size(); //5-2 提取關鍵點 vector<vector<Point>>contours_poly(contours.size()); vector<Rect>boundRect(contours.size()); //5-3 確定下四個點來用於框選目標物體 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(); }
到此這篇關於Qt+OpenCV利用幀差法實現車輛識別的文章就介紹到這瞭,更多相關Qt OpenCV車輛識別內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- OpenCV實現車輛識別和運動目標檢測
- OpenCV+Qt實現圖像處理操作工具的示例代碼
- OpenCV+Qt實現圖像處理操作
- OpenCV 輪廓周圍繪制矩形框和圓形框的方法
- 基於opencv實現車道線檢測