目录

1.初始模板匹配

2.模板匹配函数

3.车牌字符模板匹配

3.1图像预处理

3.2图像分割

3.3得到单个字符外接矩形

3.4单个字符图片的列表

3.5读取模板

3.6依次检测中文、英文/数字字符

4.完整代码

前言:模板匹配是物体检测的最简单的方法之一。

➢车牌字符模板匹配实现思路:

•1. 获取所有模板图片路径,注意分开记录中文和英文模板路径

•2. 对于一张要匹配的图片,获取它与所有模板图片的匹配结果分数,记录分数最高的模板字符并返回

1.初始模板匹配

下图是模板匹配工作流程的一个例子,取想要检测的对象/模板,源图像,然后在源图像中找到模板。

➢为了在源图像中找到模板图像,在源图像中从左到右和从上到下依次滑动模板,

进行卷积值计算

➢在每一个位置都计算一个分数,表明这个位置模板和源图图像块之间匹配程度

的高低

➢当模板和源图中的物体完全重合时,分数最高

➢模板匹配的优点

•单次匹配效率高

•实现简单

➢模板匹配缺点

•源图像中的目标和模板如果有大小、比例、旋转、视角上的区别,匹配容易失效

•为了保证匹配效果,对于一个物体需要准备大量模板,降低匹配效率

2.模板匹配函数

 ➢result = cv2.matchTemplate(image,template, method)

参数解释如下:

•image:要进行物体检测的源图像

•template:模板图像

•method:模板匹配方法

•具体算法见附录

•result: 每个位置的分数值

3.车牌字符模板匹配

部分知识点总结:

详细可参考文章:http://t.csdn.cn/Eh0RZ

➢基于阈值的图像分割

• 自适应阈值分割 – 图片不同区域计算不同阈值

• Otsu阈值分割 – 不同的图片计算不同阈值

➢轮廓和外接矩形检测

•contours, hierarchy = cv2.findContours(image, mode, method)

•rect= cv2.boundingRect(points)

➢模板匹配–简单的物体检测方法

•result = cv2.matchTemplate(image,template, method)

3.1图像预处理

# 图片预处理
def pre_processing(image):'''对图片进行预处理,保证后续操作的结果'''#第一步:将图片的高转换为120,保证各个函数传入参数的适用性target_height = 120h, w, _ = image.shaperesize_ratio = target_height/himage = cv2.resize(image, None, fx=resize_ratio, fy=resize_ratio)#第二部:去噪image = cv2.GaussianBlur(image, (3, 3), 0)#第三步:转换为灰度图gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# cv2.imshow("gray_image", gray_image)# cv2.waitKey()return gray_image

3.2图像分割

# 图像分割
def get_segment(gray_image):'''得到图像分割结果,区分出字符和非字符区域'''#第一步:使用0tsu阅值分割算法对分割出字符和非字符区域ret,  thresh_image = cv2. threshold(gray_image, 200, 255,cv2.THRESH_BINARY + cv2.THRESH_OTSU)#第二步:比较分割结果中白色和黑色像素数量,保证字符区域是白色area_white = 0area_black = 0height, width = gray_image.shapefor i in range(width):for j in range(height):if thresh_image[j, i]==0:area_black += 1else:area_white += 1if area_white > area_black:thresh_image = 255 - thresh_image# cv2.imshow("thresh_image", thresh_image)# cv2.waitKey()return thresh_image

3.3得到单个字符外接矩形

# 单个字符外接矩形
def get_rectangles(thresh_image, draw_contours=False, draw_rectangle=False):'''获取一张阈值分割结果,返回单个字符的外接矩形坐标列表draw_contours:显示轮廓绘制的结果draw_rectangle:显示矩形绘制的结果'''# 轮廓检测th1 = cv2.dilate(thresh_image, None)  # 膨胀contours, hierachy = cv2.findContours(th1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 轮廓可视化th1_bgr = cv2.cvtColor(th1, cv2.COLOR_GRAY2BGR)  # 把单通道变成三通道,方便显示彩色if draw_contours:cv2.drawContours(th1_bgr, contours, -1, (0,0,255), 2)# cv2.imshow("contours", th1_bgr)# cv2.waitKey()'''外接矩形(包围框的提取于绘制)'''words = []  # 保存所有字符的外接矩形height, width = th1.shape  # 拿到整张图片的高和宽for contour in contours:  # 拿到每条轮廓的点的坐标rect = cv2.boundingRect(contour)  # 获取当前轮廓的外接矩形# 只保留高宽比在1.5-3.5范围内的矩形,并且这个矩形的高/整张图像的高大于0.3if rect[3] / rect[2] > 1.5 and rect[3] / rect[2] < 3.5 and rect[3] / height > 0.3:words.append(rect)  # 将当前矩形加入矩形列表if draw_rectangle:cv2.rectangle(th1_bgr, (rect[0], rect[1]), (rect[0] + rect[2], rect[1] + rect[3]),(255, 255, 0), 3)  # 绘制矩形# cv2.imshow("rectangle", th1_bgr)# cv2.waitKey()return words

3.4单个字符图片的列表

# 单字符图片列表
def get_single_words(image, words):'''对矩形从左至右排序,并且提取每一个矩形的ori; image:二值图片,words:矩形列表'''#根据每个元素的第一个值进行从小到大的排序words.sort(key=lambda x:x[0])#提取单个字符的ori,把单个字符的图片保存在words——imgs中words_imgs = []for rect in words:#取左上角xy坐标分别为(rect[0], rect[1]), 宽和高分别为rect[2]和rect[3]的oricurrent_img = image[rect[1]:rect[1]+rect[3], rect[0]:rect[0]+rect[2]]words_imgs.append(current_img)cv2.imshow("current_img",current_img)cv2.waitKey()return words_imgs

3.5读取模板


import cv2, os
import numpy as np# 读取模板
template_chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9','A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K','L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z','藏', '川', '鄂', '甘', '赣', '贵', '桂', '黑', '沪', '吉','冀', '津', '晋', '京', '辽', '鲁', '蒙', '闽', '宁','青', '琼', '陕', '苏', '皖', '湘', '新', '渝', '豫', '粤', '云', '浙']def read_directory(directory_name):'''遍历文件夹,返回文件夹下所有文件的路径'''referImg_list = []for filename in os.listdir(directory_name):referImg_list.append(directory_name + "/" + filename)return referImg_listdef get_templates():'''获取字符模板图片路径'''# 获取中文字符模板路径chinese_words = []for i in range(34, 64):c_word = read_directory('D:\\desk\\images\\refer1\\' + template_chars[i])chinese_words.append(c_word)# 获取英文和数字字符模板路径english_words = []for i in range(0, 34):c_word = read_directory('D:\\desk\\images\\refer1\\' + template_chars[i])english_words.append(c_word)return chinese_words, english_words

3.6依次检测中文、英文/数字字符


def get_charactor(char_img, templates, match_chinese=True):'''根据字符模板获取最佳匹配字符,并返回char_img: 要识别的字符图片, templates: 模板路径列表,natch_chinese: 是否匹配中文'''best_score = 0 #记录最高得分best_char = '' #记录最高得分对应的字符# TO DO:遍历所有字符模板,i代表字符序号,返回最高得分的字符for i in range(len(templates)):current_char_paths = templates[i] #拿到第i个字符所有模板图片路径for current_char_path in current_char_paths: #拿到当前的模板图片路径#读取模板图片templates_img = cv2.imdecode(np.fromfile(current_char_path, dtype=np.uint8), 1)#对模板图片进行阈值分割templates_img = cv2.cvtColor(templates_img, cv2.COLOR_BGR2GRAY)ret, templates_img = cv2.threshold(templates_img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)#将要识别的字符图片缩放到和模板图片一样的大小height, width = templates_img.shapechar_img = cv2.resize(char_img, (width, height))#进行模板匹配result = cv2.matchTemplate(char_img, templates_img, cv2.TM_CCOEFF)#记录最高的得分和对应的字符if result[0][0] > best_score:best_score = result[0][0]if match_chinese:best_char = template_chars[i+34]else:best_char = template_chars[i]return best_char

4.完整代码

'''(模板匹配)'''import cv2, os
import numpy as np# 读取模板
template_chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9','A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K','L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z','藏', '川', '鄂', '甘', '赣', '贵', '桂', '黑', '沪', '吉','冀', '津', '晋', '京', '辽', '鲁', '蒙', '闽', '宁','青', '琼', '陕', '苏', '皖', '湘', '新', '渝', '豫', '粤', '云', '浙']# 图片预处理
def pre_processing(image):'''对图片进行预处理,保证后续操作的结果'''#第一步:将图片的高转换为120,保证各个函数传入参数的适用性target_height = 120h, w, _ = image.shaperesize_ratio = target_height/himage = cv2.resize(image, None, fx=resize_ratio, fy=resize_ratio)#第二部:去噪image = cv2.GaussianBlur(image, (3, 3), 0)#第三步:转换为灰度图gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# cv2.imshow("gray_image", gray_image)# cv2.waitKey()return gray_image# 图像分割
def get_segment(gray_image):'''得到图像分割结果,区分出字符和非字符区域'''#第一步:使用0tsu阅值分割算法对分割出字符和非字符区域ret,  thresh_image = cv2. threshold(gray_image, 200, 255,cv2.THRESH_BINARY + cv2.THRESH_OTSU)#第二步:比较分割结果中白色和黑色像素数量,保证字符区域是白色area_white = 0area_black = 0height, width = gray_image.shapefor i in range(width):for j in range(height):if thresh_image[j, i]==0:area_black += 1else:area_white += 1if area_white > area_black:thresh_image = 255 - thresh_image# cv2.imshow("thresh_image", thresh_image)# cv2.waitKey()return thresh_image# 单个字符外接矩形
def get_rectangles(thresh_image, draw_contours=False, draw_rectangle=False):'''获取一张阈值分割结果,返回单个字符的外接矩形坐标列表draw_contours:显示轮廓绘制的结果draw_rectangle:显示矩形绘制的结果'''# 轮廓检测th1 = cv2.dilate(thresh_image, None)  # 膨胀contours, hierachy = cv2.findContours(th1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 轮廓可视化th1_bgr = cv2.cvtColor(th1, cv2.COLOR_GRAY2BGR)  # 把单通道变成三通道,方便显示彩色if draw_contours:cv2.drawContours(th1_bgr, contours, -1, (0,0,255), 2)# cv2.imshow("contours", th1_bgr)# cv2.waitKey()'''外接矩形(包围框的提取于绘制)'''words = []  # 保存所有字符的外接矩形height, width = th1.shape  # 拿到整张图片的高和宽for contour in contours:  # 拿到每条轮廓的点的坐标rect = cv2.boundingRect(contour)  # 获取当前轮廓的外接矩形# 只保留高宽比在1.5-3.5范围内的矩形,并且这个矩形的高/整张图像的高大于0.3if rect[3] / rect[2] > 1.5 and rect[3] / rect[2] < 3.5 and rect[3] / height > 0.3:words.append(rect)  # 将当前矩形加入矩形列表if draw_rectangle:cv2.rectangle(th1_bgr, (rect[0], rect[1]), (rect[0] + rect[2], rect[1] + rect[3]),(255, 255, 0), 3)  # 绘制矩形# cv2.imshow("rectangle", th1_bgr)# cv2.waitKey()return words# 单字符图片列表
def get_single_words(image, words):'''对矩形从左至右排序,并且提取每一个矩形的ori; image:二值图片,words:矩形列表'''#根据每个元素的第一个值进行从小到大的排序words.sort(key=lambda x:x[0])#提取单个字符的ori,把单个字符的图片保存在words——imgs中words_imgs = []for rect in words:#取左上角xy坐标分别为(rect[0], rect[1]), 宽和高分别为rect[2]和rect[3]的oricurrent_img = image[rect[1]:rect[1]+rect[3], rect[0]:rect[0]+rect[2]]words_imgs.append(current_img)cv2.imshow("current_img",current_img)cv2.waitKey()return words_imgsdef read_directory(directory_name):'''遍历文件夹,返回文件夹下所有文件的路径'''referImg_list = []for filename in os.listdir(directory_name):referImg_list.append(directory_name + "/" + filename)return referImg_listdef get_templates():'''获取字符模板图片路径'''# 获取中文字符模板路径chinese_words = []for i in range(34, 64):c_word = read_directory('D:\\desk\\images\\refer1\\' + template_chars[i])chinese_words.append(c_word)# 获取英文和数字字符模板路径english_words = []for i in range(0, 34):c_word = read_directory('D:\\desk\\images\\refer1\\' + template_chars[i])english_words.append(c_word)return chinese_words, english_wordsdef get_charactor(char_img, templates, match_chinese=True):'''根据字符模板获取最佳匹配字符,并返回char_img: 要识别的字符图片, templates: 模板路径列表,natch_chinese: 是否匹配中文'''best_score = 0 #记录最高得分best_char = '' #记录最高得分对应的字符# TO DO:遍历所有字符模板,i代表字符序号,返回最高得分的字符for i in range(len(templates)):current_char_paths = templates[i] #拿到第i个字符所有模板图片路径for current_char_path in current_char_paths: #拿到当前的模板图片路径#读取模板图片templates_img = cv2.imdecode(np.fromfile(current_char_path, dtype=np.uint8), 1)#对模板图片进行阈值分割templates_img = cv2.cvtColor(templates_img, cv2.COLOR_BGR2GRAY)ret, templates_img = cv2.threshold(templates_img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)#将要识别的字符图片缩放到和模板图片一样的大小height, width = templates_img.shapechar_img = cv2.resize(char_img, (width, height))#进行模板匹配result = cv2.matchTemplate(char_img, templates_img, cv2.TM_CCOEFF)#记录最高的得分和对应的字符if result[0][0] > best_score:best_score = result[0][0]if match_chinese:best_char = template_chars[i+34]else:best_char = template_chars[i]return best_charrawImage = cv2.imread("D:\\desk\\images\\car_license\\test1.png")
cv2.imshow("rawImage",rawImage)
#预处理
gray_image = pre_processing(rawImage)
# 分割字符和非字符区域
thresh_image = get_segment(gray_image)
#得到单个字符的外接矩形坐标
words_rectangle = get_rectangles(thresh_image, draw_contours=True,draw_rectangle=True)
#得到单个字符图片的列表
words_imgs = get_single_words(thresh_image, words_rectangle)
# #读取模板
chinese_words, english_words = get_templates()
# #检测中文字符(第一个字符)
chinese_word_img = words_imgs[0]
best_word = get_charactor(chinese_word_img,  chinese_words,match_chinese=True)
print(best_word,end='  ')
#检测数字和英文字符
for  i in range(1,  len(words_imgs)):#得到第1个字符words_img = words_imgs[i]best_word = get_charactor (words_img, english_words, match_chinese=False)print(best_word,end='  ')

opencv库功能强大,车牌识别只是基于opencv的物体检测案例之一,本项目为车牌字符模板匹配,小编借此抛砖引玉,不足之处还请各位大佬多多指教!

【opencv项目】物体检测——车牌字符模板匹配相关推荐

  1. OpenCV学习——直方图、边缘检测、模板匹配以及霍夫变化

    OpenCV学习--直方图.边缘检测.模板匹配以及霍夫变化 OpenCV学习--直方图.边缘检测.模板匹配以及霍夫变化 直方图 图像直方图 直方图的术语和意义 掩膜的应用 直方图均衡化 自适应的直方图 ...

  2. OpenCV与图像处理学习十六——模板匹配

    OpenCV与图像处理学习十六--模板匹配 一.模板匹配介绍 二.代码应用 一.模板匹配介绍 模板匹配是一种最原始.最基本的模式识别方法,研究某一特定目标的图像位于图像的什么地方,进而对图像进行定位. ...

  3. 【项目实战二】基于模板匹配和形态学操作的信用卡卡号识别(OpenCV+Python)

    前言:信用卡卡号识别技术的发展有利于提高银行系统的业务水平和办事效率.相信此次通过学习使用OpenCV中的图像处理方法来实现信用卡卡号识别的项目,能让大家清楚地了解图像处理技术的一般方法与步骤以及如何 ...

  4. VS Opencv 字符模板匹配小实例

    初步认识 #include "opencv2/imgcodecs.hpp" #include "opencv2/highgui.hpp" #include &q ...

  5. 使用Opencv进行轮廓检测,字符提取,简单的直方图字符识别!

    一.使用Opencv进行轮廓检测! 所需函数: 1. cvFindContours 函数功能:从二值图像中检索轮廓,并返回检测到的轮廓的个数 函数原型: int)  cvFindContours( C ...

  6. python中括号配对检测_使用模板匹配在Python上进行对象检测!(附代码)

    了解如何在没有机器学习或任何框架的情况下在Python上进行对象检测 每当我们听说" 对象检测 "时,我们就会想到机器学习以及不同的框架.但是我们实际上可以在不使用机器学习或任何其 ...

  7. OpenCV探索之路(九):模板匹配

    模板匹配的作用在图像识别领域作用可大了.那什么是模板匹配? 模板匹配,就是在一幅图像中寻找另一幅模板图像最匹配(也就是最相似)的部分的技术. 说的有点抽象,下面给个例子说明就很明白了. 在上面这幅全明 ...

  8. opencv进阶学习笔记8:模板匹配

    基础版笔记传送门: python3+opencv学习笔记汇总目录(适合基础入门学习) 进阶版笔记目录链接: python+opencv进阶版学习笔记目录(适合有一定基础) 模板匹配原理 模板匹配(Te ...

  9. 车牌识别-模板匹配-BP神经网络-卷积神经网络[深度学习]

    文章来源:http://blog.csdn.net/fighting_dreamer/article/details/56285738 1 车牌识别的步骤 车牌定位 车牌分割 字符识别  正如上面所讲 ...

  10. 【opencv学习笔记】028之模板匹配——matchTemplate函数详解

    目录 一.前言 二.模板匹配 1.模板匹配是个啥 2.常用匹配算法 1.平方差匹配-CV_TM_SQDIFF 2.标准平方差匹配-CV_TM_SQDIFF_NORMED 3.相关匹配-CV_TM_CC ...

最新文章

  1. 服务器的BIOS引导模式设置为什么,Legacy BIOS 引导模式和 UEFI 引导模式
  2. js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)...
  3. JavaScript基础---语言基础(1)
  4. Python学习笔记:Day14 完成Web App
  5. openstack+essex+quantum成功show
  6. 音视频技术开发周刊 | 227
  7. The Stable Marriage Problem(POJ-3487)
  8. SVN安装不成功卸载不干净后如何重装SVN和右键显示SVN
  9. 中科院-杨力祥视频教程 04课程
  10. 初中计算机课堂游戏设计方案,初中信息技术教案设计
  11. 视频教程-思科CCNP路由实验专题--EIGRP篇【适用于思科CCNA、CCNP】-网络技术
  12. 屏幕录制(Giphy Capture)并导出Gif动图
  13. COSOSWAP官网2.0升级——线上圆桌会议重点回顾
  14. 【论文解读 | AAAI2020】NeuralCD:Neural Cognitive Diagnosis for Intelligent Education Systems
  15. 多可系统中如何修改注册信息
  16. wxpython中表格顶角怎么设置_wxpython编程之 grid(数据表格) | 学步园
  17. tp-link tl-wr740n 虚拟服务器,TP-Link TL-WR740N无线路由器的上网设置教程
  18. 标准SPI,Dual SPI和Qual SPI
  19. MarsEdit for Mac(博客写作软件)
  20. Python实现全自动购买火车票!抢票回家过年咯

热门文章

  1. 网狐荣耀之微星棋牌搭建ios苹果APP编译
  2. 继暗影机器人跑路,守护者群管作者也宣布退网
  3. 武田宣布发表ICLUSIG(R) (ponatinib)枢纽性2期PACE血液病试验的终局数据
  4. Vue 动态组件component
  5. vrep与vs2015联合仿真(C/C++)
  6. Echarts 环图 颜色渐变、灰色背景、自适应
  7. 牛X的规则引擎urule2
  8. 单片机段式LCD驱动教程
  9. CAD软件绘图如何提高效率 (下)
  10. android_root后的玩机:magisk模块root隐藏/lsposedxposed框架的使用/MIUI小窗多开