图像局部特征提取 (2)

Harris角点检测是一种基于图像灰度的一阶导数矩阵检测方法。检测器的主要思想是局部自相似性/自相关性,即在某个局部窗口内图像块与在各个方向微小移动后的窗口内图像块的相似性。该算法认为像素周围显示存在多余一个方向的边,便认为该点为兴趣点,即称为角点。

Harris算法步骤

利用水平、竖直差分算子对图像每个像素进行滤波以求得\(I_x, I_y\),进而求得图像域中点\(x\)上的对称半正定矩阵\(M_I = M_I(x)\)
\[ M_I=\nabla I \nabla I^T=\left[ \begin{array}{c} I_x \\ I_y \end{array} \right] \left[ \begin{array}{c} I_x & I_y \end{array}\right] = \left[ \begin{array}{cc} I_x^2 & I_x I_y \\ I_x I_y & I_y^2 \end{array} \right] \]

选择权重矩阵\(W\)(通常为高斯滤波器\(G\))对\(M\)进行滤波
\[ W = exp(- \frac{x^2+y^2}{2\sigma^2}) \]
\[ M_I = W * M_I \]

利用\(M\)计算对应于每个像素的角点量\(cim\)\(R\):
\[ cim = \frac{I_x^2*I_y^2-(I_xI_y)^2}{I_x^2+I_y^2} \]

在矩阵 \(cim\) 中,同时满足 \(cim\) 大于一阙值 \(thresh\)\(cim\) 是某领域内的局部极大值,这两个条件的点被认为是角点。

提高阙值,则提取的角点数目变少,降低阙值,则提取的角点数目变多
另外求局部极大值的领域大小也会影响提取角点的数目和容忍度

Harris角点性质

该算法算子对亮度和对比度的变化不敏感。

这是因为在进行Harris角点检测时,使用了微分算子对图像进行微分运算,而微分运算对图像密度的拉升或收缩和对亮度的抬高或下降不敏感。换言之,对亮度和对比度的仿射变换并不改变Harris响应的极值点出现的位置,但是,由于阈值的选择,可能会影响角点检测的数量。

算子具有旋转不变性。

Harris角点检测算子使用的是角点附近的区域灰度二阶矩矩阵。而二阶矩矩阵可以表示成一个椭圆,椭圆的长短轴正是二阶矩矩阵特征值平方根的倒数。当特征椭圆转动时,特征值并不发生变化,所以判断角点响应值也不发生变化,由此说明Harris角点检测算子具有旋转不变性。

算子不具有尺度不变性。

Harris算法实现

import numpy as np import matplotlib.pyplot as plt from PIL import Image from scipy.ndimage import filters class Harris: def __init__(self, img_path): self.img_path = img_path self.grayImg = None self.Ix = None self.Iy = None self.Ix_mul_Ix = None self.Ix_mul_Iy = None self.Iy_mul_Iy = None self.cim = None self.filtered_coords = None def _rgb2gray(self): self.grayImg = Image.open(self.img_path).convert('L') self.grayImg = np.array(self.grayImg) def _cal_ix_iy(self, sigma=3): # 计算导数 self.Ix = np.zeros(self.grayImg.shape) filters.gaussian_filter(self.grayImg, (sigma, sigma), (0, 1), self.Ix) self.Iy = np.zeros(self.grayImg.shape) filters.gaussian_filter(self.grayImg, (sigma, sigma), (1, 0), self.Iy) def _cal_para(self): # 计算Ix^2,Iy^2和Ix*Iy并加入高斯滤波 self.Ix_mul_Ix = filters.gaussian_filter(self.Ix*self.Ix, 3) self.Iy_mul_Iy = filters.gaussian_filter(self.Iy*self.Iy, 3) self.Ix_mul_Iy = filters.gaussian_filter(self.Ix*self.Iy, 3) def _cal_cim(self): self.cim = (self.Ix_mul_Ix*self.Iy_mul_Iy - 2*self.Ix_mul_Iy) / (self.Ix_mul_Ix + self.Iy_mul_Iy) def cal_harris(self, min_dist=10, threshold=0.1): self._rgb2gray() self._cal_ix_iy() self._cal_para() self._cal_cim() conner_threshold = self.cim.max()*threshold self.cim = (self.cim > conner_threshold) * 1 coords = np.array(self.cim.nonzero()).T candidate_values = [self.cim[c[0], c[1]] for c in coords] index = np.argsort(candidate_values) allowed_locations = np.zeros(self.cim.shape) allowed_locations[min_dist:-min_dist, min_dist:-min_dist] = 1 self.filtered_coords = [] for i in index: if allowed_locations[coords[i, 0], coords[i, 1]] == 1: self.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 # 此处保证min_dist*min_dist只有一个harris特征点 return self.filtered_coords def plot_harris_point(self): plt.figure() plt.gray() plt.imshow(Image.open(self.img_path).convert('L')) plt.plot([p[1] for p in self.filtered_coords], [p[0] for p in self.filtered_coords], '*') plt.axis('off') plt.show() if __name__ == '__main__': img_path = "./imgs/3.jpg" harris = Harris(img_path) harris.cal_harris() harris.plot_harris_point()

结果演示

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpspfx.html