- 自定义角点检测器基于Harris与Shi-Tomasi角点检测
- 首先通过计算矩阵M得到 λ1 λ2 两个特征值根据他们得到角点响应值
- 然后自己设置阈值实现计算出阈值得到有效响应值的角点位置
void cornerEigenValsAndVecs( // harris时计算 λ1 λ2 ,参数与harris角点检测一致
InputArray src,
OutputArray dst,
int blockSize,
int ksize,
int borderType = BORDER_DEFAULT
);
代码
#include "../common/common.hpp"
static Mat src, gray, harris_dst, harrisRspImg;
static const char title_harris[] = "corner_detect_harris";
static int thresh_v_harris = 30;
static int thresh_max_harris = 100;
static RNG rng(12345);
static double harris_min_rsp; // harris 角度响应最小值
static double harris_max_rsp; // harris 角度响应最大值
static void corner_detect_harris(int, void*);
void main(int argc, char** argv)
{
src = imread(getCVImagesPath("images/home.jpg"), IMREAD_COLOR);
imshow("src2-6", src);
cvtColor(src, gray, CV_BGR2GRAY);
// 计算特征值 eigon values λ1 λ2
int blockSize = 3; // blockSize取2或取3,会导致计算出来的角度响应的最大最小值不一样,下面的阈值需要适当调整
int ksize = 3;
double k = 0.04;
harris_dst = Mat::zeros(src.size(), CV_32FC(6)); // 深度为 CV_32F 通道数为6 ,通道数不一定要6 大于等于2就行
harrisRspImg = Mat::zeros(src.size(), CV_32FC1);
cornerEigenValsAndVecs(gray, harris_dst, blockSize, ksize, BORDER_DEFAULT); // 计算 λ1 λ2
// 计算角度响应
for (int row = 0; row < harris_dst.rows; row++)
{
for (int col = 0; col < harris_dst.cols; col++)
{
double lambda1 = harris_dst.at<Vec6f>(row, col)[0]; // λ1
double lambda2 = harris_dst.at<Vec6f>(row, col)[1]; // λ2
// harris角度响应计算,公式 R = det(M) - k*(trace(M))^2, det(M)=λ1*λ2, trace(M)=λ1+λ2
harrisRspImg.at<float>(row, col) = lambda1*lambda2 - k*pow((lambda1 + lambda2), 2);
}
}
minMaxLoc(harrisRspImg, &harris_min_rsp, &harris_max_rsp, 0, 0, Mat());//寻找harrisRspImg中角度响应最大值,最小值,及它们所在的位置,位置参数传0表示不管
printf("harris_min_rsp=%f, harris_max_rsp=%f\n", harris_min_rsp, harris_max_rsp); //harris_min_rsp = -0.003276, harris_max_rsp = 0.011325
namedWindow(title_harris, CV_WINDOW_AUTOSIZE);
createTrackbar("harris thresh:", title_harris, &thresh_v_harris, thresh_max_harris, corner_detect_harris);
corner_detect_harris(0, 0);
waitKey(0);
}
void corner_detect_harris(int, void*) // 自定义harris角点检测,与harris函数计算的结果差不多
{
if (thresh_v_harris < 10) thresh_v_harris = 10;
Mat retImg = gray.clone();
cvtColor(retImg, retImg, CV_GRAY2BGR); // 让原图灰度,角点彩色
//定义阈值, 以 thresh_v_harris / thresh_max_harris 的比例显示角点
float t = harris_min_rsp + ((double)thresh_v_harris / thresh_max_harris)*(harris_max_rsp - harris_min_rsp);
for (int row = 0; row < retImg.rows; row++)
{
for (int col = 0; col < retImg.cols; col++)
{
float v = harrisRspImg.at<float>(row, col);
if (v > t)
{
// 角度响应大于阈值,在当前位置显示出来,当角度响应阈值设的很低时,因为绘制的多,所以绘制速度会很慢
circle(retImg, Point(col, row), 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 2, 8, 0);
}
}
}
imshow(title_harris, retImg);
}
效果图