1. 程式人生 > >opencv光流法對特定區域進行跟蹤

opencv光流法對特定區域進行跟蹤

本例子使用了opencv3.0,利用滑鼠選擇矩形框,然後對選擇的區域進行跟蹤

//---------------------------------光流法對特定區域進行跟蹤-----------------
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/video.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <cstdio> using namespace std; using namespace cv; //------------------------------------【全域性函式宣告】------------------------------ void tracking(Mat &frame,Mat &output); //-------------------------------------【全域性變數宣告】------------------------------- string window_name = "flow tracking"
; Mat gray; //當前幀圖片 Mat gray_prev; //預測幀圖片 Mat image; vector<Point2f> points[2]; //point0為特徵點的原來位置,point1位特徵點新的位置 vector<uchar> status; //跟蹤特徵的狀態,特徵的流發現為1,否則為0
vector<float> err; Rect selection; Point origin; //定義原點, Point pointCentral; bool selectObject = false; int trackObject = 0; static void onMouse(int event,int x,int y,int ,void*) { if(selectObject) { selection.x=MIN(x,origin.x); selection.y=MIN(y,origin.y); selection.width = abs(x-origin.x); selection.height = abs(y-origin.y); selection &= Rect(0,0,image.cols,image.rows); //保證selection在畫面的裡邊 } switch (event) { case EVENT_LBUTTONDOWN: origin = Point(x,y); selection = Rect(x,y,0,0); selectObject = true; break; case EVENT_LBUTTONUP: selectObject = false; if(selection.width > 0 && selection.height > 0) { trackObject = -1; } break; } } int main() { Mat frame;//定義視訊幀 Mat result;//定義結果 VideoCapture capture(0); //讀取視訊 if(capture.isOpened()) //如果視訊開啟成功,則進行以下步驟 { while(true) { capture>>frame; //讀取當前視訊幀到frame中 frame.copyTo(image); setMouseCallback(window_name,onMouse,0); if(!frame.empty()) //如果當前幀不為空 { tracking(image,result); //呼叫定義的函式,開始跟蹤 } else { cout<<"沒有視訊幀"; //否則報錯 break; } int c = waitKey(50); //每隔50ms重新整理一次 if((char)c == 27) //使用者在50ms以內按下“esc”這個按鍵,則跳出迴圈 { break; } switch (c) { case 'c': //停止追蹤 trackObject = 0; break; default: break; } } } return 0; } void tracking(Mat &frame,Mat &output) { cvtColor(frame,gray,COLOR_BGR2GRAY); //將當前的視訊幀轉換為灰度圖,儲存到gray中 frame.copyTo(output); //拷貝當前幀到輸出output中 if(selectObject) { rectangle(output,Point(selection.x,selection.y),Point(selection.x+selection.width, selection.y+selection.height),Scalar(255,0,0)); } //滑鼠擡起時,進行檢測 if(trackObject == -1) { //選取selection區域的中心點為初始點 pointCentral = Point(selection.x+selection.width/2,selection.y+selection.height/2); points[0].push_back(pointCentral); if(gray_prev.empty()) { gray.copyTo(gray_prev); //如果前一幀為空,則複製當前幀到前一幀 } if(points[0].size() == 0) { cout<<"這裡錯了;額"<<endl; } calcOpticalFlowPyrLK(gray_prev,gray, points[0],points[1],status,err); //繪製跟蹤框圖,以point【1】為中心,與selection的長和寬相同的矩形 rectangle(output,Point(points[1][0].x - selection.width/2,points[1][0].y+selection.height/2), Point(points[1][0].x + selection.width/2,points[1][0].y-selection.height/2),Scalar(255,0,0),3,8,0); //畫線,在output影象上,點initial[i]到點points[1][i]的直線段,顏色為(0,0,255) line(output,points[0][0],points[1][0],Scalar(0,0,255),4,8); //畫圓,在output影象上,圓心為point[1][i],半徑為3,圓的顏色為(0,255,0) circle(output,points[1][0],6,Scalar(0,255,0),-1,8); swap(points[1],points[0]); //交換特徵點容器points[0]和特徵點容器points[1] swap(gray_prev,gray); //把當前幀的影象賦值為上一幀影象,以便傳入下一次迭代的calcOpticalFlowPyrLK } imshow(window_name,output); //在視窗window_name展示輸出的結果 }