python opencv识别蓝牌车牌号 之 取出车牌号 (1/3)
概述
车牌识别是计算机视频图像识别技术在车辆牌照识别中的一种应用,通常来讲如果结合opencv进行车牌识别主要分为四个大步骤,分别为:
- 图像采集
- 车牌定位
- 分割车牌字符
- 字符识别
当然,如果结合了机器学习可能步骤会变得更为精简,但是从opencv基础方法开始也不失为一种学习进步,此案例仅仅从蓝牌车牌入手,作为学习交流用,暂不打算花时间研究绿牌、黄牌车等车牌识别。
图像采集我们直接掠过,现在假设我们已经完成了图像采集,得到了包含车牌的图片。我们直接从车牌定位开始。
*** 文中的车辆、车牌均来自网络,与现实中任何事务无关。***
取出车牌
现在我们目的是从一张图片中识别出车牌位置,并将车牌位置的矩形单独取出来形成一张图片。为了达到这样的目的我们需要完成以下几步:
- 尺寸调整:将较大尺寸图片处理成较小尺寸图片,避免图像处理过慢
- 色域分析:取出蓝色色彩范围
- 色域叠加:将色域分析出的蓝色范围在图片中进行叠加,更加方便识别
- 调整为灰度图像:牢记我们最终目的是进行车牌识别,调整为灰度图像更方便后续使用
- 高斯过滤:主要过滤噪点等干扰
- 形态学处理:通常使用一次侵蚀和膨胀作为基本操作来执行形态转换,以方便后面的图像边缘检测
- 二值化:将灰度图像的某个值以下的全部设置为0,该值以上的全部设置为255,更加方便后续的图片边缘检测
- 边缘检测:检测图片中的边缘
- 特征找牌:根据车牌宽高比的特征取出车牌
当然,为什么要进行以上几步才找出车牌这个仁者见仁智者见智,就类似如果要吃饭首先要淘米,然后放入锅中煮一样,总而言之有更好更简洁高效的方式也是可以的。
尺寸调整
刚才说到,尺寸调整的目的是避免因图片尺寸过大而引起计算机处理速度过慢,在这里需要重点注意的是在调整尺寸的时候需要注意保持好图片的宽高比,假设我们需要做的是将图片的宽度变为500px,并同时假设我们手中的图片是19201080px,那么我们最终处理好的图片应该是889500,即500/1080*1920
以下代码来自网络,在python opencv中保持宽高比地处理图片:
点击查看代码
def resize_keep_aspectratio(image_src, dst_size):
src_h, src_w = image_src.shape[:2]
# print(src_h, src_w)
dst_h, dst_w = dst_size
# 判断应该按哪个边做等比缩放
h = dst_w * (float(src_h) / src_w) # 按照w做等比缩放
w = dst_h * (float(src_w) / src_h) # 按照h做等比缩放
h = int(h)
w = int(w)
if h <= dst_h:
image_dst = cv2.resize(image_src, (dst_w, int(h)))
else:
image_dst = cv2.resize(image_src, (int(w), dst_h))
h_, w_ = image_dst.shape[:2]
return image_dst
我们使用img = self.resize_keep_aspectratio(image, [500, 500])即可进行调用,其中虽然传递为[500,500],实际上改方法会根据宽高比自动调整。
色域分析&叠加
色域分析的关键函数是调用cv2.inRange方法,围绕该方法我们写出以下代码:
点击查看代码
# hsv提取蓝色部分
def hsv_color_find(img):
img_copy = img.copy()
"""
提取图中的蓝色部分 hsv范围可以自行优化
"""
hsv = cv2.cvtColor(img_copy, cv2.COLOR_BGR2HSV)
low_hsv = np.array([100, 80, 80])
high_hsv = np.array([124, 255, 255])
# 设置HSV的阈值
mask = cv2.inRange(hsv, lowerb=low_hsv, upperb=high_hsv)
cv2.imshow("hsv_color_find", mask)
# 将掩膜与图像层逐像素相加
res = cv2.bitwise_and(img_copy, img_copy, mask=mask)
cv2.imshow("hsv_color_find2", res)
return res
其中low_hsv以及high_hsv是根据经验设定的在hsv色域取出蓝色的值,最终效果如下:
原图:

进行色域分析后的图:

进行色域分析后进行叠加的图:

调整为灰度图像
点击查看代码
# RGB->灰度
gray_img = cv2.cvtColor(img_copy, cv2.COLOR_BGR2GRAY)
高斯过滤
点击查看代码
gray_img_ = cv2.GaussianBlur(gray_img, (5, 5), 0, 0, cv2.BORDER_DEFAULT)
其中(5, 5)也是经验值,可以自行调整
经过灰度处理和高斯过滤后结果如下:

形态学处理
点击查看代码
kernel = np.ones((23, 23), np.uint8)
# 使用侵蚀和膨胀作为基本操作来执行高级形态转换。任何操作都可以就地完成.在多通道图像的情况下,每个通道都是独立处理的.
img_opening = cv2.morphologyEx(gray_img, cv2.MORPH_OPEN, kernel)
# 计算两个数组的加权和
img_opening = cv2.addWeighted(gray_img, 1, img_opening, -1, 0)
进行形态学处理的主要方法是cv2.morphologyEx,里面包括了两个重要的参数,对于这两个重要的参数可以通过搜索引擎得知其用途。
处理过后效果如下:

二值化
ret2, img_thresh2 = cv2.threshold(img_opening, 0, 255, cv2.THRESH_BINARY)
效果如下:

边缘检测
点击查看代码
# # 使用开运算和闭运算让图像边缘成为一个整体
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 10))
img_edge1 = cv2.morphologyEx(img_edge, cv2.MORPH_CLOSE, kernel)
img_edge2 = cv2.morphologyEx(img_edge1, cv2.MORPH_OPEN, kernel)
img_edge3 = cv2.morphologyEx(img_thresh2, cv2.MORPH_CLOSE, kernel)
img_edge4 = cv2.morphologyEx(img_edge3, cv2.MORPH_CLOSE, kernel)
contours, hierarchy = cv2.findContours(img_edge4, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
真正检测边缘的代码实际上就是
cv2.findContours
但是在真正进行检测的时候还做了几次开运算和闭运算,这样可以使碎片化的二值化图像形成一个整体,以便后续进行整体识别。
识别过后针对边缘画出的边缘图像如下:

根据车牌宽高比的特征取出车牌
从上一步得知,我们进行边缘检测得到的边缘多达9个,我们需要从这些边缘中找出车牌号的那块,OpenCV自带的cv2.contourArea()函数可以实现计算点集(轮廓)所围区域的面积,cv2.minAreaRect()函数可以计算出点集的最小外包旋转矩形,cv2.boxPoints()函数可以根据旋转矩形的中心的坐标、尺寸和旋转角度,计算出旋转矩形的四个顶点。
我们可以通过测量知道中国的蓝牌和黑牌是440×140,黄牌前牌尺寸同,后牌为440×220;摩托车及轻便摩托车前牌是220×95,后牌是220×140。我们可以通如下代码筛选:
点击查看代码
## 先筛选面积较大的地方
for contour in contours:
if cv2.contourArea(contour) > 2000:
temp_contours.append(contour)
for temp_contour in temp_contours:
rect_tupple = cv2.minAreaRect(temp_contour)
rect_width, rect_height = rect_tupple[1]
if rect_width < rect_height:
rect_width, rect_height = rect_height, rect_width
aspect_ratio = rect_width / rect_height
if aspect_ratio > 1.5 and aspect_ratio < 4.65: #此处可根据具体的情况针对比例进行具体的调整
car_plate1.append(temp_contour)
rect_vertices = cv2.boxPoints(rect_tupple)
#最后进行矩阵和投影变换,将斜着的矩形摆正
rect = cv2.minAreaRect(car_plate)
# 计算最小区域的坐标
box = cv2.boxPoints(rect)
wh = np.int0(rect[1])
# 变换矩阵
if 0<rect[2]<=45:
mat = cv2.getPerspectiveTransform(np.float32([[box[0][0], box[0][1]], [box[1][0], box[1][1]], [box[2][0], box[2][1]], [box[3][0], box[3][1]]]),np.float32([[0, wh[1]], [0, 0], [wh[0], 0], [wh[0], wh[1]]]))
# 投影变换
lic = cv2.warpPerspective(img, mat, (wh[0], wh[1]))
if 45 < rect[2] <= 90:
mat = cv2.getPerspectiveTransform(np.float32(
[[box[0][0], box[0][1]], [box[1][0], box[1][1]], [box[2][0], box[2][1]],
[box[3][0], box[3][1]]]), np.float32([[0, 0], [wh[1], 0], [wh[1], wh[0]], [0, wh[0]]]))
# 投影变换
lic = cv2.warpPerspective(img, mat, (wh[1], wh[0]))
cv2.imshow("card_img", lic)
得到的结果如下:

至此,我们完成了车牌的提取,得到这张图片后我们可以即可以进行后续的操作!
python opencv识别蓝牌车牌号 之 取出车牌号 (1/3)的更多相关文章
- Android OpenCV集成摄像头图片动态识别车牌号
最近两天开发一个使用OpenCV集成的一个识别车牌号的项目,困难重重,总结一下相关经验,以及开发注意事项: 一.开发环境: Android Studio 个人版本 3.1.4 NDK下载:14b CM ...
- 基于TensorFlow的车牌号识别系统
简介 过去几周我一直在涉足深度学习领域,尤其是卷积神经网络模型.最近,谷歌围绕街景多位数字识别技术发布了一篇不错的paper.该文章描述了一个用于提取街景门牌号的单个端到端神经网络系统.然后,作者阐述 ...
- Ubuntu下OpenCV不能被某个python版本识别
Ubuntu下OpenCV不能被某个python版本识别 Solution: 可以进入相应版本的python,查看该python的path: python import sys print(sys.p ...
- python的车牌号的检测
自己总结一下,从网上找到的关于车牌号的识别的一些博文.https://www.jianshu.com/p/fcfbd3131b84 https://www.cnblogs.com/do-hardwor ...
- 转载:使用 OpenCV 识别 QRCode
原文链接:http://coolshell.cn/articles/10590.html#jtss-tsina 识别二维码的项目数不胜数,每次都是开箱即用,方便得很. 这次想用 OpenCV 从零识别 ...
- 搭建基于python +opencv+Beautifulsoup+Neurolab机器学习平台
搭建基于python +opencv+Beautifulsoup+Neurolab机器学习平台 By 子敬叔叔 最近在学习麦好的<机器学习实践指南案例应用解析第二版>,在安装学习环境的时候 ...
- 【python+opencv】直线检测+圆检测
Python+OpenCV图像处理—— 直线检测 直线检测理论知识: 1.霍夫变换(Hough Transform) 霍夫变换是图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也有很多改进 ...
- OpenCV识别技术
OpenCV识别技术# 老师:james 20181019 # 识别技术# Pycharm + Python3 + OpenCV """ 一.识别技术: 什么是OpenC ...
- python+opencv实现车牌定位
写在前面 HIT大三上学期视听觉信号处理课程中视觉部分的实验三,经过和学长们实验的对比发现每一级实验要求都不一样,因此这里标明了是2019年秋季学期的视觉实验三. 由于时间紧张,代码没有进行任何优化, ...
随机推荐
- RSS生成工具/服务推荐
时至2022,关于碎片化阅读.信息焦虑的讨论仍在继续且似乎并没有形成广泛共识的解决办法.而研究生期间主要研究方向就是推荐系统且未来也大概率从事相关岗位的我,对以算法为中心的信息获取方式可以说是又爱又恨 ...
- Argo 安装和 workflow 实例配置文件解析
一.Argo 安装配置 1.1 Argo 安装 $ kubectl create ns argo $ kubectl apply -n argo -f https://raw.githubuserco ...
- unicode家族
定义 如果把各种文字编码形容为各地的方言,那么Unicode就是世界各国合作开发的一种语言. Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储. UTF ...
- 在java中静态方法与非静态方法
在java中public void与public static void有什么区别 ? public void 修饰是非静态方法,该类方法属于对象,在对象初始化(new Object())后才能被调用 ...
- JAVA多线程学习十六 - 同步集合类的应用
1.引言 在多线程的环境中,如果想要使用容器类,就需要注意所使用的容器类是否是线程安全的.在最早开始,人们一般都在使用同步容器(Vector,HashTable),其基本的原理,就是针对容器的每一个操 ...
- SSH 密钥登录
一.什么是SSH? 简单说,SSH是一种网络协议,用于计算机之间的加密登录. 如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会 ...
- transition过渡2D、3D效果
过渡(transition)是CSS3中具有颠覆性的特征之一,我们可以在不使用 Flash 动画或 JavaScript 的情况下,当元素从一种样式变换为另一种样式时为元素添加效果. 帧动画:通过一帧 ...
- Eclipse 找不到或者无法加载主类
最近因为频繁练习JDBC更换了几次驱动jar包,然后突然发现出现了找不到或者无法加载主类的错误, 项目上出现了一个感叹号. 解决方法: 项目-右键 properties-java Build Path ...
- docker | jenkins 实现自动化部署项目,后端躺着把运维的钱挣了!(上)
前言 背景 最近在帮学校导师写项目,团队有4个人,项目前后端分离.如果是选择瀑布式开发:(在约定好接口的情况下)A.B同学写前端,C.D同学写后端,然后约定一个时间统一联调,最后将项目交付安装到客户机 ...
- 详解Java12新增语法switch表达式
引言 在学习分支语句的时候,我们都学过 switch 语句,相比于 if-else 语句,他看起来更加整洁,逻辑更加清晰,Java中当然也给我们提了相关的 switch 方法.但是Java的强大之处在 ...