运动目标检测__光流法
以下內(nèi)容摘自一篇碩士論文《視頻序列中運(yùn)動(dòng)目標(biāo)檢測與跟蹤算法的研究》:
1950年Gibson首先提出了光流的概念,光流(optical flow)法是空間運(yùn)動(dòng)物體在觀測成像面上的像素運(yùn)動(dòng)的瞬時(shí)速度。物體在運(yùn)動(dòng)的時(shí)候,它在圖像上對(duì)應(yīng)點(diǎn)的亮度模式也在做相應(yīng)的運(yùn)動(dòng),這種圖像亮度模式的表觀運(yùn)動(dòng)就是光流。光流的研究就是利用圖像序列中像素的強(qiáng)度數(shù)據(jù)的時(shí)域變化和相關(guān)性來確定各自像素位置的“運(yùn)動(dòng)”。光流表達(dá)了圖像的變化,因此可被觀察者用來確定目標(biāo)的運(yùn)動(dòng)情況。一般情況下,光流由相機(jī)運(yùn)動(dòng)、場景中目標(biāo)運(yùn)動(dòng)或兩者的共同運(yùn)動(dòng)產(chǎn)生。
光流場是由光流引申出來的,它指的是景物中可見像素點(diǎn)的三維速度矢量在成像表面投影形成的二維瞬時(shí)速度場。空間中的運(yùn)動(dòng)場轉(zhuǎn)移到圖像上就表示為光流場,光流場反映了圖像上每一點(diǎn)的灰度變化趨勢。光流場包含了被觀察物體的運(yùn)動(dòng)信息以及有關(guān)景物豐富的三維結(jié)構(gòu)的信息,它是如今計(jì)算機(jī)視覺及有關(guān)研究領(lǐng)域中的一個(gè)重要組成部分。
光流法檢測運(yùn)動(dòng)目標(biāo),其基本思想是賦予圖像中的每一個(gè)像素點(diǎn)一個(gè)速度矢量,從而形成了該圖像的運(yùn)動(dòng)場。圖像上的點(diǎn)和三維物體上的點(diǎn)在某一特定的運(yùn)動(dòng)時(shí)刻是一一對(duì)應(yīng)的,根據(jù)各像素點(diǎn)的速度矢量特征對(duì)圖像進(jìn)行動(dòng)態(tài)的分析。若圖像中不存在運(yùn)動(dòng)目標(biāo),那么光流矢量在整個(gè)圖像區(qū)域則是連續(xù)變化的,而當(dāng)物體和圖像背景中存在相對(duì)運(yùn)動(dòng)時(shí),運(yùn)動(dòng)物體所形成的速度矢量則必然不同于鄰域背景的速度矢量,從而將運(yùn)動(dòng)物體的位置檢測出來。
光流不能由運(yùn)動(dòng)圖像的局部信息來唯一的確定,例如,亮度等值線上的點(diǎn)或者亮度比較均勻的區(qū)域都無法唯一的確定其點(diǎn)的運(yùn)動(dòng)對(duì)應(yīng)性,但是運(yùn)動(dòng)是可以進(jìn)行觀察得到。由此說明運(yùn)動(dòng)場和光流不一定是唯一對(duì)應(yīng)的,即光流不一定是由物體運(yùn)動(dòng)產(chǎn)生的,反之如果物體發(fā)生了運(yùn)動(dòng)也不一定就能產(chǎn)生光流。但是一般情況下,表觀運(yùn)動(dòng)和物體真實(shí)運(yùn)動(dòng)之間的差異是可以忽略的,可以用光流場代替運(yùn)動(dòng)場來分析圖像中的運(yùn)動(dòng)目標(biāo)及其相關(guān)的運(yùn)動(dòng)參數(shù)。
可以證明動(dòng)能場不僅僅是分塊連續(xù)的,并且其間斷點(diǎn)恰好為物體的邊緣。如此,我們便可以利用圖像每一幀的運(yùn)動(dòng)場,在動(dòng)能變化矩陣中提取極值點(diǎn),便可以得到運(yùn)動(dòng)物體的邊緣。可將動(dòng)能大致相同的點(diǎn)歸于同一物體,進(jìn)而對(duì)圖像序列進(jìn)行分割,從而檢測出多個(gè)運(yùn)動(dòng)目標(biāo)。這樣,我們就將運(yùn)動(dòng)目標(biāo)檢測問題,借助光流場轉(zhuǎn)換為靜態(tài)圖像的區(qū)域分割問題。
算法步驟如下:
(1)令i=1,獲得第i幀圖像I(x,i);
(2)獲得第i+1幀圖像I(x,i+1);
(3)對(duì)圖像去噪,得到去燥后圖像I '(x, i)和I '(x, i+1);
(4)利用I '(x, i)和I '(x, i+1)計(jì)算得到光流場;
(5)計(jì)算得到局部動(dòng)能場K(i);
(6)利用邊緣檢測算法(如基于小波的方法)局部動(dòng)能場并分割圖像得到不同的運(yùn)動(dòng)單元也理解為一個(gè)運(yùn)動(dòng)單元);
(7)由于目標(biāo)一般較背景小,故提取出體積較運(yùn)動(dòng)單元作為檢測目標(biāo);
(8)計(jì)算其質(zhì)心作為目標(biāo)位置;
(9)置i=i+1,重復(fù)(2)~(8),直至檢測結(jié)束。
基于光流場分析的運(yùn)動(dòng)目標(biāo)檢測方法,不僅包含了被觀察物體的運(yùn)動(dòng)信息,而且攜帶了三維結(jié)構(gòu)的豐富信息,因此它不僅可以用于運(yùn)動(dòng)目標(biāo)檢測,還可以直接應(yīng)用于運(yùn)動(dòng)目標(biāo)跟蹤,能夠很精確的計(jì)算出運(yùn)動(dòng)目標(biāo)的速度,同時(shí)在攝像機(jī)存在運(yùn)動(dòng)的情況下也能夠檢測出運(yùn)動(dòng)目標(biāo)。而在實(shí)際的應(yīng)用中,由于存在多光源、遮擋性、噪聲和透明性等多方面的原因,光流場基本方程中的灰度守恒這個(gè)假設(shè)條件是得不到滿足的,因此不能求解出正確的光流場,同時(shí)由于其采用的是迭代的求解計(jì)算方法,故需要的計(jì)算時(shí)間比較長,從而無法滿足實(shí)時(shí)的要求,并且該方法受噪聲的影響較大,因而該方法多適用于目標(biāo)運(yùn)動(dòng)速度不大,圖像噪聲比較小的情況。
轉(zhuǎn)自:http://blog.csdn.net/zht9961020/article/details/7032059
cvCalcOpticalFlowPyrLK 函數(shù)在使用時(shí),首先要確定特征點(diǎn),也就是目標(biāo)舊的位置。
本程序通過使用cvGoodFeaturesToTrack 函數(shù)選擇角點(diǎn)作為特征點(diǎn)。
本程序只是一個(gè)簡單的運(yùn)動(dòng)檢測,在具體應(yīng)用過程中,可以根據(jù)自己的需要修正
#include <cv.h>
#include <highgui.h>
?
int main (int argc, char **argv)
{?
??? CvCapture* capture = 0;
??? capture = cvCaptureFromCAM(? CV_CAP_ANY );?
?
??? int i;
?
??? int corner_count = 1000;?
?
??? CvTermCriteria criteria;?
??? criteria = cvTermCriteria (CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 64, 0.01);
?
??? IplImage *src_img1;
??? IplImage *src_img2;
??? IplImage *dst_img;
??? IplImage *pre_img;
?
??? IplImage *eig_img;
??? IplImage *temp_img;
??? IplImage *prev_pyramid;
??? IplImage *curr_pyramid;
?
??? CvPoint2D32f *corners1;
??? CvPoint2D32f *corners2;?
??? corners1 = (CvPoint2D32f *) cvAlloc (corner_count * sizeof (CvPoint2D32f));?
??? corners2 = (CvPoint2D32f *) cvAlloc (corner_count * sizeof (CvPoint2D32f));
??? cvNamedWindow ("Image", 1);
??? char *status;
??? status = (char *) cvAlloc (corner_count);?
??? while (1)
??? {
??????? pre_img = cvQueryFrame(capture);
?
??????? CvSize img_sz = cvGetSize(pre_img);
??????? src_img1 = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
??????? cvCvtColor(pre_img, src_img1, CV_RGB2GRAY);
?
??????? dst_img = cvQueryFrame(capture);
??????? src_img2 = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
??????? cvCvtColor(dst_img, src_img2, CV_RGB2GRAY);
?
??????? eig_img = cvCreateImage (img_sz, IPL_DEPTH_32F, 1);
??????? temp_img = cvCreateImage (img_sz, IPL_DEPTH_32F, 1);
?
??????? prev_pyramid = cvCreateImage (cvSize (src_img1->width + 8, src_img1->height / 3), IPL_DEPTH_8U, 1);?
??????? curr_pyramid = cvCreateImage (cvSize (src_img1->width + 8, src_img1->height / 3), IPL_DEPTH_8U, 1);
?
??????? cvGoodFeaturesToTrack (src_img1, eig_img, temp_img, corners1, &corner_count, 0.001, 5, NULL);
?
??????? cvCalcOpticalFlowPyrLK (src_img1, src_img2, prev_pyramid, curr_pyramid,??????????????????????
??????????? corners1, corners2, corner_count, cvSize (10, 10), 4, status, NULL, criteria, 0);?
?
??????? for (i = 0; i < corner_count; i++)
??????? {???
??????????? if (status[i])?????
??????????????? cvLine (dst_img, cvPointFrom32f (corners1[i]), cvPointFrom32f (corners2[i]), CV_RGB (255, 0, 0), 1, CV_AA, 0);?
??????? }?
?
??????? cvShowImage ("Image", dst_img);?
??????? cvWaitKey (1);
??????? cvReleaseImage (&src_img1);?
??????? cvReleaseImage (&src_img2);
??????? cvReleaseImage (&eig_img);
??????? cvReleaseImage (&temp_img);?
??????? cvReleaseImage (&prev_pyramid);?
??????? cvReleaseImage (&curr_pyramid);
??? }
?
??? cvDestroyWindow ("Image");
??? cvReleaseImage (&dst_img);
??? cvReleaseImage(&pre_img);
??? return 0;
}
轉(zhuǎn)自:http://blog.csdn.net/zht9961020/article/details/7032061
cvCalcOpticalFlowPyrLK 需要確定特征點(diǎn)。
本程序,通過幀差獲得運(yùn)動(dòng)的點(diǎn)作為特征點(diǎn)。
本程序原本的目的是計(jì)算運(yùn)動(dòng)點(diǎn)的速度,通過修正可以進(jìn)行運(yùn)動(dòng)跟蹤。
?
#include <cv.h>
#include <highgui.h>
#include <iostream>
using namespace std;
int const MAX_CORNERS = 1000;
int main (int argc, char **argv)
{?
??? CvCapture* capture = 0;
??? capture = cvCaptureFromCAM(? CV_CAP_ANY );? //get frame
?
??? IplImage *src_img1;? //the previous frame (gray)
??? IplImage *src_img2;? //the current frame(gray)
?
??? IplImge *dst_img;?? //the result
??? IplImage *cur_img; ??
??? IplImage *pre_img;
?
??? CvPoint2D32f * move_old_point = new CvPoint2D32f[ MAX_CORNERS];
??? CvPoint2D32f * move_new_point = new CvPoint2D32f[ MAX_CORNERS];
??? char *features_found = new char[MAX_CORNERS];
??? float *features_error = new float[MAX_CORNERS];
??? CvTermCriteria criteria;
??? criteria = cvTermCriteria (CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 64, 0.01);
??? while(1)
??? {
??????? int i,j;
??????? int dx, dy;
??????? int p = 0;
??????? int rows, cols;
??????? int countn = MAX_CORNERS;
??????? pre_img = cvQueryFrame(capture);
?
??????? CvSize img_sz = cvGetSize(pre_img);
??????? src_img1 = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
??????? cvCvtColor(pre_img, src_img1, CV_RGB2GRAY);
?
??????? cur_img = cvQueryFrame(capture);
??????? src_img2 = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
??????? cvCvtColor(cur_img, src_img2, CV_RGB2GRAY);
??? ??? dst_img = (IplImage *)cvClone(cur_img);
?
??????? IplImage *move_img = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
??????? cvZero(move_img);
??????? //cvAbsDiff(src_img1, src_img2,move_img);
??????? cols = src_img1->width;?
??????? rows = src_img1->height;
??????? for (i = 0; i <cols; i++)
??????? {
??????????? for (j = 0; j<rows; j++)
??????????? {
??????????????? double a = abs(cvGet2D(src_img1, j, i).val[0]-cvGet2D(src_img2, j, i).val[0]);
??????????????? CvScalar b = cvScalar(a, 0, 0,0);
??????????????? cvSet2D(move_img, j, i,b);
??????????????? if (a>40)
??????????????? {
??????????????????? if (p<MAX_CORNERS-1)
??????????????????? {
??????????????????????? int d = ++p;
??????????????????????? move_old_point[d].x = i;
??????????????????????? move_old_point[d].y = j;
??????????????????? }
??????????????? }
??????????? }
??????? }
??????? cvNamedWindow("moving object", 1);
??????? cvShowImage("moving object", move_img);
?
??????? CvSize Pyrsize = cvSize(src_img1->width +8, src_img1->height/3);
??????? IplImage * pyrA = cvCreateImage(Pyrsize, IPL_DEPTH_32F, 1); //pyrA是需要尋找的點(diǎn),不是沒有初始化的
??????? IplImage * pyrB = cvCreateImage(Pyrsize, IPL_DEPTH_32F, 1);
?
??????? cvCalcOpticalFlowPyrLK(src_img1,
??????????? src_img2,
??????????? pyrA,
??????????? pyrB,
??????????? move_old_point,
??????????? move_new_point,
??????????? countn,
??????????? cvSize(10, 10),
??????????? 3,
??????????? features_found,
??????????? features_error,
??????????? criteria,
??????????? 0
??????????? );
??????? for (i = 0; i < countn; i++)
??????? {??
??????????? int x1 = (int)move_new_point[i].x;
??????????? int x2 = (int)move_old_point[i].x;
??????????? int y1 = (int)move_new_point[i].y;
??????????? int y2 = (int)move_old_point[i].y;
?
??????????? dx =(int) abs(x1 - x2) ;
??????????? dy = (int)abs(y1 - y2);
??????????? if (dx >= 5&& dy >= 5)
??????????? {
??????????????? cvLine (dst_img, cvPoint(x2, y2),cvPoint(x2+5, y2+5) , CV_RGB (255, 0, 0), 1, CV_AA, 0);
??????????? }
??????? }
?
??????? cvNamedWindow ("ImagePyrLK", 1);?
??????? cvShowImage ("ImagePyrLK", dst_img);
??????? cvWaitKey (1);
??????? cvReleaseImage (&dst_img);
??????? cvReleaseImage(&pyrA);
??????? cvReleaseImage(&pyrB);
??????? cvReleaseImage(&move_img);
??? }
?
??? cvDestroyWindow("moving object");
??? cvDestroyWindow ("ImagePyrLK");?
??? cvReleaseImage (&src_img1);
??? cvReleaseImage (&src_img2);
?
??? cvReleaseImage (&pre_img);
??? cvReleaseImage (&cur_img);
?
??? return 0;
}
其它參考文獻(xiàn):
1、? http://blog.csdn.net/gnuhpc/article/details/4355137
2、? http://blog.csdn.net/yang_xian521/article/details/6987447
3、? http://blog.csdn.net/gnuhpc/article/details/4355137
4、? http://blog.csdn.net/gnuhpc/article/details/4329857
5、? http://blog.csdn.net/gnuhpc/article/details/4291460
總結(jié)
以上是生活随笔為你收集整理的运动目标检测__光流法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu下,Java中利用JNI调用
- 下一篇: OpenCV中响应鼠标信息cvSetMo