一、Harri角点检测
1、Harri角点介绍
**角点:**图像中存在物体边缘角落上的点或者是一些其他特殊位置的点。
**Harri角点:**定义一个矩形区域,将这个矩形区域放置在图像中,求取这个区域内所有的像素值之和,之后移动这个区域再次计算像素值之和,如果移动前和移动后两者之间的差值比较小,那么就不是Harri角点,如果两者之间的差值比较大,那么就认定为移动之前所覆盖的区域内存在一个角点。

Harris 判定公式:
存在问题:
- 参数 kkk 需要人工调整
- 不同图像效果差异较大
2、相关函数
cpp
/* 用途:用于检测图像中的Harris角点,
即图像中"两个方向灰度变化都非常明显"的位置 */
void cv::cornerHarris( InputArray src, OutputArray dst, int blockSize,
int ksize, double k,
int borderType = BORDER_DEFAULT );
/*
src:待检测Harris角点的输入图像,图像必须是CV_8U或者CV_32F的单通道灰度图像
dst:存放Harris评价系数的R矩阵,数据类型为CV_32F的单通道图像,与输入图像具有相同的尺寸
blockSize:邻域大小,一般取值为2
ksize:Sobel算子的半径,用于得到梯度信息
k:计算Harris评价系数R的权重系数,一般取值范围为0.02 ~ 0.04
borderType:像素外推算法标志
*/
cpp
/* 用途:用于将检测到的特征点绘制到图像上,
方便观察和分析特征点位置、
尺寸以及方向信息 */
void cv::drawKeypoints( InputArray image, const std::vector<KeyPoint>& keypoints,
InputOutputArray outImage,
const Scalar& color=Scalar::all(-1),
DrawMatchesFlags flags=DrawMatchesFlags::DEFAULT );
/*
image:输入原始图像
keypoints:特征点集合,通常由SIFT、SURF、ORB、FAST、Harris等特征检测算法得到
outImage:输出绘制后的图像
color:绘制特征点的颜色,默认值Scalar::all(-1)表示随机颜色
flags:特征点绘制方式标志,用于控制是否绘制方向、尺寸信息等
*/
3、示例代码
cpp
QString imgPath = QApplication::applicationDirPath() + "/Images";
cv::String s_imgPath = imgPath.toLocal8Bit().data();
Mat img = imread(s_imgPath + "/lena.jpg", IMREAD_COLOR);
if (img.empty())
{
qDebug() << "图片加载失败, 请确认图像文件名称是否正确";
return;
}
/*转成灰度图*/
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
/*计算Harris系数*/
Mat harris;
int blockSize = 2;/*邻域半径*/
int apertureSize = 3;
cornerHarris(gray, harris, blockSize, apertureSize, 0.04);
/*归一化便于进行数值比较和结果显示*/
Mat harrisn;
normalize(harris, harrisn, 0, 255, NORM_MINMAX);
/*将图像的数据类型变为CV_8U*/
convertScaleAbs(harrisn, harrisn);
/*寻找Harris角点*/
vector<KeyPoint> keyPoints;
for (int row = 0; row < harrisn.rows; row++)
{
for (int col = 0; col < harrisn.cols; col++)
{
int R = harrisn.at<uchar>(row,col);
if (R > 125)
{
/*将角点存入KeyPoint中*/
KeyPoint keyPoint;
keyPoint.pt.y = row;
keyPoint.pt.x = col;
keyPoints.push_back(keyPoint);
}
}
}
drawKeypoints(img, keyPoints, img);
imshow("harrisn", harrisn);
imshow("img", img);
waitKey(0);
destroyAllWindows();
二、Shi-Tomas角点检测
1、Shi-Tomas角点介绍
Shi-Tomasi 判定公式:
- 取两个特征值中的较小值
- 如果最小特征值仍然很大,说明两个方向变化都明显,则认为是角点
2、相关函数
cpp
/* 用途:用于检测图像中"质量较好"的角点,
自动筛选出稳定且明显的特征点。
默认使用Shi-Tomasi角点检测算法,
相比Harris角点,对跟踪任务通常更加稳定 */
void cv::goodFeaturesToTrack( InputArray image, OutputArray corners,
int maxCorners, double qualityLevel, double minDistance,
InputArray mask = noArray(), int blockSize = 3,
bool useHarrisDetector = false, double k = 0.04 );
/*
image:输入图像,必须为8位或32位单通道灰度图像
corners:输出检测到的角点坐标集合
maxCorners:要寻找的角点数目
qualityLevel:角点阈值与最佳角点的关系,又称质量等级,当参数为0.01,表示焦点阈值时最佳角点的0.01倍
minDistance:两个角点之间允许的最小距离,用于避免角点过于密集
mask:掩码矩阵,表示检测角点的区域
blockSize:计算梯度协方差矩阵的尺寸
useHarrisDetector:是否使用Harris角点检测,false表示使用Shi-Tomasi算法
k:Harris角点检测中的权重系数,仅在useHarrisDetector=true时有效
*/
3、示例代码
cpp
QString imgPath = QApplication::applicationDirPath() + "/Images";
cv::String s_imgPath = imgPath.toLocal8Bit().data();
Mat img = imread(s_imgPath + "/lena.jpg", IMREAD_COLOR);
if (img.empty())
{
qDebug() << "图片加载失败, 请确认图像文件名称是否正确";
return;
}
/*转成灰度图*/
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
/*提取角点*/
int maxCorners = 100;/*检测角点数目*/
double quality_level = 0.01;/*质量等级,或者说阈值与最佳角点的比例关系*/
double minDistance = 0.04;/*两个角点之间的最小欧氏距离*/
vector<Point2f> corners;
goodFeaturesToTrack(gray, corners, maxCorners, quality_level, minDistance, Mat(), 3, false);
/*绘制角点*/
vector<KeyPoint> keyPoints;/*存放角点的KeyPoint类,用于后期绘制角点时使用*/
for (int i = 0; i < corners.size(); i++)
{
/*将角点存入KeyPoint中*/
KeyPoint keyPoint;
keyPoint.pt = corners[i];
keyPoints.push_back(keyPoint);
}
drawKeypoints(img, keyPoints, img);
imshow("img", img);
waitKey(0);
destroyAllWindows();
三、亚像素级别角点位置优化
1、亚像素级别角点位置优化原理介绍
**亚像素级别角点位置优化是指:**在已经检测到角点的大致像素位置后,再进一步计算,使角点坐标精确到"小数级别"。
**核心思想:**通过分析角点邻域灰度变化,迭代计算更精确的角点位置,使角点坐标不再局限于整数像素,而能够达到小数级精度。
2、相关函数
cpp
/* 用途:用于对已有角点位置进行亚像素级精度优化,
提高角点定位准确性 */
void cv::cornerSubPix( InputArray image, InputOutputArray corners,
Size winSize, Size zeroZone,
TermCriteria criteria );
/*
image:输入图像,必须是CV_8U或者CV_32F的单通道灰度图像
corners:角点坐标,既是输入的角点坐标又是精确后的角点坐标
winSize:搜索窗口的一半尺寸,必须是整数,实际的搜索窗口尺寸比该参数的2倍大1
zeroZone:搜索区域中间死区大小的一半,即不提取像素点的区域,(-1,-1)表示没有死区
criteria:终止角点优化迭代的条件
*/
3、示例代码
cpp
QString imgPath = QApplication::applicationDirPath() + "/Images";
cv::String s_imgPath = imgPath.toLocal8Bit().data();
Mat img = imread(s_imgPath + "/lena.jpg", IMREAD_COLOR);
if (img.empty())
{
qDebug() << "图片加载失败, 请确认图像文件名称是否正确";
return;
}
/*转成灰度图*/
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
/*提取角点*/
int maxCorners = 100;/*检测角点数目*/
double quality_level = 0.01;/*质量等级,或者说阈值与最佳角点的比例关系*/
double minDistance = 0.04;/*两个角点之间的最小欧氏距离*/
vector<Point2f> corners;
goodFeaturesToTrack(gray, corners, maxCorners, quality_level, minDistance, Mat(), 3, false);
/*计算亚像素级别角点坐标*/
vector<Point2f> cornersSub = corners;/*角点备份,防止被函数修改*/
Size winSize = Size(5, 5);
Size zeroZone = Size(-1, -1);
TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 40, 0.001);
cornerSubPix(gray, cornersSub, winSize, zeroZone, criteria);
for (int i = 0; i < corners.size(); i++)
{
string str = to_string(i);
cout << i << "Coordinates: " << corners[i] << " Fine coordinates: " << cornersSub[i] << endl;
}
waitKey(0);
destroyAllWindows();