OpenCV_Corner Detect with Harris and goodFeaturesToTrack( 基于Harris及适合跟踪的优质特征的角点检测)

目录

一. 概念

Harris角点检测内部实现:

优缺点

二. 代码

main函数

HarrisDetector.h

HarrisDetector.cpp

三. 效果图


一. 概念

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;
	}
}

 

三. 效果图


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

惊鸿一博

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值