首页 > 代码库 > OpenCV —— 跟踪与运动

OpenCV —— 跟踪与运动

理解物体运动主要包含两个部分:识别和建模

识别在视频流后续的帧中找出之前某帧镇南关的感兴趣物体

 

寻找角点

可跟踪的特征点都称为角点,从直观上讲,角点(而非边缘)是一类含有足够信息且能从当前帧和下一帧中都能提取出来的点

Harris 角点位于图像二阶导数的自相关矩阵有两个最大特征值的地方,这在本质上表示以此点为中心周围存在至少两个不同方向的纹理,正如实际的角点是由至少两个边缘相交于一点而产生

cvGoodFeaturesToTrack 采用Shi 和Tomasi提出的方法,先计算二阶导数,在计算特征值,返回满足易于跟踪的定义的一系列点(角点数组)

void cvGoodFeaturesToTrack(

const CvArrr* image,   8为或32位单通道图像

CvArr* eigImage,   每个元素包含了输入图像中对应点的最小特征值

CvArr* tempImage,   临时变量

CvPoint2D32f* corners,   输出

int * corner_count,   可以返回的最大角点数目

double quality_level,   认为是角点的可接受的最小特征值,不应超过1

double min_distance,  剔除距离较近的角点

const CvArr* mask = NULL,

int block_size=3,

int use_harris=0,

double k=0.4

);


亚像素级角点

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

实际计算亚像素级的角点位置时,解的是一个点积的表达式为0的方程组,其中每一个方程都是由q邻域的一个点产生。

搜索窗口的中心是整数坐标值的角点并从中心点在每个方向上扩展窗口尺寸指定的像素


不变特征

SIFT 在一点处检测主要梯度方向,根据这个方向记录局部梯度直方图结果,拥有旋转不变性

 


光流

可以将图像中的每个像素与速度关联,或者等价地,与表示像素在连续两帧之间的位移关联。这样得到的是稠密光流 —— 每个像素都与速度关联

稀疏光流的计算需要在被跟踪之前指定一组点 —— 角点

Lucas – Kanade 方法

LK算法只需要每个兴趣点周围小窗口的局部信息,所以它可以应用于稀疏内容。

不足 —— 较大的运动会将点移出这个小窗口

解决 —— 金字塔,跟踪图像金字塔允许小窗口捕获较大的运动

算法原理

1,亮度恒定 —— 场景中物体被跟踪部分的亮度不变

2,时间连续或者运动是“小运动” —— 运动相对于帧率是缓慢的

3,空间一致 —— 相邻的店保持相邻

 

在图像金字塔的最高层计算光流,用得到的运动估计结果作为下一层金字塔的起始点,重复这个过程直到到达金字塔的最底层,这样就将不满足运动假设的可能性降到最小。

cvCalcOpticalFlowLK —— 非金字塔的LK稠密光流算法

cvCalcOpticalFlowPyrLK —— 金字塔的LK代码

  图像金字塔的计算量较大,计算得到的图像对的后面一帧被作为下次计算的图像对的初始帧

#include <cv.h>#include <cxcore.h>#include <highgui.h>const int MAX_CORNERS=500;int main(int argc,char** argv){    IplImage* imgA=cvLoadImage("image0.jpg",CV_LOAD_IMAGE_GRAYSCALE);    IplImage* imgB=cvLoadImage("image1.jpg",CV_LOAD_IMAGE_GRAYSCALE);    CvSize img_sz=cvGetSize(imgA);    int win_size=10;    IplImage* imgC=cvLoadImage("",CV_LOAD_IMAGE_UNCHANGED);    // get the features    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,        0,        3,        0,        0.04);    cvFindCornerSubPix(        imgA,        cornersA,        corner_count,        cvSize(win_size,win_size),        cvSize(-1,-1),        cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03);        );        // LK                char features_found[MAX_CORNERS];        float fearture_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,            features_found,            fearture_errors,            cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.3),            0            );        // 结果显示        for (int i=0;i<corner_count;i++)        {            if (features_found[i]==0||fearture_errors[i]>550)            {                printf("Error is %f\n",fearture_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);        }}

稠密跟踪方法

亮度恒定假设,速度的平滑约束 (通过对光流速度分量的二阶导数进行规则化获得)

与LK算法一样,HornSchunck方法也要通过迭代来解微分方程

cvCalcOpticalFlowHS


mean – shift

在一组数据的密度分布中寻找局部极值的稳定的方法

mean – shift 等价于先对连续分布用 mean-shift核进行卷积,然后再应用爬山算法

cvMeanShift

反向投影图 —— 概率密度图,用输入图像的某一位置上像素值对应直方图bin上的值来代替该像素值

 

Camshift 搜索窗口会自我调整尺寸

cvCamShift


运动模板

可应用于姿态识别

运动模板需要知道物体的轮廓

运动历史图像

OpenCV 中完成运动模板构建的函数是 cvUpdateMotionHistory

一旦运动模板记录了不同时间的物体轮廓,就可以用计算运动模板图像的梯度来获取全局运动信息

cvCalcMotionGradient 计算梯度 (输入有允许的最小和最大的梯度值)

cvCalcGlobalOrientation 计算有效梯度方向矢量和来获取全局运动方向

cvSegmentMotion 分割和计算局部运动


预估器

预测阶段 —— 用从过去得到的信息进一步修正模型以取得下一个将会出现的位置

矫正阶段 —— 获得一个测量,然后与基于前一次测量的预期值进行调整

Kalman 滤波器

若有一组强而合理的假设,给出系统的历史测量值,则可以建立最大化这些早前测量值的后验概率的系统状态模型

假设:1,被建模的系统是线性的;2,影响测量的噪声属于白噪声;3,噪声本质上是高斯分布的

额,这个内容挺多的,应该专门看一下