车牌识别 opencv python(简单版)
Posted 防搞活机
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了车牌识别 opencv python(简单版)相关的知识,希望对你有一定的参考价值。
实验目标
使用形态学处理,识别图片中车牌的位置,并识别每个字符的位置
实验原理
1.车牌识别:
(1)车牌的背景色是蓝色,所以先提取图中蓝色的部分,转化为二值图像(蓝色部分为1,其余为0)。
(2)再检测边缘,标出边缘的外接矩形,根据此矩形的长宽比和面积,就可以筛选出车牌的位置所在的矩形。
2.字符识别:
(1)使用连通域检测可以获得所有连通域及其外接矩形。
(2)通过约束外接矩形的长宽比和面积,可以过滤掉噪声。
(3)数字一般在一个连通域内,但汉字往往分多个连通域,所以在连通域检测前,需要使用膨胀,将汉字的间隙填充。
import cv2
import numpy as np
# 主函数区
if __name__ == '__main__':
num = 5
img = cv2.imread(str(num) + '.png', 1)
oriimg = img.copy()
# 进行中值滤波去噪或高斯滤波
# img = cv2.medianBlur(img, 9)
img = cv2.GaussianBlur(img, (5, 5), 0)
oriimg2 = img.copy()
# RGB转HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 蓝色的范围
lower = np.array([100, 100, 100])
upper = np.array([140, 255, 255])
# 根据阈值构建掩模,只留下蓝色
mask = cv2.inRange(hsv, lower, upper)
cv2.imshow('mask', mask) # 车牌的矩形
# cv2.waitKey(0)
# 检测轮廓
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
blocks = []
for c in contours:
x, y, w, h = cv2.boundingRect(c) # 画出矩形
# 根据轮廓形状特点,确定车牌的轮廓位置并截取图像
if (w > (h * 2)) and (w < (h * 6)):
# img=oriimg[y:y+h,x:x+w]
# cv2.rectangle(oriimg, (x, y), (x+w, y+h), (0, 255, 0), 2)
blocks.append([x, y, w, h, w * h])
max_rec = max(blocks, key=lambda a: a[4]) # 找出面积最大的矩形
# 画出车牌的矩形
cv2.rectangle(oriimg, (max_rec[0], max_rec[1]), (max_rec[0] + max_rec[2], max_rec[1] + max_rec[3]), (255, 0, 255),
2)
cv2.imshow('plate', oriimg) # 车牌的矩形
# cv2.waitKey(0)
cv2.imwrite(str(num) + "plate.png", oriimg)
"""
以上是车牌定位的代码,运行后会得到一个车牌的矩形框
以下是车牌字符分割的代码,运行后会得到每个字符的矩形框
"""
ROI = oriimg2[max_rec[1]:max_rec[1] + max_rec[3], max_rec[0]:max_rec[0] + max_rec[2], :] # 截取车牌部分
ROI_gray = cv2.cvtColor(ROI, cv2.COLOR_BGR2GRAY)
ret, threshold = cv2.threshold(ROI_gray, 0, 255, cv2.THRESH_OTSU) # 车牌部分二值化
cv2.imshow('plate_bin', threshold)
# cv2.waitKey(0)
# 去掉最边缘的一部分
margin_size = 10
threshold[0:margin_size, :] = 0
threshold[-margin_size:, :] = 0
threshold[:, 0:margin_size] = 0
threshold[:, -margin_size:] = 0
# 膨胀,把汉字中孤立的部分连通起来
kernel1 = np.ones((1, 3), dtype=np.uint8) # 主要在横向方向膨胀
dilate = cv2.dilate(threshold, kernel1, 1)
kernel2 = np.ones((7, 1), dtype=np.uint8) # 主要在纵向向方向膨胀
dilate = cv2.dilate(dilate, kernel2, 1)
erose=cv2.erode(dilate,kernel2,1) # 主要在横向方向腐蚀,防止数字连在一起
cv2.imshow('dilate', erose) # 膨胀后的车牌
# cv2.waitKey(0)
# 检测连通域
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(erose, connectivity=4)
# 画出每个连通域的矩形框
word_rect = []
for r in stats:
x, y, w, h, s = r.tolist()
if w * 1.5 < h and w * 10 > h and h > threshold.shape[0] / 2: # 约束长宽比和高度
word_rect.append(r)
cv2.rectangle(ROI, (x, y), (x + w, y + h), (255, 0, 255), 2) # 画出每个字符的矩形框
cv2.imshow('words', ROI) # 框出车牌的每个字符
cv2.waitKey(0)
cv2.imwrite(str(num) + "words.png", ROI)
结果
此方法比较简单,具有局限性:
(1)如果遇到灰度图或者图片颜色不明显,就不能通过检测蓝色来识别车牌位置。
(2)如果图片质量很低,例如很模糊,则需要经过更多的预处理,例如去噪。否则连通域检测会出错。
(3)如果图片有扭曲,则过滤外接矩形的长宽比也要相应调整。
总体来说,仅仅使用形态学处理的车牌识别方法,对于质量好的图片是可以实现。但是实际中可能会遇到更复杂的情况,这时候往往需要深度学习的方法进行识别。
以上是关于车牌识别 opencv python(简单版)的主要内容,如果未能解决你的问题,请参考以下文章