2019-6-18 车牌识别尝试-图像抗扭处理和SVM学习(opencv)

  • 抗扭曲函数deskew
  • 利用opencv中svm算法学习图片和识别图片
  • 抽取特征向量函数hot分析

车牌识别中涉及字符的识别,识别方法可以用opencv自带的机器学习算法svm(支持向量机)来实现,参见https://docs.opencv.org/3.1.0/dd/d3b/tutorial_py_svm_opencv.html
训练数据来自网上,都是20*20像素。数字和大写字母图片保存在train\chars2目录下,一万三千多张图片。

抗扭曲函数deskew

训练数据中有些图像是扭曲的,需要做抗扭曲处理,也就是把歪了的图片摆正
以下函数是在网上搜来的

# 使用方向梯度直方图Histogram of Oriented Gradients (HOG)作为特征向量
def deskew(img): #对一个图像进行抗扭斜(deskew)处理,把歪了的图片摆正
	m = cv2.moments(img) # 计算图像中的中心矩(最高到三阶)
	if abs(m['mu02']) < 1e-2:
		return img.copy()
	skew = m['mu11']/m['mu02']
	M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]])

	# 图像的平移,参数:输入图像、变换矩阵、变换后的大小
	img = cv2.warpAffine(img, M, (SZ, SZ), flags=cv2.WARP_INVERSE_MAP | cv2.INTER_LINEAR)
	return img

测试一下
原图
在这里插入图片描述
抗扭曲处理后

cv2.imwrite('0-deskew.jpg', deskew(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)))

在这里插入图片描述
图像摆正了。

利用opencv中svm算法学习图片和识别图片

下面就该开始学习图像中的字符识别了。
关于svm可以参见
https://zhuanlan.zhihu.com/p/32188239
https://zhuanlan.zhihu.com/p/32305140
https://zhuanlan.zhihu.com/p/32319251
https://zhuanlan.zhihu.com/p/32372743
https://zhuanlan.zhihu.com/p/32390371
其实svm的核函数,训练,预测都可以自己写代码来实现,不过这里都是用opencv自带的方法。
具体实现如下,说明在代码注释里基本都有。
主要函数包含:

  • train_svm,训练识别图片中字符。

    • 初始化SVM实例,设置属性。这是opencv自带的
    • 依次读取train\chars2目录中训练用图片,转化为灰度图,保存到训练数据集合。
    • 保存分类标签到对应的标签集合。每个字符图片保存在以该字符名称对应的目录中,所以把目录名称对应的ASCII码作为训练数据的分类。
    • 调用deskew函数,对训练图片(灰度图)进行抗扭曲处理,摆正
    • 调用hot函数,获得每张图片的特征向量(64个)
    • 调用SVM实例的train方法,送入训练数据集合和标签集合进行机器学习。
    • 学习结果(支持向量机)保存在svm.dat文件中,用于识别图片(车牌)时候使用。识别是利用svm的predict方法,也是opencv中自带的。
  • hot,用于从图片中抽取特征向量(64个)。

    • 计算图像 X 方向和 Y 方向的 Sobel 导数
    • 计算得到每个像素的梯度角度angle和梯度大小magnitude
    • 把这个梯度的角度转换成 0至16 之间的整数
    • 将图像分为4个小的方块,对每一个小方块计算它们梯度角度的直方图histogram(16个 bin),使用梯度的大小做权重。每一个小方块都会得到一个含有16个值的向量,4 个小方块的4个向量就组成了这个图像的特征向量(包含64个值)。

关于直方图,可以参见https://blog.csdn.net/on2way/article/details/46881599。

  • 直方图就是对图像中的像素点的值进行统计,得到一个统一的整体的灰度概念。
  • 一般情况下直方图都是灰度图像,直方图x轴是灰度值(一般0~255),y轴就是图像中每一个灰度级对应的像素点的个数。
  • 直方图的好处就在于可以清晰了解图像的整体灰度分布,这对于后面依据直方图处理图像来说至关重要。
  • 直方图计算实现可以使用np.histogram和np.bincount()函数。bincount计算的速度更快。

至于为什么要利用梯度直方图来获取图像特征值,可以参见https://www.leiphone.com/news/201708/ZKsGd2JRKr766wEd.html

SZ = 20          #训练图片长宽
class StatModel(object):
	def load(self, fn):
		self.model = self.model.load(fn)  
	def save(self, fn):
		self.model.save(fn)

#利用OpenCV中的SVM进行机器学习
class SVM(StatModel):
	def __init__(self, C = 1, gamma = 0.5):
		self.model = cv2.ml.SVM_create() #创建SVM model

		#属性设置
		self.model.setGamma(gamma)
		self.model.setC(C)
		self.model.setKernel(cv2.ml.SVM_RBF) #径向基核函数((Radial Basis Function),比较好的选择,gamma>0;
		self.model.setType(cv2.ml.SVM_C_SVC)
	#训练svm
	def train(self, samples, responses): #SVM的训练函数
		self.model.train(samples, cv2.ml.ROW_SAMPLE, responses)
	#字符识别
	def predict(self, samples):
		r = self.model.predict(samples)
		return r[1].ravel()
		#来自opencv的sample,用于svm训练
		
#获得数据的特征向量
def hog(digits):
	samples = []

	'''
	step1.先计算图像 X 方向和 Y 方向的 Sobel 导数。
	step2.然后计算得到每个像素的梯度角度angle和梯度大小magnitude。
	step3.把这个梯度的角度转换成 0至16 之间的整数。
	step4.将图像分为 4 个小的方块,对每一个小方块计算它们梯度角度的直方图(16 个 bin),使用梯度的大小做权重。
	这样每一个小方块都会得到一个含有 16 个值的向量。
	4 个小方块的 4 个向量就组成了这个图像的特征向量(包含 64 个值)。
	这就是我们要训练数据的特征向量。
	'''
	
	for img in digits:
		#plt.subplot(221)
		#plt.imshow(img,'gray')
		# step1.计算图像的 X 方向和 Y 方向的 Sobel 导数
		gx = cv2.Sobel(img, cv2.CV_32F, 1, 0)
		gy = cv2.Sobel(img, cv2.CV_32F, 0, 1)
		mag, ang = cv2.cartToPolar(gx, gy) # step2.笛卡尔坐标(直角/斜角坐标)转换为极坐标, → magnitude, angle
		
		bin_n = 16
		bin = np.int32(bin_n*ang/(2*np.pi)) #step3. quantizing binvalues in (0...16)。2π就是360度。

		#step4. Divide to 4 sub-squares
		bin_cells = bin[:10,:10], bin[10:,:10], bin[:10,10:], bin[10:,10:]
		mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:]

		#zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
		#a = [1,2,3];b = [4,5,6];zipped = zip(a,b)  结果[(1, 4), (2, 5), (3, 6)]
		hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
		hist = np.hstack(hists) # hist is a 64 bit vector
		#plt.subplot(223)
		#plt.plot(hist)
		
		# transform to Hellinger kernel
		eps = 1e-7
		hist /= hist.sum() + eps
		hist = np.sqrt(hist)
		hist /= norm(hist) + eps
		#plt.subplot(224)
		#plt.plot(hist)
		#plt.show()
		
		samples.append(hist)
		
	return np.float32(samples)
	def train_svm():
	#识别英文字母和数字
	model = SVM(C=1, gamma=0.5)
	if os.path.exists("svm.dat"):
		model.load("svm.dat") #如果存在,不再训练,直接导入训练好的结果
	else:
		chars_train = []
		chars_label = []

		start_time = datetime.datetime.now()
		for root, dirs, files in os.walk("train\\chars2"):
			
			"""
			root:所指的是当前正在遍历的这个文件夹的本身的地址
			dirs:是一个 list ,内容是该文件夹中所有的目录的名字(不包括子目录)
			files:同样是 list , 内容是该文件夹中所有的文件(不包括子目录)

			train\chars2目录下保存有数字和大写字母图片,用于训练
			"""
			#os.path.basename(),返回path最后的文件名
			#例:root=train\chars2\7,那么os.path.basename(root)=7

			if len(os.path.basename(root)) > 1:#目录是单个字母或者数字
				continue
			root_int = ord(os.path.basename(root)) #转化为ASCII字符
			for filename in files:
				filepath = os.path.join(root,filename)
				digit_img = cv2.imread(filepath)
				
				#https://www.aiuai.cn/aifarm365.html
				#把图片转化为灰度图
				#print 'filename: '+filename
				digit_img = cv2.cvtColor(digit_img, cv2.COLOR_BGR2GRAY) 

				#print digit_img.shape #打印测试一下,可以看到是单通道的灰度图。(20L, 20L)
				#采用PIL库可视化显示一下灰度图
				#img_pil = Image.fromarray(digit_img); #Image.fromarray实现array到image的转换
				#img_pil.show()

				#print '***************************************\n'
				#print digit_img  #打印一下转化的灰度图矩阵
				
				chars_train.append(digit_img) #训练样本集合
				#chars_label.append(1)
				chars_label.append(root_int) #训练样本标签,这里用字符的ASCII表示

		end_time = datetime.datetime.now()
		print '----------'
		print start_time,end_time,(end_time - start_time).seconds #116秒

		#map() 会根据提供的函数对指定序列做映射。
		#第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
		#把灰度图的训练样本集合中每个元素逐一送入deskew函数进行抗扭斜处理--也就是把图片摆正
		chars_train = list(map(deskew, chars_train))
		
		chars_train = hog(chars_train)#获得特征向量

		#print '---chars_label---'
		#print chars_label

		#chars_train = chars_train.reshape(-1, 20, 20).astype(np.float32)
		chars_label = np.array(chars_label)		
		
		print(chars_train.shape) #(13161L, 64L),13161个图片文件-训练数据,每个数据有64个特征值
		print chars_train[1,:] #打印第一行,看一下数据
		'''
		 [0.24786814 0.1749242  0.08778299 0.00753186 0.01336179 0.00632773
		 0.00311627 0.19113976 0.17932086 0.10021677 0.16336742 0.00659011
		 0.04025392 0.00959834 0.13348056 0.14601281 0.22560228 0.11686099
		 0.0091089  0.04411138 0.11550057 0.10916684 0.07274474 0.25117615
		 0.15250775 0.00763328 0.         0.         0.03396014 0.04497053
		 0.13273223 0.2175272  0.16252412 0.         0.         0.
		 0.         0.07764773 0.18924566 0.23582923 0.19936399 0.00881415
		 0.         0.03948144 0.10984423 0.08513948 0.11275985 0.22381228
		 0.25372562 0.07138055 0.11284041 0.11512272 0.01229106 0.
		 0.00824488 0.17906618 0.31182316 0.04935603 0.03621576 0.
		 0.         0.         0.         0.16095926]
		'''
	
		print (chars_label.shape) #一维矩阵,长度13161L。每个训练数据的标签(分类)
		
		model.train(chars_train, chars_label) #SVM训练,opencv自带

	if not os.path.exists("svm.dat"):
		model.save("svm.dat")

	#测试一下训练结果
	img = cv2.imread('test-0.jpg')
	img = cv2.resize(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY), (SZ, SZ), interpolation=cv2.INTER_AREA)
	#print img
	resp = model.predict(hog([img]))
	charactor = chr(resp[0])
	print '--result---'+charactor  #--result---0

代码中使用的测试图片如下
在这里插入图片描述
结果正确。

抽取特征向量函数hot分析

尝试把测试数据test-0.jpg在hot中中间变量逐一打印出来,可以理解转化和抽取特征变量过程

1.把梯度的角度转化为0至16之间的整数
bin = np.int32(bin_n*ang/(2 *np.pi))
print bin,打印结果,20x20。因为图片是20x20像素的。

[[ 0  0  8  8  0  0  0  0  8  8  0  0  8  8  8  8  8  0  0  0]
 [ 0  0  6  6  1  0  0  0  9 11 12 12 14  6  6  6  8  0  0  0]
 [ 0 15 12  8 14  0  0  0  9 10 12 13 14  7  6  7  7  0  0  0]
 [ 4  0 12 11 12  0  0  8  9  9 12 15 15  9  7  7  9  0  0  0]
 [12  8  1  3  5 15 15  8  8  9  9 15  0  0  8  8  9  0  0  0]
 [12  9  0  0  4  0 15  8  7  7  1  0  0 15  8  8  6  0  0  0]
 [ 0  1  1 11 14  0  0  7  8  8 14 15 15 15  8  8  8  0  0  0]
 [12 14  9  7 14 15  0  7  8  8  0 15 15  0  7  8  9  0  0  0]
 [ 0 14 12 14  4  0  0  7  7  7 12 15  0 15  8  7  6  0  0  0]
 [ 0  0  0  0  0  0  0  8  7  7  4  0 15 15  7  7  8  0  0  0]
 [ 0  0  0  0  0  0  0  8  8  8  6 15 15  0  7  8  8  0  0  0]
 [ 0  0  0  0  0  0  0  7  7  8 10  0  0  0  8  8  6  0  0  0]
 [ 0  0  0  0  0  0  0  7  8  8  4  0 15 15  7  8  8  0  0  0]
 [ 0  0  0  0  0  0  0  8  8  8  0  0 15 15  7  7  9  0  0  0]
 [ 0  0  0  0  0  0  0  7  7  8  0  0  0  1  8  8  0  0  0  0]
 [ 4  3  4  1  0 15 15  7  7  6  0  0  0  6  8  8  0  0  0  0]
 [ 4  1  4  8  0 15 15  7  6  6  2  1  0  9  9  8  6  0  0  0]
 [ 4  2  7  4  2 15 15 15  6  5  2  2  1  9  9  9  8  0  0  0]
 [12 15  8  0 14 15 14 14  5  4  3  1  9  8  8  6  8  0  0  0]
 [ 0  0  8  0  0  0  0  0  0  8  0  0  8  8  8  8  8  0  0  0]]

2.将图像分为 4 个小的方块
bin_cells = bin[:10,:10], bin[10:,:10], bin[:10,10:], bin[10:,10:],经过转化的角度
说明:获得矩阵中的子矩阵,[行开始:行结束,列开始:列结束]
print bin_cells,打印结果

(array([[ 0,  0,  8,  8,  0,  0,  0,  0,  8,  8],
       [ 0,  0,  6,  6,  1,  0,  0,  0,  9, 11],
       [ 0, 15, 12,  8, 14,  0,  0,  0,  9, 10],
       [ 4,  0, 12, 11, 12,  0,  0,  8,  9,  9],
       [12,  8,  1,  3,  5, 15, 15,  8,  8,  9],
       [12,  9,  0,  0,  4,  0, 15,  8,  7,  7],
       [ 0,  1,  1, 11, 14,  0,  0,  7,  8,  8],
       [12, 14,  9,  7, 14, 15,  0,  7,  8,  8],
       [ 0, 14, 12, 14,  4,  0,  0,  7,  7,  7],
       [ 0,  0,  0,  0,  0,  0,  0,  8,  7,  7]]), 
       array([[ 0,  0,  0,  0,  0,  0,  0,  8,  8,  8],
       [ 0,  0,  0,  0,  0,  0,  0,  7,  7,  8],
       [ 0,  0,  0,  0,  0,  0,  0,  7,  8,  8],
       [ 0,  0,  0,  0,  0,  0,  0,  8,  8,  8],
       [ 0,  0,  0,  0,  0,  0,  0,  7,  7,  8],
       [ 4,  3,  4,  1,  0, 15, 15,  7,  7,  6],
       [ 4,  1,  4,  8,  0, 15, 15,  7,  6,  6],
       [ 4,  2,  7,  4,  2, 15, 15, 15,  6,  5],
       [12, 15,  8,  0, 14, 15, 14, 14,  5,  4],
       [ 0,  0,  8,  0,  0,  0,  0,  0,  0,  8]]), 
       array([[ 0,  0,  8,  8,  8,  8,  8,  0,  0,  0],
       [12, 12, 14,  6,  6,  6,  8,  0,  0,  0],
       [12, 13, 14,  7,  6,  7,  7,  0,  0,  0],
       [12, 15, 15,  9,  7,  7,  9,  0,  0,  0],
       [ 9, 15,  0,  0,  8,  8,  9,  0,  0,  0],
       [ 1,  0,  0, 15,  8,  8,  6,  0,  0,  0],
       [14, 15, 15, 15,  8,  8,  8,  0,  0,  0],
       [ 0, 15, 15,  0,  7,  8,  9,  0,  0,  0],
       [12, 15,  0, 15,  8,  7,  6,  0,  0,  0],
       [ 4,  0, 15, 15,  7,  7,  8,  0,  0,  0]]), 
       array([[ 6, 15, 15,  0,  7,  8,  8,  0,  0,  0],
       [10,  0,  0,  0,  8,  8,  6,  0,  0,  0],
       [ 4,  0, 15, 15,  7,  8,  8,  0,  0,  0],
       [ 0,  0, 15, 15,  7,  7,  9,  0,  0,  0],
       [ 0,  0,  0,  1,  8,  8,  0,  0,  0,  0],
       [ 0,  0,  0,  6,  8,  8,  0,  0,  0,  0],
       [ 2,  1,  0,  9,  9,  8,  6,  0,  0,  0],
       [ 2,  2,  1,  9,  9,  9,  8,  0,  0,  0],
       [ 3,  1,  9,  8,  8,  6,  8,  0,  0,  0],
       [ 0,  0,  8,  8,  8,  8,  8,  0,  0,  0]]))

mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:],梯度大小。
print mag_cells,打印结果

(array([[   0.       ,    6.       ,    2.       ,    2.       ,
           2.       ,  274.       , 1016.       ,  736.       ,
          16.       ,   10.       ],
       [   0.       ,    7.071068 ,    2.828427 ,    2.828427 ,
           4.2426405,  433.24356  , 1052.821    ,  618.5208   ,
         344.07266  ,  742.5416   ],
       [   0.       ,    6.3245554,    2.       ,    2.       ,
           2.828427 ,  674.87036  , 1042.5986   ,  240.07498  ,
         865.9157   , 1036.2866   ],
       [   4.       ,    0.       ,    5.0990195,    5.0990195,
           4.       ,  909.1754   , 1038.5615   ,  371.6154   ,
        1108.2562   ,  611.3673   ],
       [   2.       ,    3.1622777,    2.828427 ,    5.0990195,
           4.472136 , 1017.00055  , 1011.00446  ,  846.3569   ,
        1042.3099   ,  226.45972  ],
       [   2.       ,    1.4142135,    4.       ,    2.       ,
           3.1622777, 1012.0079   , 1008.002    ,  962.00214  ,
        1013.0044   ,   44.04543  ],
       [   0.       ,    2.828427 ,    1.4142135,    5.0990195,
           7.071068 , 1013.0005   , 1004.008    ,  961.00055  ,
        1012.00195  ,   47.09565  ],
       [   2.       ,    4.472136 ,    1.4142135,    3.1622777,
           4.472136 , 1017.0123   , 1012.0079   ,  969.02527  ,
        1016.002    ,   43.011627 ],
       [   0.       ,    2.828427 ,    4.       ,    1.4142135,
           2.       , 1017.0005   , 1020.       ,  971.00464  ,
        1019.02405  ,   43.104523 ],
       [   0.       ,    0.       ,    0.       ,    4.       ,
           0.       , 1016.       , 1020.       ,  968.       ,
        1015.00446  ,   50.159744 ]], dtype=float32), array([[   0.       ,    0.       ,    0.       ,    4.       ,
           0.       , 1016.       , 1020.       ,  972.00824  ,
        1011.0243   ,   48.04165  ],
       [   0.       ,    0.       ,    0.       ,    4.       ,
           0.       , 1016.       , 1020.       ,  974.0021   ,
        1013.0005   ,   45.099888 ],
       [   0.       ,    0.       ,    0.       ,    4.       ,
           0.       , 1016.       , 1020.       ,  971.0005   ,
        1018.00006  ,   44.       ],
       [   0.       ,    0.       ,    0.       ,    4.       ,
           0.       , 1016.       , 1020.       ,  970.       ,
        1020.       ,   43.011627 ],
       [   0.       ,    0.       ,    0.       ,    4.       ,
           0.       , 1016.       , 1020.       ,  968.0021   ,
        1020.0079   ,   49.0102   ],
       [   2.       ,    3.1622777,    4.       ,    2.828427 ,
           0.       , 1014.00195  , 1020.0079   ,  838.7729   ,
        1055.6439   ,  233.65787  ],
       [   2.       ,    2.828427 ,    2.       ,    2.       ,
           2.       ,  905.8267   , 1041.2684   ,  360.51352  ,
        1108.1967   ,  608.69037  ],
       [   4.       ,    4.472136 ,    3.1622777,    2.       ,
           7.2111025,  676.5042   , 1038.2524   ,  230.21729  ,
         850.73267  , 1004.6502   ],
       [   2.       ,    3.1622777,    6.       ,    4.       ,
           2.828427 ,  432.66617  ,  977.7372   ,  710.6757   ,
         161.22655  ,  678.56323  ],
       [   0.       ,    4.       ,    6.       ,    4.       ,
           0.       ,  268.       ,  766.       ,  744.       ,
         240.       ,    4.       ]], dtype=float32), array([[  14.000001 ,   16.       ,  222.       , 1018.00006  ,
         790.       ,    2.       ,    4.       ,    0.       ,
           0.       ,    0.       ],
       [ 880.786    ,  642.162    ,  101.82338  ,  937.183    ,
        1002.7203   ,  231.93533  ,    4.       ,    0.       ,
           0.       ,    0.       ],
       [ 992.5684   , 1045.5859   ,  724.50946  ,  434.01382  ,
        1099.298    ,  588.6561   ,    5.0990195,    0.       ,
           0.       ,    0.       ],
       [ 147.38385  ,  833.09186  ,  955.1178   ,   11.401754 ,
        1014.6576   ,  819.5267   ,    4.472136 ,    0.       ,
           0.       ,    0.       ],
       [   1.4142135,  761.0007   , 1012.00195  ,  106.16968  ,
        1016.       ,  871.0052   ,    1.4142135,    0.       ,
           0.       ,    0.       ],
       [   5.8309517,  758.0238   , 1013.0005   ,  102.176315 ,
        1017.01227  ,  868.       ,    1.4142135,    0.       ,
           0.       ,    0.       ],
       [   8.944272 ,  759.006    , 1008.002    ,  100.02     ,
        1014.00195  ,  865.00055  ,    2.       ,    0.       ,
           0.       ,    0.       ],
       [   5.0990195,  758.01056  , 1013.0005   ,  101.12369  ,
        1017.0044   ,  865.00055  ,    1.4142135,    0.       ,
           0.       ,    0.       ],
       [   3.1622777,  759.0007   , 1016.       ,   99.12618  ,
        1016.00793  ,  864.0023   ,    2.828427 ,    0.       ,
           0.       ,    0.       ],
       [   2.       ,  762.0026   , 1011.0005   ,   99.00505  ,
        1012.00195  ,  863.00055  ,    4.       ,    0.       ,
           0.       ,    0.       ]], dtype=float32), array([[   1.4142135,  758.01056  , 1010.0179   ,  106.       ,
        1015.00055  ,  864.0023   ,    3.1622777,    0.       ,
           0.       ,    0.       ],
       [   5.8309517,  760.       , 1016.0492   ,   99.04544  ,
        1016.0177   ,  860.       ,    4.472136 ,    0.       ,
           0.       ,    0.       ],
       [   6.       ,  760.0105   , 1018.00793  ,   93.00538  ,
        1015.00446  ,  858.       ,    5.0990195,    0.       ,
           0.       ,    0.       ],
       [   7.071068 ,  751.0007   , 1009.04016  ,  109.11462  ,
        1014.03156  ,  867.0052   ,    2.828427 ,    0.       ,
           0.       ,    0.       ],
       [  18.110771 ,  814.2789   , 1002.20764  ,   83.4386   ,
        1012.00195  ,  873.00055  ,    0.       ,    0.       ,
           0.       ,    0.       ],
       [  34.928497 ,  939.2444   ,  991.3728   ,   94.75231  ,
        1016.00195  ,  869.0052   ,    0.       ,    0.       ,
           0.       ,    0.       ],
       [ 475.1105   , 1099.9972   ,  779.4318   ,  413.03754  ,
        1105.0901   ,  683.6987   ,    2.828427 ,    0.       ,
           0.       ,    0.       ],
       [1108.4584   ,  978.57446  ,  193.74725  ,  910.949    ,
        1057.463    ,  306.88434  ,    4.       ,    0.       ,
           0.       ,    0.       ],
       [ 653.65436  ,  268.71545  ,  469.57428  , 1097.6603   ,
         628.05414  ,    1.4142135,    4.       ,    0.       ,
           0.       ,    0.       ],
       [  12.       ,    0.       ,  626.       , 1014.       ,
         388.       ,    2.       ,    4.       ,    0.       ,
           0.       ,    0.       ]], dtype=float32))

3.每一个小方块计算它们梯度角度的直方图(16 个 bin),使用梯度的大小做权重。

 For each sub-square, calculate the histogram of direction (16 bins) weighted with their magnitude.

每个小方块都会得到一个包含16个值的向量,四个这样的矢量(四个小方块)一起给出了包含64个值的特征向量
hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
先打印一下for b, m in zip(bin_cells, mag_cells)中的b和m
其实就是把4个小方块的梯度角度和梯度大小一一对应起来

[[ 0  0  8  8  0  0  0  0  8  8]
 [ 0  0  6  6  1  0  0  0  9 11]
 [ 0 15 12  8 14  0  0  0  9 10]
 [ 4  0 12 11 12  0  0  8  9  9]
 [12  8  1  3  5 15 15  8  8  9]
 [12  9  0  0  4  0 15  8  7  7]
 [ 0  1  1 11 14  0  0  7  8  8]
 [12 14  9  7 14 15  0  7  8  8]
 [ 0 14 12 14  4  0  0  7  7  7]
 [ 0  0  0  0  0  0  0  8  7  7]]
[[   0.           6.           2.           2.           2.
   274.        1016.         736.          16.          10.       ]
 [   0.           7.071068     2.828427     2.828427     4.2426405
   433.24356   1052.821      618.5208     344.07266    742.5416   ]
 [   0.           6.3245554    2.           2.           2.828427
   674.87036   1042.5986     240.07498    865.9157    1036.2866   ]
 [   4.           0.           5.0990195    5.0990195    4.
   909.1754    1038.5615     371.6154    1108.2562     611.3673   ]
 [   2.           3.1622777    2.828427     5.0990195    4.472136
  1017.00055   1011.00446    846.3569    1042.3099     226.45972  ]
 [   2.           1.4142135    4.           2.           3.1622777
  1012.0079    1008.002      962.00214   1013.0044      44.04543  ]
 [   0.           2.828427     1.4142135    5.0990195    7.071068
  1013.0005    1004.008      961.00055   1012.00195     47.09565  ]
 [   2.           4.472136     1.4142135    3.1622777    4.472136
  1017.0123    1012.0079     969.02527   1016.002       43.011627 ]
 [   0.           2.828427     4.           1.4142135    2.
  1017.0005    1020.         971.00464   1019.02405     43.104523 ]
 [   0.           0.           0.           4.           0.
  1016.        1020.         968.        1015.00446     50.159744 ]]
[[ 0  0  0  0  0  0  0  8  8  8]
 [ 0  0  0  0  0  0  0  7  7  8]
 [ 0  0  0  0  0  0  0  7  8  8]
 [ 0  0  0  0  0  0  0  8  8  8]
 [ 0  0  0  0  0  0  0  7  7  8]
 [ 4  3  4  1  0 15 15  7  7  6]
 [ 4  1  4  8  0 15 15  7  6  6]
 [ 4  2  7  4  2 15 15 15  6  5]
 [12 15  8  0 14 15 14 14  5  4]
 [ 0  0  8  0  0  0  0  0  0  8]]
[[   0.           0.           0.           4.           0.
  1016.        1020.         972.00824   1011.0243      48.04165  ]
 [   0.           0.           0.           4.           0.
  1016.        1020.         974.0021    1013.0005      45.099888 ]
 [   0.           0.           0.           4.           0.
  1016.        1020.         971.0005    1018.00006     44.       ]
 [   0.           0.           0.           4.           0.
  1016.        1020.         970.        1020.          43.011627 ]
 [   0.           0.           0.           4.           0.
  1016.        1020.         968.0021    1020.0079      49.0102   ]
 [   2.           3.1622777    4.           2.828427     0.
  1014.00195   1020.0079     838.7729    1055.6439     233.65787  ]
 [   2.           2.828427     2.           2.           2.
   905.8267    1041.2684     360.51352   1108.1967     608.69037  ]
 [   4.           4.472136     3.1622777    2.           7.2111025
   676.5042    1038.2524     230.21729    850.73267   1004.6502   ]
 [   2.           3.1622777    6.           4.           2.828427
   432.66617    977.7372     710.6757     161.22655    678.56323  ]
 [   0.           4.           6.           4.           0.
   268.         766.         744.         240.           4.       ]]
[[ 0  0  8  8  8  8  8  0  0  0]
 [12 12 14  6  6  6  8  0  0  0]
 [12 13 14  7  6  7  7  0  0  0]
 [12 15 15  9  7  7  9  0  0  0]
 [ 9 15  0  0  8  8  9  0  0  0]
 [ 1  0  0 15  8  8  6  0  0  0]
 [14 15 15 15  8  8  8  0  0  0]
 [ 0 15 15  0  7  8  9  0  0  0]
 [12 15  0 15  8  7  6  0  0  0]
 [ 4  0 15 15  7  7  8  0  0  0]]
[[  14.000001    16.         222.        1018.00006    790.
     2.           4.           0.           0.           0.       ]
 [ 880.786      642.162      101.82338    937.183     1002.7203
   231.93533      4.           0.           0.           0.       ]
 [ 992.5684    1045.5859     724.50946    434.01382   1099.298
   588.6561       5.0990195    0.           0.           0.       ]
 [ 147.38385    833.09186    955.1178      11.401754  1014.6576
   819.5267       4.472136     0.           0.           0.       ]
 [   1.4142135  761.0007    1012.00195    106.16968   1016.
   871.0052       1.4142135    0.           0.           0.       ]
 [   5.8309517  758.0238    1013.0005     102.176315  1017.01227
   868.           1.4142135    0.           0.           0.       ]
 [   8.944272   759.006     1008.002      100.02      1014.00195
   865.00055      2.           0.           0.           0.       ]
 [   5.0990195  758.01056   1013.0005     101.12369   1017.0044
   865.00055      1.4142135    0.           0.           0.       ]
 [   3.1622777  759.0007    1016.          99.12618   1016.00793
   864.0023       2.828427     0.           0.           0.       ]
 [   2.         762.0026    1011.0005      99.00505   1012.00195
   863.00055      4.           0.           0.           0.       ]]
[[ 6 15 15  0  7  8  8  0  0  0]
 [10  0  0  0  8  8  6  0  0  0]
 [ 4  0 15 15  7  8  8  0  0  0]
 [ 0  0 15 15  7  7  9  0  0  0]
 [ 0  0  0  1  8  8  0  0  0  0]
 [ 0  0  0  6  8  8  0  0  0  0]
 [ 2  1  0  9  9  8  6  0  0  0]
 [ 2  2  1  9  9  9  8  0  0  0]
 [ 3  1  9  8  8  6  8  0  0  0]
 [ 0  0  8  8  8  8  8  0  0  0]]
[[   1.4142135  758.01056   1010.0179     106.        1015.00055
   864.0023       3.1622777    0.           0.           0.       ]
 [   5.8309517  760.        1016.0492      99.04544   1016.0177
   860.           4.472136     0.           0.           0.       ]
 [   6.         760.0105    1018.00793     93.00538   1015.00446
   858.           5.0990195    0.           0.           0.       ]
 [   7.071068   751.0007    1009.04016    109.11462   1014.03156
   867.0052       2.828427     0.           0.           0.       ]
 [  18.110771   814.2789    1002.20764     83.4386    1012.00195
   873.00055      0.           0.           0.           0.       ]
 [  34.928497   939.2444     991.3728      94.75231   1016.00195
   869.0052       0.           0.           0.           0.       ]
 [ 475.1105    1099.9972     779.4318     413.03754   1105.0901
   683.6987       2.828427     0.           0.           0.       ]
 [1108.4584     978.57446    193.74725    910.949     1057.463
   306.88434      4.           0.           0.           0.       ]
 [ 653.65436    268.71545    469.57428   1097.6603     628.05414
     1.4142135    4.           0.           0.           0.       ]
 [  12.           0.         626.        1014.         388.
     2.           4.           0.           0.           0.       ]]

再打印一下b.ravel(),可以知道ravel作用就是把压扁了,降为1维

[ 0  0  8  8  0  0  0  0  8  8  0  0  6  6  1  0  0  0  9 11  0 15 12  8
 14  0  0  0  9 10  4  0 12 11 12  0  0  8  9  9 12  8  1  3  5 15 15  8
  8  9 12  9  0  0  4  0 15  8  7  7  0  1  1 11 14  0  0  7  8  8 12 14
  9  7 14 15  0  7  8  8  0 14 12 14  4  0  0  7  7  7  0  0  0  0  0  0
  0  8  7  7]
[ 0  0  0  0  0  0  0  8  8  8  0  0  0  0  0  0  0  7  7  8  0  0  0  0
  0  0  0  7  8  8  0  0  0  0  0  0  0  8  8  8  0  0  0  0  0  0  0  7
  7  8  4  3  4  1  0 15 15  7  7  6  4  1  4  8  0 15 15  7  6  6  4  2
  7  4  2 15 15 15  6  5 12 15  8  0 14 15 14 14  5  4  0  0  8  0  0  0
  0  0  0  8]
[ 0  0  8  8  8  8  8  0  0  0 12 12 14  6  6  6  8  0  0  0 12 13 14  7
  6  7  7  0  0  0 12 15 15  9  7  7  9  0  0  0  9 15  0  0  8  8  9  0
  0  0  1  0  0 15  8  8  6  0  0  0 14 15 15 15  8  8  8  0  0  0  0 15
 15  0  7  8  9  0  0  0 12 15  0 15  8  7  6  0  0  0  4  0 15 15  7  7
  8  0  0  0]
[ 6 15 15  0  7  8  8  0  0  0 10  0  0  0  8  8  6  0  0  0  4  0 15 15
  7  8  8  0  0  0  0  0 15 15  7  7  9  0  0  0  0  0  0  1  8  8  0  0
  0  0  0  0  0  6  8  8  0  0  0  0  2  1  0  9  9  8  6  0  0  0  2  2
  1  9  9  9  8  0  0  0  3  1  9  8  8  6  8  0  0  0  0  0  8  8  8  8
  8  0  0  0]

然后print hists,这里用到了bitcount函数,它有3个参数,

  • b.ravel()是梯度角度的1维数组。bitcount会统计数组b.ravel()中每个数(从0至15)出现的次数,然后放入结果数组对应的位置。例如,数n在b.ravel()出现了m次,最终输出Out[n]=m。
  • m.ravel()是梯度的大小,这个是bitcount函数的权重。矩阵大小必须与第一个参数一致。它的作用是,假设数n在b.ravel()中出现在b[2],b[5],b[7]中,那么就要去找m.ravel()中对应的m[2],m[5],m[7]的值,最终输出出变为Out[n]=m[2]+m[5]+m[7]。例如:在第四个方块中,数字4在b中出现了1次,位置是21。于是去m中的位置21找到对应的值为6,最终bitcount输出结果,位置4的值就是6。下面打印的结果可以证实: 6.00000000e+00。
  • bin_n,输出的数组最小包含16个数

详细说明可以参见https://www.cnblogs.com/eilearn/p/9015375.html

[array([1.61749622e+04, 1.13137082e+01, 0.00000000e+00, 5.09901953e+00,
       9.16227770e+00, 4.47213602e+00, 5.65685415e+00, 6.08853527e+03,
       6.34355785e+03, 3.15890005e+03, 1.03628662e+03, 7.52739665e+02,
       2.10990195e+01, 0.00000000e+00, 2.30864080e+01, 4.05934390e+03]), array([1.22320000e+04, 5.65685415e+00, 1.16832385e+01, 3.16227770e+00,
       6.94563232e+02, 1.16587675e+03, 2.80127756e+03, 7.20410542e+03,
       5.23819590e+03, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
       2.00000000e+00, 0.00000000e+00, 1.69124133e+03, 6.36190736e+03]), array([4.80342119e+03, 5.83095169e+00, 0.00000000e+00, 0.00000000e+00,
       2.00000000e+00, 0.00000000e+00, 3.27537928e+03, 6.61796251e+03,
       9.57802844e+03, 2.01165301e+01, 0.00000000e+00, 0.00000000e+00,
       2.66606255e+03, 1.04558594e+03, 8.35277112e+02, 8.25755807e+03]), array([8.09075155e+03, 1.64589851e+03, 2.56214334e+03, 6.53654358e+02,
       6.00000000e+00, 0.00000000e+00, 1.04881302e+02, 3.91104169e+03,
       1.18277043e+04, 4.26582660e+03, 5.83095169e+00, 0.00000000e+00,
       0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 3.99719636e+03])]

hist = np.hstack(hists) # hist is a 64 bit vector
print hist

[1.61749622e+04 1.13137082e+01 0.00000000e+00 5.09901953e+00
 9.16227770e+00 4.47213602e+00 5.65685415e+00 6.08853527e+03
 6.34355785e+03 3.15890005e+03 1.03628662e+03 7.52739665e+02
 2.10990195e+01 0.00000000e+00 2.30864080e+01 4.05934390e+03
 1.22320000e+04 5.65685415e+00 1.16832385e+01 3.16227770e+00
 6.94563232e+02 1.16587675e+03 2.80127756e+03 7.20410542e+03
 5.23819590e+03 0.00000000e+00 0.00000000e+00 0.00000000e+00
 2.00000000e+00 0.00000000e+00 1.69124133e+03 6.36190736e+03
 4.80342119e+03 5.83095169e+00 0.00000000e+00 0.00000000e+00
 2.00000000e+00 0.00000000e+00 3.27537928e+03 6.61796251e+03
 9.57802844e+03 2.01165301e+01 0.00000000e+00 0.00000000e+00
 2.66606255e+03 1.04558594e+03 8.35277112e+02 8.25755807e+03
 8.09075155e+03 1.64589851e+03 2.56214334e+03 6.53654358e+02
 6.00000000e+00 0.00000000e+00 1.04881302e+02 3.91104169e+03
 1.18277043e+04 4.26582660e+03 5.83095169e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 3.99719636e+03]

hstack函数,实现从水平方向合并hists。

4.transform to Hellinger kernel。
关于这个,我猜测是要进行特征数据的归一化。
因为处理后的数据明显收敛,可以看后面打印的图,y轴取值范围变小。
不过网上常用归一化方法没查到Hellinger转化。
eps = 1e-7
hist /= hist.sum() + eps
hist = np.sqrt(hist)
hist /= norm(hist) + eps
打印一下hist

[0.32916595 0.00870554 0.         0.00584436 0.00783421 0.00547332
 0.00615575 0.20195271 0.20613879 0.14546591 0.08331692 0.07100937
 0.01188843 0.         0.01243573 0.1649002  0.2862477  0.00615575
 0.00884657 0.00460249 0.06821018 0.088373   0.13698447 0.21967635
 0.18732    0.         0.         0.         0.00366023 0.
 0.10643784 0.20643672 0.17937776 0.00624976 0.         0.
 0.00366023 0.         0.14812354 0.21055009 0.25329775 0.01160833
 0.         0.         0.13363753 0.08368992 0.0748012  0.23519013
 0.23280253 0.10500133 0.13100715 0.06617095 0.0063397  0.
 0.02650588 0.16185998 0.28147738 0.1690421  0.00624976 0.
 0.         0.         0.         0.16363305]

5.打印图像
把输入的灰度图,直方图计算结果,和Hellinger kernel的转化结果一起打印一下。
在这里插入图片描述

然后再把x方向的导数 ,y方向的导数,以及梯度的大小(magnitude)以图像方式打印一下

plt.subplot(221)
plt.imshow(img,'gray')
plt.subplot(223)
plt.imshow(gx,'gray')
plt.subplot(224)
plt.imshow(gy,'gray')
plt.subplot(222)
plt.imshow(mag,'gray')
plt.show()

在这里插入图片描述
右上方梯度的大小(magnitude)反应的是图像有剧烈变化的地方
左下方x方向导数凸显了图像垂直方向的线条
右下方x方向导数凸显了图像水平方向的线条
通过4个图对比可以直观的了解变化过程。

图像的梯度去掉了很多不必要的信息(比如不变的背景色),加重了轮廓。

猜你喜欢

转载自blog.csdn.net/weixin_42555985/article/details/92770488#comments_18267318