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ù)運行于信號發(fā)送者所在的線程,效果上就像是直接在信號發(fā)送的位置調(diào)用了槽函數(shù)
3 QueuedConnection 槽函數(shù)在控制回到接收者所在線程的事件循環(huán)時被調(diào)用,槽函數(shù)運行于信號接收者所在線程。發(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ù)運行完。接收者和發(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 幀差處理 目的 找到幀與幀之間的差異(正在運動的物體)
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ù)據(jù)結(jié)構(gòu)超詳細(xì)講解順序表
程序中經(jīng)常需要將一組數(shù)據(jù)元素作為整體管理和使用,需要創(chuàng)建這種元素組,用變量記錄它們,傳進(jìn)傳出函數(shù)等。一組數(shù)據(jù)中包含的元素個數(shù)可能發(fā)生變化,順序表則是將元素順序地存放在一塊連續(xù)的存儲區(qū)里,元素間的順序關(guān)系由它們的存儲順序自然表示2022-03-03
深入分析為Visual Assist設(shè)置快捷鍵的方法
本篇文章是對為Visual Assist設(shè)置快捷鍵的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
c# 實現(xiàn)獲取漢字十六進(jìn)制Unicode編碼字符串的實例
下面小編就為大家?guī)硪黄猚# 實現(xiàn)獲取漢字十六進(jìn)制Unicode編碼字符串的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01
C++?this原理與可變參數(shù)及友元函數(shù)友元類分步詳解用法
可變參數(shù)模板(variadic?templates)是C++11新增的強(qiáng)大的特性之一,它對模板參數(shù)進(jìn)行了高度泛化,能表示0到任意個數(shù)、任意類型的參數(shù),這篇文章主要介紹了C++?this原理與可變參數(shù)及友元函數(shù)友元類2022-11-11
c語言標(biāo)準(zhǔn)庫中字符轉(zhuǎn)換函數(shù)和數(shù)字轉(zhuǎn)換函數(shù)
這篇文章主要介紹了c標(biāo)準(zhǔn)庫中字符轉(zhuǎn)換函數(shù)和數(shù)字轉(zhuǎn)換函數(shù),需要的朋友可以參考下2014-04-04

