机器学习笔记-模式识别的应用场景之一简单车牌识别(代码片段)

坐望云起 坐望云起     2022-12-16     799

关键词:

一、关于模式识别

        模式(Pattern)是指具有某种特定性质的感知对象。一般情况下,待观察的事物都具有时空分布信息。模式识别(Pattern Recognition)又称为模式分类,指对待观察事物的各种信息进行处理、描述、分类和解释的过程。按照有无训练样本,模式识别可分为监督模式识别和非监督模式识别两种。

        模式识别的研究方向主要有两个:第一个是研究生物体是如何感知世界的;第二个是研究如何用机器(包括计算机)识别特定对象的模式。这些特定对象可以是字符、语音、图像等具体的事物,也可以是状态、程度、范围等抽象的表达。模式识别与数学、医学、心理学、语言学、物理学及计算机科学等都有关系。

机器学习笔记 - 简单了解模式识别在数据中寻找模式是一个有着悠久历史的问题。模式识别是一种数据分析方法,它使用机器学习 算法自动识别数据中的模式和规律。这些数据可以是任何东西,从文本和图像到声音或其他可量化的数据。模式识别系统可以快速准确地识别熟悉的模式。他们还可以识别和分类不熟悉的物体,从不同角度识别形状和物体,并识别图案和物体。2、模式识别的特点模式识别从数据中学习。即使部分可见,也能自动识别图案。应该能够识别熟悉的模式。应从不同的角度和形状识别图案。https://skydance.blog.csdn.net/article/details/126520391

        下面的代码都来自别人的github,是基于图像处理+支持向量机实现的,也是模式识别的范畴。比较典型也易于理解,是一个用于了解模式识别比较好的入门示例。 

二、车辆识别

        对于传入的车牌图像,基于旋转校正、阈值分割、边缘检测等常用的图像分割算法。颜色分割算法/边缘检测算法完成车牌区域定位;然后对车牌区域校正,分割字符区域;最后导入预训练的SVM分类器,识别字符区域,输出识别结果。

1、定位车牌

		if type(car_pic) == type(""):
			img = imreadex(car_pic)
		else:
			img = car_pic
		pic_hight, pic_width = img.shape[:2]
		if pic_width > MAX_WIDTH:
			pic_rate = MAX_WIDTH / pic_width
			img = cv2.resize(img, (MAX_WIDTH, int(pic_hight*pic_rate)), interpolation=cv2.INTER_LANCZOS4)
		
		if resize_rate != 1:
			img = cv2.resize(img, (int(pic_width*resize_rate), int(pic_hight*resize_rate)), interpolation=cv2.INTER_LANCZOS4)
			pic_hight, pic_width = img.shape[:2]
			
		print("h,w:", pic_hight, pic_width)
		blur = self.cfg["blur"]
		#高斯去噪
		if blur > 0:
			img = cv2.GaussianBlur(img, (blur, blur), 0)#图片分辨率调整
		oldimg = img
		img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
		#equ = cv2.equalizeHist(img)
		#img = np.hstack((img, equ))
		#去掉图像中不会是车牌的区域
		kernel = np.ones((20, 20), np.uint8)
		img_opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
		img_opening = cv2.addWeighted(img, 1, img_opening, -1, 0);

		#找到图像边缘
		ret, img_thresh = cv2.threshold(img_opening, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
		img_edge = cv2.Canny(img_thresh, 100, 200)
		#使用开运算和闭运算让图像边缘成为一个整体
		kernel = np.ones((self.cfg["morphologyr"], self.cfg["morphologyc"]), np.uint8)
		img_edge1 = cv2.morphologyEx(img_edge, cv2.MORPH_CLOSE, kernel)
		img_edge2 = cv2.morphologyEx(img_edge1, cv2.MORPH_OPEN, kernel)

		#查找图像边缘整体形成的矩形区域,可能有很多,车牌就在其中一个矩形区域中
		try:
			contours, hierarchy = cv2.findContours(img_edge2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
		except ValueError:
			image, contours, hierarchy = cv2.findContours(img_edge2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
		contours = [cnt for cnt in contours if cv2.contourArea(cnt) > Min_Area]
		print('len(contours)', len(contours))
		#一一排除不是车牌的矩形区域
		car_contours = []
		for cnt in contours:
			rect = cv2.minAreaRect(cnt)
			area_width, area_height = rect[1]
			if area_width < area_height:
				area_width, area_height = area_height, area_width
			wh_ratio = area_width / area_height
			#print(wh_ratio)
			#要求矩形区域长宽比在2到5.5之间,2到5.5是车牌的长宽比,其余的矩形排除
			if wh_ratio > 2 and wh_ratio < 5.5:
				car_contours.append(rect)
				box = cv2.boxPoints(rect)
				box = np.int0(box)
				#oldimg = cv2.drawContours(oldimg, [box], 0, (0, 0, 255), 2)
				#cv2.imshow("edge4", oldimg)
				#cv2.waitKey(0)

		print(len(car_contours))

		print("精确定位")
		card_imgs = []
		#矩形区域可能是倾斜的矩形,需要矫正,以便使用颜色定位
		for rect in car_contours:
			if rect[2] > -1 and rect[2] < 1:#创造角度,使得左、高、右、低拿到正确的值
				angle = 1
			else:
				angle = rect[2]
			rect = (rect[0], (rect[1][0]+5, rect[1][1]+5), angle)#扩大范围,避免车牌边缘被排除

			box = cv2.boxPoints(rect)
			heigth_point = right_point = [0, 0]
			left_point = low_point = [pic_width, pic_hight]
			for point in box:
				if left_point[0] > point[0]:
					left_point = point
				if low_point[1] > point[1]:
					low_point = point
				if heigth_point[1] < point[1]:
					heigth_point = point
				if right_point[0] < point[0]:
					right_point = point

			if left_point[1] <= right_point[1]:#正角度
				new_right_point = [right_point[0], heigth_point[1]]
				pts2 = np.float32([left_point, heigth_point, new_right_point])#字符只是高度需要改变
				pts1 = np.float32([left_point, heigth_point, right_point])
				M = cv2.getAffineTransform(pts1, pts2)
				dst = cv2.warpAffine(oldimg, M, (pic_width, pic_hight))
				point_limit(new_right_point)
				point_limit(heigth_point)
				point_limit(left_point)
				card_img = dst[int(left_point[1]):int(heigth_point[1]), int(left_point[0]):int(new_right_point[0])]
				card_imgs.append(card_img)
				#cv2.imshow("card", card_img)
				#cv2.waitKey(0)
			elif left_point[1] > right_point[1]:#负角度
				
				new_left_point = [left_point[0], heigth_point[1]]
				pts2 = np.float32([new_left_point, heigth_point, right_point])#字符只是高度需要改变
				pts1 = np.float32([left_point, heigth_point, right_point])
				M = cv2.getAffineTransform(pts1, pts2)
				dst = cv2.warpAffine(oldimg, M, (pic_width, pic_hight))
				point_limit(right_point)
				point_limit(heigth_point)
				point_limit(new_left_point)
				card_img = dst[int(right_point[1]):int(heigth_point[1]), int(new_left_point[0]):int(right_point[0])]
				card_imgs.append(card_img)
				#cv2.imshow("card", card_img)
				#cv2.waitKey(0)
		#开始使用颜色定位,排除不是车牌的矩形,目前只识别蓝、绿、黄车牌
		colors = []
		for card_index,card_img in enumerate(card_imgs):
			green = yello = blue = black = white = 0
			card_img_hsv = cv2.cvtColor(card_img, cv2.COLOR_BGR2HSV)
			#有转换失败的可能,原因来自于上面矫正矩形出错
			if card_img_hsv is None:
				continue
			row_num, col_num= card_img_hsv.shape[:2]
			card_img_count = row_num * col_num

			for i in range(row_num):
				for j in range(col_num):
					H = card_img_hsv.item(i, j, 0)
					S = card_img_hsv.item(i, j, 1)
					V = card_img_hsv.item(i, j, 2)
					if 11 < H <= 34 and S > 34:#图片分辨率调整
						yello += 1
					elif 35 < H <= 99 and S > 34:#图片分辨率调整
						green += 1
					elif 99 < H <= 124 and S > 34:#图片分辨率调整
						blue += 1
					
					if 0 < H <180 and 0 < S < 255 and 0 < V < 46:
						black += 1
					elif 0 < H <180 and 0 < S < 43 and 221 < V < 225:
						white += 1
			color = "no"

			limit1 = limit2 = 0
			if yello*2 >= card_img_count:
				color = "yello"
				limit1 = 11
				limit2 = 34#有的图片有色偏偏绿
			elif green*2 >= card_img_count:
				color = "green"
				limit1 = 35
				limit2 = 99
			elif blue*2 >= card_img_count:
				color = "blue"
				limit1 = 100
				limit2 = 124#有的图片有色偏偏紫
			elif black + white >= card_img_count*0.7:#TODO
				color = "bw"
			print(color)
			colors.append(color)
			print(blue, green, yello, black, white, card_img_count)
			#cv2.imshow("color", card_img)
			#cv2.waitKey(0)
			if limit1 == 0:
				continue
			#以上为确定车牌颜色
			#以下为根据车牌颜色再定位,缩小边缘非车牌边界
			xl, xr, yh, yl = self.accurate_place(card_img_hsv, limit1, limit2, color)
			if yl == yh and xl == xr:
				continue
			need_accurate = False
			if yl >= yh:
				yl = 0
				yh = row_num
				need_accurate = True
			if xl >= xr:
				xl = 0
				xr = col_num
				need_accurate = True
			card_imgs[card_index] = card_img[yl:yh, xl:xr] if color != "green" or yl < (yh-yl)//4 else card_img[yl-(yh-yl)//4:yh, xl:xr]
			if need_accurate:#可能x或y方向未缩小,需要再试一次
				card_img = card_imgs[card_index]
				card_img_hsv = cv2.cvtColor(card_img, cv2.COLOR_BGR2HSV)
				xl, xr, yh, yl = self.accurate_place(card_img_hsv, limit1, limit2, color)
				if yl == yh and xl == xr:
					continue
				if yl >= yh:
					yl = 0
					yh = row_num
				if xl >= xr:
					xl = 0
					xr = col_num
			card_imgs[card_index] = card_img[yl:yh, xl:xr] if color != "green" or yl < (yh-yl)//4 else card_img[yl-(yh-yl)//4:yh, xl:xr]
		#以上为车牌定位

2、识别字符

        车牌字符识别使用的算法是opencv的SVM, opencv的SVM使用代码来自于opencv附带的sample,StatModel类和SVM类都是sample中的代码。SVM训练使用的训练样本来自于github上的EasyPR的c++版本。由于训练样本有限,你测试时会发现,车牌字符识别,可能存在误差,尤其是第一个中文字符出现的误差概率较大。源码中有EasyPR中的训练样本,在train目录下,如果要重新训练请解压在当前目录下,并删除原始训练数据文件svm.dat和svmchinese.dat。

#以下为识别车牌中的字符
		predict_result = []
		roi = None
		card_color = None
		for i, color in enumerate(colors):
			if color in ("blue", "yello", "green"):
				card_img = card_imgs[i]
				gray_img = cv2.cvtColor(card_img, cv2.COLOR_BGR2GRAY)
				#黄、绿车牌字符比背景暗、与蓝车牌刚好相反,所以黄、绿车牌需要反向
				if color == "green" or color == "yello":
					gray_img = cv2.bitwise_not(gray_img)
				ret, gray_img = cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
				#查找水平直方图波峰
				x_histogram  = np.sum(gray_img, axis=1)
				x_min = np.min(x_histogram)
				x_average = np.sum(x_histogram)/x_histogram.shape[0]
				x_threshold = (x_min + x_average)/2
				wave_peaks = find_waves(x_threshold, x_histogram)
				if len(wave_peaks) == 0:
					print("peak less 0:")
					continue
				#认为水平方向,最大的波峰为车牌区域
				wave = max(wave_peaks, key=lambda x:x[1]-x[0])
				gray_img = gray_img[wave[0]:wave[1]]
				#查找垂直直方图波峰
				row_num, col_num= gray_img.shape[:2]
				#去掉车牌上下边缘1个像素,避免白边影响阈值判断
				gray_img = gray_img[1:row_num-1]
				y_histogram = np.sum(gray_img, axis=0)
				y_min = np.min(y_histogram)
				y_average = np.sum(y_histogram)/y_histogram.shape[0]
				y_threshold = (y_min + y_average)/5#U和0要求阈值偏小,否则U和0会被分成两半

				wave_peaks = find_waves(y_threshold, y_histogram)

				#for wave in wave_peaks:
				#	cv2.line(card_img, pt1=(wave[0], 5), pt2=(wave[1], 5), color=(0, 0, 255), thickness=2) 
				#车牌字符数应大于6
				if len(wave_peaks) <= 6:
					print("peak less 1:", len(wave_peaks))
					continue
				
				wave = max(wave_peaks, key=lambda x:x[1]-x[0])
				max_wave_dis = wave[1] - wave[0]
				#判断是否是左侧车牌边缘
				if wave_peaks[0][1] - wave_peaks[0][0] < max_wave_dis/3 and wave_peaks[0][0] == 0:
					wave_peaks.pop(0)
				
				#组合分离汉字
				cur_dis = 0
				for i,wave in enumerate(wave_peaks):
					if wave[1] - wave[0] + cur_dis > max_wave_dis * 0.6:
						break
					else:
						cur_dis += wave[1] - wave[0]
				if i > 0:
					wave = (wave_peaks[0][0], wave_peaks[i][1])
					wave_peaks = wave_peaks[i+1:]
					wave_peaks.insert(0, wave)
				
				#去除车牌上的分隔点
				point = wave_peaks[2]
				if point[1] - point[0] < max_wave_dis/3:
					point_img = gray_img[:,point[0]:point[1]]
					if np.mean(point_img) < 255/5:
						wave_peaks.pop(2)
				
				if len(wave_peaks) <= 6:
					print("peak less 2:", len(wave_peaks))
					continue
				part_cards = seperate_card(gray_img, wave_peaks)
				for i, part_card in enumerate(part_cards):
					#可能是固定车牌的铆钉
					if np.mean(part_card) < 255/5:
						print("a point")
						continue
					part_card_old = part_card
					#w = abs(part_card.shape[1] - SZ)//2
					w = part_card.shape[1] // 3
					part_card = cv2.copyMakeBorder(part_card, 0, 0, w, w, cv2.BORDER_CONSTANT, value = [0,0,0])
					part_card = cv2.resize(part_card, (SZ, SZ), interpolation=cv2.INTER_AREA)
					#cv2.imshow("part", part_card_old)
					#cv2.waitKey(0)
					#cv2.imwrite("u.jpg", part_card)
					#part_card = deskew(part_card)
					part_card = preprocess_hog([part_card])
					if i == 0:
						resp = self.modelchinese.predict(part_card)
						charactor = provinces[int(resp[0]) - PROVINCE_START]
					else:
						resp = self.model.predict(part_card)
						charactor = chr(resp[0])
					#判断最后一个数是否是车牌边缘,假设车牌边缘被认为是1
					if charactor == "1" and i == len(part_cards)-1:
						if part_card_old.shape[0]/part_card_old.shape[1] >= 8:#1太细,认为是边缘
							print(part_card_old.shape)
							continue
					predict_result.append(charactor)
				roi = card_img
				card_color = color
				break
				
		return predict_result, roi, card_color#识别到的字符、定位的车牌图像、车牌颜色

         识别结果如下

h,w: 394 631
len(contours) 3
2
精确定位
blue
3800 21 0 67 9 4641
no
1 420 897 24 270 20145
['粤', 'X', '8', '3', '3', '3', '8']

        车牌定位算法的参数受图像分辨率、色偏、车距影响,如果是基于深度学习的算法效果可能会更好。

车牌ocr识别的流程,手机车牌识别

 车牌的OCR识别的流程如下:手机车牌识别背景  随着人们生活水平的提高,汽车方面的业务量也日益暴涨,加上如今“互联网+”的提出,智能终端(智能手机及平板电脑)及移动通信(4G)发展迅速,人们用手机的频率比用... 查看详情

车牌识别的移动端与pc端比较

...停车等诸多行业都有着很重要的地位,那么您知道车牌识别的原理吗?车牌识别技术要求能够将运动中的汽车牌照从复杂背景中提取并识别出来,通过车牌提取、图像预处理、特征提取、车牌字符识别等技术,识别车辆牌号、颜... 查看详情

移动端车牌识别的原理以及特点

伴随着经济水平的不断提升与发展,汽车数量的持续增长给车辆管理带来了一定的困难。目前,车牌识别方式已经成为每个城市的车辆管理重点工作之一,有效、准确、及时的车牌识别可以方便警务人员的交通执法、停车场车辆... 查看详情

巡逻机器人用应用的pc端车牌识别

...牌识别使用背景人工智能的发展,京东送件也用上了送件机器人,某机器人公司如今研发出巡逻机器人,用于对可以车辆的抓拍与检查,在停车的区域内,通过算法控制,边巡逻,边识别车牌号码,其中,此识别的算法恰恰用上... 查看详情

技术解析:手机车牌识别软件—移动端车牌识别/ocr算法

...理大致这样:使用摄像头充当“眼睛”,使用openCV与深度学习充当“大脑”。实时车牌识别工作步骤:摄像头抓拍—>o 查看详情

技术解析:手机车牌识别软件—移动端车牌识别/ocr算法

...理大致这样:使用摄像头充当“眼睛”,使用openCV与深度学习充当“大脑”。实时车牌识别工作步骤:摄像头抓拍—>o 查看详情

技术解析:手机车牌识别软件—移动端车牌识别/ocr算法

...理大致这样:使用摄像头充当“眼睛”,使用openCV与深度学习充当“大脑”。实时车牌识别工作步骤:摄像头抓拍—>o 查看详情

移动端车牌识别ocr识别的流程介绍

移动端车牌识别背景越发达的地区,人均保有车辆越多,加上我国的“互联网+”提出,移动业务越来越兴旺发达,智能终端(智能手机及平板电脑)及移动通信(4G)发展迅速,人们用手机的频率比用电脑的多,灵活便捷,随处... 查看详情

私有化部署车牌识别的好处

...车牌识别、云端车牌识别、ocr车牌识别私有化部署车牌识别的好处?私有云车牌识别产品是一款基于服务器平台的车牌OCR识别服务程序,企业可将该识别服务部署在自有服务器上(云服务器或本地服务器),部署完成后,APP端、PC... 查看详情

pc端车牌识别在智能机器人上的应用

人工智能的发展,京东送件也用上了送件机器人,某机器人公司如今研发出巡逻机器人,用于对可以车辆的抓拍与检查,在停车的区域内,通过算法控制,边巡逻,边识别车牌号码,其中,此识别的算法恰恰用上的是我们的PC版... 查看详情

车牌识别及验证码识别的一般思路

...文分两部分,第一部分讲车牌识别及普通验证码这一类识别的普通方法,第二部分讲对类似QQ验证码,Gmail验证码这一类变态验证码的识别方法和思路。一、车牌/验证码识别的普通方法车牌、验证码识别的普通方法为:(1) ... 查看详情

移动互联时代,移动端车牌识别的价值在哪?

随着互联网的发展,传统行业迎来了一次不小的机遇,同样也面临着一波猛烈的冲击。b2b、b2c、c2c、o2o这些电子商务词汇就是这个时代的产物。现在移动互联网成为了热点,为了能赶上这一波红利,企业都推出了app来触达用户。... 查看详情

关于车牌识别的工作原理和技术参数

综合网上上各种车牌识别方法,总结出一个较为简单的车牌识别方案,采用VS2013+OpenCv2.4.9实现。并且附上可运行的源代码以及测试图片和视频,详细参数设置请参照源代码。识别部分的训练样本见我上传的资源。实现方法(一)检... 查看详情

基于svm支持向量机的车牌分割识别算法matlab仿真(代码片段)

...22?type=blog擅长技术:1.无线基带,无线图传,编解码2.机器视觉,图像处理,三维重建3.人工智能,深度学习4.智能控制,智能优化5.其他一、理论基础    车牌识别系统集合了先进的光电、计算机视觉、信号处理、图像处理、模式... 查看详情

中文识别数据集生成脚本

...的字符输出为不同字体的图像文件,用于训练文字识别的机器学习模型或用于其他文字识别OCR项目详细代码下载:http://www.demodashi.com/demo/13952.html 一、开发背景随着近几年来计算机算力的不断提升,机器学习也迎来了爆发式... 查看详情

如何去使用移动端车牌识别?

...车牌照图像,然后通过OCR软件对车牌颜色、车牌号进行识别的过程。二、移动端车牌识别的功能特点1、识别速度快,只需0.5S。2、识别率高,识别率高达98%3、支持超大角度识别,准确识别车牌4、视频流识别,“只需扫一扫,快... 查看详情

车牌自动识别能快速准确的识别车牌是啥原理?

...动态视频或静态图像进行牌照号码、牌照颜色自动识别的模式识别技术。通过对图像的采集和处理,完成车牌自动识别功能,能从一幅图像中自动提取车牌图像,自动分割字符,进而对字符进行识别.其硬件基础一般包括触发设... 查看详情

[声纹识别]语音识别的发展史

...研究经历了知识积累、模板匹配、模式识别、统计模型、机器学习和深度学习等五个发展阶段[1]。   1.知识积累阶段。20世纪30-50年代,针对特定语音或小词表的孤立词,设计专门的语音识别算法或装置。    2.模板匹... 查看详情