1. 程式人生 > >OpenCV21(金字塔LK光流演算法)

OpenCV21(金字塔LK光流演算法)

最好的教程,就是看Blog,然後最後一定要回歸書本。

一、LK演算法提到了三個假設

(高深:就是用你認識的字寫你看不懂的東西。辦法:多看幾遍,查閱Blog上接地氣的說法)

1.灰度不變

         解釋一下:假設有一段博爾特跑過的視訊,相鄰兩幀上,博爾特的頭的灰度是不變的。

         好像是廢話,其實不然。博爾特的頭,確切的來講,要說他頭上的某一畫素點。在不同幀間,座標是變化的。但是我們的假設提出來,首先我們認為這個點,在相鄰幀之間的對應點的灰度值是不變的。

2.時間連續

         解釋一下:相鄰幀間,博爾特頭移動的很慢很慢很慢。

         順便提一下書上的公式,最後結論v = It / Ix ;補充一下過程:


3.空間一致性

解釋一下:這一幀相鄰的兩個畫素,下一幀還相鄰。

二維的推導沒看明白,歡迎交流。

二、金字塔LK

在大多數情況下,以上的3個假設都是很難滿足的。物體運動的速度一般是很快速的,所以考慮到適用性,提出了金字塔LK。

什麼意思呢,應為金字塔是對圖形進行降取樣的(也就是影象越處理越小),所以一個大範圍的運動就可以在一個較小的範圍內檢測到了,滿足了以上3個條件。

大致就是這樣,有了感性認識,再好好看書吧。下面來看程式碼,最好執行一下。

三、程式碼

取自書上的原始碼。考慮到現在3.0的Mat的寫法越來越多,這個IplImage結構體,估計要被淘汰了。不過,還是先放上這個版本。(opencv249+vs2012)

// 光流.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"

const int MAX_CORNERS = 500;

int _tmain(int argc, _TCHAR* argv[])
{
	IplImage* imgA = cvLoadImage("1.bmp",CV_LOAD_IMAGE_GRAYSCALE);
	IplImage* imgB = cvLoadImage("2.bmp",CV_LOAD_IMAGE_GRAYSCALE);

	CvSize img_sz = cvGetSize( imgA );
	int win_size = 10;

	IplImage* imgC = cvCreateImage(cvGetSize(imgA),IPL_DEPTH_8U,3);
	cvZero(imgC);

	IplImage* eig_image = cvCreateImage(img_sz,IPL_DEPTH_32F,1);
	IplImage* tmp_image = cvCreateImage(img_sz,IPL_DEPTH_32F,1);

	int corner_count = MAX_CORNERS;
	CvPoint2D32f* cornersA = new CvPoint2D32f [MAX_CORNERS];

	cvGoodFeaturesToTrack(imgA,eig_image,tmp_image,cornersA,&corner_count,0.01,5.0);

	cvFindCornerSubPix(imgA,cornersA,corner_count,cvSize(win_size,win_size),cvSize(-1,-1),cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03) );

	char feature_found[MAX_CORNERS];
	float feature_errors[MAX_CORNERS];

	CvSize pyr_sz = cvSize( imgA->width + 8 , imgB->height/3 );
	IplImage* pyrA = cvCreateImage(pyr_sz,IPL_DEPTH_32F,1);
	IplImage* pyrB = cvCreateImage(pyr_sz,IPL_DEPTH_32F,1);

	CvPoint2D32f* cornersB = new CvPoint2D32f [MAX_CORNERS];

	cvCalcOpticalFlowPyrLK(imgA,imgB,pyrA,pyrB,cornersA,cornersB,corner_count,cvSize(win_size,win_size),5,feature_found,feature_errors,
		cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, .3),0);

	for(int i=0; i<corner_count; i++)
	{
		if( feature_found[i] == 0 || feature_errors[i]>550 )
		{
			printf("Error is %f\n",feature_errors[i]);
			continue;
		}
		printf("Got it!\n");
		CvPoint p1 = cvPoint(cvRound( cornersA[i].x),cvRound( cornersA[i].y));
		CvPoint p2 = cvPoint(cvRound( cornersB[i].x),cvRound( cornersB[i].y));
		cvLine(imgC,p1,p2,CV_RGB(255,255,255),1);
	}

	cvShowImage("1",imgA);
	cvShowImage("2",imgB);
	cvShowImage("3",imgC);

	cvWaitKey(0);

	return 0;
}