首頁 > 軟體

Qt+OpenCV利用幀差法實現車輛識別

2022-08-03 18:04:50

一、目標

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車輛識別內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com