计算机视觉--Harris角点检测实现与分析(二)
关于Harris角点检测的基本概念和不同场景下的检测结果分析已记录在上一篇博客中(点击查看): 计算机视觉–Harris角点检测实现与分析(一).本篇主要对Harris角点检测响应函数进行分析。
一、Harris角点检测
1.1 基本原理
人眼对角点的识别通常是在一个局部的小区域或小窗口完成的。如果在各个方向上移动这个特征的小窗口,窗口内区域的灰度发生了较大的变化,那么就认为在窗口内遇到了角点。如果这个特定的窗口在图像各个方向上移动时,窗口内图像的灰度没有发生变化,那么窗口内就不存在角点;如果窗口在某一个方向移动时,窗口内图像的灰度发生了较大的变化,而在另一些方向上没有发生变化,那么,窗口内的图像可能就是一条直线的线段。
1.2 数学表达
将图像窗口平移[u,v]产生灰度变化E(u,v):
如何求解平移后的图像灰度I(x+u,y+v),以及灰度变化E(u,v)?
这里用到知识点二元函数泰勒展开,将I(x+u, y+v)函数在(x, y)处泰勒展开,得:
于是对于局部微小的移动量 [u,v],可以近似得到下面的表达:
其中M是 2*2 矩阵,可由图像的导数求得:
窗口移动导致的图像变化量:实对称矩阵M的特征值分析
记M的特征值为λ1、λ2。
定义:角点响应函数R:
二、代码实现
Harris角点检测器响应函数为compute_harris_response(im, sigma=3),在本段代码中,将其重写,便于观察角点响应函数R的值。
# -*- coding: utf-8 -*-
from pylab import *
from PIL import Image
from PCV.localdescriptors import harris
from scipy.ndimage import filters
"""
Example of detecting Harris corner points (Figure 2-1 in the book).
"""
def compute_harris_response(im, sigma=3):
# 在一幅灰度图像中,对每个像素计算Harris角点检测器响应函数
# 计算导数
k = 0.04
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)
# 计算harris矩阵分量
Wxx = filters.gaussian_filter(imx * imx, sigma)
Wxy = filters.gaussian_filter(imx * imy, sigma)
Wyy = filters.gaussian_filter(imy * imy, sigma)
# 计算矩阵的特征值和迹
Wdet = Wxx * Wyy - Wxy ** 2
Wtr = Wxx + Wyy
# 返回像素值为 Harris 响应函数值的一幅图像
print(Wdet - (k * Wtr)) # 输出角点响应函数R
R=Wdet - (k * Wtr)
#figure()
#imshow(R)
return Wdet / Wtr # 此处可消除参数k的影响
# 读入图像(读取图像到数组中)
im = array(Image.open('../data/empire.jpg').convert('L')) # 括号内:读取一幅图像,并将其转换成灰度图像
# 检测harris角点
harrisim = compute_harris_response(im)
# compute_harris_response(im, sigma):
# 在一幅灰度图像中,对每一个像素计算Harris角点检测器响应函数
# im:(数组图像) sigma:标准差默认为3
# Harris响应函数
# print (harrisim)
harrisim1 = 255 - harrisim
figure()
gray()
# 画出Harris响应图
subplot(141)
imshow(harrisim1)
print harrisim1.shape
axis('off')
axis('equal')
threshold = [0.01, 0.05, 0.1]
for i, thres in enumerate(threshold):
# enumerate()函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在for 循环当中
filtered_coords = harris.get_harris_points(harrisim, 6, thres)
# get_harris_points(harrisim, min_dist=10, threshold=0.1):
# 从一幅Harris 响应图像harrisim中返回角点。min_dist 为分割角点和图像边界的最少像素数目(默认为10)。
# threshold 为阀值,大于阀值的harris响应函数值被认为是可能的角点,并在harrism_t矩阵中相应的位置1,其余地方置0
subplot(1, 4, i + 2)
imshow(im)
print im.shape
plot([p[1] for p in filtered_coords], [p[0] for p in filtered_coords], '*') # 标出角点
axis('off')
show()
三、结果与分析
3.1 不同场景的R值讨论
场景一:垂直或水平边缘多
场景二:纹理角点丰富
场景三:平坦
分析:由上述运行结果可得–
-
对于R的表达式:
R只与M的特征值有关 -
对于纹理角点丰富的场景,R为大数值正数
-
对于垂直或水平边缘多的场景,R为大数值负数
-
对于平坦的场景,R为小数值
3.2 参数k对角点检测的影响
在其他条件不变的前提下,改变k值:
k=0.02:
k=0.04:
k=0.05:
k=0.06:
k=0.08:
分析:
增大k的值,将减小角点响应值R,降低角点检测的灵性,减少被检测角点的数量;减小k值,将增大角点响应值R,增加角点检测的灵敏性,增加被检测角点的数量。
四、总结
在三种不同的场景下,得到的R值结果不同。k值增大,R值会随之减小,检测角点数量也会减少。本次实验中,遇到的问题是在测试图片的R值时出现报错,经检查发现是图片像素太高,进入图片-编辑,修改像素值为较小值即可。