关键点和跟踪基础

//文章内的所有内容均是本人学习笔记和个人理解,不构成教程,若有错误,欢迎指出//

本章分为两部分,一是角点的介绍,二是Lucas-Kanade稀疏光流算法介绍。

角点检测
角点是图像中一小块具有丰富局部信息的图像块,数学含义则是局部导数最大的点。关键点则是在这一基础上的拓展,可以理解为是在众多角点中选择一些具有很高辨识度的角点当做特征点,以便在多幅图像中建立联系,因此关键点的选择越是唯一越好。

opencv3中使用cv::goodFeaturesToTrack()寻找角点

void cv::goodFeatureToTrack(
	cv::InputArray  image,             //输入单通道图像,CV_8UC1,CV_32FC1
	cv::OutputArray corners,           //保存角点坐标的数组,
	int             maxCorners,		   //限制找到的角点数
	double 			qualityLevel,	   //点的返回质量,通常0.10-0.01,最大不超过1.0,这里涉及角点的判定
	double 			minDistance,	   //相邻角点的最小距离
	cv::InputArray  mask    			=noArray(),		//mask,用于确定寻找角点的区域,和image相同尺寸,0为不寻找
	int 			blockSize           =3,   //计算角点需要考虑的区域大小
	bool 			useHarrisDetector   =false,	//是否使用harris算法,false则使用Shi和Tomasi方法
	double  		k					=0.4   //只有使用harris算法才有意义,并且最好使用默认值
  );

对于保存角点的数组,如果是vector,那么他应该是cv::Point2f的vector,如果是Mat型,那么他是一个Nx2的Mat,每一列均是一个角点,两列分别代表该点x,y。

亚像素角点

当角点用于图像测量时,而不是特征点提取,那么就需要图像提供更高的分辨率,换句说法就是特征点提取的是整数坐标,但我们有时候会需要小数坐标。当目标相对较小时,那么它的中心不会恰好在像素的中心。为解决这个问题,可以尝试将曲线拟合到图像像素值,然后使用数学方法确定像素之间出现峰值的位置。可以详见下面两篇论文:

[1]Chen.D.,and G.Zheng."A new sub-pixel detector for x-corners in camera calibration targets,"WSCG Short Papers(2005):97-100
[2]Lucchese,L.,and S.K.Mitra. "Using saddle points for subpixel feature detection in camera calibration targets,"Proceedings of the 2002 Asia Pacific Conference on Circuits and Systems(pp.191-195),December 2002

这种测量常见用途包括三维重建、相机标定、扭曲场景的部分重叠视图以最自然的方式进行拼接,以及在准确定位。

亚像素细化最常用的方法是基于向量与其正交向量之间的点积为0。算法流程如下

  1. 寻找到角点整数坐标opencv绘制三维图 opencv显示三维点_opencv绘制三维图
  2. 以该角点为中心创建窗口,窗口内的所有像素点定义为群众点opencv绘制三维图 opencv显示三维点_光流_02。所有群众点与原始角点形成向量 opencv绘制三维图 opencv显示三维点_像素点_03。定义pi点的梯度值为opencv绘制三维图 opencv显示三维点_角点_04,对于任一像素点opencv绘制三维图 opencv显示三维点_光流_02,要么它处在均匀区域,此时opencv绘制三维图 opencv显示三维点_光流_06,要么存在梯度,即存在与opencv绘制三维图 opencv显示三维点_像素点_03正交的向量,此时opencv绘制三维图 opencv显示三维点_opencv绘制三维图_08恒成立。
  3. 最小二乘法求解。2中的公式化为opencv绘制三维图 opencv显示三维点_opencv绘制三维图_09,即有opencv绘制三维图 opencv显示三维点_角点_10,求解q。
  4. (不停地进行迭代,将坐标更加细化)

opencv3中使用cv::cornerSubPix()寻找角点

void cv::cornerSubPix(
	cv::InputArray		image,			//输入图像
	cv::InputOutArray   corners,		//包含整数形式的像素坐标,被设为角点起始坐标
	cv::Size			winsize,   		//形成群众角点的窗口大小,窗口大小为2*winsize+1
	cv::Size			zeroZone,		//由于是在角点附近选取群众点,若从离p非常近的位置选群众角点,有时形成的矩阵是不可逆的,该参数定义了一个窗口,在该窗口内的点将不再被考虑,我的理解是在稍远但又附近的区域选点,书中用到附近一词,这里不是很理解
	cv::TermCriteria    criteria 		//迭代终止条件,通常是cv::TermCriteria::MAX_ITER或cv::TermCriteria::EPS
);

光流简介

光流问题涉及找出一幅图像中的很多点(全部点)在第二幅图中移动的位置,也可能是视频序列,因此假设大部分点都可以在第二幅图像中找到,这里根据找到的点的数量分为稀疏光流和稠密光流。常用于场景中的物体的运动估计、相机相对于场景的相对运动估计。

Lucas-Kanade稀疏光流算法

该算法可以详见论文:

Lucas,B.D.,and T.Kanade."An iterative image registration technique with an application to stereo vision,"Proceedings of the 1981 DARPA Imaging Understanding Workshop(pp.121-130),1981.

论文本意是为了计算稠密光流,但方法很容易用到输入图像中的点的子集,所以反而成了稀疏光流的主要技术。它仅依赖于围绕每个兴趣点的小窗口,类似于互相关算法,优点是速度快,缺点是对于一些移出窗口的像素点就不再能捕获到。因此发展出了基于全局计算的Horn-Schunck光流法(这里先不谈);“金字塔LK”算法,它从(最低细节)最高级别到(最高细节)最低级别进行跟踪计算,允许大幅度运动被局部窗口捕获。多尺度的光流法可以看看论文:

Ruhnau P,Kohlberger T,Schnorr C,Nobach H(2005) Variational optical flow estimation for particle image velocimetry.Exp Fluids 32(1):21-32

LK算法的基本思想建立在三个假设上:

  1. 亮度恒定,像素点的移动不会导致像素点在帧与帧之间的亮度变化;
  2. 偏移量很小,像素点的运动随时间变化很缓慢。
  3. 空间的一致性,属于相同表面上的像素点具有相似的运动,并且投影到图像平面上的点距离也很近。