上一篇博客中讲到了goodFeatureToTrack()这个API函数能够获取图像中的强角点。但是获取的角点坐标是整数,但是通常情况下,角点的真实位置并不一定在整数像素位置,因此为了获取更为精确的角点位置坐标,需要角点坐标达到亚像素(subPixel)精度。
1. 求取亚像素精度的原理
找到一篇讲述原理非常清楚的文档
2. OpenCV源代码分析
OpenCV中有cornerSubPixel()这个API函数用来针对初始的整数角点坐标进行亚像素精度的优化,该函数原型如下:
voidcv::cornerSubPix( InputArray _image, InputOutputArray _corners,
Size win, Size zeroZone, TermCriteria criteria )
_image为输入的单通道图像;_corners为提取的初始整数角点(比如用goodFeatureToTrack提取的强角点);win为求取亚像素角点的窗口大小,比如设置Size(11,11),需要注意的是11为半径,则窗口大小为23x23;zeroZone是设置的“零区域”,在搜索窗口内,设置的“零区域”内的值不会被累加,权重值为0。如果设置为Size(-1,-1),则表示没有这样的区域;critteria是条件阈值,包括迭代次数阈值和误差精度阈值,一旦其中一项条件满足设置的阈值,则停止迭代,获得亚像素角点。
这个API通过下面示例的语句进行调用:
cv::cornerSubPix(grayImg, pts, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
首先看criteria包含的两个条件阈值在代码中是怎么设置的。如下所示,最大迭代次数为100次,误差精度为eps*eps,也就是0.1*0.1。
const int MAX_ITERS = 100;int win_w = win.width * 2 + 1, win_h = win.height * 2 + 1;inti, j, k;int max_iters = (criteria.type & CV_TERMCRIT_ITER) ? MIN(MAX(criteria.maxCount, 1), MAX_ITERS) : MAX_ITERS;double eps = (criteria.type & CV_TERMCRIT_EPS) ? MAX(criteria.epsilon, 0.) : 0;
eps*= eps; //use square of error in comparsion operations
然后是高斯权重的计算,如下所示,窗口中心附近权重高,越往窗口边界权重越小。如果设置的有“零区域”,则权重值设置为0。计算出的权重分布如下图:
Mat mask