1.步骤
(1)定义好Harris角点检测与Shi-Tomas角点检测需要的变量,存放响应值的矩阵以及滑块响应函数
(2)源图像灰度处理
(3)Harris使用cornerEigenValsAndVecs函数,获取特征值;Shi-Tomas使用cornerMinEigenVal函数获取特征值
(4)公式计算响应值:Harris为: lamda1*lamda2 - k*(lamda1 + lamda2)^2
(5)计算阈值公式:threshold=最小响应值+q*(最大响应值-最小响应值) (q为0-1之间的小数,可以通过滑块动态控制)
(6)响应值与阈值进行比较,比阈值大的判定为角点,用circle作出来
2.相关API
(1)cv::cornerEigenValsAndVecs(InputArray src,OutputArray dst,int blocksize,int ksize,int borderType=BORDER_DEFAULT)
src:源图像
dst:输出矩阵,存放(λ1, λ2, x1, y1, x2, y2),2个特征值与特征向量,所以必须比输入图像宽 6 倍
blocksize:计算导数微分不同的窗口大小
ksize:移动窗口大小
borderType:边界处理方式
(2)cv::cornerMinEigenVal(InputArray src,OutputArray dst,int blocksize,int ksize,int borderType=BORDER_DEFAULT)
src:源图像
dst:存放最小特征值
blocksize:计算导数微分不同的窗口大小
ksize:移动窗口大小
borderType:边界处理方式
3.代码实现
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
Mat src, dst, graySrc;
//定义窗口
const char* harris_win = "Custom Harris Corners Detector";
const char* shitomasi_win = "Custom shitomasi_win Corners Detector";
//Harris角点检测所需
Mat harris_dst,harrisRspImg; //分别存放特征值和角点响应值
double harris_min_rsp; //分别存放最大最小角点响应值,用于计算合理阈值判断角点
double harris_max_rsp;
void CustomHarris_Demo(int, void*); //call函数
//Shitomasi角点检测所需
Mat shiTomasiRsp;
double shitomasi_max_rsp;
double shitomasi_min_rsp;
void CustomShiTomasi_Demo(int, void*);
//滑块变量
int quality_value = 30;
int quality_max = 120;
int main()
{
src = imread("D:/VS project/Image/qp.jpg");
if (src.empty())
{
cout << "无法找到图像" << endl;
return -1;
}
namedWindow("inputName", CV_WINDOW_AUTOSIZE);
imshow("inputName", src);
cvtColor(src, graySrc, COLOR_BGR2GRAY);
//自定义Harris角点检测
int blockSize = 3;
int ksize = 3;
double k = 0.04;
harris_dst = Mat::zeros(src.size(), CV_32FC(6)); //必须比输入图像宽 6 倍,存放(λ1, λ2, x1, y1, x2, y2),2个特征值与特征向量
harrisRspImg = Mat::zeros(src.size(), CV_32FC1);
cornerEigenValsAndVecs(graySrc, harris_dst, blockSize, ksize, 4);//检测矩阵对应的特征值
for (int row = 0; row < harris_dst.rows; row++) //计算响应值每个点
{
for (int col = 0; col < harris_dst.cols; col++)
{
double lamda1 = harris_dst.at<Vec6f>(row, col)[0];
double lamda2 = harris_dst.at<Vec6f>(row, col)[1];
harrisRspImg.at<float>(row, col) = lamda1*lamda2 - k*pow((lamda1 + lamda2), 2);
}
}
minMaxLoc(harrisRspImg, &harris_min_rsp, &harris_max_rsp, 0, 0, Mat());//取出响应值最大最小值
namedWindow(harris_win, CV_WINDOW_AUTOSIZE);
createTrackbar("Harris Quatity_level Value:", harris_win, &quality_value, quality_max, CustomHarris_Demo);
CustomHarris_Demo(0, 0);
//shiTomas自定义角点检测
shiTomasiRsp = Mat::zeros(src.size(), CV_32FC1);
cornerMinEigenVal(graySrc, shiTomasiRsp, blockSize, ksize, 4);
minMaxLoc(shiTomasiRsp, &shitomasi_min_rsp, &shitomasi_max_rsp, 0, 0, Mat());
namedWindow(shitomasi_win, CV_WINDOW_AUTOSIZE);
createTrackbar("ShiTomas Quatity_level Value:", shitomasi_win, &quality_value, quality_max, CustomShiTomasi_Demo);
CustomShiTomasi_Demo(0, 0);
waitKey(0);
}
void CustomHarris_Demo(int, void *)
{
if (quality_value < 10)
{
quality_value = 10;
}
Mat resultImg = src.clone(); //输出图像克隆下原图
float harris_threshold= harris_min_rsp + (((double)quality_value) / quality_max)*(harris_max_rsp - harris_min_rsp);//算出阈值
for (int row = 0; row < src.rows; row++) {
for (int col = 0; col < src.cols; col++)
{
float harris_value = harrisRspImg.at<float>(row, col);
if (harris_value>harris_threshold) {
circle(resultImg, Point(col, row), 2, Scalar(0, 0, 255), 2, 8, 0);
}
}
}
imshow(harris_win, resultImg);
}
void CustomShiTomasi_Demo(int, void*) {
if (quality_value < 10)
{
quality_value = 10;
}
Mat resultImg = src.clone(); //输出图像克隆下原图
float shiTomas_threshold= shitomasi_min_rsp + (((double)quality_value) / quality_max)*(shitomasi_max_rsp - shitomasi_min_rsp);
for (int row = 0; row < src.rows; row++) {
for (int col = 0; col < src.cols; col++) {
float shiTomas_value = shiTomasiRsp.at<float>(row, col);
if (shiTomas_value > shiTomas_threshold) {
circle(resultImg, Point(col, row), 2, Scalar(0, 0, 255), 2, 8, 0);
}
}
}
imshow(shitomasi_win, resultImg);
}