OpenCV之光流法运动目标跟踪
[光流Optical Flow]的概念是Gibson在1950年首先提出來的。它是空間運動物體在觀察成像平面上的像素運動的瞬時速度,是利用圖像序列中像素在時間域上的變化以及相鄰幀之間的相關(guān)性來找到上一幀跟當(dāng)前幀之間存在的對應(yīng)關(guān)系,從而計算出相鄰幀之間物體的運動信息的一種方法。
一般而言,光流是由于場景中前景目標(biāo)本身的移動、相機的運動,或者兩者的共同運動所產(chǎn)生的。當(dāng)人的眼睛觀察運動物體時,物體的景象在人眼的視網(wǎng)膜上形成一系列連續(xù)變化的圖像,這一系列連續(xù)變化的信息不斷流過視網(wǎng)膜(即圖像平面),好像一種光的流;,故稱之為光流(optical flow)。
光流表達了圖像的變化,由于它包含了目標(biāo)運動的信息,因此可被觀察者用來確定目標(biāo)的運動情況。從圖片序列中近似得到不能直接得到的運動場<運動場,其實就是物體在三維真實世界中的運動;光流場,是運動場在二維圖像平面上(人的眼睛或者攝像頭)的投影。
那通俗的講就是通過一個圖片序列,把每張圖像中每個像素的運動速度和運動方向找出來就是光流場。那怎么找呢?咱們直觀理解肯定是:第t幀的時候A點的位置是(x1, y1),那么我們在第t+1幀的時候再找到A點,假如它的位置是(x2,y2),那么我們就可以確定A點的運動了:(ux, vy) = (x2, y2) - (x1,y1)。?
那怎么知道第t+1幀的時候A點的位置呢? 這就存在很多的光流計算方法了。
光流計算方法
大致可分為三類:基于匹配的方法、頻域的方法和梯度的方法。
1. 基于匹配的光流計算方法包括基于特征和基于區(qū)域兩種
2. 基于頻域的方法,也稱為基于能量的方法,利用速度可調(diào)的濾波組輸出頻率或相位信息。
3. 基于梯度的方法利用圖像序列亮度的時空微分計算2D速度場(光流)。
當(dāng)前對于光流法的研究主要有兩個方向
一是研究在固有硬件平臺基礎(chǔ)上實現(xiàn)現(xiàn)有算法?
二是研究新的算法。
光流算法的主要目的就是基于序列圖像實現(xiàn)對光流場的可靠、快速、精確以及魯棒性的估計。然而,由于圖像序列目標(biāo)的特性、場景中照明,光源的變化、運動的速度以及噪聲的影響等多種因素影響著光流算法的有效性。
函數(shù)詳解
1.CalcOpticalFlowPyrLK
計算一個稀疏特征集的光流,使用金字塔中的迭代 Lucas-Kanade 方法?
C++函數(shù)代碼
函數(shù)參數(shù)詳解:
| prevImg | 深度為8位的前一幀圖像或金字塔圖像。 |
| nextImg | 和prevImg有相同的大小和類型,后一幀圖像或金字塔。 |
| prevPts | 計算光流所需要的輸入2D點矢量,點坐標(biāo)必須是單精度浮點數(shù)。 |
| nextPts | 輸出2D點矢量(也是單精度浮點數(shù)坐標(biāo)),點矢量中包含的是在后一幀圖像上計算得到的輸入特征新位置。 |
| status | 輸出狀態(tài)矢量(元素是無符號char類型,uchar),如果相應(yīng)特征的流發(fā)現(xiàn)則矢量元素置為1,否則,為0。 |
| err | 輸出誤差矢量。 |
| winSize | 每個金字塔層搜索窗大小。 |
| maxLevel | 金字塔層的最大數(shù)目;如果置0,金字塔不使用(單層);如果置1,金字塔2層,等等以此類推。 |
| criteria | 指定搜索算法收斂迭代的類型 |
| minEigTheshold | 算法計算的光流等式的2x2常規(guī)矩陣的最小特征值。 |
金字塔Lucas-Kannade算法:
LK算法有三個假設(shè):亮度恒定,即圖像場景中目標(biāo)的像素在幀間運動時外觀上保持不變;時間連續(xù)或者運動是”小運動“,即圖像的運動隨時間的變化比較緩慢;空間一致,即一個場景中同一表面上鄰近的點具有相似的運動。然而,對于大多數(shù)30HZ的攝像機,大而連貫的運動是普遍存在的情況,所以LK光流正因為這個原因在實際中的跟蹤效果并不是很好。我們需要大的窗口來捕獲大的運動,而大窗口往往違背運動連貫的假設(shè)!而圖像金字塔可以解決這個問題,于是乎,金字塔Lucas-Kanade就提出來了。?
金字塔Lucas-Kanade跟蹤方法是:在圖像金字塔的最高層計算光流,用得到的運動估計結(jié)果作為下一層金字塔的起始點,重復(fù)這個過程直到到達金字塔的最底層。這樣就將不滿足運動的假設(shè)可能性降到最小從而實現(xiàn)對更快和更長的運動的跟蹤。
2.cvGoodFeaturesToTrack
函數(shù) cvGoodFeaturesToTrack 在圖像中尋找具有大特征值的角點。該函數(shù),首先用cvCornerMinEigenVal 計算輸入圖像的每一個像素點的最小特征值,并將結(jié)果存儲到變量 eig_image 中。然后進行非最大值抑制(僅保留3x3鄰域中的局部最大值)。下一步將最小特征值小于 quality_level?max(eig_image(x,y)) 排除掉。最后,函數(shù)確保所有發(fā)現(xiàn)的角點之間具有足夠的距離,(最強的角點第一個保留,然后檢查新的角點與已有角點之間的距離大于 min_distance )。?
C++函數(shù)代碼
函數(shù)參數(shù)詳解:
| image | 輸入圖像,8-位或浮點32-比特,單通道 |
| eig_image | 臨時浮點32-位圖像,尺寸與輸入圖像一致 |
| temp_image | 另外一個臨時圖像,格式與尺寸與 eig_image 一致 |
| corners | 輸出參數(shù),檢測到的角點 |
| corner_count | 輸出參數(shù),檢測到的角點數(shù)目 |
| quality_level | 最大最小特征值的乘法因子。定義可接受圖像角點的最小質(zhì)量因子。 |
| min_distance | 限制因子。得到的角點的最小距離。使用 Euclidian 距離 |
| mask | ROI感興趣區(qū)域。函數(shù)在ROI中計算角點,如果 mask 為 NULL,則選擇整個圖像。 |
| block_size | 計算導(dǎo)數(shù)的自相關(guān)矩陣時指定點的領(lǐng)域,采用小窗口計算的結(jié)果比單點(也就是block_size為1)計算的結(jié)果要好。 |
| use_harris | 標(biāo)志位。當(dāng)use_harris的值為非0,則函數(shù)使用Harris的角點定義;若為0,則使用Shi-Tomasi的定義。 |
| k | 當(dāng)use_harris為k且非0,則k為用于設(shè)置Hessian自相關(guān)矩陣即對Hessian行列式的相對權(quán)重的權(quán)重系數(shù) |
實例代碼塊
本代碼參考@淺墨_毛星云的書籍《OpenCV3編程入門》,代碼版權(quán)歸老師所有,僅供學(xué)習(xí)借鑒只用。?
——博主
@--751407505@qq.com // 程序描述:來自O(shè)penCV安裝目錄下Samples文件夾中的官方示例程序-利用光流法進行運動目標(biāo)檢測 // 描述:包含程序所使用的頭文件和命名空間 #include <opencv2/video/video.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <iostream> #include <cstdio> using namespace std; using namespace cv; // 描述:聲明全局函數(shù) void tracking(Mat &frame, Mat &output); bool addNewPoints(); bool acceptTrackedPoint(int i); // 描述:聲明全局變量 string window_name = "optical flow tracking"; Mat gray; // 當(dāng)前圖片 Mat gray_prev; // 預(yù)測圖片 vector<Point2f> points[2]; // point0為特征點的原來位置,point1為特征點的新位置 vector<Point2f> initial; // 初始化跟蹤點的位置 vector<Point2f> features; // 檢測的特征 int maxCount = 500; // 檢測的最大特征數(shù) double qLevel = 0.01; // 特征檢測的等級 double minDist = 10.0; // 兩特征點之間的最小距離 vector<uchar> status; // 跟蹤特征的狀態(tài),特征的流發(fā)現(xiàn)為1,否則為0 vector<float> err; //輸出相應(yīng)信息和OpenCV版本----- static void helpinformation() {cout <<"\n\n\t\t\t 光流法跟蹤運動目標(biāo)檢測\n"<<"\n\n\t\t\t 當(dāng)前使用的OpenCV版本為:" << CV_VERSION <<"\n\n" ; }//main( )函數(shù),程序入口 int main() {Mat frame;Mat result;//加載使用的視頻文件,放在項目程序運行文件下VideoCapture capture("1.avi");//顯示信息函數(shù)helpinformation();// 攝像頭讀取文件開關(guān)if(capture.isOpened()) {while(true){capture >> frame;if(!frame.empty()){ tracking(frame, result);}else{ printf(" --(!) No captured frame -- Break!");break;}int c = waitKey(50);if( (char)c == 27 ){break; } }}return 0; }// parameter: frame 輸入的視頻幀 // output 有跟蹤結(jié)果的視頻幀 void tracking(Mat &frame, Mat &output) {cvtColor(frame, gray, CV_BGR2GRAY);frame.copyTo(output);// 添加特征點if (addNewPoints()){goodFeaturesToTrack(gray, features, maxCount, qLevel, minDist);points[0].insert(points[0].end(), features.begin(), features.end());initial.insert(initial.end(), features.begin(), features.end());}if (gray_prev.empty()){gray.copyTo(gray_prev);}// l-k光流法運動估計calcOpticalFlowPyrLK(gray_prev, gray, points[0], points[1], status, err);// 去掉一些不好的特征點int k = 0;for (size_t i=0; i<points[1].size(); i++){if (acceptTrackedPoint(i)){initial[k] = initial[i];points[1][k++] = points[1][i];}}points[1].resize(k);initial.resize(k);// 顯示特征點和運動軌跡for (size_t i=0; i<points[1].size(); i++){line(output, initial[i], points[1][i], Scalar(0, 0, 255));circle(output, points[1][i], 3, Scalar(0, 255, 0), -1);}// 把當(dāng)前跟蹤結(jié)果作為下一此參考swap(points[1], points[0]);swap(gray_prev, gray); imshow(window_name, output); }// 檢測新點是否應(yīng)該被添加 // return: 是否被添加標(biāo)志 bool addNewPoints() {return points[0].size() <= 10; }//決定哪些跟蹤點被接受 bool acceptTrackedPoint(int i) {return status[i] && ((abs(points[0][i].x - points[1][i].x) + abs(points[0][i].y - points[1][i].y)) > 2); }總結(jié)
以上是生活随笔為你收集整理的OpenCV之光流法运动目标跟踪的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Centos7配置阿里云的镜像加速器(2
- 下一篇: 感情与公交车