opencv求两张图像光流_光流(optical flow)和openCV中实现
轉(zhuǎn)載請(qǐng)注明出處!
!
!
光流(optical flow)和openCV中實(shí)現(xiàn)
光流的概念:
是Gibson在1950年首先提出來(lái)的。
它是空間運(yùn)動(dòng)物體在觀察成像平面上的像素運(yùn)動(dòng)的瞬時(shí)速度。是利用圖像序列中像素在時(shí)間域上的變化以及相鄰幀之間的相關(guān)性來(lái)找到上一幀跟當(dāng)前幀之間存在的相應(yīng)關(guān)系,從而計(jì)算出相鄰幀之間物體的運(yùn)動(dòng)信息的一種方法。
一般而言。光流是因?yàn)閳?chǎng)景中前景目標(biāo)本身的移動(dòng)、相機(jī)的運(yùn)動(dòng),或者兩者的共同運(yùn)動(dòng)所產(chǎn)生的。
當(dāng)人的眼睛觀察運(yùn)動(dòng)物體時(shí),物體的景象在人眼的視網(wǎng)膜上形成一系列連續(xù)變化的圖像。這一系列連續(xù)變化的信息不斷“流過(guò)”視網(wǎng)膜(即圖像平面)。好像一種光的“流”,故稱之為光流(optical flow)。光流表達(dá)了圖像的變化,因?yàn)樗四繕?biāo)運(yùn)動(dòng)的信息。因此可被觀察者用來(lái)確定目標(biāo)的運(yùn)動(dòng)情況。
看以下的圖。它展示了一個(gè)小球在5個(gè)連續(xù)的幀中的運(yùn)動(dòng)。箭頭上的數(shù)字代表不同的幀。那個(gè)紅色小球的運(yùn)動(dòng)構(gòu)成了光流。
操作:
給你一個(gè)圖上的一系列點(diǎn),在另外一張圖上找到與前面一些列點(diǎn)同樣的點(diǎn)。
或者給你圖I1上的點(diǎn)[ux, uy]T。找到I2上的點(diǎn)[ux
+ δx, uy + δy]T。最小化ε:
上面增加Wx表示一塊區(qū)域,一般跟蹤一個(gè)區(qū)域的點(diǎn)。
在圖形學(xué)應(yīng)用中。在多張圖上跟蹤點(diǎn)(特征)是一項(xiàng)主要的操作:在一張圖上找到一個(gè)對(duì)象,觀察對(duì)象怎樣移動(dòng)。
基于特征點(diǎn)的跟蹤算法大致能夠分為兩個(gè)步驟:
1)探測(cè)當(dāng)前幀的特征點(diǎn);
2)通過(guò)當(dāng)前幀和下一幀灰度比較,預(yù)計(jì)當(dāng)前幀特征點(diǎn)在下一幀的位置;
3)過(guò)濾位置不變的特征點(diǎn),余下的點(diǎn)就是目標(biāo)了。
特征點(diǎn)能夠是Harris角點(diǎn),也能夠是邊緣點(diǎn)等等。
考慮一個(gè)像素
在第一幀的光強(qiáng)度(這里添加了一個(gè)維度時(shí)間。前面的時(shí)候我們僅僅是處理圖像。所以沒(méi)有必要時(shí)間。如今須要添加這個(gè)維度)。它移動(dòng)了?
的距離到一下幀。用了
時(shí)間。
由于像素點(diǎn)是一樣的。光強(qiáng)度也沒(méi)有發(fā)生變化(事實(shí)上這個(gè)光強(qiáng)度沒(méi)有改變是非常多光流算法的基本如果)。。所以我們能夠說(shuō):
然后通過(guò)泰勒級(jí)數(shù)近似展開有:
所以:
上面的等式叫做光流等式,偏導(dǎo)數(shù)能夠求出來(lái)。但是 u和v是未知的,所以無(wú)法解決上的等式。但是有非常多方法能夠解決問(wèn)題,當(dāng)中一個(gè)叫做Lucas-Kanade方法。
Lucas-Kanade:
有這么一個(gè)假定,全部的相鄰像素有相似的行動(dòng),Lucas-Kanade方法使用3*3的一塊區(qū)域,它假定這9個(gè)點(diǎn)有同樣的行動(dòng),所以如今的問(wèn)題變?yōu)橛?個(gè)等式,2個(gè)未知量,這個(gè)問(wèn)題當(dāng)然可以解決。一個(gè)好的解決方案是使用最小二乘法。
令n=9,于是便有了9個(gè)等式:
當(dāng)中q1,q2,…,代表像素點(diǎn),
是偏導(dǎo),上面的等式能夠?qū)懗梢韵碌男问?#xff1a;A
v = b,當(dāng)中:
然后,得到以下的:
終于算出來(lái)的兩個(gè)未知數(shù)的解是:
上面的解決小而連貫的運(yùn)動(dòng)。想想剛剛我們的如果是9個(gè)像素點(diǎn)速度一致。由于現(xiàn)實(shí)中大而連貫的運(yùn)動(dòng)是普遍存在的,我們須要大的窗體來(lái)捕獲運(yùn)動(dòng)。但是大窗體違背了運(yùn)動(dòng)連貫的如果。圖像金字塔能夠解決問(wèn)題。(圖像金字塔的內(nèi)容以后本人掌握很多其它的再補(bǔ)充。如今不敢亂發(fā)表)。
OpenCV中的實(shí)現(xiàn):
OpenCV提供了對(duì)上面介紹的方法的支持。函數(shù)名叫做:cv2.calcOpticalFlowPyrLK(),如今讓我們?cè)谝曨l中跟蹤一些點(diǎn)。
為了決定跟蹤哪些點(diǎn),使用cv2.goodFeaturesToTrack()。
我們得到第一幀。探測(cè)Shi-Tomasi角點(diǎn),然后我們使用?Lucas-Kanade光流法來(lái)跟綜這些點(diǎn)。
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include
#include
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 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 status;
vector 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
{
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 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é)果:任意取得一些特征點(diǎn)。特征點(diǎn)會(huì)隨著車的移動(dòng)而移動(dòng)
總結(jié)
以上是生活随笔為你收集整理的opencv求两张图像光流_光流(optical flow)和openCV中实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: apache的es的原理_Elastic
- 下一篇: sts可以安装stylus插件吗_sty