Python机器视觉--OpenCV进阶(核心)-边缘检测之Harris角点检测与Shi-Tomasi角点检测

1.Harris角点检测

1.1 Harris角点检测原理

Harris角点检测是基于Moravec角点检测之上的, Moravec角点检测算子的思想其实特别简单,在图像上取一个W*W的“滑动窗口”,不断的移动这个窗口并检测窗口中的像素变化情况E。像素变化情况E可简单分为以下三种:

  • A 如果在窗口中的图像是什么平坦的,那么E的变化不大。
  • B 如果在窗口中的图像是一条边,那么在沿这条边滑动时E变化不大,而在沿垂直于这条边的方向滑动窗口时,E的变化会很大。
  • C 如果在窗口中的图像是一个角点时,窗口沿任何方向移动E的值都会发生很大变化。

1977年,Moravec最先提出了如下的角点检测方法:

  • 对于原始图像,取偏移量(Δx,Δy)为(1,0),(1,1),(0,1),(-1,1),分别计算每一像素点(xi,yi)的灰度变化
  • 对于每一像素点(xi,yi),计算角点响应函数R(xi,yi)=min E
  • 设定阈值T,将角点响应函数R(xi,yi)中低于T的值设为0
  • 在窗口范围内进行非极大值抑制:遍历角点响应函数,若某个像素的角点响应函数在窗口内不是最大,该像素置0
  • 选择非零点作为角点检测结果

Moravec角点检测的缺点

  • 二值的窗口函数导致角点响应函数不够光滑
  • 只在四个方向上计算灰度值变化,导致角点响应函数在多处都有较大响应
  • 对于每个点只考虑E的最小值,导致算法对边缘有很强的反应

1988年,Harris和Plessey对Moravec的方法进行了改进,提出了经典的Harris角点检测算法。Harris首先将Moravec算法中的窗口函数由阶跃函数改为二维高斯函数,并通过泰勒展开考察微小移动,接下来将详细讲解 Harris 角点检测算法.


图像 I(x,y) I(x,y),当在点(x,y)(x,y)处平移( Δ x \Delta x Δx, Δ y \Delta y Δy)( Δ x \Delta x Δx, Δ y \Delta y Δy)后的自相似性:

c(x,y; Δ x \Delta x Δx, Δ y \Delta y Δy)= ∑ ( u , v ) ∈ ( x , y ) w ( u , v ) ( I ( u , v ) − I ( u + Δ x , v + Δ y ) ) 2 \sum\limits_{(u,v)\in(x,y)}w(u,v)(I(u,v)-I(u+\Delta x,v+\Delta y))^2 (u,v)(x,y)w(u,v)(I(u,v)I(u+Δx,v+Δy))2

W(x,y)W(x,y)是以点(x,y)(x,y)为中心的窗口,即为加权函数,例如高斯加权函数
在这里插入图片描述
基于泰勒展开,对图像I(x,y)I(x,y) 在平移( Δ x \Delta x Δx, Δ y \Delta y Δy)( Δ x \Delta x Δx, Δ y \Delta y Δy)后进行一阶相似:

I ( u + Δ x , v + Δ y ) = I ( u , v ) + I x ( u , v ) Δ x + I y ( u , v ) Δ y + O ( Δ x 2 , Δ y 2 ) I(u+\Delta x,v+\Delta y)=I(u,v)+I_{x}(u,v)\Delta x+I_{y}(u,v)\Delta y+O(\Delta x^2,\Delta y^2) I(u+Δx,v+Δy)=I(u,v)+Ix(u,v)Δx+Iy(u,v)Δy+O(Δx2,Δy2)

≈ I ( u , v ) + I x ( u , v ) Δ x + I y ( u , v ) Δ y \approx I(u,v)+I_{x}(u,v)\Delta x+I_{y}(u,v)\Delta y I(u,v)+Ix(u,v)Δx+Iy(u,v)Δy

其中,lx,ly,lx,ly是图像I(x,y)I(x,y)的偏导数

近似可得:
c ( x , y ; Δ x , Δ y ) ≈ ∑ w ( I x ( u , v ) Δ x + I y ( u , v ) Δ y ) 2 = [ Δ x , Δ y ] M ( x , y ) [ Δ x Δ y ] c(x,y;\Delta x,\Delta y)\approx\sum\limits_{w}(I_{x}(u,v)\Delta x+I_{y}(u,v)\Delta y)^2=[\Delta x,\Delta y]M(x,y)\begin{bmatrix} \Delta x\\ \Delta y \end{bmatrix} c(x,y;Δx,Δy)w(Ix(u,v)Δx+Iy(u,v)Δy)2=[Δx,Δy]M(x,y)[ΔxΔy]

其中M:
M ( x , y ) = ∑ w [ I x ( x , y ) 2 I x ( x , y ) I y ( x , y ) I x ( x , y ) I y ( x , y ) I x ( x , y ) 2 ] = [ ∑ w I x ( x , y ) 2 ∑ w I x ( x , y ) I y ( x , y ) ∑ w I x ( x , y ) I y ( x , y ) ∑ w I x ( x , y ) 2 ] = [ A C C B ] M(x,y)=\sum\limits_{w}\begin{bmatrix}I_{x}(x,y)^2 & I_{x}(x,y)I_{y}(x,y) \\ I_{x}(x,y)I_{y}(x,y) & I_{x}(x,y)^2 \end{bmatrix}=\begin{bmatrix}\sum_{w}I_{x}(x,y)^2 & \sum_{w}I_{x}(x,y)I_{y}(x,y) \\ \sum_{w}I_{x}(x,y)I_{y}(x,y) & \sum_{w}I_{x}(x,y)^2 \end{bmatrix}=\begin{bmatrix}A & C\\ C & B \end{bmatrix} M(x,y)=w[Ix(x,y)2Ix(x,y)Iy(x,y)Ix(x,y)Iy(x,y)Ix(x,y)2]=[wIx(x,y)2wIx(x,y)Iy(x,y)wIx(x,y)Iy(x,y)wIx(x,y)2]=[ACCB]

化简可得:
c ( x , y ; Δ x , Δ y ) ≈ A Δ x 2 + 2 C Δ x Δ y + B Δ y 2 c(x,y;\Delta x,\Delta y)\approx A\Delta x^2+2C\Delta x\Delta y+B\Delta y^2 c(x,y;Δx,Δy)AΔx2+2CΔxΔy+BΔy2

A = ∑ w I x 2 , B = ∑ w I y 2 , C = ∑ w I x I y A=\sum\limits_{w}I_{x}^2,B=\sum\limits_{w}I_{y}^2,C=\sum\limits_{w}I_{x}I_{y} A=wIx2,B=wIy2,C=wIxIy

二次项函数本质上就是一个椭圆函数,椭圆方程为:
[ Δ x , Δ y ] M ( x , y ) [ Δ x Δ y ] = 1 \begin{bmatrix} \Delta x,\Delta y \end{bmatrix}M(x,y)\begin{bmatrix} \Delta x \\ \Delta y \end{bmatrix}=1 [Δx,Δy]M(x,y)[ΔxΔy]=1

在这里插入图片描述

在这里插入图片描述

角点的响应
R = d e t M − α ( t r a c e M ) 2 R=detM-\alpha(trace M)^2 R=detMα(traceM)2

其中:
d e t M = λ 1 λ 2 detM=\lambda_{1}\lambda_{2} detM=λ1λ2
t r a c e M = λ 2 + λ 2 trace M=\lambda_{2}+\lambda_{2} traceM=λ2+λ2

检测窗口在图像上移动, 上图对应着三种情况:

  • 在平坦区域, 无论向哪个方向移动, 衡量系统变换不大.
  • 边缘区域, 垂直边缘移动时, 衡量系统变换剧烈.
  • 在角点处, 往哪个方向移动, 衡量系统都变化剧烈

1.2 Harris角点检测基于OpenCV实现

  • cornerHarris(src, blockSize, ksize, k[, dst[, borderType]])

    • blockSize: 检测窗口大小
    • ksize: sobel的卷积核
    • k: 权重系数, 即上面公式中的 α \alpha α , 是个经验值, 一般取0.04~0.06之间.一般默认0.04

代码实现

import cv2
import numpy as np

img = cv2.imread('./chess.png')

# 变成灰度图片
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# harris角点检测
dst = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04)

# 返回的东西叫做角点响应. 每一个像素点都能计算出一个角点响应来. 
# print(dst)
print(dst.shape)
# 显示角点
# 我们认为角点响应大于0.01倍的dst.max()就可以认为是角点了.
img[dst > 0.01 * dst.max()] = [0, 0, 255]
cv2.imshow('img', img)

cv2.waitKey(0)
cv2.destroyAllWindows()

效果如图

在这里插入图片描述

2. Shi-Tomasi角点检测

  • Shi-Tomasi是Harris角点检测的改进.

  • Harris角点检测计算的稳定性和K有关, 而K是一个经验值, 不太好设定最佳的K值.

  • Shi-Tomasi 发现,角点的稳定性其实和矩阵 M 的较小特征值有关,于是直接用较小的那个特征值作为分数。这样就不用调整k值了。

    • Shi-Tomasi 将分数公式改为如下形式: R = m i n ( λ 1 λ 2 ) R= min(\lambda_1\lambda_2) R=min(λ1λ2)
    • 和 Harris 一样,如果该分数大于设定的阈值,我们就认为它是一个角点。
  • goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance[, corners[, mask[, blockSize[, useHarrisDetector[, k]]]]])

    • maxCorners: 角点的最大数, 值为0表示无限制
    • qualityLevel: 角点质量, 小于1.0的整数, 一般在0.01-0.1之间.
    • minDistance: 角之间最小欧式距离, 忽略小于此距离的点.
    • mask: 感兴趣的区域.
    • blockSize: 检测窗口大小
    • useHarrisDetector: 是否使用Harris算法.
    • k: 默认是0.04

代码实现

import cv2
import numpy as np

#harris
# blockSize = 2
# ksize = 3
# k = 0.04

#Shi-Tomasi
maxCorners = 1000
ql = 0.01
minDistance = 10

img = cv2.imread('chess.png')

#灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

corners = cv2.goodFeaturesToTrack(gray, maxCorners, ql, minDistance)
corners = np.int0(corners)

#Shi-Tomasi绘制角点
for i in corners:
    x,y = i.ravel()
    cv2.circle(img, (x,y), 3, (255,0,0), -1)

cv2.imshow('Shi-Tomasi', img)
cv2.waitKey(0)

效果如图

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43944517/article/details/126915286