Haar特征最初是用来进行人脸特征的表示的,最近重新看了SURF算法,发现在生成特征点描述子的时候也有用到Haar特征。查看了一些博文,自己整理一些,方便以后复习。
Haar特征分为三类:边缘特征、线性特征、中心特征和对角线特征,组合成特征模型。特征模板有黑白两种颜色,且定义模板的特征值为模板中 白色区域的像素总和 减去 黑色区域的像素总和。这里还涉及到积分图像的应用。Haar特征反应的是图像的灰度变化情况。但是矩形特征只对一些简单的图形结构,如边缘、线段比较敏感,所以只能描述特定走向(水平、垂直、对角)的结构。
积分图像
积分图像是一种能够描述全局信息的矩阵表示方法,他的构造方式 是积分图中某个点的值表示该点左上角所有像素之和,具体方式如下所示:
1) 用 s(i,j)表示行方向的累加和,即第i行前j列像素之和,初始化为s(i,-1)=0
2) 用 T(i,j)表示一个积分图像,初始化为T(-1,j)=0
3) 逐行扫描图像,递归计算每个像素(i,j)行方向的累加和s(i,j) 与(i,j)左上角方向积分图的累加和
s(i,j) = s(i,j-1) + I(i,j)
T(i,j) = T(i-1,j) + s(i,j)
如下图所示:
在上述积分图像中,若要得到 A区域的像素和,则需要T(4) , B区域的像素和为T(12) - T(11) ,区域C的像素和为 T(16) - T(14), 区域D的像素和为 T(8) + T(5) - T(6) - T(7)
Haar特征的模板有如下几种
关于一幅图像有多少个特征数量可以参考这个博客
特征模板数量计算参考
import cv2
#积分图
def intergralMat(input=[],weight=0,height=0):
output=[]
#output.clear()
columnSum = [0 for i in range(weight)] #[0, 0, 0, 0, 0, 0, 0, 0, 0]
for i in range(height):
output.append([0 for x in range(weight)])
for j in range(weight):
if j==0:
columnSum[j] = int(input[i][j])
else:
columnSum[j]=columnSum[j-1] + int(input[i][j])
if i==0:
output[i][j]=columnSum[j]
else:
output[i][j]=output[i-1][j]+columnSum[j]
return output
#Haar特征 默认size=1 ,deep=2
def wHaar(interM = [],weigth = 0,height = 0,size = 1,deep = 2):
dst = []
for i in range(height - deep + 1):
dst.append([0 for x in range(weigth - size)])
for j in range(weigth - 2*size +1):
white,black = (0,0)
if j == 0 and i==0:
white = int(interM[i+deep-1][j+size-1])
elif i!=0 and j==0:
white = int(interM[i + deep - 1][j + size - 1]) - int(interM[i - 1][j + size -1])
elif i == 0 and j != 0:
white = int(interM[i+deep-1][j+size-1]) - int(interM[i+deep-1][j-1])
else:
white = int(interM[i+deep-1][j+size-1]) + int(interM[i+deep-3][j+size-2]) - int(interM[i+deep-1][j+size-2]) - int(interM[i+deep-3][j+ size -1])
_i = i
_j = j + size
if _i == 0:
black = int(interM[_i+deep-1][_j+size-1]) - int(interM[_i+deep-1][_j+size-2])
else:
black = int(interM[_i+deep-1][_j+size-1]) + int(interM[_i+deep-3][_j+size-2]) - int(interM[_i+deep-1][_j+size-2]) - int(interM[i+deep-3][_j+size-1])
dst[i][j] = black - white
return dst
if __name__ == '__main__':
src = cv2.imread(r'D:\Python Code\picture\cat1.jpg')
tmp = src.copy()
b,g,r = cv2.split(src)
_w = len(g[0]) #图像的宽 391
_h = len(g) #图像的长220
#print _w , _h
#g通道
in_g = intergralMat(g,_w,_h) #返回积分图像
Haar_g = wHaar(in_g,_w,_h) #返回Haar特征
#b通道
in_b = intergralMat(b,_w,_h) #返回积分图像
Haar_b = wHaar(in_b,_w,_h) #返回Haar特征
#r通道
in_r = intergralMat(r,_w,_h) #返回积分图像
Haar_r = wHaar(in_r,_w,_h) #返回Haar特征
dst1 = []
dst2 = []
dst3 = []
#print len(Haar_b), len(Haar_b[0])
for x in range(len(Haar_g)): #219
dst1.append([])
dst2.append([])
dst3.append([])
for y in range(len(Haar_g[0])): #390
if Haar_g[x][y] > 0:
dst2[x].append(255)
else:
dst2[x].append(0)
if Haar_b[x][y] > 0:
dst1[x].append(255)
else:
dst1[x].append(0)
if Haar_r[x][y] > 0:
dst3[x].append(255)
else:
dst3[x].append(0)
for x in range(len(dst1)):
for y in range(len(dst1[0])):
f1 = dst1[x][y]
f2 = dst2[x][y]
f3 = dst3[x][y]
tmp[x,y] = [f1,f2,f3]
cv2.imshow('src',src)
cv2.imshow('test',tmp)
cv2.waitKey(0)
参考的别人的博客,只用了竖直方向的模板,模板如上图所示。其他模板也类似,旋转45度的可能有点难度,具体可以参考这篇文献
Empirical Analysis of Detection Cascades of Boosted Classifiers for Rapid Object Detection