??OpenCV的機器視覺包含靜態(tài)圖像處理(2D與3D)與動態(tài)視頻處理恰起,本主題主要梳理下C++的視頻采集處理淮逻。
OpenCV視頻處理結(jié)構(gòu)
結(jié)構(gòu)圖
核心類說明
VideoCapture類
- 負責抓取視頻刨沦,抓取源支持:照相機,視頻文件敏释,圖形序列等骂澄。
VideoWriter
- 負責寫視頻數(shù)據(jù)到文件,包括壓縮等挣柬。
VideoCapture視頻抓取
構(gòu)造器
- 一共三個構(gòu)造器
- 默認構(gòu)造器
- 視頻設備構(gòu)造器
- 視頻文件構(gòu)造器器
- 默認構(gòu)造器
- 默認構(gòu)造器沒有初始化設備潮酒,需要調(diào)用open函數(shù)初始化設備。
cv::VideoCapture::VideoCapture( )
- 視頻設備構(gòu)造器
cv::VideoCapture::VideoCapture(
int index, // 視頻設備編號邪蛔,從0開始
int apiPreference = CAP_ANY // 視頻處理的底層API急黎。FFMPEG,IMAGES侧到,DSHOW
)
- FFMPEG:開源的視頻處理框架勃教;
- IMAGES:圖片序列(比如:GIF);
- DSHOW:微軟的DirectX中視頻模塊DSHOW匠抗;
- 視頻文件構(gòu)造器
cv::VideoCapture::VideoCapture(
const String & filename, // 視頻文件路徑故源。
int apiPreference = CAP_ANY // 視頻處理的底層API。
)
設備初始化
- 使用open函數(shù)實現(xiàn)設備初始化汞贸。
- 與構(gòu)造器相同心软。
- 使用視頻文件初始化
virtual bool open (const String &filename, int apiPreference=CAP_ANY)
- 使用視頻設備初始化
virtual bool open (int index, int apiPreference=CAP_ANY)
判別設備是否初始化
- isOpened函數(shù)
virtual bool isOpened () const
讀取數(shù)據(jù)
- 讀取數(shù)據(jù)兩種方式
- 直接讀取
- 多設備情況下,需要先抓取緩沖著蛙,然后讀壬玖濉;
直接讀取數(shù)據(jù)
- 使用read函數(shù)與操作符讀忍けぁ猎唁;
- read函數(shù)讀取
virtual bool read (OutputArray image)
- OutputArray image返回抓取的視頻圖像。
-
>>
操作符讀取
virtual VideoCapture& cv::VideoCapture::operator >>(Mat & image )
緩沖讀取
- 緩沖讀取分成兩步:
- 使用grap函數(shù)抓取到緩沖顷蟆;
- 使用retrieve函數(shù)返回視頻圖像诫隅;
- grap函數(shù)
- 抓取視頻圖像成功,返回true帐偎;否則返回false
virtual bool grab ()
- retrieve 函數(shù)
- 返回抓取的圖像逐纬,比read多一個讀取標記;
virtual bool retrieve (
OutputArray image,
int flag=0) // 用來指定圖像的幀索引削樊,或者底層IP的讀取標記豁生;
屬性處理
- 提供了set/get來設置與獲取設備與底層屬性
- set函數(shù)
virtual bool set (int propId, double value)
- get函數(shù)
virtual double get (int propId) const
釋放設備
- 使用release函數(shù)釋放
virtual void release()
視頻抓取應用例子
- 例子的思路:
- 創(chuàng)建一個線程兔毒,不同抓取視頻圖像,然后用信號的方式發(fā)送給窗體顯示甸箱;
抓取圖像的線程
- 頭文件
#ifndef VIDEO_THRWAD_H
#define VIDEO_THRWAD_H
#include <opencv2/opencv.hpp>
#include <QThread>
class VideoThread : public QThread{
Q_OBJECT
public:
VideoThread();
VideoThread(int deviceid);
~VideoThread();
private:
cv::VideoCapture *device;
protected:
virtual void run();
// 信號
signals:
void video(cv::Mat img);
};
#endif // !VIDEO_THRWAD_H
- 實現(xiàn)文件
#include "videoth.h"
#include<iostream>
// 構(gòu)造器
VideoThread::VideoThread():
device(new cv::VideoCapture(0)){
}
VideoThread::VideoThread(int deviceid):
device(new cv::VideoCapture(deviceid)){
}
// 析構(gòu)器
VideoThread::~VideoThread(){
device->release();
delete device;
}
// 線程主方法
void VideoThread::run(){
while(true){
// 抓取圖像育叁,發(fā)送信息
cv::Mat img;
device->read(img);
emit video(img);
QThread::usleep(100);
}
}
圖像處理類
- 頭文件
#ifndef IMAGE_PROCESSING_H
#define IMAGE_PROCESSING_H
#include <opencv2/opencv.hpp>
class ImageProcessing{
public:
ImageProcessing();
~ImageProcessing();
public:
void handle_filter2d(cv::InputArray img_src, cv::OutputArray img_out);
};
#endif // !IMAGE_PROCESSING_H
- 實現(xiàn)文件
#include "imageprocessing.h"
ImageProcessing::ImageProcessing(){
}
ImageProcessing::~ImageProcessing(){
}
void ImageProcessing::handle_filter2d(cv::InputArray img_src, cv::OutputArray img_dst){
cv::Mat kernel = (cv::Mat_<int>(3,3) <<
-1,-1,-1,
0, 0, 0,
1, 1, 1);
cv::filter2D(
img_src,
img_dst,
-1, // 輸出圖像的深度
kernel, // 濾波核
cv::Point2i(-1, -1), // 錨點
64.0, // 正向(加法運算)偏移值
cv::BORDER_REFLECT_101
);
}
UI文件的設計
信號傳遞的用戶類型處理
-
引入頭文件
#include<QMetaType>
-
申明需要注冊的類型
Q_DECLARE_METATYPE(cv::Mat);
-
注冊類型
qRegisterMetaType<cv::Mat>("Mat");
qRegisterMetaType<cv::Mat>("Mat&");
在主程序中注冊的完整代碼
#include <QApplication>
#include "dlgvideo.h"
#include <iostream>
#include<QMetaType>
Q_DECLARE_METATYPE(cv::Mat);
int main(int argc, char* argv[]) {
// 初始化QT應用
QApplication app(argc, argv);
qRegisterMetaType<cv::Mat>("Mat");
qRegisterMetaType<cv::Mat>("Mat&");
DlgVideo dlg;
dlg.show();
return app.exec();
}
對話框類
- 頭文件
#ifndef DLG_VIDEO_H
#define DLG_VIDEO_H
#include <opencv2/opencv.hpp>
#include <QDialog>
#include "ui_output.h"
#include "videoth.h"
#include "imageprocessing.h"
class DlgVideo: public QDialog{
Q_OBJECT
public:
DlgVideo(QWidget *parent = 0);
~DlgVideo();
private:
Ui::dlg_video *dlg;
VideoThread *th;
ImageProcessing *proc;
private slots:
void record();
void showImage(cv::Mat img);
};
#endif
- 實現(xiàn)文件
#include "dlgvideo.h"
#include <iostream>
// 構(gòu)造器與析構(gòu)器
DlgVideo::DlgVideo(QWidget *parent):
QDialog(parent),
dlg(new Ui::dlg_video()),
th(new VideoThread()),
proc(new ImageProcessing()){
dlg->setupUi(this);
QObject::connect(th, SIGNAL(video(cv::Mat)), this, SLOT(showImage(cv::Mat)));
th->start();
}
DlgVideo::~DlgVideo(){
th->terminate();
delete dlg; // 釋放對話框
delete th; // 線程對象釋放
delete proc;
}
// 線程信號發(fā)過來的圖像,并顯示
void DlgVideo::showImage(cv::Mat img){
if(img.empty()) return; // 圖像非空才顯示
cv::Mat img_src;
proc->handle_filter2d(img, img_src);
cv::Mat m_out;
// OpenCV到Qt的顏色格式轉(zhuǎn)換
cv::cvtColor(img_src, m_out, cv::COLOR_BGR2RGBA);
// 轉(zhuǎn)換為Qt圖像
QImage i_out(m_out.data, m_out.cols, m_out.rows, QImage::Format_RGBA8888);
// 轉(zhuǎn)換為組件能處理的像素格式
QPixmap p_out = QPixmap::fromImage(i_out);
// 顯示圖像
dlg->lbl_video->setPixmap(p_out);
// 縮放圖像適應組件大小
dlg->lbl_video->setScaledContents(true);
}
// 事件處理
void DlgVideo::record(){
}
Makefile
- 這個文件使用了文件處理函數(shù)芍殖,來生成moc文件豪嗽;因為有多個moc文件需要生成,所以還采用了循環(huán)豌骏。
- opencv的視頻處理需要的共享庫:
opencv_videoio
INCLUDES =-I/Users/yangqiang/Qt512/5.12.1/Src/qtbase/include \
-I/Users/yangqiang/Qt512/5.12.1/Src/qtbase/include/QtCore \
-I/Users/yangqiang/Qt512/5.12.1/Src/qtbase/include/GtGui \
-I/Users/yangqiang/Qt512/5.12.1/Src/qtbase/include/QtWidgets \
-I/Users/yangqiang/Qt512/5.12.1/Src/qtbase/include/QThread \
-I/usr/local/include/opencv4/
LIBS =-lopencv_core \
-lopencv_highgui \
-lopencv_imgcodecs \
-lopencv_imgproc \
-lopencv_videoio
FRAMEWORKS =-F/Users/yangqiang/Qt512/5.12.1/clang_64/lib \
-framework QtCore \
-framework QtGui \
-framework QtWidgets
LD_ARGS =-Wl,-rpath,/Users/yangqiang/Qt512/5.12.1/clang_64/lib
UICTOOL =/usr/local/Qt-5.12.1/bin/uic
MOCTOOL =/usr/local/Qt-5.12.1/bin/moc
HEADER =dlgvideo.h videoth.h
MOCS =$(HEADER:%.h=moc_%.cpp)
SOURCES =main.cpp dlgvideo.cpp videoth.cpp imageprocessing.cpp
UICS =ui_output.ui
UICH =$(UICS:%.ui=%.h)
main: $(SOURCES) $(UICH) $(MOCS)
g++ -omain $(SOURCES) $(MOCS) -std=c++11 $(INCLUDES) $(LIBS) $(FRAMEWORKS) $(LD_ARGS)
$(MOCS): $(HEADER)
$(foreach VAR, $(HEADER), $(MOCTOOL) -o $(VAR:%.h=moc_%.cpp) $(VAR);)
$(UICH): $(UICS)
$(UICTOOL) -o $(UICS:%.ui=%.h) $(UICS)
clean:
rm -f main $(MOCS) $(UICS:%.ui=%.h) moc_*.cpp
VideoWriter視頻存儲
- 視頻存儲的API與VideoCapture類似龟梦,主要包含:
- 構(gòu)造器
- 初始化
virtual bool open (const String &filename, int fourcc, double fps, Size frameSize, bool isColor=true)
- 是否初始化
virtual bool isOpened () const
- 寫入
virtual void write (InputArray image)
virtual VideoWriter & operator<< (const Mat &image)
- 釋放;
virtual void release ()
- 屬性設置
virtual double get (int propId) const
virtual bool set (int propId, double value)