OpenCV使用稀疏光流實(shí)現(xiàn)視頻對(duì)象跟蹤的方法詳解
1、概述
案例:使用稀疏光流實(shí)現(xiàn)對(duì)象跟蹤
稀疏光流API介紹:
calcOpticalFlowPyrLK( InputArray prevImg, InputArray nextImg, InputArray prevPts, InputOutputArray nextPts, OutputArray status, OutputArray err, Size winSize = Size(21,21), int maxLevel = 3, TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01), int flags = 0, double minEigThreshold = 1e-4 );
- prevImg:視頻前一幀圖像/金字塔,單通道CV_8UC1
- nextImg:視頻后一幀圖像/金字塔,單通道CV_8UC1
- preVPts:前一幀圖像的特征向量(輸入)需要找到流的2D點(diǎn)的矢量(vector of 2D points for which the flow needs to be found;);點(diǎn)坐標(biāo)必須是單精度浮點(diǎn)數(shù)
- nextPts:后一幀圖像的特征向量(輸出),輸出二維點(diǎn)的矢量(具有單精度浮點(diǎn)坐標(biāo)),包含第二圖像中輸入特征的計(jì)算新位置;當(dāng)傳遞OPTFLOW_USE_INITIAL_FLOW標(biāo)志時(shí),向量必須與輸入中的大小相同。
- status:輸出狀態(tài)向量(無符號(hào)字符);如果找到相應(yīng)特征的流,則向量的每個(gè)元素設(shè)置為1,否則設(shè)置為0
- err:輸出錯(cuò)誤的矢量; 向量的每個(gè)元素都設(shè)置為相應(yīng)特征的錯(cuò)誤,錯(cuò)誤度量的類型可以在flags參數(shù)中設(shè)置; 如果未找到流,則未定義錯(cuò)誤(使用status參數(shù)查找此類情況)
- winSize:每個(gè)金字塔等級(jí)的搜索窗口的winSize大小
- maxLevel:基于0的最大金字塔等級(jí)數(shù);如果設(shè)置為0,則不使用金字塔(單級(jí)),如果設(shè)置為1,則使用兩個(gè)級(jí)別,依此類推;如果將金字塔傳遞給輸入,那么算法將使用與金字塔一樣多的級(jí)別,但不超過maxLevel
- criteria:停止條件,指定迭代搜索算法的終止條件(在指定的最大迭代次數(shù)criteria.maxCount之后或當(dāng)搜索窗口移動(dòng)小于criteria.epsilon時(shí))。
- flags:操作標(biāo)志,OPTFLOW_USE_INITIAL_FLOW使用初始估計(jì),存儲(chǔ)在nextPts中;如果未設(shè)置標(biāo)志,則將prevPts復(fù)制到nextPts并將其視為初始估計(jì)。
- OPTFLOW_LK_GET_MIN_EIGENVALS使用最小特征值作為誤差測(cè)量(參見minEigThreshold描述);如果沒有設(shè)置標(biāo)志,則將原稿周圍的色塊和移動(dòng)點(diǎn)之間的L1距離除以窗口中的像素?cái)?shù),用作誤差測(cè)量
- minEigThreshold:算法計(jì)算光流方程的2x2正常矩陣的最小特征值,除以窗口中的像素?cái)?shù);如果此值小于minEigThreshold,則過濾掉相應(yīng)的功能并且不處理其流程,因此它允許刪除壞點(diǎn)并獲得性能提升
算法實(shí)現(xiàn)步驟:
1.實(shí)例化VideoCapture
2.循環(huán)讀取視頻數(shù)據(jù)
3.視頻幀灰度轉(zhuǎn)換
4.執(zhí)行角點(diǎn)檢測(cè)
5.保存角點(diǎn)檢測(cè)的特征數(shù)據(jù)
6.初始化時(shí)如果檢測(cè)到前一幀為空,把當(dāng)前幀的灰度圖像給前一幀
7.執(zhí)行光流跟蹤,并輸出跟蹤后的特征向量
8.遍歷光流跟蹤的輸出特征向量,并得到距離和狀態(tài)都符合預(yù)期的特征向量。讓后將其重新填充到fpts[1]中備用
9.重置集合大小
10.繪制光流線
11.交換特征向量的輸入和輸出
12.將用于跟蹤的角點(diǎn)繪制出來
13.展示最終的跟蹤效果
14.循環(huán)3~13步驟
15.結(jié)束
2、代碼示例
KLT_Object_Tracking::KLT_Object_Tracking(QWidget *parent) : MyGraphicsView{parent} { isShowLine = false; this->setWindowTitle("KLT稀疏光流實(shí)現(xiàn)對(duì)象跟蹤"); QPushButton *btn = new QPushButton(this); btn->setText("選擇視頻"); connect(btn,&QPushButton::clicked,[=](){ //選擇視頻 path = QFileDialog::getOpenFileName(this,"請(qǐng)選擇視頻","/Users/yangwei/Downloads/",tr("Image Files(*.mp4 *.avi)")); qDebug()<<"視頻路徑:"<<path; startKltTracking(path.toStdString().c_str()); }); // QButtonGroup * group = new QButtonGroup(this); QRadioButton * radioNo = new QRadioButton(this); radioNo->setText("否"); radioNo->setChecked(true); QRadioButton *radioYes = new QRadioButton(this); radioYes->setText("是"); group->addButton(radioNo,0); group->addButton(radioYes,1); radioNo->move(0,btn->y()+btn->height()+20); radioYes->move(radioNo->x()+radioNo->width()+20,btn->y()+btn->height()+20); connect(radioNo,&QRadioButton::clicked,[=](){ isShowLine = false;//顯示光流線 }); connect(radioYes,&QRadioButton::clicked,[=](){ isShowLine = true;//不顯示光流線 }); } void KLT_Object_Tracking::startKltTracking(const char* filePath){ //【1】實(shí)例化VideoCapture并打開視頻 VideoCapture capture;//實(shí)例化視頻捕獲器 capture.open(filePath);//打開視頻文件(或攝像頭) if(!capture.isOpened()){//檢測(cè)文件是否打開,如果沒打開直接退出 qDebug()<<"無法打開視頻"; return; } Mat frame,gray; vector<Point2f> features;//檢測(cè)出來的角點(diǎn)集合 vector<Point2f> inPoints;//這個(gè)主要是為了畫線用的 vector<Point2f> fpts[2];//[0],存入的是是二維特征向量,[1]輸出的二維特征向量 Mat pre_frame,pre_gray; vector<uchar> status;//光流輸出狀態(tài) vector<float> err;//光流輸出錯(cuò)誤 //【2】循環(huán)讀取視頻 while(capture.read(frame)){//循環(huán)讀取視頻中每一幀的圖像 //【3】將視頻幀圖像轉(zhuǎn)為灰度圖 cvtColor(frame,gray,COLOR_BGR2GRAY);//ps:角點(diǎn)檢測(cè)輸入要求單通道 //【4】如果特征向量(角點(diǎn))小于40個(gè)我們就重新執(zhí)行角點(diǎn)檢測(cè) if(fpts[0].size()<40){//如果小于40個(gè)角點(diǎn)就重新開始執(zhí)行角點(diǎn)檢測(cè) //執(zhí)行角點(diǎn)檢測(cè) goodFeaturesToTrack(gray,features,5000,0.01,10,Mat(),3,false,0.04); //【5】將檢測(cè)到的角點(diǎn)放入fpts[0]中作為,光流跟蹤的輸入特征向量 //將檢測(cè)到的角點(diǎn)插入vector fpts[0].insert(fpts[0].begin(),features.begin(),features.end()); inPoints.insert(inPoints.end(),features.begin(),features.end()); qDebug()<<"角點(diǎn)檢測(cè)執(zhí)行完成,角點(diǎn)個(gè)數(shù)為:"<<features.size(); }else{ qDebug()<<"正在跟蹤..."; } //【6】初始化的時(shí)候如果檢測(cè)到前一幀為空,這個(gè)把當(dāng)前幀的灰度圖像給前一幀 if(pre_gray.empty()){//如果前一幀為空就給前一幀賦值一次 gray.copyTo(pre_gray); } //執(zhí)行光流跟蹤 qDebug()<<"開始執(zhí)行光流跟蹤"; //【7】執(zhí)行光流跟蹤,并將輸出的特征向量放入fpts[1]中 calcOpticalFlowPyrLK(pre_gray,gray,fpts[0],fpts[1],status,err); qDebug()<<"光流跟蹤執(zhí)行結(jié)束"; //【8】遍歷光流跟蹤的輸出特征向量,并得到距離和狀態(tài)都符合預(yù)期的特征向量。讓后將其重新填充到fpts[1]中備用 int k =0; for(size_t i=0;i<fpts[1].size();i++){//循環(huán)遍歷二維輸出向量 double dist = abs(fpts[0][i].x - fpts[1][i].x) + abs(fpts[0][i].y - fpts[1][i].y);//特征向量移動(dòng)距離 if(dist>2&&status[i]){//如果距離大于2,status=true(正常) inPoints[k] = inPoints[i]; fpts[1][k++] = fpts[1][i]; } } //【9】重置集合大?。ㄓ捎谟绣e(cuò)誤/不符合條件的輸出特征向量),只拿狀態(tài)正確的 //重新設(shè)置集合大小 inPoints.resize(k); fpts[1].resize(k); //【10】繪制光流線,這一步要不要都行 //繪制光流線 if(isShowLine){ for(size_t i = 0;i<fpts[1].size();i++){ line(frame,inPoints[i],fpts[1][i],Scalar(0,255,0),1,8,0); circle(frame, fpts[1][i], 2, Scalar(0, 0, 255), 2, 8, 0); } } qDebug()<<"特征向量的輸入輸出交換數(shù)據(jù)"; //【11】交換特征向量的輸入和輸出,(循環(huán)往復(fù)/進(jìn)入下一個(gè)循環(huán)),此時(shí)特征向量的值會(huì)遞減 std::swap(fpts[1],fpts[0]);//交換特征向量的輸入和輸出,此處焦點(diǎn)的總數(shù)量會(huì)遞減 //【12】將用于跟蹤的角點(diǎn)繪制出來 //將角點(diǎn)繪制出來 for(size_t i = 0;i<fpts[0].size();i++){ circle(frame,fpts[0][i],2,Scalar(0,0,255),2,8,0); } //【13】重置前一幀圖像(每一個(gè)循環(huán)都要刷新) gray.copyTo(pre_gray); frame.copyTo(pre_frame); //【14】展示最終的效果 imshow("frame",frame); int keyValue = waitKey(100); if(keyValue==27){//如果用戶按ese鍵退出播放 break; } } }
3、圖像演示
到此這篇關(guān)于OpenCV使用稀疏光流實(shí)現(xiàn)視頻對(duì)象跟蹤的方法詳解的文章就介紹到這了,更多相關(guān)OpenCV視頻對(duì)象跟蹤內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言深入探究sizeof與整型數(shù)據(jù)存儲(chǔ)及數(shù)據(jù)類型取值范圍
在main函數(shù)中,sizeof是可以正常工作的,但是在自定義函數(shù)中就不可以了。所以本文將為大家詳細(xì)講解一下關(guān)鍵字sizeof、整型數(shù)據(jù)存儲(chǔ)深入、數(shù)據(jù)類型取值范圍深入2022-07-07OpenCV實(shí)現(xiàn)圖像轉(zhuǎn)換為漫畫效果
這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)圖像轉(zhuǎn)換為漫畫效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08C語言中計(jì)算字符串長(zhǎng)度與分割字符串的方法
這篇文章主要介紹了C語言中計(jì)算字符串長(zhǎng)度與分割字符串的方法,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-08-08C++替換棧中和.data中的cookie實(shí)現(xiàn)步驟詳解
這篇文章主要介紹了C++替換棧中和.data中的cookie實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-10-10C++實(shí)現(xiàn)惡搞電腦關(guān)機(jī)小程序的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C++實(shí)現(xiàn)一個(gè)簡(jiǎn)單的惡搞電腦關(guān)機(jī)小程序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-11-11VC實(shí)現(xiàn)ODBC數(shù)據(jù)庫(kù)操作實(shí)例解析
這篇文章主要介紹了VC實(shí)現(xiàn)ODBC數(shù)據(jù)庫(kù)操作的方法,非常有實(shí)用價(jià)值,需要的朋友可以參考下2014-07-07C++簡(jiǎn)單又輕松的講解類和對(duì)象中友元函數(shù)
采用類的機(jī)制后實(shí)現(xiàn)了數(shù)據(jù)的隱藏與封裝,類的數(shù)據(jù)成員一般定義為私有成員,成員函數(shù)一般定義為公有的,依此提供類與外界間的通信接口。但是,有時(shí)需要定義一些函數(shù),這些函數(shù)不是類的一部分,但又需要頻繁地訪問類的數(shù)據(jù)成員,這時(shí)可以將這些函數(shù)定義為該類的友元函數(shù)2022-06-06C語言實(shí)現(xiàn)計(jì)算雙色球的中獎(jiǎng)率
這篇文章主要為大家詳細(xì)介紹了如何利用C語言實(shí)現(xiàn)計(jì)算雙色球的中獎(jiǎng)率,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-12-12