为何需要进行亚像素定位?
数字图像通常是离散化成像素;每个像素对应一个整数坐标位置;整数坐标位置对于很多应用并不精确,比如跟踪、相机标定、图像配准、图像拼接以及三维重构;为达到有些应用的精确性,需要精确到浮点坐标位置;所以亚像素定位问题。亚像素定位就是计算特征所在图像中的真实位置,而真实位置有时候并不在像素所在整数坐标位置上,而是在像素的内部。
点的灰度分布特征跟二维高斯模型很相似,中心处最亮,离中心距离越远会随之变暗。所以这里的图像特征,我们用高斯模型进行描述。
利用高斯模型,我们可以构建点的最终模型函数M,如下:
上述表达式中的各个参数解释如下:
>M:代表对应像素位置上的强烈程度
>(x,y):图像中某个像素位置
>A:背景的强烈程度,比如上面的黑色区域
>B:亮区域中的强烈程度的峰值
>(u,v):亮区域中的峰值所在的位置
>sigma:高斯模型方差
即对应像素位置的强度与模型函数M估计出来的强度相同,那么我们认为用该模型匹配点区域的像素值是完美的,该模型是适合描述该区域的特征。事实上,在点区域里,保证不了左右两等式相等,我们只求左右两等式尽量逼近,求解模型的最佳参数,基本都是通过残差进行分析,如:
在进行残差计算前,首先使用一个简单算法粗定位一个位置,将窗口中心移动至该位置上,再进行残差计算。我们的目的是最小化误差,即可获取亚像素位置坐标(u,v)。 亚像素定位方法可以直接对误差函数的每一个参数进行偏导求取,也可以使用梯度下降法进行求解,最终得到模型的相关参数(这里极有可能得到的解是局部最优解)。当然求解的方法很多,最好使用的方法能解出全局最优解,这样解的模型才是最优的。
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h> #include <stdlib.h> using namespace cv; using namespace std; #define WINDOW_NAME "Shi-Tomasi CornorDetect" Mat src, gray; vector<Point2f> corners;//声明为全局变量否则报错,圆心坐标 int maxCornerNum = 10; int maxTrackbarNum = 300; //滚动条回调函数 void cornersRefinement(int, void*){ Mat copy = src.clone(); if (maxCornerNum <= 1){ maxCornerNum = 1; } //角点检测参数准备 double qualityLevel = 0.2;//角点检测可接受的最小特征值0.01 double minDistance = 10;//角点之间的最小距离 int blockSize = 3;//计算导数自相关矩阵时的指定的领域范围 double k = 0.04;//权重系数 //进行Shi-Tomasi角点检测 goodFeaturesToTrack(gray, corners, maxCornerNum, qualityLevel, minDistance, Mat(), blockSize, false, k); //像素级角点使用蓝色圆圈绘制 for (int i = 0; i <maxCornerNum; i++){ circle(copy, corners[i], 8, Scalar(255, 0, 0), 2, 8, 0); } /// 角点位置精准化参数 Size winSize = Size(5, 5); Size zeroZone = Size(-1, -1); //迭代的终止条件 TermCriteria criteria = TermCriteria( CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 40, //maxCount=40 0.001); //epsilon=0.001 /// 计算精准化后的角点位置 cornerSubPix(gray, corners, winSize, zeroZone, criteria); //亚像素级角点使用品红色圆圈绘制 for (int i = 0; i < maxCornerNum; i++){ circle(copy, corners[i], 4, Scalar(255, 0, 255), 2, 8, 0); // 输出角点坐标 cout << " [" << i << "] (" << corners[i].x << "," << corners[i].y << ")" << endl; } cout << endl; imshow(WINDOW_NAME, copy); } int main(){ src = imread("Goldhill.bmp", 1); cvtColor(src, gray, CV_BGR2GRAY); namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE); imshow(WINDOW_NAME, src); createTrackbar("MaxNofCornor:", WINDOW_NAME, &maxCornerNum, maxTrackbarNum, cornersRefinement); cornersRefinement(0, 0); cvWaitKey(0); return 0; }
————————————————
版权声明:本文为CSDN博主「凡是坚持」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_22424571/article/details/81674852

