运动目标检测__光流法
以下內容摘自一篇碩士論文《視頻序列中運動目標檢測與跟蹤算法的研究》:
1950年Gibson首先提出了光流的概念,光流(optical flow)法是空間運動物體在觀測成像面上的像素運動的瞬時速度。物體在運動的時候,它在圖像上對應點的亮度模式也在做相應的運動,這種圖像亮度模式的表觀運動就是光流。光流的研究就是利用圖像序列中像素的強度數據的時域變化和相關性來確定各自像素位置的“運動”。光流表達了圖像的變化,因此可被觀察者用來確定目標的運動情況。一般情況下,光流由相機運動、場景中目標運動或兩者的共同運動產生。
光流場是由光流引申出來的,它指的是景物中可見像素點的三維速度矢量在成像表面投影形成的二維瞬時速度場。空間中的運動場轉移到圖像上就表示為光流場,光流場反映了圖像上每一點的灰度變化趨勢。光流場包含了被觀察物體的運動信息以及有關景物豐富的三維結構的信息,它是如今計算機視覺及有關研究領域中的一個重要組成部分。
光流法檢測運動目標,其基本思想是賦予圖像中的每一個像素點一個速度矢量,從而形成了該圖像的運動場。圖像上的點和三維物體上的點在某一特定的運動時刻是一一對應的,根據各像素點的速度矢量特征對圖像進行動態的分析。若圖像中不存在運動目標,那么光流矢量在整個圖像區域則是連續變化的,而當物體和圖像背景中存在相對運動時,運動物體所形成的速度矢量則必然不同于鄰域背景的速度矢量,從而將運動物體的位置檢測出來。
光流不能由運動圖像的局部信息來唯一的確定,例如,亮度等值線上的點或者亮度比較均勻的區域都無法唯一的確定其點的運動對應性,但是運動是可以進行觀察得到。由此說明運動場和光流不一定是唯一對應的,即光流不一定是由物體運動產生的,反之如果物體發生了運動也不一定就能產生光流。但是一般情況下,表觀運動和物體真實運動之間的差異是可以忽略的,可以用光流場代替運動場來分析圖像中的運動目標及其相關的運動參數。
可以證明動能場不僅僅是分塊連續的,并且其間斷點恰好為物體的邊緣。如此,我們便可以利用圖像每一幀的運動場,在動能變化矩陣中提取極值點,便可以得到運動物體的邊緣。可將動能大致相同的點歸于同一物體,進而對圖像序列進行分割,從而檢測出多個運動目標。這樣,我們就將運動目標檢測問題,借助光流場轉換為靜態圖像的區域分割問題。
算法步驟如下:
(1)令i=1,獲得第i幀圖像I(x,i);
(2)獲得第i+1幀圖像I(x,i+1);
(3)對圖像去噪,得到去燥后圖像I '(x, i)和I '(x, i+1);
(4)利用I '(x, i)和I '(x, i+1)計算得到光流場;
(5)計算得到局部動能場K(i);
(6)利用邊緣檢測算法(如基于小波的方法)局部動能場并分割圖像得到不同的運動單元也理解為一個運動單元);
(7)由于目標一般較背景小,故提取出體積較運動單元作為檢測目標;
(8)計算其質心作為目標位置;
(9)置i=i+1,重復(2)~(8),直至檢測結束。
基于光流場分析的運動目標檢測方法,不僅包含了被觀察物體的運動信息,而且攜帶了三維結構的豐富信息,因此它不僅可以用于運動目標檢測,還可以直接應用于運動目標跟蹤,能夠很精確的計算出運動目標的速度,同時在攝像機存在運動的情況下也能夠檢測出運動目標。而在實際的應用中,由于存在多光源、遮擋性、噪聲和透明性等多方面的原因,光流場基本方程中的灰度守恒這個假設條件是得不到滿足的,因此不能求解出正確的光流場,同時由于其采用的是迭代的求解計算方法,故需要的計算時間比較長,從而無法滿足實時的要求,并且該方法受噪聲的影響較大,因而該方法多適用于目標運動速度不大,圖像噪聲比較小的情況。
轉自:http://blog.csdn.net/zht9961020/article/details/7032059
cvCalcOpticalFlowPyrLK 函數在使用時,首先要確定特征點,也就是目標舊的位置。
本程序通過使用cvGoodFeaturesToTrack 函數選擇角點作為特征點。
本程序只是一個簡單的運動檢測,在具體應用過程中,可以根據自己的需要修正
#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;
}
轉自:http://blog.csdn.net/zht9961020/article/details/7032061
cvCalcOpticalFlowPyrLK 需要確定特征點。
本程序,通過幀差獲得運動的點作為特征點。
本程序原本的目的是計算運動點的速度,通過修正可以進行運動跟蹤。
?
#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是需要尋找的點,不是沒有初始化的
??????? 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;
}
其它參考文獻:
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
總結
以上是生活随笔為你收集整理的运动目标检测__光流法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu下,Java中利用JNI调用
- 下一篇: OpenCV中响应鼠标信息cvSetMo