目录
一. 概念
Harris角点检测内部实现:
cv::cornerHarris(…)
观察一个假定的特征点,周围小窗口内的,方向强度的 加权平均变化E。
首先获取一个点平均强度变化最大值对应的方向,接着检测位于它垂直方向的变化是否也 剧烈,如果是,那么该点便是一个角点。基于两个正交方向上的强度变化率。
通过对E进行 泰勒公式 近似展开,然后使用 矩阵形式 表示 ,得到一个协方差矩阵,那么协方差矩阵的两个特征值,就反应的图像中点的性质:两个特征值都比较低——同质区域,一大一小——边,都比较高——即是角点。
为了避免计算特征值,可以利用特征值的性质,判断当前像素点是否时角点。
矩阵的特征值之积 = 矩阵的行列式的值Determinant;
矩阵的特征值之和 = 矩阵的迹 Trace ,即矩阵对角线的和
然后可以使用公式 的值判断两个特征值是否足够高。 k 取值(0.05 – 0.5)之间
优缺点
优点: 对亮度和对比度的变化不敏感,
具有旋转不变性(各个方向的强度变化)
尺度不变性(梯度变化)
缺点: 计算量大
泰勒公式:是将一个在x=x0处具有n阶导数的函数f(x)利用关于(x-x0)的n次多项式来逼近函数的方法。
协方差矩阵: 每个元素是各个向量元素 的协方差 (去当前行当前列剩余的矩阵)。
二. 代码
main函数
#include "stdafx.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "HarrisDetector.h"
int main()
{
cv::Mat image = cv::imread("../../aTestImage/Buildingsm.jpg",0);
cv::namedWindow("image");
cv::imshow("image", image);
HarrisDetector harris;
harris.detect(image); //计算harris角点值
//显示中间过程处理图像效果
//cv::namedWindow("cornerStrength");
//cv::imshow("cornerStrength", harris.cornerStrength);
//cv::namedWindow("localMax");
//cv::imshow("localMax", harris.localMax);
cv::namedWindow("cornerHarrisResult");
cv::imshow("cornerHarrisResult", harris.getCornerMap(0.01));
std::vector<cv::Point> pts;
harris.getCorners(pts, 0.01); //获取harris角点
harris.drawOnImage(image, pts); //绘制harris角点到图像上
cv::namedWindow("harrisImage");
cv::imshow("harrisImage", image);
//计算适合跟踪的优质特征
cv::Mat image1 = cv::imread("../../aTestImage/Buildingsm.jpg", 0); //上面 绘制harris角点到图像 上是引用传递 改变原图,需重新加载一张
std::vector<cv::Point2f> pts2f;
harris.getCornersGoodFeatures(pts2f, image1,100); //获取harris角点 //可以指定最大特征点数目,质量等级,两点之间最小距离
harris.drawOnImageGoodFeatures(image1, pts2f); //绘制harris角点到图像上
cv::namedWindow("goodFeaturesImage");
cv::imshow("goodFeaturesImage", image1);
cv::waitKey(0);
return 0;
}
HarrisDetector.h
#pragma once
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
class HarrisDetector
{
public:
HarrisDetector() :neighbourhood(3), aperture(3), k(0.01), maxStrength(0.0), threshold(0.01), nonMaxSize(3)
{
//setLocalMaxWindowSize(nonMaxSize); //创建非极大值抑制核
}
~HarrisDetector();
void detect(const cv::Mat &image); //检测Harris角点
cv::Mat getCornerMap(double qualityLevel); //由Harris值获取角点图
void getCorners(std::vector<cv::Point> &points, double qualityLevel); //由Harris值得到特征点
void getCorners(std::vector<cv::Point> &points, const cv::Mat &cornerMap); //由角点图获取特征点
void getCornersGoodFeatures(std::vector<cv::Point2f>& points, cv::Mat & image,
int featureNum=500, double qualityLevel=0.01, int pointDistance=10);
void drawOnImage(cv::Mat &image, const std::vector<cv::Point> &points,
cv::Scalar color = cv::Scalar(255, 255, 255), int radius = 4, int thickness = 1); //在特征点位置上绘制圆
void drawOnImageGoodFeatures(cv::Mat & image, const std::vector<cv::Point2f>& points,
cv::Scalar color = cv::Scalar(255, 255, 255), int radius = 4, int thickness = 2);
cv::Mat localMax; //局部极大值图像
cv::Mat cornerStrength; //表示角点强度的32位浮点图像
private:
cv::Mat cornerTh; //阈值化得角点强度图像
int neighbourhood; // 导数平滑的相邻像素的尺寸
int aperture; //梯度计算的孔径的大小
double k; //Harris 参数
double maxStrength; //阈值计算的最大强度
double threshold; //计算得到的阈值
int nonMaxSize; //非极大值抑制的相邻像素的尺寸
cv::Mat kernel; //非极大值抑制的核
};
HarrisDetector.cpp
#include "stdafx.h"
#include "HarrisDetector.h"
//HarrisDetector::HarrisDetector()
//{
//}
HarrisDetector::~HarrisDetector()
{
}
void HarrisDetector::detect(const cv::Mat & image)
{
cv::cornerHarris(image, cornerStrength, neighbourhood, aperture, k); //获取角点强度图像
//计算各个方向强度变化的差方和 进行比较取最大,验证该方向垂直方向的强度变化得差方和是否也变化强烈,若是 则为角点
double minStrength;
cv::minMaxLoc(cornerStrength, &minStrength, &maxStrength);
cv::Mat dilated;
cv::dilate(cornerStrength, dilated, cv::Mat()); //膨胀
cv::compare(cornerStrength, dilated, localMax, cv::CMP_EQ); //获取局部最大值图像 //compare后,localMax仅在局部最大值的位置为真
}
cv::Mat HarrisDetector::getCornerMap(double qualityLevel)
{
cv::Mat cornerMap;
threshold = qualityLevel*maxStrength;
cv::threshold(cornerStrength, cornerTh, threshold, 255, cv::THRESH_BINARY);//二值化
cornerTh.convertTo(cornerMap, CV_8U); //转换成8位灰度图
cv::bitwise_and(cornerMap, localMax, cornerMap); // 与局部最大值and操作 得到角点图
return cornerMap;
}
void HarrisDetector::getCorners(std::vector<cv::Point>& points, double qualityLevel)
{
cv::Mat cornerMap = getCornerMap(qualityLevel);
getCorners(points, cornerMap);
}
void HarrisDetector::getCorners(std::vector<cv::Point>& points, const cv::Mat & cornerMap)
{
for (int y = 0; y < cornerMap.rows; y++)
{
const uchar *rowPtr = cornerMap.ptr<uchar>(y);
for (int x = 0; x < cornerMap.cols; x++)
{
if (rowPtr[x])
{
points.push_back(cv::Point(x, y));//获取特征点
}
}
}
}
void HarrisDetector::getCornersGoodFeatures(std::vector<cv::Point2f>& points ,
cv::Mat &image,int featureNum, double qualityLevel, int pointDistance)
{
cv::goodFeaturesToTrack(image, points, featureNum, qualityLevel, pointDistance);
}
void HarrisDetector::drawOnImage(cv::Mat & image, const std::vector<cv::Point>& points,
cv::Scalar color, int radius, int thickness)
{
std::vector<cv::Point>::const_iterator it = points.begin();
while (it != points.end())
{
cv:circle(image, *it, radius, color, thickness); //将点集以圆的形式画在image上
++it;
}
}
void HarrisDetector::drawOnImageGoodFeatures(cv::Mat & image, const std::vector<cv::Point2f>& points,
cv::Scalar color, int radius, int thickness)
{
std::vector<cv::Point2f>::const_iterator it = points.begin();
while (it != points.end())
{
cv:circle(image, *it, radius, color, thickness); //将点集以圆的形式画在image上
++it;
}
}
三. 效果图