概述

车牌识别是计算机视频图像识别技术在车辆牌照识别中的一种应用,通常来讲如果结合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)的更多相关文章

  1. Android OpenCV集成摄像头图片动态识别车牌号

    最近两天开发一个使用OpenCV集成的一个识别车牌号的项目,困难重重,总结一下相关经验,以及开发注意事项: 一.开发环境: Android Studio 个人版本 3.1.4 NDK下载:14b CM ...

  2. 基于TensorFlow的车牌号识别系统

    简介 过去几周我一直在涉足深度学习领域,尤其是卷积神经网络模型.最近,谷歌围绕街景多位数字识别技术发布了一篇不错的paper.该文章描述了一个用于提取街景门牌号的单个端到端神经网络系统.然后,作者阐述 ...

  3. Ubuntu下OpenCV不能被某个python版本识别

    Ubuntu下OpenCV不能被某个python版本识别 Solution: 可以进入相应版本的python,查看该python的path: python import sys print(sys.p ...

  4. python的车牌号的检测

    自己总结一下,从网上找到的关于车牌号的识别的一些博文.https://www.jianshu.com/p/fcfbd3131b84 https://www.cnblogs.com/do-hardwor ...

  5. 转载:使用 OpenCV 识别 QRCode

    原文链接:http://coolshell.cn/articles/10590.html#jtss-tsina 识别二维码的项目数不胜数,每次都是开箱即用,方便得很. 这次想用 OpenCV 从零识别 ...

  6. 搭建基于python +opencv+Beautifulsoup+Neurolab机器学习平台

    搭建基于python +opencv+Beautifulsoup+Neurolab机器学习平台 By 子敬叔叔 最近在学习麦好的<机器学习实践指南案例应用解析第二版>,在安装学习环境的时候 ...

  7. 【python+opencv】直线检测+圆检测

     Python+OpenCV图像处理—— 直线检测 直线检测理论知识: 1.霍夫变换(Hough Transform) 霍夫变换是图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也有很多改进 ...

  8. OpenCV识别技术

    OpenCV识别技术# 老师:james 20181019 # 识别技术# Pycharm + Python3 + OpenCV """ 一.识别技术: 什么是OpenC ...

  9. python+opencv实现车牌定位

    写在前面 HIT大三上学期视听觉信号处理课程中视觉部分的实验三,经过和学长们实验的对比发现每一级实验要求都不一样,因此这里标明了是2019年秋季学期的视觉实验三. 由于时间紧张,代码没有进行任何优化, ...

随机推荐

  1. Kubernetes的Controller进阶(十二)

    一.Controller 既然学习了Pod进阶,对于管理Pod的Controller肯定也要进阶一下,之前我们已经学习过的Controller有RC.RS和Deployment,除此之外还有吗,如果感 ...

  2. Java多线程专题6: Queue和List

    合集目录 Java多线程专题6: Queue和List CopyOnWriteArrayList 如何通过写时拷贝实现并发安全的 List? CopyOnWrite(COW), 是计算机程序设计领域中 ...

  3. Spring源码-IOC部分-容器简介【1】

    实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...

  4. ApacheCN 所有教程/文档集已备份到 Coding

    QuantLearning 数据科学 WIKI 安全 WIKI 团队 WIKI Sklearn 中文文档 PyTorch 中文文档 TutorialsPoint 中文系列教程 Java8 中文官方教程 ...

  5. 「BalkanOI 2018 Day1」Minmaxtree

    「BalkanOI 2018 Day1」Minmaxtree 每个点都有一个最大和最小权值的限制. 然后每一个权值的限制都必须要取到. 每个点显然可以直接让他取到最大或最小权值. 可以想到每个点匹配一 ...

  6. JS切割图片-滑动门效果

    转载请注明来源:https://www.cnblogs.com/hookjc/ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transit ...

  7. Ubuntu安装 php + apache + mysql

    转载请注明来源:https://www.cnblogs.com/hookjc/ 1.安装SSH(必须) sudo apt-get install ssh 2.安装MySQL(虽然现在最新版为5.1,但 ...

  8. getter-setter方法练习

    // // Kline.h #import <Foundation/Foundation.h> @interface Kline : NSObject { int _max; // 最高价 ...

  9. 数组中包含多个对象 按照对象中的时间进行排序 适用与Angular.js、Jquery、微信小程序等

         LiveList.sort(this.compare('StartDate'))   //StartData:需要排序的时间   compare: function (property) { ...

  10. Spack 内置函数

    1.Map函数:通过函数传递源的每个元素,并形成新的分布式数据集. %spark #并行化集合生成RDD var data = sc.parallelize(List(10,20,30)) %输出结果 ...