目录
一、Harris 角点检测算法简介
1.角点:①局部窗口沿各方向移动,均产生明显变化的点 ②图像局部曲率突变的点
2.Harris 角点检测算法(Harris & Stephens 角点检测器)是一个极为简单的角点检测算法。该算法是利用移动的窗口在图像中计算灰度变化值,应用邻近像素点灰度差值概念,从而进行判断是否为角点、边缘、平滑区域。
3.角点检测基本思想:
边缘:沿着边缘方向移动,无灰度变化
角点:沿任意方向移动,明显灰度变化
平坦:任意方向移动,无灰度变化
二、涉及函数
1.compute_harris_response
该函数在 harris.py 文件中,该函数在一幅灰度图像中,对每个像素计算Harris角点检测器响应函数。因在角点检测中需要抑制噪声,使用了 scipy.ndimage.filters 模块中的高斯导数滤波器来计算导数。
from pylab import *
from numpy import *
# 使用 scipy.ndimage.filters 模块中的高斯导数滤波器来计算导数
from scipy.ndimage import filters
该函数有两个参数(im, sigma),im为传入图像,sigma则定义了高斯滤波器的尺度大小,该函数返回像素值为Harris响应函数的一幅图像 。
对图像中的每一个像素,计算Harris矩阵时,Harris矩阵的特征值有三种情况:
- 都是很大的正数,则该点是角点
- 一个很大,一个约等于0,则该区域存在一个边
- 都约等于0,该区域为空
def compute_harris_response(im,sigma=3):
# 在一幅灰度图像中,对每个像素计算Harris角点检测器响应函数
# 计算导数
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 响应函数值的一幅图像
return Wdet / Wtr
2.get_harris_points
该函数同样是在 harris.py 文件中,上面的compute_harris_response函数返回了像素值为 Harris 响应函数值的一幅图像,我们需要从这幅图像中挑选出需要的信息,选取像素值高于阈值的所有图像点,再加上额外的限制,即角点之间的间隔必须大于设定的最小距离。
如下函数示,获取所有的候选像素点,以角点响应值递减的顺序排序,然后将距离已标记为角点位置过近的区域从候选像素点中删除。
def get_harris_points(harrisim,min_dist=10,threshold=0.1):
# 从一幅Harris响应图像中返回角点,min_dist为分割角点和图像边界的最少像素数目
# 寻找高于阈值的候选角点
corner_threshold = harrisim.max() * threshold
harrisim_t = (harrisim > corner_threshold) * 1
# 得到候选点的坐标
coords = array(harrisim_t.nonzero()).T
# 以及它们的 Harris 响应值
candidate_values = [harrisim[c[0],c[1]] for c in coords]
# 对候选点按照 Harris 响应值进行排序
index = argsort(candidate_values)[::-1]
# 将可行点的位置保存到数组中
allowed_locations = zeros(harrisim.shape)
allowed_locations[min_dist:-min_dist,min_dist:-min_dist] = 1
# 按照 min_distance 原则,选择最佳 Harris 点
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
三、harris算法不同场景的实现
1.边缘丰富场景
该场景选取的是一个建筑群五个不同角度原图:正面和近面光线较暗,远面、侧面和旋转的面光线较好,五个不同角度的图片,背景各不相同。
五个不同角度结果图:
小结:五个场景的对比可以看出,harris算法可以将每个场景下的建筑群都能识别出来,但是正面和侧面的图中天空中的云朵也有部分被识别出来,应该是光线较亮的缘故,在该场景中,光线对于识别建筑群没有较大阻碍,因为两张较暗面下的建筑群也被很好的识别出来了。
2.角点丰富场景
该场景选取的是书桌上的一堆杂物,光线不一,角度不一:
五个不同角度结果图:
小结:从五个角度的图片对比来看,近面得到的角点较少,在该场景下,近面是某一区域的大图,囊括的物体相对较少,角点也就相对少了,五个角度的物体都能识别出来,但是远面的背景也有几个角点,可能存在是我的图片墙壁背景不够干净,但是瓶子的手提带子有在正面图中很明显却并未识别出来,而墙壁倒是有几个角点,结果不是很精确。
3.纹理平坦场景
该场景选取的是一个问了平坦的背景,选取了四个角度和一个曝光面:
五个不同角度结果图:
小结:五个不同角度下的角点,光线因素影响不大,从曝光图片和其他图片的对比可知,近面下的角点较少,因为是物体的大图,轮廓比较清晰,其他四图都是将平坦场景下的物体整个识别出来覆盖了角点。
四、小结
通过边缘丰富、角点丰富和纹理平坦三个场景,每个场景五个角度的对比可知,近面下的角点数都是较少的,因近面下的物体轮廓清晰,可以很好地分析物体轮廓精确的检测角点;平坦的界面相对于边缘、角点丰富的画面也更有利于角点的检测,因复杂背景对检测有一点的阻碍;在边缘丰富的场景下,沿边缘移动,尤其是有垂直限定线段的边缘,角点的分布还是可以看出一定的物体轮廓,而在角点丰富的场景下,任意移动,角点分布就相对杂乱。
五、代码
# -*- coding: utf-8 -*-
from pylab import *
from PIL import Image
from PCV.localdescriptors import harris
"""
Example of detecting Harris corner points (Figure 2-1 in the book).
"""
# 读入图像为im,转换为灰度图convert('L')
im = array(Image.open('data/pic/j1.jpg').convert('L'))
# 检测harris角点
harrisim = harris.compute_harris_response(im)
# Harris响应函数
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):
filtered_coords = harris.get_harris_points(harrisim, 6, thres)
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()