Qt+OpenCV利用幀差法實現(xiàn)車輛識別
一、目標(biāo)
Qt界面實現(xiàn) 點擊 線程啟動按鈕播放視頻
左邊界面顯示原視頻 右邊界面顯示車輛識別視頻
結(jié)果展示如下:
初始界面

點擊線程啟動后,即可車輛識別

二、使用Qt界面

設(shè)計好界面后最好先保存
對按鈕設(shè)置槽函數(shù)

三、代碼實現(xiàn)
難點在于:線程同步問題

需要使用到connect函數(shù)中的第五個參數(shù)【第五個參數(shù) 具體說明如下】
1 AutoConnection 為默認(rèn)參數(shù),由發(fā)送信號決定,如果發(fā)送信號和接受信號是同一個線程,則調(diào)用DirectConnection。如果不在同一個線程則調(diào)用QueuedConnection;
2 DirectConnection 槽函數(shù)運(yùn)行于信號發(fā)送者所在的線程,效果上就像是直接在信號發(fā)送的位置調(diào)用了槽函數(shù)
3 QueuedConnection 槽函數(shù)在控制回到接收者所在線程的事件循環(huán)時被調(diào)用,槽函數(shù)運(yùn)行于信號接收者所在線程。發(fā)送信號后,槽函數(shù)不會立即被調(diào)用,等到接收者當(dāng)前函數(shù)執(zhí)行完,進(jìn)入事件循環(huán)之后,槽函數(shù)才會被調(diào)用。多線程下用這個類型
4 BlockingQueuedConnection 槽函數(shù)的調(diào)用時機(jī)與Qt::QueuedConnection 一致,不過在發(fā)送完信號后,發(fā)送者所在線程會阻塞,直到槽函數(shù)運(yùn)行完。接收者和發(fā)送者絕對不能在一個線程,否則會死鎖。在多線程間需要同步的場合會用到這個
5 UniqueConnection 此類型可通過 “|” 與以上四個結(jié)合在一起使用。此類型為當(dāng)某個信號和槽已經(jīng)連接時,在進(jìn)行重復(fù)連接時就會失敗,可避免重復(fù)連接。如果重復(fù)連接,槽函數(shù)會重復(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:
//綁定線程 需要兩幀畫面 原圖和處理之后的圖 接收由同一個信號發(fā)送來的兩幀畫面
void ChangeImg(Mat oldimg,Mat newimg);
private:
Ui::Widget *ui;
videothread *pthread;
QImage oldimg;
QImage newimg;
};
#endif // WIDGET_H
源文件 界面實現(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");
//由于線程同步問題 需要使用第五個參數(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ā)送信號
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三通道轉(zhuǎn)灰度單通道 壓縮到原圖片三分之一大小
cvtColor(temp,frontGray,CV_RGB2GRAY);
cvtColor(frame,afterGray,CV_RGB2GRAY);
//2 幀差處理 目的 找到幀與幀之間的差異(正在運(yùn)動的物體)
absdiff(frontGray,afterGray,diff);
//3 二值化處理 目的 將灰度圖繼續(xù)識別轉(zhuǎn)換為黑白分明的圖像
threshold(diff,diff,25,255,CV_THRESH_BINARY);
//4 圖像降噪
//4-1 腐蝕處理 目的 去除白色噪點
erode(diff,diff,element);
//4-2 膨脹 目的 把白色區(qū)域變大
dilate(diff,diff,element2);
//5 提取關(guān)鍵點
//5-1 查找特征點
findContours(diff,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0,0));
//qDebug()<<contours.size();
//5-2 提取關(guān)鍵點
vector<vector<Point>>contours_poly(contours.size());
vector<Rect>boundRect(contours.size());
//5-3 確定下四個點來用于框選目標(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利用幀差法實現(xiàn)車輛識別的文章就介紹到這了,更多相關(guān)Qt OpenCV車輛識別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言常用庫函數(shù)的使用及模擬實現(xiàn)詳解例舉
C語言庫函數(shù)是把自定義函數(shù)放到庫里,是別人把一些常用到的函數(shù)編完放到一個文件里,供程序員使用,下面讓我們一起來詳細(xì)了解它2022-04-04
C語言編程gcc如何生成靜態(tài)庫.a和動態(tài)庫.so示例詳解
本文主要敘述了gcc如何生成靜態(tài)庫(.a)和動態(tài)庫(.so),幫助我們更好的進(jìn)行嵌入式編程。因為有些時候,涉及安全,所以可能會提供靜態(tài)庫或動態(tài)庫供我們使用2021-10-10
STL區(qū)間成員函數(shù)及區(qū)間算法總結(jié)
這篇文章主要匯總介紹了STL區(qū)間成員函數(shù)及區(qū)間算法,有需要的小伙伴可以參考下。2015-07-07
教你如何使用C++ 統(tǒng)計地鐵中站名出現(xiàn)的字的個數(shù)
通過本文教大家如何使用C++ 統(tǒng)計地鐵中站名出現(xiàn)的字的個數(shù),本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2022-01-01

