Harris角点检测、[公式推导+代码实现]

本文详细阐述了Harris角点检测的基本原理,涉及角点响应矩阵的计算以及使用OpenCV库进行高斯函数和卷积操作。通过公式推导,展示了如何利用图像的一阶导数计算角点响应R,进而实现角点检测。代码实例演示了如何在实际项目中应用这些概念。
摘要由CSDN通过智能技术生成

Harris角点检测

提示:有添加超链接,点击跳转

视频推荐:小破站,会飞的吴克:点击跳转

opencv:简述
强烈推荐:CSE486, Penn State


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


提示:以下是本篇文章正文内容,下面案例可供参考

一、基本原理

在这里插入图片描述
左侧图,窗口W在平坦区域的运动,当位移比较小时,没有差值
中间图,窗口W只有在edge垂直方向,会有较大差值
右侧图,窗口W向任何方向移动,都会有较大的差值

公式:
E ( u , v ) = ∑ ( x , y ) ϵ W w ( x , y ) [ I ( x + u , y + v ) − I ( x , y ) ] 2  (公式 1 ) 对 I ( x + u , y + v ) 进行泰勒展开。 I ( x + u , y + v ) = I ( x , y ) + ∂ I ∂ x u + ∂ I ∂ y u + o ( ) I ( x + u , y + v ) ≈ I ( x , y ) + ∂ I ∂ x u + ∂ I ∂ y u ≈ I ( x , y ) + [ I x I y ] [ u v ] ( 公式 3 ) E(u,v) = \sum_{(x,y)\epsilon W} w(x,y)[I(x+u,y+v) - I(x,y)]^2 \space(公式1)\\ 对I(x+u,y+v)进行泰勒展开。\\ I(x+u,y+v) = I(x,y)+\frac{\partial I}{\partial x}u+\frac{\partial I}{\partial y}u+o() \\ I(x+u,y+v) \approx I(x,y)+\frac{\partial I}{\partial x}u+\frac{\partial I}{\partial y}u \approx I(x,y) + \begin{bmatrix} I_x&I_y \end{bmatrix} \begin{bmatrix} u \\ v \end{bmatrix} (公式3) E(u,v)=(x,y)ϵWw(x,y)[I(x+u,y+v)I(x,y)]2 (公式1I(x+u,y+v)进行泰勒展开。I(x+u,y+v)=I(x,y)+xIu+yIu+o()I(x+u,y+v)I(x,y)+xIu+yIuI(x,y)+[IxIy][uv](公式3)
将公式3代入公式1,得到:
E ( u , v ) ≈ ∑ ( x , y ) ϵ W w ( x , y ) [ [ I x I y ] [ u v ] ] 2 = ∑ ( x , y ) ϵ W w ( x , y ) [ u v ] [ I x 2 I x I y I y I x I y 2 ] [ u v ] ( 公式 4 ) E(u,v) \approx \sum_{(x,y)\epsilon W} w(x,y)[ \begin{bmatrix} I_x&I_y \end{bmatrix} \begin{bmatrix} u \\ v\end{bmatrix} ]^2 \\= \sum_{(x,y)\epsilon W} w(x,y) \begin{bmatrix} u&v \end{bmatrix} \begin{bmatrix} I_x^2 &I_xI_y \\ I_yI_x & I_y^2 \end{bmatrix} \begin{bmatrix} u\\v \end{bmatrix} (公式4) E(u,v)(x,y)ϵWw(x,y)[[IxIy][uv]]2=(x,y)ϵWw(x,y)[uv][Ix2IyIxIxIyIy2][uv](公式4)
对公式4接着进行展开,实对称矩阵相似对角化
E ( u , v ) = [ u v ] ∑ w ( x , y ) [ I x 2 I x I y I y I x I y 2 ] [ u v ] = [ u v ] P [ λ 1 0 0 λ 2 ] P T [ u v ] T = [ u ′ v ′ ] [ λ 1 0 0 λ 2 ] [ u ′ v ′ ] T         = λ 1 u ′ 2 + λ 2 v ′ 2           上式展开 = u ′ 2 1 λ 1 + v ′ 2 1 λ 2              (公式 5 ) E(u,v) = \begin{bmatrix} u&v \end{bmatrix} \sum w(x,y) \begin{bmatrix} I_x^2 & I_xI_y \\ I_yI_x & I_y^2 \end{bmatrix} \begin{bmatrix} u\\v \end{bmatrix} \\ = \begin{bmatrix} u&v \end{bmatrix} P \begin{bmatrix} \lambda _1 & 0 \\ 0 & \lambda_2 \end{bmatrix} P^T \begin{bmatrix} u&v \end{bmatrix} ^T \\ = \begin{bmatrix} u'&v' \end{bmatrix} \begin{bmatrix} \lambda _1 & 0 \\ 0 & \lambda_2 \end{bmatrix} \begin{bmatrix} u'&v' \end{bmatrix} ^T ~~~~~~~ \\ = \lambda _1u'^2+\lambda _2v'^2 \qquad ~~~~~~~~~~上式展开\\ = \frac{u'^2}{\frac{1}{\lambda _1} } + \frac{v'^2}{\frac{1}{\lambda _2} } \qquad ~~~~~~~~~~~~~(公式5) E(u,v)=[uv]w(x,y)[Ix2IyIxIxIyIy2][uv]=[uv]P[λ100λ2]PT[uv]T=[uv][λ100λ2][uv]T       =λ1u′2+λ2v′2          上式展开=λ11u′2+λ21v′2             (公式5
由公式4可知,当中间的二维矩阵(M)特征值最大时,即得到角点。
由公式5,就是一个椭圆公式,当椭圆成圆的时候面积是最大的,即偏差E(u,v)最大。
在这里插入图片描述

M = ∑ w ( x , y ) [ I x 2 I x I y I y I x I y 2 ] M = \sum w(x,y) \begin{bmatrix} I_x^2 & I_xI_y \\ I_yI_x & I_y^2 \end{bmatrix} M=w(x,y)[Ix2IyIxIxIyIy2]

如何更方便的表示E最大呢?

Corner Response Measure
R = d e t ( M ) − k [ t r a c e ( M ) ] 2 d e t ( M ) = λ 1 ∗ λ 2 t r a c e ( M ) = λ 1 + λ 2 R = det(M)-k[trace(M)]^2\\ det(M) = \lambda_1*\lambda_2\\ trace(M) = \lambda_1+\lambda_2 R=det(M)k[trace(M)]2det(M)=λ1λ2trace(M)=λ1+λ2
k为一个经验值,k = 0.04~0.06
所以,只用求得矩阵M的行列式和迹,便可以表示R

最后,在对R进行非极大值抑制,便得到key point

二、代码实现

1.自己实现的高斯函数和卷积

def gaussian_kernel_2d(size, sigma_x, sigma_y=None):
    if sigma_y is None:
        sigma_y = sigma_x

    x, y = np.meshgrid(np.linspace(-(size//2), size//2, size),
                       np.linspace(-(size//2), size//2, size))

    kernel_2d = (1 / (2 * np.pi * sigma_x * sigma_y)) * np.exp(-(x ** 2 / (2 * sigma_x ** 2) + y ** 2 / (2 * sigma_y ** 2)))
    # 归一化
    kernel_2d /= kernel_2d.sum()

    return kernel_2d
    
def conv2d(image, kernel):
    image = np.array(image, dtype=np.float64)
    kernel = np.array(kernel, dtype=np.float64)

    im_height, im_width = image.shape
    ker_height, ker_width = kernel.shape

    padded_image = np.zeros((im_height + ker_height - 1, im_width + ker_width - 1))
    padded_image[:im_height, :im_width] = image

    result = np.zeros_like(image)

    for i in range(im_height):
        for j in range(im_width):
            # 计算当前像素周围与内核大小一致区域内的卷积结果
            window = padded_image[i:i+ker_height, j:j+ker_width]
            conv_result = np.sum(window * kernel)
            result[i, j] = conv_result

    return result

2.计算R, Response Measure

代码如下(示例):

def harris_response(im, k=0.04, window_size=3, threshold=0.1):
    im.astype(np.float32)

    x_kernel = np.array([[-1, 0, 1],
                         [-2, 0, 2],
                         [-1, 0, 1]])
    y_kernel = np.array([[-1, -2, -1],
                         [0, 0, 0],
                         [1, 2, 1]])
    gaussian_k = gaussian_kernel_2d(3, 2)

    Ix = conv2d(im, x_kernel)
    Iy = conv2d(im, y_kernel)

    Ixx = Ix * Ix
    Iyy = Iy * Iy
    Ixy = Ix * Iy
    Ixx = conv2d(Ixx, gaussian_k)
    Iyy = conv2d(Iyy, gaussian_k)
    Ixy = conv2d(Ixy, gaussian_k)

    R_ = np.zeros(im.shape)

    for i in range(im.shape[0]):
        for j in range(im.shape[1]):
            M = np.array([[Ixx[i, j], Ixy[i, j]], [Ixy[i, j], Iyy[i, j]]])
            R_[i, j] = np.linalg.det(M) - k * np.trace(M) ** 2
    return R_

3. main

import cv2
import numpy as np

if __name__ == '__main__':
    in_filename = "./126007.jpg"
    im = cv2.imread(in_filename,cv2.IMREAD_ANYCOLOR)
    R = harris_response(cv2.cvtColor(im, cv2.COLOR_BGR2GRAY))
	print(R.mean())
    im[R > R.mean()] = [0,0,255]
    cv2.imwrite("harris.jpg", im)

原图
在这里插入图片描述
im[R > R.mean()] = [0,0,255] 效果图:

在这里插入图片描述

这里先简单的im[R > 10*R.mean()] = [0,0,255] 进行处理。简单粗暴,harris基本上掌握了~
在这里插入图片描述

也可以通过归一化、滤波器对相应函数R进行处理,再进行非极大值抑制,减少冗余检测点。


参考

提示:这里对文章进行总结:

https://blog.csdn.net/LeoEdwin/article/details/127539497
https://www.cse.psu.edu/~rtc12/CSE486/lecture06.pdf

  • 36
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值