目录
一、基础理论
1、思想
把提取到的每一张字符,和模板库中的所有字符进行对比。
2、大致过程
先拿到模板库,把模板和待匹配的图像大小限制一致,匹配每一张子模板图,匹配每张模板图匹配后都会有一个得分,得分最高的最相近。再把每个子文件夹最高得分对比,用index找到最高的那个子文件夹下标,得到模板。
二、详细过程
1、首先需要模板库
模板库下载链接1:(推荐)
https://download.csdn.net/download/great_yzl/21974008
模板库下载链接2:(不推荐)
http://www.zengqiang.club/blog/34
一个大文件夹下包含很多子文件夹:
每一个子文件夹内包含该字符的一系列模板(为了更精确,牺牲了不少时间):
2、得到模板
# 路径
path = 'Template/' + List[i] + '/' + filename
# 1、得到模板
template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1) #彩(类似imread)
gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY) #灰
ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU) #二值
cv.imshow('template', template)
cv.waitKey(0)
3、原图限定大小
# 2、原图限定大小(和模板相似)
h, w = template.shape
image = cv.resize(image, (w, h))
cv.imshow('image_', image)
cv.waitKey(0)
4、模板匹配
按照名称列表的方式,遍历模板库的所有子文件夹、子文件夹内的所有子图。
# 3、模板匹配,得到得分(匹配度越高,得分越大)
result = cv.matchTemplate(image, template, cv.TM_CCOEFF)
score.append(result[0][0]) #得分(每张模板图)
5、匹配所有子文件夹,保存最佳得分(最匹配项)
匹配所有子文件夹的子图:
# 模板匹配,得到得分(匹配度越高,得分越大)
result = cv.matchTemplate(image, template, cv.TM_CCOEFF)
score.append(result[0][0]) #得分(每张模板图)
每个文件夹的最佳得分:
# 一个文件夹的最高得分(得分越高,匹配度越高)
best_score.append(max(score))
# 根据所有文件夹的最佳得分确定下标
index = best_score.index(max(best_score))+34
三、大致过程(细分类,节省时间)
由于第一个必定是汉字,第二个必定是英文字符,后面的必定是英文字符/数字,我们在那里只需要做相应的判断即可。节约了很多时间。
1、汉字匹配
# (1) 汉字(首个位置只能是汉字(省))(为了节约时间)
if con == 0:
# 遍历34——65文件夹(汉字)
for i in range(34,65):
# 单个图片的得分
score = []
ForderPath = 'Template/' + List[i]
# 遍历单文件夹(每一个文件匹配)
for filename in os.listdir(ForderPath):
# 路径
path = 'Template/' + List[i] + '/' + filename
# 1、得到模板
template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1) #彩(类似imread)
gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY) #灰
ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU) #二值
# 2、原图限定大小(和模板相似)
h, w = template.shape
image = cv.resize(image, (w, h))
cv.imshow('image_', image)
cv.waitKey(0)
# 3、模板匹配,得到得分(匹配度越高,得分越大)
result = cv.matchTemplate(image, template, cv.TM_CCOEFF)
score.append(result[0][0]) #得分(每张模板图)
# 4、保存子文件夹的最高得分(得分越高,匹配度越高)
best_score.append(max(score))
# 5、根据所有文件夹的最佳得分确定下标
index = best_score.index(max(best_score))+34
2、英文字符匹配
# (2) 字母(第二个位置只能为字母)
elif con == 1:
# 遍历10~34文件夹(字母文件夹)
for i in range(10,34):
# 单个图片的得分
score = []
ForderPath = 'Template/' + List[i]
# 遍历单文件夹(每一个文件匹配)
for filename in os.listdir(ForderPath):
# 路径
path = 'Template/' + List[i] + '/' + filename
# 模板
template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1) #彩(类似imread)
gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY) #灰
ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU) #二值
h, w = template.shape
image = cv.resize(image, (w, h))
# 模板匹配,得到得分(匹配度越高,得分越大)
result = cv.matchTemplate(image, template, cv.TM_CCOEFF)
score.append(result[0][0]) #得分(每张模板图)
# 一个文件夹的最高得分(得分越高,匹配度越高)
best_score.append(max(score))
# 根据所有文件夹的最佳得分确定下标
index = best_score.index(max(best_score)) + 10
3、数字/英文匹配
# (3) 数字+字母
else:
# 遍历0~34文件夹(数字+字母)
for i in range(34):
# 单个图片的得分
score = []
ForderPath = 'Template/' + List[i]
# 遍历单文件夹(每一个文件匹配)
for filename in os.listdir(ForderPath):
# 路径
path = 'Template/' + List[i] + '/' + filename
# 模板
template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1) #彩(类似imread)
gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY) #灰
ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU) #二值
h, w = template.shape
image = cv.resize(image, (w, h))
# 模板匹配,得到得分(匹配度越高,得分越大)
result = cv.matchTemplate(image, template, cv.TM_CCOEFF)
score.append(result[0][0]) #得分(每张模板图)
# 一个文件夹的最高得分(得分越高,匹配度越高)
best_score.append(max(score))
# 根据所有文件夹的最佳得分确定下标
index = best_score.index(max(best_score))
4、显示
在切割字符函数的尾部,所有字符切割完、立刻进行模板匹配,同一张车牌所有字符切割完毕后,进行显示。
# 显示识别结果(图像)
Show_Result_Image()
# 显示识别结果(图像)
def Show_Result_Image():
p = image_rect[0], image_rect[1]
w, h = image_rect[2] , image_rect[3]
# 框出车牌
cv.rectangle(img, (p[0],p[1]), (p[0]+w, p[1]+h), (0,0,255), 2)
# 输出字符(中文)
result = Text(img, str(final_result), p, (255,0,0), 16)
cv.imshow('result-%d'%count, result)
# cv.waitKey(0)
模板匹配总代码
# 显示文字(中文)(用的PIL,RGB正常显示,即和opencv的RGB相反)
def Text(image, text, p, color, size):
# cv2读取图片
# BGR转RGB:cv2和PIL中颜色的hex码的储存顺序不同
cv2_image = cv.cvtColor(image, cv.COLOR_RGB2BGR)
pil_image = Image.fromarray(cv2_image)
# PIL图片上打印汉字
draw = ImageDraw.Draw(pil_image) # 图片上打印
font = ImageFont.truetype("./simhei.ttf", size, encoding="utf-8") # 参数1:字体文件路径,参数2:字体大小
draw.text((p[0]-60, p[1]-20), text, color, font=font)
# PIL图片转cv2 图片
cv2_result = cv.cvtColor(np.array(pil_image), cv.COLOR_RGB2BGR)
# cv2.imshow("图片", cv2_result) # 汉字窗口标题显示乱码
# cv.imshow("photo", cv2_result) # 输出汉字
return cv2_result
# 显示识别结果(文字)
def Show_Result_Words(index):
print(List[index])
final_result.append(List[index])
print(final_result)
# 显示识别结果(图像)
def Show_Result_Image():
p = image_rect[0], image_rect[1]
w, h = image_rect[2] , image_rect[3]
# 框出车牌
cv.rectangle(img, (p[0],p[1]), (p[0]+w, p[1]+h), (0,0,255), 2)
# 输出字符(中文)
result = Text(img, str(final_result), p, (255,0,0), 16)
cv.imshow('result-%d'%count, result)
# cv.waitKey(0)
# 三、模板匹配
# 原图和模板进行对比,越匹配,得分越大
def Template_Match(image):
# 单文件夹内的最佳得分
best_score = []
# 遍历所有文件夹(每一个文件夹匹配)
# (1) 汉字(首个位置只能是汉字(省))(为了节约时间)
if con == 0:
# 遍历34——65文件夹(汉字)
for i in range(34,65):
# 单个图片的得分
score = []
ForderPath = 'Template/' + List[i]
# 遍历单文件夹(每一个文件匹配)
for filename in os.listdir(ForderPath):
# 路径
path = 'Template/' + List[i] + '/' + filename
# 1、得到模板
template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1) #彩(类似imread)
gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY) #灰
ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU) #二值
# 2、原图限定大小(和模板相似)
h, w = template.shape
image = cv.resize(image, (w, h))
# 3、模板匹配,得到得分(匹配度越高,得分越大)
result = cv.matchTemplate(image, template, cv.TM_CCOEFF)
score.append(result[0][0]) #得分(每张模板图)
# 4、保存子文件夹的最高得分(得分越高,匹配度越高)
best_score.append(max(score))
# 5、根据所有文件夹的最佳得分确定下标
index = best_score.index(max(best_score))+34
# (2) 字母(第二个位置只能为字母)
elif con == 1:
# 遍历10~34文件夹(字母文件夹)
for i in range(10,34):
# 单个图片的得分
score = []
ForderPath = 'Template/' + List[i]
# 遍历单文件夹(每一个文件匹配)
for filename in os.listdir(ForderPath):
# 路径
path = 'Template/' + List[i] + '/' + filename
# 模板
template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1) #彩(类似imread)
gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY) #灰
ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU) #二值
h, w = template.shape
image = cv.resize(image, (w, h))
# 模板匹配,得到得分(匹配度越高,得分越大)
result = cv.matchTemplate(image, template, cv.TM_CCOEFF)
score.append(result[0][0]) #得分(每张模板图)
# 一个文件夹的最高得分(得分越高,匹配度越高)
best_score.append(max(score))
# 根据所有文件夹的最佳得分确定下标
index = best_score.index(max(best_score)) + 10
# (3) 数字+字母
else:
# 遍历0~34文件夹(数字+字母)
for i in range(34):
# 单个图片的得分
score = []
ForderPath = 'Template/' + List[i]
# 遍历单文件夹(每一个文件匹配)
for filename in os.listdir(ForderPath):
# 路径
path = 'Template/' + List[i] + '/' + filename
# 模板
template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1) #彩(类似imread)
gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY) #灰
ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU) #二值
h, w = template.shape
image = cv.resize(image, (w, h))
# 模板匹配,得到得分(匹配度越高,得分越大)
result = cv.matchTemplate(image, template, cv.TM_CCOEFF)
score.append(result[0][0]) #得分(每张模板图)
# 一个文件夹的最高得分(得分越高,匹配度越高)
best_score.append(max(score))
# 根据所有文件夹的最佳得分确定下标
index = best_score.index(max(best_score))
# 显示结果(文字)(每识别一个显示一次)
Show_Result_Words(index)
总的来讲,为了追求较高的精度,匹配时间较长, 一张车牌约20秒。这里的模板匹配不算非常的精确,并且耗时严重,已经逐渐被淘汰了,这里只是作为学习用途,没有太高的实际应用价值。(后期进军深度学习/机器学习,可能会对这些进行优化)。有什么好的建议大家可以提出来,共同进步,谢谢~