Opencv项目实战Vision-Life(3) 车牌识别

前言

今天是Vision-Life项目组的第三个小项目,做的是一个简单的车牌识别。

车牌识别算是一个比较经典的项目了,网上也有很多资料,没什么创意,做的目的呢是因为它恰好涵盖了我之前一段时间所学的知识,权当是对前面知识的总结复习吧🍔🍟🍿

知识体系

架构

0

效果图

对指定图片可以达到检测的目的

1

检测车牌位置

图像预处理

图像预处理包括:降分辨率、灰度、降噪与Canny边缘检测

img = cv2.imread('carcard.jpg')
img = cv2.resize(img,(640,420),interpolation=cv2.INTER_LANCZOS4)
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 双边滤波模糊
gray_img = cv2.bilateralFilter(gray_img,3,45,45)
gray_img = cv2.Canny(gray_img,20,300)

首先我们选一张图片,它初始的时候是这样子的

大小为1080x540,RGB格式

2

由于不同图像的分辨率不同,所以我们要统一大小。同时要保证,我们感兴趣的区域(ROI,这里是车牌),必须保留在框架中

img = cv2.resize(img,(640,420),interpolation=cv2.INTER_LANCZOS4)

这里我使用640*420的分辨率,相较之前缩小了一半

3

因为在处理图像的时候我们不需要关注颜色细节,所以灰度图能减少图像的颜色通道,方便后期处理

gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

4

灰度变换之后,由于车的背景(如两座山,围栏)对识别有影响,所以我们应对图片进行滤波,突出主题,为后面的Canny检测作铺垫

gray_img = cv2.bilateralFilter(gray_img,3,45,45)

注意事项

这里为什么用双边滤波呢?我们知道,双边滤波在模糊的同时,还能突出边缘。这大大改善Canny检测的效果

开始的时候我曾用过中值滤波,发现边缘也被模糊了。于是Canny检测后的图像的矩形轮廓有断点,计算机无法找到车牌的位置

5

上图是对灰度图模糊的对比,也许你看不出有什么区别

但如果我Canny检测之后呢?

6

我们放大车牌部分,发现中值模糊下的断点更多,而双边模糊的断点更少;从而左边的车牌构不成一个完整的轮廓,而右边的可以构成一个完整的轮廓,从而被计算机找到

寻找车牌轮廓

# opencv2返回两个值:contours、hierarchy。opencv3返回三个值:img(图像)、countours(轮廓)、hierarchy(层次结构)
contours = cv2.findContours(gray_img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

# imutils.grab_contours的作用,返回cnts中的countors(轮廓),不区分opencv2或opencv3
contours = imutils.grab_contours(contours)

# 想要过滤掉那些微小琐碎的轮廓,只显示这幅图中面积大的轮廓。代码思路是将findContours查找到的轮廓按照面积排序
contours = sorted(contours,key=cv2.contourArea, reverse = True)[0:10]
screenCnt = None

for c in contours:
    area = cv2.contourArea(c)
    print(area)
    epsilon = 0.02*cv2.arcLength(c,True)

    # approxPolyDP()返回值顶点的坐标
    approx = cv2.approxPolyDP(c,epsilon,True)

    if len(approx) == 4:
      screenCnt = approx
      print(len(screenCnt))
      cv2.drawContours(img, [screenCnt], -1, (0, 0, 255), 1)

      break

  1. cv2.findContours()寻找到轮廓
  2. 由于Opencv2和3函数返回值不同,所以我们imutils.grab_contours()统一返回的数据格式
  3. sorted()将各个轮廓按面积大小由高到低排序,[0:10]是指排到第十名就不排了
  4. 轮询各个轮廓
  5. cv2.approxPolyDP()得到各个轮廓顶点坐标(坐标的个数不限,反正按顺序连接这些顶点能大概绘制出轮廓的样子就行)
  6. 因为车牌是矩形,所以我们车牌轮廓一定有4个顶点(理想状态下…)
  7. cv2.drawContours()绘制车牌区域

经过这一系列操作后,我们的图像将会变成这样

7

这样,车牌部分就被找出来了😎😎😎

字符分割

蒙版操作

现在我们知道车牌在哪里了,剩下的信息对我们来说几乎没用。因此,我们可以对没用的部分进行遮挡(涂黑)

# 创建蒙版
img_mask = np.zeros(gray_img.shape,np.uint8)

new_img = cv2.drawContours(img_mask,[screenCnt],0,255,-1)
cv2.imshow('new_img',new_img)
# 与操作
img=cv2.bitwise_and(img,img,mask=new_img)

被遮挡的图像如下

8

于是,我们可以根据蒙版的数值(黑=0,白=255),裁剪图像

蒙版图👇👇👇

9

裁剪操作

(x,y)=np.where(img_mask==255)
topx=np.max(x)
topy=np.max(y)
bottomx=np.min(x)
bottomy=np.min(y)
Cropped = np.zeros(gray_img.shape,np.uint8)
Cropped = cv2.rectangle(Cropped,(topy,topx),(bottomy,bottomx),255,1)
Cropped=img[bottomx:topx,bottomy:topy]
  1. np.where(img_mask==255)找蒙版为白色像素,np.max(y)找返回的y数组里最大的那个值
  2. Cropped = cv2.rectangle(Cropped,(topy,topx),(bottomy,bottomx),255,1)这里要注意坐标格式为==(y,x)==
  3. Cropped=img[bottomx:topx,bottomy:topy]直接操作元组切割图像,注意bottomx:topx,bottomy:topy,topx-bottomx>0

裁剪后的图像如下

10

最后放大一下裁剪的图像,方便OCR识别

Cropped = cv2.resize(Cropped,(400,200),interpolation=cv2.INTER_LANCZOS4)

字符识别

OCR(Optical character recognition,光学字符识别)是一种将图像中的手写字或者印刷文本转换为机器编码文本的技术。通过数字方式存储文本数据更容易保存和编辑,可以存储大量数据,比如1G的硬盘可以存储数百万本书。

OCR工具安装

参考链接:Python OCR工具pytesseract详解

这里我装的路径为:pytesseract.pytesseract.tesseract_cmd=r’D:\GoogleOCR\tesseract.exe’

将路径复制到代码上

import cv2
import numpy as np
import imutils
import pytesseract
pytesseract.pytesseract.tesseract_cmd=r'D:\GoogleOCR\tesseract.exe'

数字识别

# 识别字符
text = pytesseract.image_to_string(Cropped,config='--psm 11')
print("Detected license plate number is:",text)
print(text[0:7])

打印一下

Detected license plate number is: CZ20FSE.

成功🤔🤤🤤🤤

再看一次效果

1

结语

代码已经扔进仓库里了,需要的自取:Vision-Life3 车牌检测

接下来如果有时间的话,将会用Opencv4+Unity3D做点好玩的东西,应该会非常有创意🤔🤔🤔

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落叶随峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值