Python计算机视觉——Harris角点检测

Python计算机视觉——Harris角点检测

写在前面

在传统目标识别中,特征提取是最终目标识别效果好坏的一个重要决定因素,因此,在这项工作里,有很多研究者把主要精力都放在特征提取方向。在传统目标识别中,主要使用的特征主要有如下几类:

  • 边缘特征(Canny算子)
  • 纹理特征(小波Gabor算子)
  • 角点特征(Harris算子)

那何为角点?

  • 局部窗口沿各方向移动,均产生明显变化的点
  • 图像局部曲率突变的点

在这里插入图片描述

1 Harris角点检测基本思想

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

在这里插入图片描述

2 Harris角点检测公式推导

将窗口平移[u, v]产生的灰度变化E(u, v),根据上述的基本思想可知,若E(u, v)越大,则是角点的概率就越大。公式如下:
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)是窗口函数,以点(x,y)为中心的窗口。I(x+u, y+v)是平移后的图像灰度,I(x, y)是平移前的灰度。
f ( x + u , y + v ) = f ( x , y ) + u f x ( x , y ) + v f y ( x , y ) + F i r s t − p a r t i a l − d e r i v a t i v e s 1 2 ! [ u 2 f x x ( x , y ) + u v f x y x , y + v 2 f y y ( x , y ) ] + S e c o n d − p a r t i a l − d e r i v a t i v e s … … f(x+u, y+v)=f(x, y)+u f_{x}(x, y)+v f_{y}(x, y)+\\First-partial- derivatives\\\frac{1}{2 !}\left[u^{2} f_{x x}(x, y)+u v f_{x y} x, y+v^{2} f_{y y}(x, y)\right]+\\Second-partial-derivatives\\…… f(x+u,y+v)=f(x,y)+ufx(x,y)+vfy(x,y)+Firstpartialderivatives2!1[u2fxx(x,y)+uvfxyx,y+v2fyy(x,y)]+Secondpartialderivatives
所以,可以约等于
f ( x + u , y + v ) ≈ f ( x , y ) + u f x ( x , y ) + v f y ( x , y ) 即 等 于 : I ( x + u , y + v ) ≈ I ( x , y ) + u I x ( x , y ) + v I y ( x , y ) f(x+u, y+v) \approx f(x, y)+u f_{x}(x, y)+v f_{y}(x, y)\\即等于:\\I(x+u, y+v) \approx I(x, y)+u I_{x}(x, y)+v I_{y}(x, y) f(x+u,y+v)f(x,y)+ufx(x,y)+vfy(x,y)I(x+u,y+v)I(x,y)+uIx(x,y)+vIy(x,y)
因此得到如下推导:

在这里插入图片描述

于是对于局部微小的移动量 [u, v],可以近似得到下面的表达式:
E ( u , v ) ≅ [ u , v ] M [ u v ] E(u, v) \cong[u, v] M\left[\begin{array}{l} u \\ v \end{array}\right] E(u,v)[u,v]M[uv]
其中M是 2×2 矩阵,可由图像的导数求得:
M = ∑ x , y w ( x , y ) [ I x 2 I x I y I x I y I y 2 ] M=\sum_{x, y} w(x, y)\left[\begin{array}{cc} I_{x}^{2} & I_{x} I_{y} \\ I_{x} I_{y} & I_{y}^{2} \end{array}\right] M=x,yw(x,y)[Ix2IxIyIxIyIy2]
窗口移动导致的图像变化量:实对称矩阵M的 特征值分析:
E ( u , v ) ≅ [ u , v ] M [ u v ]  记  M  的特征值为  λ 1 , λ 2 \begin{array}{l} E(u, v) \cong[u, v] M\left[\begin{array}{l} u \\ v \end{array}\right]\\ \text { 记 } M \text { 的特征值为 } \lambda_{1}, \lambda_{2} \end{array} E(u,v)[u,v]M[uv]  M 的特征值为 λ1,λ2
则根据两个特征值得到结论

  • 如果矩阵对应的两个特征值都较大,那么窗口内含有角点
  • 如果特征值一个大一个小,那么窗口内含有线性边缘
  • 如果两个特征值都很小,那么窗口内为平坦区域

所以上述兜兜转转,把角点的检测转化为数学模型,就是求解窗口内矩阵的特征值并且判断特征值的大小。

再多定义个式子:角点响应函数R
R = det ⁡ M − k ( trace ⁡ M ) 2 其 中 : det ⁡ M = λ 1 λ 2  trace  M = λ 1 + λ 2 ( k −  empirical constant,  k = 0.04 ∼ 0.06 ) \begin{array}{c} R=\operatorname{det} M-k(\operatorname{trace} M)^{2} \\其中:\\ \operatorname{det} M=\lambda_{1} \lambda_{2} \\ \text { trace } M=\lambda_{1}+\lambda_{2} \\ (k-\text { empirical constant, } k=0.04 \sim 0.06) \end{array} R=detMk(traceM)2:detM=λ1λ2 trace M=λ1+λ2(k empirical constant, k=0.040.06)
同理可得:

  • 角点:R 为大数值正数
  • 边缘:R为大数值负数
  • 平坦区:R为小数值

3 实验分析

捋一下整个Harris角点检测步骤:

  1. 读取图片,将图片转化成灰度图
  2. 计算响应函数
  3. 基于响应值选择角点
  4. 在原图中画出检测的角点

源码如下:

新建文件Harris_Detector.py

from pylab import *
from numpy import *
from scipy.ndimage import filters


def compute_harris_response(im,sigma=3):
    """ Compute the Harris corner detector response function 
        for each pixel in a graylevel image. """
    
    # derivatives
    imx = zeros(im.shape)
    filters.gaussian_filter(im, (sigma,sigma), (0,1), imx)
    imy = zeros(im.shape)
    filters.gaussian_filter(im, (sigma,sigma), (1,0), imy)
    
    # compute components of the Harris matrix
    Wxx = filters.gaussian_filter(imx*imx,sigma)
    Wxy = filters.gaussian_filter(imx*imy,sigma)
    Wyy = filters.gaussian_filter(imy*imy,sigma)
    
    # determinant and trace
    Wdet = Wxx*Wyy - Wxy**2
    Wtr = Wxx + Wyy
    
    return Wdet / Wtr
   
    
def get_harris_points(harrisim,min_dist=10,threshold=0.1):
    """ Return corners from a Harris response image
        min_dist is the minimum number of pixels separating 
        corners and image boundary. """
    
    # find top corner candidates above a threshold
    corner_threshold = harrisim.max() * threshold
    harrisim_t = (harrisim > corner_threshold) * 1
    
    # get coordinates of candidates
    coords = array(harrisim_t.nonzero()).T
    
    # ...and their values
    candidate_values = [harrisim[c[0],c[1]] for c in coords]
    
    # sort candidates (reverse to get descending order)
    index = argsort(candidate_values)[::-1]
    
    # store allowed point locations in array
    allowed_locations = zeros(harrisim.shape)
    allowed_locations[min_dist:-min_dist,min_dist:-min_dist] = 1
    
    # select the best points taking min_distance into account
    filtered_coords = []
    for i in index:
        if allowed_locations[coords[i,0],coords[i,1]] == 1:
            filtered_coords.append(coords[i])
            allowed_locations[(coords[i,0]-min_dist):(coords[i,0]+min_dist), 
                        (coords[i,1]-min_dist):(coords[i,1]+min_dist)] = 0
    
    return filtered_coords
    
    
def plot_harris_points(image,filtered_coords):
    """ Plots corners found in image. """
    
    figure()
    gray()
    imshow(image)
    plot([p[1] for p in filtered_coords],
                [p[0] for p in filtered_coords],'*')
    axis('off')
    show()

上述三个函数分别代表这步骤中的234。1步骤则新建test_harris.py

from PIL import Image
from numpy import *
# 这就是为啥上述要新建一个的原因,因为现在就可以import
import Harris_Detector
from pylab import *
from scipy.ndimage import filters

# filename
im = array(Image.open(r"  ").convert('L'))
harrisim=Harris_Detector.compute_harris_response(im)
filtered_coords=Harris_Detector.get_harris_points(harrisim)
Harris_Detector.plot_harris_points(im,filtered_coords)

实验结果如下:由图可知不同的阈值,检测出的角点个数会不同。阈值越小,则检测出的角点会越多,意味着符合该条件的角点就会多,但同样意味着放低了条件,有些不确定不准确的角点也有可能被检测;增大阈值范围,则检测到的角点会变少,但相对来说每个角点的置信程度较高,所以说阈值的选择就是empirical constant。其实现在opencv也有自带的函数库 cv2.cornerHarris能够直接完成harris角点检测,可直接使用。
在这里插入图片描述
对于图像匹配,在Harris_Detector.py中加入如下5个函数。Harris 角点检测器仅仅能够检测出图像中的兴趣点,但是没有给出通过比较图像间的兴趣点来寻找匹配角点的方法。我们需要在每个点上加入描述子信息,并给出一个比较这些描述子的方法。兴趣点描述子是分配给兴趣点的一个向量,描述该点附近的图像的表观信息。描述子越好,寻找到的对应点越好。我们用对应点或者点的对应来描述相同物体和场景点在不同图像上形成的像素点。

def get_descriptors(image,filtered_coords,wid=5):
    """ For each point return pixel values around the point
        using a neighbourhood of width 2*wid+1. (Assume points are 
        extracted with min_distance > wid). """
    
    desc = []
    for coords in filtered_coords:
        patch = image[coords[0]-wid:coords[0]+wid+1,
                            coords[1]-wid:coords[1]+wid+1].flatten()
        desc.append(patch)
    
    return desc


def match(desc1,desc2,threshold=0.5):
    """ For each corner point descriptor in the first image, 
        select its match to second image using
        normalized cross correlation. """
    
    n = len(desc1[0])
    
    # pair-wise distances
    d = -ones((len(desc1),len(desc2)))
    for i in range(len(desc1)):
        for j in range(len(desc2)):
            d1 = (desc1[i] - mean(desc1[i])) / std(desc1[i])
            d2 = (desc2[j] - mean(desc2[j])) / std(desc2[j])
            ncc_value = sum(d1 * d2) / (n-1) 
            if ncc_value > threshold:
                d[i,j] = ncc_value
            
    ndx = argsort(-d)
    matchscores = ndx[:,0]
    
    return matchscores


def match_twosided(desc1,desc2,threshold=0.5):
    """ Two-sided symmetric version of match(). """
    
    matches_12 = match(desc1,desc2,threshold)
    matches_21 = match(desc2,desc1,threshold)
    
    ndx_12 = where(matches_12 >= 0)[0]
    
    # remove matches that are not symmetric
    for n in ndx_12:
        if matches_21[matches_12[n]] != n:
            matches_12[n] = -1
    
    return matches_12


def appendimages(im1,im2):
    """ Return a new image that appends the two images side-by-side. """
    
    # select the image with the fewest rows and fill in enough empty rows
    rows1 = im1.shape[0]    
    rows2 = im2.shape[0]
    
    if rows1 < rows2:
        im1 = concatenate((im1,zeros((rows2-rows1,im1.shape[1]))),axis=0)
    elif rows1 > rows2:
        im2 = concatenate((im2,zeros((rows1-rows2,im2.shape[1]))),axis=0)
    # if none of these cases they are equal, no filling needed.
    
    return concatenate((im1,im2), axis=1)
    
    
def plot_matches(im1,im2,locs1,locs2,matchscores,show_below=True):
    """ Show a figure with lines joining the accepted matches 
        input: im1,im2 (images as arrays), locs1,locs2 (feature locations), 
        matchscores (as output from 'match()'), 
        show_below (if images should be shown below matches). """
    
    im3 = appendimages(im1,im2)
    if show_below:
        im3 = vstack((im3,im3))
    
    imshow(im3)
    
    cols1 = im1.shape[1]
    for i,m in enumerate(matchscores):
        if m>0:
            plot([locs1[i][1],locs2[m][1]+cols1],[locs1[i][0],locs2[m][0]],'c')
    axis('off')

然后新建match_harris.py调用

import Harris_Detector
from pylab import *
from PIL import Image
 

im1 = array(Image.open(r"  ").convert("L"))
im2 = array(Image.open(r"  ").convert("L"))

wid =5
harrisim = Harris_Detector.compute_harris_response(im1,5)
filtered_coords1 = Harris_Detector.get_harris_points(harrisim,wid+1)
d1 = Harris_Detector.get_descriptors(im1,filtered_coords1,wid)

harrisim = Harris_Detector.compute_harris_response(im2,5)
filtered_coords2 = Harris_Detector.get_harris_points(harrisim,wid+1)
d2 = Harris_Detector.get_descriptors(im2,filtered_coords2,wid)

print('starting mathching')
matches = Harris_Detector.match_twosided(d1,d2)

figure()
gray()
Harris_Detector.plot_matches(im1,im2,filtered_coords1,filtered_coords2,matches)
show()

效果如下:
在这里插入图片描述
在这里插入图片描述
若匹配的图片完全一样,则可以发现,角点匹配完全正确。可是若照片中的目标发生了偏移,发现该算法存在一些不正确的匹配,是由于图像像素块的互相关矩阵具有较弱的描述性,在实际运用中,可以使用更加稳健的方法来处理这些对应匹配。

  • 27
    点赞
  • 118
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
import cv2 as cv import numpy as np """"" cv2.cornerHarris() 可以用来进行角点检测。参数如下: • img - 数据类型为 float32 的输入图像。 • blockSize - 角点检测中要考虑的领域大小。 • ksize - Sobel 求导中使用的窗口大小 • k - Harris 角点检测方程中的自由参数,取值参数为 [0,04,0.06] """"" src_inital = cv.imread("E:/opencv/picture/building.jpg") src = cv.cvtColor(src_inital,cv.COLOR_BGR2GRAY) src = np.float32(src) dst = cv.cornerHarris(src,3,3,0.04) #R值是由det(M)-K(trace(M))*(trace(M)),当该点是角点时,该点所对应的R值就会很大,通过设置对R的阈值,就可以筛选得到角点 #这里的dst就是R值构成的灰度图像,灰度图像坐标会与原图像对应,R值就是角点分数,当R值很大的时候 就可以认为这个点是一个角点 print(dst.shape) src_inital[dst>0.08*dst.max()]=[0,0,255] """"" src_inital[dst>0.08*dst.max()]=[0,0,255] 这句话来分析一下 dst>0.08*dst.max()这么多返回是满足条件的dst索引值,根据索引值来设置这个点的颜色 这里是设定一个阈值 当大于这个阈值分数的都可以判定为角点 dst其实就是一个个角度分数R组成的,当λ1和λ2都很大,R 也很大,(λ1和λ2中的最小值都大于阈值)说明这个区域是角点。 那么这里为什么要大于0.08×dst.max()呢 注意了这里R是一个很大的值,我们选取里面最大的R,然后只要dst里面的值大于百分之八的R的最大值  那么此时这个dst的R值也是很大的 可以判定他为角点,也不一定要0.08可以根据图像自己选取不过如果太小的话 可能会多圈出几个不同的角点 """"" cv.imshow("inital_window",src_inital) cv.waitKey(0) cv.destroyAllWindows() 目标: 理解Harris角点检测的概念 使用函数cv2.cornerHarris(),cv2.cornerSubPix() 原理: Harris 角点检测的方法大概原理就是建立一个窗口区域,然后以当前窗口为中心向各个方向进行偏移。 如上图所示,第一个窗口向各个方向偏移的时候,像素值没有变化,因为窗口偏移的时候没有遇到任何边缘信息。 第二个图,窗口当中有一个直线(即block是在边缘上),如果当前窗口进行上下的移动,也没有像素值发生变化(在其他方向上灰度值也会变化)。 第三个图,窗口覆盖了一个“拐角”,如果窗口进行偏移,任何方向上都会有像素变化。 所以,第三张图片判断为检测到角点。 判断特征点是否为角点的依据:R只与M值有关,R为大数值正数时特征点为角点,R为大数值负数时为边缘,R为小数值时为平坦区 寻找R位于一定阈值之上的局部最大值,去除伪角点。 方向导数IxIx和IyIy可以使用cv2.Sobel()函数得到 Harris角点检测的结果是灰度图,图中的值为角点检测的打分值。需要选取合适的阈值对结果进行二值化来检测角点。
### 回答1: Harris角点检测是一种常见的计算机视觉算法,它可以检测图像中的角点。在Python中,可以使用OpenCV库来实现Harris角点检测。 下面是一个简单的Harris角点检测Python实现的示例: ``` import cv2 import numpy as np # 加载图像 img = cv2.imread('image.jpg') # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 计算Harris角点 dst = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04) # 通过阈值进行筛选 img[dst > 0.01 * dst.max()] = [0, 0, 255] # 显示结果 cv2.imshow('Harris Corner Detection', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 首先,使用`cv2.imread`函数加载要处理的图像。然后,将图像转换为灰度图像,以便进行角点检测。接下来,使用`cv2.cornerHarris`函数计算图像中的Harris角点。在这个函数中,`blockSize`是要考虑的邻域大小,`ksize`是Sobel算子的大小,`k`是Harris角点响应函数的参数。然后,通过设置一个阈值来筛选角点,并将它们用红色标记出来。最后,使用`cv2.imshow`函数显示结果。 这是一个简单的Harris角点检测Python实现示例,可以根据具体情况进行调整和优化。 ### 回答2: Harris角点检测是一种计算机视觉中常用的角点检测算法,用于识别图像中的角点。Python有很多库可以实现Harris角点检测,这里以OpenCV库为例进行讲解。 首先,我们需要导入OpenCV库: ```python import cv2 ``` 然后,读取图像并将其转换为灰度图像: ```python image = cv2.imread('image.jpg') # 读取图像 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转换为灰度图像 ``` 接下来,通过调用`cv2.cornerHarris()`函数实现Harris角点检测: ```python dst = cv2.cornerHarris(gray, 2, 3, 0.04) # 进行Harris角点检测 ``` 在上述代码中,`gray`是输入的灰度图像,`2`是角点窗口(卷积窗口)的大小,`3`是Sobel算子(用于计算梯度的算子)的孔径尺寸,`0.04`是Harris角点检测的自由参数k。 接下来,使用`cv2.dilate()`函数对角点图像进行膨胀操作,以便更好地显示角点: ```python dst = cv2.dilate(dst, None) # 对角点图像进行膨胀操作 ``` 然后,根据设定的阈值,将角点标记为最大值: ```python image[dst > 0.01 * dst.max()] = [0, 0, 255] # 根据阈值将角点标记为红色 ``` 最后,显示检测结果的图像: ```python cv2.imshow('Harris Corner Detection', image) # 显示检测结果 cv2.waitKey(0) cv2.destroyAllWindows() ``` 以上就是使用Python实现Harris角点检测的步骤。通过对图像进行角点检测,我们可以在图像中找到重要的角点,这对于很多计算机视觉任务(如特征提取、图像配准等)是非常有用的。 ### 回答3: Harris角点检测是一种经典的计算机视觉算法,用于检测图像中的角点。下面是使用Python实现Harris角点检测的步骤: 1. 导入所需的库:首先导入OpenCV和NumPy库,用于图像处理和数组计算。 2. 读取图像:使用OpenCV的imread函数读取待处理的图像。 3. 图像灰度化:将读取的图像转换为灰度图像,可以使用OpenCV的cvtColor函数实现。 4. 计算图像的梯度:使用Sobel算子计算图像在x和y方向的梯度值,可以使用OpenCV的Sobel函数。 5. 计算Harris响应函数:根据Harris角点检测的定义,计算Harris响应函数R。 6. 阈值处理:设置一个阈值,将Harris响应函数大于阈值的像素点作为角点。 7. 绘制角点:根据计算得到的角点位置,在原图像上绘制特殊标记,可以使用OpenCV的circle函数。 8. 显示结果:显示处理结果,可以使用OpenCV的imshow函数。 9. 保存结果:保存处理后的图像,可以使用OpenCV的imwrite函数。 以上就是使用Python实现Harris角点检测的基本步骤。在实际编码中,还可以根据需要进行参数调整和优化,以获得更好的检测结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值