光流(optical flow)和openCV中實現(xiàn),,opticalopencv轉(zhuǎn)載請注明出處?。?!http://blog.csdn.net/zhonghuan1992 光流(optical flow)和openCV中實現(xiàn)光流的概念: 是Gibson在1950年首先提出來的,。它是空間運動物體在觀察成像平面上的像素運動的瞬時速度,是利用圖像序列中像素在時間域上的變化以及相鄰幀之間的相關(guān)性來找到上一幀跟當(dāng)前幀之間存在的對應(yīng)關(guān)系,,從而計算出相鄰幀之間物體的運動信息的一種方法,。一般而言,光流是由于場景中前景目標(biāo)本身的移動,、相機的運動,,或者兩者的共同運動所產(chǎn)生的。 當(dāng)人的眼睛觀察運動物體時,,物體的景象在人眼的視網(wǎng)膜上形成一系列連續(xù)變化的圖像,,這一系列連續(xù)變化的信息不斷“流過”視網(wǎng)膜(即圖像平面),好像一種光的“流”,,故稱之為光流(optical flow),。光流表達(dá)了圖像的變化,由于它包含了目標(biāo)運動的信息,,因此可被觀察者用來確定目標(biāo)的運動情況,。 看下面的圖,它展示了一個小球在5個連續(xù)的幀中的運動,,箭頭上的數(shù)字代表不同的幀,,那個紅色小球的運動構(gòu)成了光流。
操作: 給你一個圖上的一系列點,,在另外一張圖上找到與前面一些列點相同的點,。 或者給你圖I1上的點[ux, uy]T,找到I2上的點[ux + δx, uy + δy]T,,最小化ε:
上面加入Wx表示一塊區(qū)域,,一般跟蹤一個區(qū)域的點,。 在圖形學(xué)應(yīng)用中,在多張圖上跟蹤點(特征)是一項基本的操作:在一張圖上找到一個對象,,觀察對象如何移動,。 基于特征點的跟蹤算法大致可以分為兩個步驟: 1)探測當(dāng)前幀的特征點; 2)通過當(dāng)前幀和下一幀灰度比較,,估計當(dāng)前幀特征點在下一幀的位置,; 3)過濾位置不變的特征點,余下的點就是目標(biāo)了,。 特征點可以是Harris角點,,也可以是邊緣點等等。 考慮一個像素在第一幀的光強度(這里增加了一個維度時間,,前面的時候我們只是處理圖像,,所以沒有必要時間。現(xiàn)在需要增加這個維度),。它移動了 的距離到一下幀,,用了時間。因為像素點是一樣的,,光強度也沒有發(fā)生變化(其實這個光強度沒有改變是很多光流算法的基本假設(shè)),。,所以我們可以說: 然后通過泰勒級數(shù)近似展開有: 所以: 上面的等式叫做光流等式,,偏導(dǎo)數(shù)可以求出來,,可是 u和v是未知的,所以無法解決上的等式,。但是有很多方法可以解決這個問題,,其中一個叫做Lucas-Kanade方法。 Lucas-Kanade:有這么一個假定,,所有的相鄰像素有相似的行動,,Lucas-Kanade方法使用3*3的一塊區(qū)域,它假定這9個點有相同的行動,,所以現(xiàn)在的問題變?yōu)橛?個等式,,2個未知量,這個問題當(dāng)然能夠解決,。一個好的解決方式是使用最小二乘法,。 令n=9,于是便有了9個等式:
其中q1,,q2,,…,代表像素點,, 是偏導(dǎo),,上面的等式可以寫成下面的形式:A v = b,,其中: 然后,得到下面的:
最終算出來的兩個未知數(shù)的解是: 上面的解決小而連貫的運動,,想想剛剛我們的假設(shè)是9個像素點速度一致。因為現(xiàn)實中大而連貫的運動是普遍存在的,,我們需要大的窗口來捕獲運動,,可是大窗口違背了運動連貫的假設(shè),圖像金字塔可以解決這個問題,。(圖像金字塔的內(nèi)容以后本人掌握更多的再補充,,現(xiàn)在不敢亂發(fā)表)。 OpenCV中的實現(xiàn):OpenCV提供了對上面介紹的方法的支持,,函數(shù)名叫做:cv2.calcOpticalFlowPyrLK(),,現(xiàn)在讓我們在視頻中跟蹤一些點。為了決定跟蹤哪些點,,使用cv2.goodFeaturesToTrack(),。 我們得到第一幀,探測Shi-Tomasi角點,,然后我們使用 Lucas-Kanade光流法來跟綜這些點,。 #include "opencv2/video/tracking.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> #include <ctype.h> using namespace cv; using namespace std; static void help() { // print a welcome message, and the OpenCV version cout << "\nThis is ademo of Lukas-Kanade optical flow lkdemo(),\n" "Using OpenCVversion "<< CV_VERSION << endl; cout << "\nIt usescamera by default, but you can provide a path to video as an argument.\n"; cout << "\nHot keys:\n" "\tESC - quitthe program\n" "\tr -auto-initialize tracking\n" "\tc - deleteall the points\n" "\tn - switch the\"night\" mode on/off\n" "To add/removea feature point click it\n" << endl; } Point2f point; bool addRemovePt = false; static void onMouse(int event, int x, int y, int /*flags*/, void* /*param*/) { if (event == CV_EVENT_LBUTTONDOWN) { point = Point2f((float)x, (float)y); addRemovePt = true; } } int main(int argc, char** argv) { help(); VideoCapture cap; TermCriteria termcrit(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03); Size subPixWinSize(10, 10), winSize(31, 31); const int MAX_COUNT = 500; bool needToInit = false; bool nightMode = false; /*if (argc == 1 || (argc == 2 && strlen(argv[1])== 1 && isdigit(argv[1][0]))) cap.open(argc == 2 ? argv[1][0] - '0' :0); else if (argc == 2) cap.open(argv[1]);*/ cap.open("G:\\視頻分析入門練習(xí)\\視頻分析入門練習(xí) - 附件\\sample.avi"); if (!cap.isOpened()) { cout << "Could notinitialize capturing...\n"; return 0; } namedWindow("LK", 1); setMouseCallback("LK", onMouse, 0); Mat gray, prevGray, image; vector<Point2f> points[2]; for (;;) { Mat frame; cap >> frame; if (frame.empty()) break; frame.copyTo(image); cvtColor(image, gray, COLOR_BGR2GRAY); if (nightMode) image = Scalar::all(0); if (needToInit) { // automaticinitialization goodFeaturesToTrack(gray, points[1],100, 0.01, 10, Mat(), 3, 0, 0.04); cornerSubPix(gray, points[1],subPixWinSize, Size(-1, -1), termcrit); addRemovePt = false; } else if(!points[0].empty()) { vector<uchar> status; vector<float> err; if (prevGray.empty()) gray.copyTo(prevGray); calcOpticalFlowPyrLK(prevGray, gray,points[0], points[1], status, err, winSize, 3, termcrit, 0, 0.001); size_t i, k; for (i = k = 0; i <points[1].size(); i++) { if (addRemovePt) { if (norm(point -points[1][i]) <= 5) { addRemovePt = false; continue; } } if (!status[i]) continue; points[1][k++] = points[1][i]; circle(image, points[1][i], 3, Scalar(0, 255, 0), -1, 8); } points[1].resize(k); } if (addRemovePt&& points[1].size() < (size_t)MAX_COUNT) { vector<Point2f> tmp; tmp.push_back(point); cornerSubPix(gray, tmp, winSize,cvSize(-1, -1), termcrit); points[1].push_back(tmp[0]); addRemovePt = false; } needToInit = false; imshow("LK", image); char c = (char)waitKey(100); if (c == 27) break; switch (c) { case 'r': needToInit = true; break; case 'c': points[0].clear(); points[1].clear(); break; case 'n': nightMode = !nightMode; break; } std::swap(points[1], points[0]); cv::swap(prevGray, gray); } return 0; }
結(jié)果:隨意取得一些特征點,特征點會隨著車的移動而移動
在opencv中calcOpticalFlowPyrLK 函數(shù)有計算出光流矢量這個不是計算出矢量 是預(yù)測出下一個點出現(xiàn)的位置 這個函數(shù)會一系列的點返回…… 什叫光流,?光流(optical flow)法是目前運動圖像分析的重要方法,,它的概念是由Gibso。于1950年首先提出的,,是指時變圖像中模式運動速度,。因為當(dāng)物體在運動時,它在圖像上對應(yīng)點的亮度模式也在運動,。這種圖像亮度模式的表觀運動(apparent motion)就是光流,。光流表達(dá)了圖像的變化,由于它包含了目標(biāo)運動的信息,,因此可被觀察者用來確定目標(biāo)的運動情況,。 由光流的定義可以引申出光流場,它是指圖像中所有像素點構(gòu)成的一種二維(2D)瞬時速度場,,其中的二維速度矢量是景物中可見點的三維速度矢量在成像表面的投影,。所以光流不僅包含了被觀察物體的運動信息,而且還包含有關(guān)景物三維結(jié)構(gòu)的豐富信息,。 對光流的研究成為計算機視覺及有關(guān)研究領(lǐng)域中的一個重要部分,。因為在計算機視覺中,光流扮演著重要角色,,在目標(biāo)對象分割,、識別,、跟蹤、機器人導(dǎo)航以及形狀信息恢復(fù)等都有著非常重要的應(yīng)用,。從光流中恢復(fù)物體三維結(jié)構(gòu)和運動則是計算機視覺研究所面臨的最富有意義和挑戰(zhàn)性的任務(wù)之一,。正是由于光流的這種重要地位和作用,使得眾多的心理物理學(xué)家,、生理學(xué)家和工程研究人員都加入了它的研究行列,。十多年來,他們提出了許多種計算光流的方法,,而且新的方法還在不斷涌現(xiàn),。 |
|