亚像素级角点定位原理及opencv实现

为何需要进行亚像素定位?

数字图像通常是离散化成像素;每个像素对应一个整数坐标位置;整数坐标位置对于很多应用并不精确,比如跟踪、相机标定、图像配准、图像拼接以及三维重构;为达到有些应用的精确性,需要精确到浮点坐标位置;所以亚像素定位问题。亚像素定位就是计算特征所在图像中的真实位置,而真实位置有时候并不在像素所在整数坐标位置上,而是在像素的内部。

点的灰度分布特征跟二维高斯模型很相似,中心处最亮,离中心距离越远会随之变暗。所以这里的图像特征,我们用高斯模型进行描述。

上述表达式中的各个参数解释如下:

>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;
}

      

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ai智享

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值