本文共 4592 字,大约阅读时间需要 15 分钟。
在处理适用于多幅图像的特征描述子时,主要有两种特征检测方法:一种是基于角的检测,另一种是处理图像中的所有区域。这里主要讨论一下基于角的检测。
1988年,Harris和Stephens提出了一种角检测算法——HS角检测器。这一算法通过数学公式来区分三种情况:
HS角检测器通过计算每个像素点周围邻域的灰度变化量,找到灰度变化最大的方向,即角的位置。
HS角检测器计算每个像素点周围邻域的灰度变化量。具体来说,对于图像中的一个像素点 $(s, t)$,其周围邻域的像素点 $(s+x, t+y)$ 的灰度变化量的平方和可以表示为:
$$C(x, y) = \sum_{s,t} \omega(s,t) [f(s+x, t+y) - f(s, t)]^2$$
其中,$\omega(s,t)$ 是一个加权函数,用于控制每个像素点对周围变化的敏感度。$f(s+x, t+y)$ 表示泰勒展开的近似值:
$$f(s+x, t+y) \approx f(s, t) + x f_x(s, t) + y f_y(s, t)$$
将上述近似代入灰度变化量的计算中,得到:
$$C(x, y) = \sum_{s,t} \omega(s,t) [x f_x(s, t) + y f_y(s, t)]^2$$
这可以表示为矩阵形式:
$$C(x, y) = [x, y] M [x; y]$$
其中,$M$ 是一个 2x2 矩阵:
$$M = \sum_{s,t} \omega(s,t) A$$
$A$ 是一个矩阵,用于计算梯度的平方和:
$$A = \begin{bmatrix}f_x^2 & f_x f_y \f_x f_y & f_y^2\end{bmatrix}$$
$M$ 被称为 Harris矩阵。矩阵 $M$ 的特征值与特征向量方向上的数据扩展量成正比。特征值的大小反映了灰度变化的程度:
为了避免手动计算特征值,HS角检测器使用迹和行列式来判断角的存在。
$k$ 的值影响角的检测数量:$k$ 越小,检测到的角越多。
为了进一步提高角点检测的稳定性和鲁棒性,Jianbo Shi 和 Carlo Tomasi 在 1994 年提出了 Shi-Tomasi 角点检测器。该算法直接使用最小特征值作为度量:
$$R = \min(\lambda_x, \lambda_y)$$
与 HS 角检测器不同,Shi-Tomasi 算法避免了超参数 $k$ 的使用,从而更加简洁和灵活。
OpenCV 提供了丰富的函数和接口来实现角检测和相关操作。以下是相关 API 的说明:
void cv::cornerHarris(InputArray src, OutputArray dst, int blockSize, int ksize, double k, int borderType = BORDER_DEFAULT)
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)
该函数实现了角点检测的完整流程:
以下是一个使用 OpenCV 实现角点检测的示例代码:
#include#include #include #include using namespace cv;using namespace std;Mat src, src_gray;int maxCorners = 23;int maxTrackbar = 100;RNG rng(12345);int thresh = 200;int max_thresh = 255;const char* source_window = "Source image";const char* corners_window = "Corners detected";void cornerHarris_demo(int, void*) { int blockSize = 2; int apertureSize = 3; double k = 0.04; Mat dst = Mat::zeros(src.size(), CV_32FC1); cornerHarris(src_gray, dst, blockSize, apertureSize, k); Mat dst_norm, dst_norm_scaled; normalize(dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat()); convertScaleAbs(dst_norm, dst_norm_scaled); for (int i = 0; i < dst_norm.rows; i++) { for (int j = 0; j < dst_norm.cols; j++) { if ((int)dst_norm.at (i, j) > thresh) { circle(dst_norm_scaled, Point(j, i), 5, Scalar(0), 2, 8, 0); } } } namedWindow(corners_window); imshow(corners_window, dst_norm_scaled); imwrite("corner_grid.png", dst_norm_scaled);}void goodFeaturesToTrack_Demo(int, void*) { maxCorners = MAX(maxCorners, 1); vector corners; double qualityLevel = 0.01; double minDistance = 10; int blockSize = 3, gradientSize = 3; bool useHarrisDetector = false; double k = 0.04; Mat copy = src.clone(); goodFeaturesToTrack(src_gray, corners, maxCorners, qualityLevel, minDistance, Mat(), blockSize, gradientSize, useHarrisDetector, k); cout << "** Number of corners detected: " << corners.size() << endl; int radius = 8; for (size_t i = 0; i < corners.size(); i++) { circle(copy, corners[i], radius, Scalar(0, 0, rng.uniform(0, 256)), FILLED); } namedWindow(source_window); imwrite("corner_grid_st.png", copy); imshow(source_window, copy);}int main(int argc, char** argv) { CommandLineParser parser(argc, argv, "{@input | building.jpg | input image}"); src = imread(samples::findFile(parser.get ("@input"))); if (src.empty()) { cout << "Could not open or find the image!\n"; cout << "Usage: " << argv[0] << " \n"; return -1; } cvtColor(src, src_gray, COLOR_BGR2GRAY); namedWindow(source_window); createTrackbar("Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo); imshow(source_window, src); goodFeaturesToTrack_Demo(0, 0); waitKey(); return 0;}
cornerHarris 函数计算角度度量,并绘制结果图像。goodFeaturesToTrack 函数检测角点,并绘制结果图像。通过这些函数,可以轻松实现基于 Harris 和 Shi-Tomasi 算法的角点检测,适用于多种图像处理任务。
转载地址:http://uohfk.baihongyu.com/