opencv学习(四十四)之图像角点检测Harris

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/keith_bb/article/details/70208222

1.概述

角点是图像很重要的特征,对图像图形的理解和分析有很重要的作用,在保留图像图形重要特征的同时,可以有效减少信息的数据量,使信息的含量很高,有效提高计算速度,有利于图像的可靠匹配,使得实时处理成为可能。在物体识别、图像匹配、视觉跟踪和三维重建等方面有很重要的应用。
角点可以认为是窗口向任意方向的移动都导致图像灰度的明显变化。从图像分析的角度来定义角点可以有一下两种:
1.角点可以是两个边缘的角点
2.角点是邻域内具有两个主方向的特征点
前者往往需要对图像边缘进行编码,这在很大程度上依赖于图像的分割与边缘提取,具有相当大的难度和计算量,且一旦待检测目标局部发生变化,很可能导致操作的失败。
角点检测算法可以归纳为三类:基于灰度图像的角点检测、基于二值图像的角点检测、基于轮廓曲线的角点检测。基于灰度图像的检测又可细分为基于梯度、基于模板、基于模板梯度组合三类方法,其中基于模板的方法主要考虑像素邻域点的灰度变化,即图像亮度的变化,将与邻点亮度对比足够大的点定义为角点。常见的基于模板的角点检测算法有Kitchen-Rosenfeld角点检测,Harris角点检测算法,KLT角点检测和SUSAN角点检测。本文主要介绍Harris角点检测。

2.Harris角点检测原理

Harris角点检测原理推导靠一篇博客讲清楚不太现实,这里介绍一个比较直观的概念而不是数学推导。
Harris角点检测是一种直接基于灰度图像的角点提取算法,稳定性高,尤其对L型角点检测精度高。
人眼对角点的识别通常是在一个局部的小区域或小窗口完成的。如下图所示:

在各个方向上移动这个特征的小窗口,窗口内区域的灰度发生了较大的变化,那么久认为在窗口内遇到了角点,如果这个特定的窗口在图像各个方向上移动时,窗口内图像的灰度发生了很大变化,而在另一些方向上没有发生变化,那么窗口内的图像可能就是一条直线的线段。

3.opencv API

opencv提供cornerHarris()提取Harris角点。cornerHarris函数对每一个像素在blockSize x blockSize邻域内,计算2 x 2梯度的协方差矩阵M(x,y),,接着它计算如下公式输出局部最大值,即为角点。

void cv::cornerHarris   (   InputArray  src,
                            OutputArray     dst,
                            int     blockSize,
                            int     ksize,
                            double  k,
                            int     borderType = BORDER_DEFAULT 
                        )   

src:输入图像,Mat类型即可,必须为单通道8-bit或浮点型图像
dst:角点检测的输出结果,与原图像有相同的尺寸和类型
blockSize:邻域大小,可以查看cornerEigenValsAndVecs()得到更多关于blockSize的信息
ksize:表示Sobel()算子孔径大小
**k:**Harris参数,用于判断是否为角点
borderType:前面已多次介绍,为图像边界模式,有默认值BORDER_DEFAULT

4.示例代码

#include <iostream>
#include <stdlib.h>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace std;
using namespace cv;

//定义全局变量
Mat srcImage, grayImage;
int thresh = 100;
const int threshMaxValue = 255;

//声明回调函数
void cornerHarris_detect(int, void*);

int main()
{
    srcImage = imread("harris.jpg");

    //判断文件是否加载成功
    if (srcImage.empty())
    {
        cout << "图像加载失败!";
        return -1;
    }
    else
        cout << "图像加载成功..." << endl << endl;

    cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
    namedWindow("grayImage", WINDOW_AUTOSIZE);
    imshow("grayImage", grayImage);

    createTrackbar("Threshold:", "grayImage", &thresh, threshMaxValue, cornerHarris_detect);
    cornerHarris_detect(thresh, 0);

    waitKey(0);

    return 0;
}

void cornerHarris_detect(int, void*)
{
    Mat dstImage, dst_norm_image, dst_norm_scaled;
    dstImage = Mat::zeros(srcImage.size(), CV_32FC1);

    //检测器参数设置
    int blockSize = 2;          //邻域尺寸
    int apertureSize = 3;       //Sobel算子孔径
    double k = 0.04;            //Harris参数

    //角点检测
    cornerHarris(grayImage, dstImage, blockSize, apertureSize, k, BORDER_DEFAULT);

    normalize(dstImage, dst_norm_image, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
    convertScaleAbs(dst_norm_image, dst_norm_scaled);   //强归一化后的图像线性变换为8位无符号整型

    //绘制角点
    for (int j = 0; j < dst_norm_image.rows; j++)
    {
        for (int i = 0; i < dst_norm_image.cols; i++)
        {
            if ((int)dst_norm_image.at<float>(j,i)>thresh)
            {
                circle(dst_norm_scaled, Point(i, j), 5, Scalar(0), 2, 8, 0);
                circle(grayImage, Point(i, j), 5, Scalar(0, 0, 255), 2, 8, 0);
            }
        }
    }
    namedWindow("cornerHarris", WINDOW_AUTOSIZE);
    imshow("cornerHarris", dst_norm_scaled);
    namedWindow("corner_grayImage", WINDOW_AUTOSIZE);
    imshow("corner_grayImage", grayImage);
}

运行结果

5.参考文献

http://www.360doc.com/content/15/1212/23/20007814_519967668.shtml

猜你喜欢

转载自blog.csdn.net/keith_bb/article/details/70208222