OpenCV-车牌号检测

在github上看到一个小项目觉得挺有意思:借助传统图像处理技巧,通过opencv进行车牌号位置检测。虽然我实际测试后效果不太好,但也能学到另一种处理思路。

原作者链接:https://github.com/Aqsa-K/Car-Number-Plate-Detection-OpenCV-Python


文章目录

  • OpenCV-车牌号检测
  • 一、传统图像处理方法
  • 二、效果
  • 三、深入思考
  • 四、源码
  • 五、项目链接


一、传统图像处理方法

输入一张原始图片,要求检测出车牌号位置。

第1步:对图像进行resize、灰度处理、双边滤波降噪,得到一张更加干净的图片。
第2步:利用cv2.Canny函数做边缘检测,检测出图片中主要物体的边缘信息。
第3步:利用cv2.findContours函数查找物体的轮廓,分别归到不同的类别。相当于利用物体的轮廓信息,对图片中不同的物体做了聚类处理。
第4步:对不同的聚类结果,利用cv2.approxPolyDP函数分别进行曲线拟合。
第5步:针对每次拟合的结果,添加if语句进行车牌号判别。

二、效果

原始输入图片,并进行resize:

python opencv 车牌提取 基于opencv的车牌识别_opencv

进行灰度处理:

python opencv 车牌提取 基于opencv的车牌识别_计算机视觉_02


通过双边滤波降噪,得到一张更加干净的图片:

python opencv 车牌提取 基于opencv的车牌识别_算法_03


利用cv2.Canny函数做边缘检测:

python opencv 车牌提取 基于opencv的车牌识别_算法_04


利用cv2.findContours函数查找物体的轮廓,根据边缘检测结果分类可得到263个区域。我们对其中合适大小的区域进行cv2.approxPolyDP曲线拟合,如果拟合出的形状接近长方形,且长宽比例合适,我们就认为它是车牌号位置区域。

python opencv 车牌提取 基于opencv的车牌识别_计算机视觉_05

三、深入思考

说实话,这个项目实际场景的应用效果并不好。我从网上随意找了10张图片进行测试,大概只有1-2张图片能准确检测出车牌号位置。

python opencv 车牌提取 基于opencv的车牌识别_算法_06


因为算法主要依靠边缘特征进行处理,因此它在车牌号的边缘非常明显的情况下检测效果不错,例如这种车辆的图片:

python opencv 车牌提取 基于opencv的车牌识别_计算机视觉_07


python opencv 车牌提取 基于opencv的车牌识别_图像处理_08


从项目效果可以看出,相比于无监督学习,有监督学习的算法效果往往能好很多。突然发现,在计算机专业学习时,自己接触到的大部分图像处理算法,都是借助无监督的思路来设计的;而在数学专业学习时,自己接触到的大部分图像处理算法,却都是借助有监督的思路来设计的。

四、源码

代码如下:

import numpy as np
import cv2
import imutils

# Read the image file
image = cv2.imread('0.jpg')
# (423, 640, 3)

# Resize the image - change width to 500
image = imutils.resize(image, width=500)
# (330, 500, 3)
cv2.namedWindow("image")
cv2.imshow("image", image)
cv2.waitKey(0)

# RGB to Gray scale conversion
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# (330, 500)
cv2.namedWindow("Grayscale Conversion")
cv2.imshow("Grayscale Conversion", gray)
cv2.waitKey(0)

# Noise removal with iterative bilateral filter(removes noise while preserving edges)
gray = cv2.bilateralFilter(gray, 11, 17, 17)
cv2.namedWindow("Bilateral Filter")
cv2.imshow("Bilateral Filter", gray)
cv2.waitKey(0)

# Find Edges of the grayscale image
edged = cv2.Canny(gray, 170, 200)
# (330, 500)
cv2.namedWindow("Canny Edges")
cv2.imshow("Canny Edges", edged)
cv2.waitKey(0)


# Find contours based on Edges
(cnt, _) = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# sort contours based on their area keeping minimum required area
# as '30' (anything smaller than this will not be considered)
cnt = sorted(cnt, key=cv2.contourArea, reverse=True)[:30]


# we currently have no Number plate contour
NumberPlateCnt = None

# loop over our contours to find the best possible approximate contour of number plate
for c in cnt:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.01 * peri, True)

    if len(approx) == 4:

        approx = approx[:, 0, :]
        x1 = np.min(approx[:, 0])
        y1 = np.min(approx[:, 1])
        x2 = np.max(approx[:, 0])
        y2 = np.max(approx[:, 1])

        w = x2 - x1
        h = y2 - y1
        ratio = w/h

        if 3 < ratio < 6:
            NumberPlateCnt = approx
            print(x1, y1, x2, y2, ratio)
            cv2.drawContours(image, [NumberPlateCnt], -1, (0, 255, 0), 3)


# Drawing the selected contour on the original image
cv2.namedWindow("Final Image")
cv2.imshow("Final Image", image)
cv2.waitKey(0)

五、项目链接