OpenCV-车牌号检测
在github上看到一个小项目觉得挺有意思:借助传统图像处理技巧,通过opencv进行车牌号位置检测。虽然我实际测试后效果不太好,但也能学到另一种处理思路。
原作者链接:https://github.com/Aqsa-K/Car-Number-Plate-Detection-OpenCV-Python
文章目录
一、传统图像处理方法
输入一张原始图片,要求检测出车牌号位置。
第1步:对图像进行resize、灰度处理、双边滤波降噪,得到一张更加干净的图片。
第2步:利用cv2.Canny函数做边缘检测,检测出图片中主要物体的边缘信息。
第3步:利用cv2.findContours函数查找物体的轮廓,分别归到不同的类别。相当于利用物体的轮廓信息,对图片中不同的物体做了聚类处理。
第4步:对不同的聚类结果,利用cv2.approxPolyDP函数分别进行曲线拟合。
第5步:针对每次拟合的结果,添加if语句进行车牌号判别。
二、效果
原始输入图片,并进行resize:
进行灰度处理:
通过双边滤波降噪,得到一张更加干净的图片:
利用cv2.Canny函数做边缘检测:
利用cv2.findContours函数查找物体的轮廓,根据边缘检测结果分类可得到263个区域。我们对其中合适大小的区域进行cv2.approxPolyDP曲线拟合,如果拟合出的形状接近长方形,且长宽比例合适,我们就认为它是车牌号位置区域。
三、深入思考
说实话,这个项目实际场景的应用效果并不好。我从网上随意找了10张图片进行测试,大概只有1-2张图片能准确检测出车牌号位置。
因为算法主要依靠边缘特征进行处理,因此它在车牌号的边缘非常明显的情况下检测效果不错,例如这种车辆的图片:
从项目效果可以看出,相比于无监督学习,有监督学习的算法效果往往能好很多。突然发现,在计算机专业学习时,自己接触到的大部分图像处理算法,都是借助无监督的思路来设计的;而在数学专业学习时,自己接触到的大部分图像处理算法,却都是借助有监督的思路来设计的。
四、源码
代码如下:
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)
五、项目链接
如果代码跑不通,可以去下载项目链接:https://blog.****.net/Twilight737