opencv关于图像金字塔Lucas-Kanade光流检测的实现

首先我们来学习几个用到的函数:

1)GoodFeaturesToTrack   确定图像的强角点

void cvGoodFeaturesToTrack( const CvArr* image, CvArr* eig_image, CvArr* temp_image,

CvPoint2D32f* corners, int* corner_count, double quality_level, double min_distance,

const CvArr* mask=NULL );

参数解析:

image:输入图像,8-位或浮点32-比特,单通道

eig_image:临时浮点32-位图像,尺寸与输入图像一致

temp_image:另外一个临时图像,格式与尺寸与 eig_image 一致

corners:输出参数,检测到的角点

corner_count:输出参数,检测到的角点数目

quality_level:最大最小特征值的乘法因子。定义可接受图像角点的最小质量因子。

min_distance:限制因子。得到的角点的最小距离。使用 Euclidian 距离

mask:ROI:感兴趣区域。函数在ROI中计算角点,如果 mask 为 NULL,则选择整个图像

该函数 cvGoodFeaturesToTrack 在图像中寻找具有大特征值的角点首先用cvCornerMinEigenVal 计算输入图像的每一个像素点的最小特征值,并将结果存储到变量 eig_image 中。然后进行非最大值抑制(仅保留3x3邻域中的局部最大值)。下一步将最小特征值小于 quality_level?max(eig_image(x,y)) 排除掉。最后,函数确保所有发现的角点之间具有足够的距离,(最强的角点第一个保留,然后检查新的角点与已有角点之间的距离大于 min_distance )。

2) cvFindCornerSubPix   用于发现亚像素 精度的角点位置

void cvFindCornerSubPix(

const CvArr* image,

CvPoint2D32f* corners,

int count,

CvSize win,

CvSize zero_zone,

CvTermCriteria criteria

);

输入图像image是8位通道的灰度图像 。corners为整数值的像素位置,corners设定了角点的初始位置。count为需要计算的角点数目。win指定了等式产生的窗口的尺寸。输入参数zero_zone定义了一个禁区(与win相似,但通常比win小),这个区域在方程组 以及自相关矩阵 中不被考虑。如果不需要这样一个禁区,则zero_zone应设置为cvSize(-1,-1)。最后一个参数为用户定义的迭代终止条件。迭代过程的终止条件可以是最大迭代次数CV_TERMCRIT_ITER类型,或者是设定的精度CV_TERMCRIT_EPS类型(或者是两者的组合)。终止条件的设置在极大程度上影响最终得到的亚像素值的精度。例如,指定0.10,则求得的亚像素级精度为像素的十分之一。

3)void cvCalcOpticalFlowPyrLK( const CvArr* prev, const CvArr* curr, CvArr* prev_pyr, CvArr* curr_pyr, 

const CvPoint2D32f* prev_features, CvPoint2D32f* curr_features, int count, CvSize win_size,

 int level, char* status, float* track_error, CvTermCriteria criteria, int flags )

  • prev
  • 在时间 t 的第一帧
  • curr
  • 在时间 t + dt 的第二帧
  • prev_pyr
  • 第一帧的金字塔缓存. 如果指针非 NULL , 则缓存必须有足够的空间来存储金字塔从层 1 到层 #level 的内容。尺寸 (image_width+8)*image_height/3 比特足够了
  • curr_pyr
  • 与 prev_pyr 类似, 用于第二帧
  • prev_features
  • 需要发现光流的点集
  • curr_features
  • 包含新计算出来的位置的 点集
  • count
  • 特征点的数目
  • win_size
  • 每个金字塔层的搜索窗口尺寸
  • level
  • 最大的金字塔层数。如果为 0 , 不使用金字塔 (即金字塔为单层), 如果为 1 , 使用两层,下面依次类推。
  • status
  • 数组。如果对应特征的光流被发现,数组中的每一个元素都被设置为 1, 否则设置为 0。
  • error
  • 双精度数组,包含原始图像碎片与移动点之间的差。为可选参数,可以是 NULL .
  • criteria
  • 准则,指定在每个金字塔层,为某点寻找光流的迭代过程的终止条件。
  • flags
  • 其它选项:
    • CV_LKFLOW_PYR_A_READY , 在调用之前,第一帧的金字塔已经准备好
    • CV_LKFLOW_PYR_B_READY , 在调用之前,第二帧的金字塔已经准备好
    • CV_LKFLOW_INITIAL_GUESSES , 在调用之前,数组 B 包含特征的初始坐标 (Hunnish: 在本节中没有出现数组 B,不知是指的哪一个)
应用以上几个函数进行实验,实现金字塔Lucas-Kanade稀疏光流检测图像特征点跟踪。输入两张图片:

图片1:opencv关于图像金字塔Lucas-Kanade光流检测的实现_第1张图片

:图片2:opencv关于图像金字塔Lucas-Kanade光流检测的实现_第2张图片

检测结果:opencv关于图像金字塔Lucas-Kanade光流检测的实现_第3张图片

红色线段是增加在图像中的可视性光流矢量,指示了跟踪点的变化情况。

代码如下:

#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <stdio.h>


const int MAX_CORNERS = 500;


int main(int argc, char** argv) 
{
// Initialize, load two images from the file system, and
// allocate the images and other structures we will need for
// results.
//
IplImage* imgA = cvLoadImage("p.jpg",CV_LOAD_IMAGE_GRAYSCALE);
IplImage* imgB = cvLoadImage("pa.jpg",CV_LOAD_IMAGE_GRAYSCALE);
CvSize img_sz = cvGetSize( imgA );


int win_size = 10;//窗口尺寸
IplImage* imgC = cvLoadImage("pa.jpg",CV_LOAD_IMAGE_UNCHANGED);


// The first thing we need to do is get the features
// we want to track.
//
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,//the input image
eig_image,//temp image whose result is meaningful
tmp_image,//temp image
cornersA,//contains the result points
&corner_count,//the maximum number of points
0.01,//indicates the minimal acceptable lower eigenvalue for a point to be included as a corner
5.0,//guarantees that no two returned points are within the indicated number of pixels.
0,//no mask is used
3,// the region around a given pixel that is considered when computing the autocorrelation matrix of derivatives.
0,//use the the Shi-Tomasi deinition
0.04
);
/* Further find more accurate points */
cvFindCornerSubPix(
imgA,
cornersA,
corner_count,
cvSize(win_size,win_size),
cvSize(-1,-1),
cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03)
);
// Call the Lucas Kanade algorithm
//
char features_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 ];
//金字塔lk光流算法
cvCalcOpticalFlowPyrLK(
imgA,
imgB,
pyrA,
pyrB,
cornersA,
cornersB,
corner_count,
cvSize( win_size,win_size ),
5,
features_found,
feature_errors,
cvTermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, .3 ),
0
);
// Now make some image of what we are looking at:
//
for( int i=0; i<corner_count; i++ ) 
{
if( features_found[i]==0|| feature_errors[i]>550 ) 
{
// printf("Error is %f/n",feature_errors[i]);
continue;
}
// printf("Got it/n");
CvPoint p0 = cvPoint(cvRound( cornersA[i].x ),cvRound( cornersA[i].y ));
CvPoint p1 = cvPoint(cvRound( cornersB[i].x ),cvRound( cornersB[i].y ));
cvLine( imgC, p0, p1, CV_RGB(255,0,0),2 );
}


cvNamedWindow("ImageA",0);
cvNamedWindow("ImageB",0);
cvNamedWindow("LKpyr_OpticalFlow",0);


cvSaveImage("result_LK.jpg",imgC);
cvShowImage("ImageA",imgA);
cvSaveImage("input.jpg",imgA);

cvShowImage("ImageB",imgB);
cvSaveImage("input1.jpg",imgB);
cvShowImage("LKpyr_OpticalFlow",imgC);


cvWaitKey(0);
return 0;
}




你可能感兴趣的:(opencv关于图像金字塔Lucas-Kanade光流检测的实现)