常规的角点检测算法输出的角点坐标是整数,即角点位置恰好与像素位置重合。
实际场景中角点位置是连续的,而相机的像素是离散的,两者总是有偏差。如果需要基于图像进行几何测量,这个偏差是不能容忍的。这就是亚像素角点检测问题的背景。相比常规角点检测,亚像素角点检测用实数取代整数来表示角点坐标。
亚像素角点检测算法
亚像素角点检测需要先运行常规的角点检测,得到整数表示的角点坐标。然后算法对每个角点做细化,得到实数表示的角点坐标
第一步:goodFeaturesToTrack() //检测角点
第二步:TermCriteria() //设置迭代算法的终止条件
TermCriteria(int type,int max_iter, double epsilon);
参数
type:终止条件类型;
CV_TERMCRIT_ITER--max_iter达到最大值后停止算法;
CV_TERMCRIT_EPS--当算法依赖的精确度低于epsilon后,停止算法;
CV_TERMCRIT_ITER+CV_TERMCRIT_EPS--当max_iter达到最大值或算法依赖的精确度低于epsilon任一个满足时,停止算法;
max_iter:最大迭代次数;
epsilon:要求精度;
第三步:cornerSubPix() //细化角点位置;
void cornerSubPix(InputArray image, InputOutputArray corners, Size winSize, Size zeroZone, TermCriteria criteria);
参数:
image:输入图像;
corners:初始化输入角点的坐标,为输出提供细化的坐标;
winSize:搜索窗口的边长的一半;
zeroZone:搜索区域中间的死区的一半大小,对它在下边的求和公式不计算,有时候它用来避免可能的自相关矩阵的奇异性,(-1,-1)用来表明这里没有这样的规模;
criteria:角点细化的迭代过程的终止条件;
代码示例:
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
int num_corners = 10;
int max_count = 100;
Mat src, gray_src;
const char* output_title = "SubPixel Result";
void SubPixel_Demo(int, void*);
int main(int argc, char** argv)
{
src = imread("D:/cv400/house.jpg");
if (src.empty())
{
cout<<"could not load image..."<<endl;
return -1;
}
namedWindow("input image", WINDOW_AUTOSIZE);
imshow("input image", src);
cvtColor(src, gray_src, COLOR_BGR2GRAY);
namedWindow(output_title, WINDOW_AUTOSIZE);
createTrackbar("Corners:", output_title, &num_corners, max_count, SubPixel_Demo);
SubPixel_Demo(0, 0);
waitKey(0);
return 0;
}
void SubPixel_Demo(int, void*)
{
if (num_corners < 5)
num_corners = 5;
vector<Point2f> corners;
double qualityLevel = 0.01;
double minDistance = 10;
int blockSize = 3;
double k = 0.04;
goodFeaturesToTrack(gray_src, corners, num_corners, qualityLevel, minDistance, Mat(), blockSize, false, k);
cout << "number of corners: " << corners.size() << endl;
Mat resultImg = src.clone();
for (size_t t = 0; t < corners.size(); t++)
circle(resultImg, corners[t], 2, Scalar(0, 0, 255), 2, 8, 0);
imshow(output_title, resultImg);
Size winSize = Size(5, 5);
Size zerozone = Size(-1, -1);
TermCriteria tc = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.001);
cornerSubPix(gray_src, corners, winSize, zerozone, tc);
for (size_t t = 0; t < corners.size(); t++)
cout << "corners"<<(t + 1) << " .[x, y] = " << corners[t].x << " , " << corners[t].y << endl;
return;
}
原图:
角点检测:
角点坐标: