• 为了保证你在浏览本网站时有着更好的体验,建议使用类似Chrome、Firefox之类的浏览器~~
    • 如果你喜欢本站的内容何不Ctrl+D收藏一下呢,与大家一起分享各种编程知识~
    • 本网站研究机器学习、计算机视觉、模式识别~当然不局限于此,生命在于折腾,何不年轻时多折腾一下

Opencv学习笔记(3)–Harris角点详细介绍

C++ admin 4年前 (2015-05-30) 3769次浏览 0个评论 扫描二维码

Harris 角点

基本原理

人眼对角点的识别通常是在一个局部的小区域或小窗口完成的。如果在各个方向上移动这个特征的小窗口,窗口内区域的灰度发生了较大的变化,那么就认为在窗口内遇到了角点。如果这个特定的窗口在图像各个方向上移动时,窗口内图像的灰度没有发生变化,那么窗口内就不存在角点;如果窗口在某一个方向移动时,窗口内图像的灰度发生了较大的变化,而在另一些方向上没有发生变化,那么,窗口内的图像可能就是一条直线的线段。

对于图像 I(x,y),当在点(x,y)处平移(Δx,Δy)后的自相似性,可以通过自相关函数给出:

其中,W(x,y)是以点(x,y)为中心的窗口,w(u,v)为加权函数,它既可是常数,也可以是高斯加权函数。


根据泰勒展开,对图像 I(x,y)在平移(Δx,Δy)后进行一阶近似:

其中,Ix,Iy 是图像 I(x,y)的偏导数,这样的话,自相关函数则可以简化为:

其中

也就是说图像 I(x,y)在点(x,y)处平移(Δx,Δy)后的自相关函数可以近似为二项函数:


其中:


二次项函数本质上就是一个椭圆函数。椭圆的扁率和尺寸是由 M(x,y)的特征值λ1、λ2 决定的,椭贺的方向是由 M(x,y)的特征矢量决定的,如下图所示,椭圆方程为:


椭圆函数特征值与图像中的角点、直线(边缘)和平面之间的关系如下图所示。共可分为三种情况:

– 图像中的直线。一个特征值大,另一个特征值小,λ1≫λ2 或λ2≫λ1。自相关函数值在某一方向上大,在其他方向上小。
– 图像中的平面。两个特征值都小,且近似相等;自相关函数数值在各个方向上都小。
– 图像中的角点。两个特征值都大,且近似相等,自相关函数在所有方向都增大。


根据二次项函数特征值的计算公式,我们可以求 M(x,y)矩阵的特征值。但是 Harris 给出的角点差别方法并不需要计算具体的特征值,而是计算一个角点响应值 R 来判断角点。R 的计算公式为:


式中,detM 为矩阵 M=[ABBC]的行列式;traceM 为矩阵 M 的直迹;α为经常常数,取值范围为 0.04~0.06。事实上,特征是隐含在 detM 和 traceM 中,因为:

说明

– 图像(x,y)与平移(Δx,Δy)之后得到的点之间的自相似性可以使用自相关函数表示。自相关函数维基百科上给出的定义如下:

根据期望的定义可以分解为上述像素点之间的近似性描述。

– R 的值决定了该像素点是否为角点。根据矩阵理论特征值与聚珍版本身的联系,R 值的求解至于特征值本身存在着关系。当特征值都大时,R 值也随之变大。特征值都小时,R 值更小。特征之一大一小,结果也不会比之前描述的情况大,这介于特征值都大和特征值都小之间。

Harris 算法流程

根据上述讨论,可以将 Harris 图像角点检测算法归纳如下,共分以下五步:

– 计算图像 I(x,y)在 X 和 Y 两个方向的梯度 Ix、Iy。

– 计算图像两个方向梯度的乘积。

– 使用高斯函数对 I2x、I2y 和 Ixy 进行高斯加权(取σ=1),生成矩阵 M 的元素 A、B 和 C。

– 计算每个像素的 Harris 响应值 R,并对小于某一阈值 t 的 R 置为零。

– 在 3×3 或 5×5 的邻域内进行非最大值抑制,局部最大值点即为图像中的角点。

实验数据分析

//HarrisDect.h

#if !defined HARRISD
#define HARRISD

#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/nonfree/features2d.hpp>
class HarrisDetector {

private:

// 32-bit float image of corner strength
cv::Mat cornerStrength;
// 32-bit float image of thresholded corners
cv::Mat cornerTh;
// image of local maxima (internal)
cv::Mat localMax;
// size of neighbourhood for derivatives smoothing
int neighbourhood;
// aperture for gradient computation
int aperture;
// Harris parameter
double k;
// maximum strength for threshold computation
double maxStrength;
// calculated threshold (internal)
double threshold;
// size of neighbourhood for non-max suppression
int nonMaxSize;
// kernel for non-max suppression
cv::Mat kernel;

public:

HarrisDetector() : neighbourhood(3), aperture(3), k(0.1), maxStrength(0.0), threshold(0.01), nonMaxSize(3) {

setLocalMaxWindowSize(nonMaxSize);
}

// Create kernel used in non-maxima suppression
void setLocalMaxWindowSize(int size) {

nonMaxSize= size;
kernel.create(nonMaxSize,nonMaxSize,CV_8U);
}

// Compute Harris corners
void detect(const cv::Mat& image) {

// Harris computation
cv::cornerHarris(image,cornerStrength,
neighbourhood,// neighborhood size
aperture,     // aperture size
k);           // Harris parameter

// internal threshold computation
double minStrength; // not used
cv::minMaxLoc(cornerStrength,&minStrength,&maxStrength);

// local maxima detection
cv::Mat dilated;  // temporary image
cv::dilate(cornerStrength,dilated,cv::Mat());
cv::compare(cornerStrength,dilated,localMax,cv::CMP_EQ);
}

// Get the corner map from the computed Harris values
cv::Mat getCornerMap(double qualityLevel) {

cv::Mat cornerMap;

// thresholding the corner strength
threshold= qualityLevel*maxStrength;
cv::threshold(cornerStrength,cornerTh,threshold,255,cv::THRESH_BINARY);

// convert to 8-bit image
cornerTh.convertTo(cornerMap,CV_8U);

// non-maxima suppression
cv::bitwise_and(cornerMap,localMax,cornerMap);

return cornerMap;
}

// Get the feature points vector from the computed Harris values
void getCorners(std::vector<cv::Point> &points, double qualityLevel) {

// Get the corner map
cv::Mat cornerMap= getCornerMap(qualityLevel);
// Get the corners
getCorners(points, cornerMap);
}

// Get the feature points vector from the computed corner map
void getCorners(std::vector<cv::Point> &points, const cv::Mat& cornerMap) {

// Iterate over the pixels to obtain all feature points
for( int y = 0; y < cornerMap.rows; y++ ) {

const uchar* rowPtr = cornerMap.ptr<uchar>(y);

for( int x = 0; x < cornerMap.cols; x++ ) {

// if it is a feature point
if (rowPtr[x]) {

points.push_back(cv::Point(x,y));
}
}
}
}

// Draw circles at feature point locations on an image
void drawOnImage(cv::Mat &image, const std::vector<cv::Point> &points, cv::Scalar color= cv::Scalar(255,255,255), int radius=3, int thickness=2) {

std::vector<cv::Point>::const_iterator it= points.begin();

// for all corners
while (it!=points.end()) {

// draw a circle at each corner location
cv::circle(image,*it,radius,color,thickness);
++it;
}
}
};

#endif

主程序:

#include <iostream>
#include <vector>
#include <HarrisDect.h>
int main()
{
// Read input image
cv::Mat image= cv::imread("church01.jpg",0);
if (!image.data)
return 0;

// Display the image
cv::namedWindow("Original Image");
cv::imshow("Original Image",image);

// Detect Harris Corners
cv::Mat cornerStrength;
cv::cornerHarris(image,cornerStrength,
3,     // neighborhood size
3,     // aperture size
0.01); // Harris parameter

// threshold the corner strengths
cv::Mat harrisCorners;
double threshold= 0.0001;
cv::threshold(cornerStrength,harrisCorners,
threshold,255,cv::THRESH_BINARY_INV);

// Display the corners
cv::namedWindow("Harris Corner Map");
cv::imshow("Harris Corner Map",harrisCorners);

// Create Harris detector instance
HarrisDetector harris;
// Compute Harris values
harris.detect(image);
// Detect Harris corners
std::vector<cv::Point> pts;
harris.getCorners(pts,0.01);
// Draw Harris corners
harris.drawOnImage(image,pts);

// Display the corners
cv::namedWindow("Harris Corners");
cv::imshow("Harris Corners",image);
cv::waitKey();
}

注释:实验代码借用 Opencv2 计算机视觉编程手册,发现作者给出的代码出现部分头文件缺失,代码地址为[点击这里](https://github.com/ITpublishing/opencv-2-cookbook-src)

只要在头文件中加入#include <opencv2/nonfree/features2d.hpp>即可!
## 结果示意图 ##
实验原图:

角点图:


原图+角点:

结果分析

对于实验的结果图中检测出大量的角点,但是通过改变角点响应值的阈值大小可以同步改变被检测出角点的数量。


Deeplearn, 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明Opencv 学习笔记(3)–Harris 角点详细介绍
喜欢 (1)
admin
关于作者:
互联网行业码农一枚/业余铲屎官/数码影音爱好者/二次元

您必须 登录 才能发表评论!