Harris角点检测

opencv官网教程
参考1
参考2

理论

在这里插入图片描述

在图像中取一个滑动窗口 W ( x y ) W_{(xy)} W(xy),不断移动窗口,观察窗口内的像素变化情况:

  • 任何一个方向上变化都很大: 角点
  • 一个方向变化大,另一个方向没有变化:边缘
  • 所有方向都没什么变化:平坦区域

数学表达:

  1. 对于灰度图像,滑动窗口,计算窗口的像素变化:
    E ( u , v ) = ∑ x , y w ( x , y ) [ I ( x + u , y + v ) − I ( x , y ) ] 2 E(u,v)=\sum_{x,y}{w(x,y)[I(x+u,y+v)-I(x,y)]}^2 E(u,v)=x,yw(x,y)[I(x+u,y+v)I(x,y)]2
    w ( x , y ) w(x,y) w(x,y):窗口的在(x,y)的位置
    I ( x , y ) I(x,y) I(x,y):在(x,y) 的像素值

  2. ∑ x , y [ I ( x + u , y + v ) − I ( x , y ) ] 2 \sum_{x,y}{[I(x+u,y+v)-I(x,y)]}^2 x,y[I(x+u,y+v)I(x,y)]2进行泰勒级数展开:
    ≈ ∑ x , y [ I ( x , y ) + u I x + v I y − I ( x , y ) ] 2 \approx \sum_{x,y}{[I(x,y)+uI_x+vI_y-I(x,y)]^2} x,y[I(x,y)+uIx+vIyI(x,y)]2
    展开多项式:
    ≈ ∑ x , y u 2 I x 2 + 2 u v I x I y + v 2 I y 2 \approx \sum_{x,y}{u^2I_x^2+2uvI_xI_y+v^2I_y^2} x,yu2Ix2+2uvIxIy+v2Iy2

  3. E ( u , v ) E(u,v) E(u,v)写成矩阵的形式: E ( u , v ) ≈ [ u ,   v ] ( ∑ x , y w ( x , y ) [ I x 2 I x I y I x I y I y 2 ] ) [ u v ] E(u,v)\approx\left[ \begin{matrix} u, \space v \end{matrix} \right] \left( \sum_{x,y}w(x,y) \left[ \begin{matrix} I_x^2 & I_xI_y\\ I_xI_y & I_y^2 \end{matrix} \right] \right)\left[ \begin{matrix} u \\ v \end{matrix} \right] E(u,v)[u, v](x,yw(x,y)[Ix2IxIyIxIyIy2])[uv]


  1. 我们让中间的部分记作 M M M(协方差矩阵),则有:
    E ( u , v ) = [ u ,   v ] M [ u v ] E(u,v)= \left[\begin{matrix} u, \space v \end{matrix} \right]M\left[ \begin{matrix} u \\ v \end{matrix} \right] E(u,v)=[u, v]M[uv]

  1. 我们规定 R R R代表每个窗口的得分,根据 R R R来判断窗口内是否有角点: R = d e t ( M ) − k ( T r a c e ( M ) ) 2 R=det(M)-k(Trace(M))^2 R=det(M)k(Trace(M))2
    d e t ( M ) = λ 1 λ 2 det(M)=\lambda_1\lambda_2 det(M)=λ1λ2
    T r a c e ( M ) = λ 1 + λ 2 Trace(M)=\lambda_1+\lambda_2 Trace(M)=λ1+λ2

  2. 结论:
    R R R > threashold :这是一个角点
    R R R < 0 并且 数值较大:这是边缘
    ∣ R ∣ = |R|= R=:小值:这是平坦区域



代码

#include <iostream>
#include <opencv2/opencv.hpp>


using namespace cv;
using namespace std;


Mat src, src_gray;
int thresh = 200;
int max_thresh = 255;

const char* source_window = "Source Image";
const char* corners_window = "Corners detected";

void cornerHarris_Demo(int, void*);


int main(void)
{

    src = imread("../res/image.png");
    if(src.empty())
    {
        cout << "can't load the image, please confirm the path" << endl;
        return -1;
    }


    cvtColor(src, src_gray, COLOR_BGR2GRAY);
    namedWindow(source_window);
    createTrackbar("Thresh", source_window, &thresh, max_thresh, cornerHarris_Demo);
    imshow(source_window ,src);
    cornerHarris_Demo(0, 0);

    waitKey();
    return 0;
}

void cornerHarris_Demo(int, void*)
{
    int blockSize = 2;
    int apertureSize = 3;
    double k = 0.04;

    Mat dst = Mat::zeros(src.size(), CV_32FC1);
    cornerHarris(src_gray, dst, blockSize, apertureSize, k);

    Mat dst_norm, dst_norm_scaled;
    normalize(dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat()); // normalize dst to dst_norm in the range of 0-255
    convertScaleAbs(dst_norm, dst_norm_scaled);   // dst(x,y) = saturate_cast<uchar>(src(x,y)*alpha+beta),defult:  alpha:1  beta:0

    for(int i=0; i<dst_norm.rows; i++)
    {
        for(int j=0; j<dst_norm.cols; j++)
        {
            if((int)dst_norm.at<float>(i,j) > thresh)
            {
                circle(dst_norm_scaled, Point(i, j), 5, Scalar(0), 2); 
                circle(src, Point(i, j), 5, Scalar(255,0,0), 2);
            }
        }
    }

    namedWindow(corners_window);
    imshow(corners_window, dst_norm_scaled);
    imshow(source_window ,src);
}

结果:

在这里插入图片描述




OpenCV API

  1. 在图像上进行Harris角点检测,对于每个像素 ( x , y ) (x,y) (x,y) ,计算2x2的梯度的协方差矩阵 M M M over blockSize x blockSize neighborhood, 然后计算: d s t ( x , y ) = d e t ( M ) − k ( T r a c e ( M ) ) 2 dst(x,y)=det(M)-k(Trace(M))^2 dst(x,y)=det(M)k(Trace(M))2

cornerHarris
(
InputArray src,     // 单通道, 8bits 或者 float 图
OutputArray dst,     // type CV_32FC1 and the same size as src,
int blockSize,     //理论里面的窗口 w w w的大小
int ksize,     // 计算梯度用的Sobel核的大小
double k,     // 上面公式的k ,一般取0.04-0.06
int borderType = BORDER_DEFAULT
)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值