今天无意中看到了别人写的一个简单的车牌定位,仔细看了下,确实写的很简单,不足之处:
(1)鲁棒性差,阈值分割、轮廓提取过程中的参数选择都是定值,对于不同场景下的不同照片的适应性差。
(2) 定位不够精确。
(3)不具备车牌的校正能力,定位之后的车牌截图没有水平校正,因此大多是倾斜的。
代码如下:
# coding=utf-8
import cv2
import numpy as np
import imutils
def main(image_path):
img_org = cv2.imread(image_path)
# 按照彩色读取图像,获的三通道的数字矩阵
cv2.imshow('原图', img_org)
size = img_org.shape
# print(size ),输出如下:
# (375, 500, 3)
if size[0] <= 776:
img_org = imutils.resize(img_org, width=900)
# imutils.resize()可以实现按比例放大,即宽度方向放大900/500=1.8倍,则
# 高度方向同样方法1.8被倍,即375*1.8=675。
# print(img_org.shape),输出如下:
# (675, 900, 3)
img_org2 = img_org.copy()
img_gray = cv2.cvtColor(img_org, cv2.COLOR_BGR2GRAY)
# 将RGB格式的彩色图转化为灰度
# print(img_gray.shape),输出如下:
# (675, 900)
ret3, img_thr = cv2.threshold(img_gray, 125, 255, cv2.THRESH_BINARY)
# 做阈值分割,得到二值图
cv2.imwrite('thresh.jpg', img_thr)
img_edg = cv2.Canny(img_thr, 100, 200)
# 用canny算子作边缘检测
cv2.imwrite('cn_edge.jpg', img_edg)
# cv2.imshow(' img_edg',img_edg)
kernel = cv2.getStructuringElement(cv2.MORPH_DILATE, (7, 7))
# 构造7*7的十字形的结构元,用于形态学操作
# print(kernel),输出如下:
# [[0 0 0 1 0 0 0]
# [0 0 0 1 0 0 0]
# [0 0 0 1 0 0 0]
# [1 1 1 1 1 1 1]
# [0 0 0 1 0 0 0]
# [0 0 0 1 0 0 0]
# [0 0 0 1 0 0 0]]
img_dil = cv2.dilate(img_edg, kernel, iterations=1)
# 作开运算,去掉细小颗粒
cv2.imwrite('dilated_img.jpg', img_dil)
(somethig_else, contours, hierarchye) = cv2.findContours(img_dil.copy(), 1, 2)
cnts = sorted(contours, key=cv2.contourArea, reverse=True)[:10]
screenCnt = None
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
# 使用多边形逼近拟合函数 cv2.approxPolyDP()来拟合轮廓
# 返回N*1*2()形式的顶点坐标
# 如果多边形的顶点个数等于4,这个轮廓就是我们想要的
if approx.shape[0] == 4:
screenCnt = approx
break
mask = np.zeros(img_gray.shape, dtype=np.uint8)
# 创建一个和img_gray同大小的黑色画布
roi_corners = np.array(screenCnt, dtype=np.int32)
ignore_mask_color = (255,255,255)
cv2.fillPoly(mask, roi_corners, ignore_mask_color)
cv2.drawContours(img_org, [screenCnt],0, (255, 255, 0), 2,8)
cv2.imwrite('plate_detedted.jpg', img_org)
ys = [screenCnt[0, 0, 1], screenCnt[1, 0, 1], screenCnt[2, 0, 1], screenCnt[3, 0, 1]]
# print(ys),输出如下:
# [239, 324, 362, 261]
xs = [screenCnt[0, 0, 0], screenCnt[1, 0, 0], screenCnt[2, 0, 0], screenCnt[3, 0, 0]]
# print(xs ),输出如下:
# [203, 212, 630, 628]
ys_sorted_index = np.argsort(ys)
# print(ys_sorted_index),输出如下:
# [0 3 1 2]
xs_sorted_index = np.argsort(xs)
# print(xs_sorted_index ),输出如下:
# [0 1 3 2]
x1 = xs[xs_sorted_index[0]]
# print(x1 ),输出如下:
# 203
x2 = xs[xs_sorted_index[3]]
# print(x2 ),输出如下:
# 630
y1 = ys[ys_sorted_index[0]]
# print(y1)
# 239
y2 = ys[ys_sorted_index[3]]
# print(y2)
# 362
img_plate = img_org2[y1:y2, x1:x2]
cv2.imshow('number plate', img_plate)
cv2.imwrite('number_plate.jpg', img_plate)
cv2.waitKey(0)
if __name__ == "__main__":
image_path = "car1.jpg"
main(image_path)
运行程序:
换张原图,如下:
再换张原图:
改进:采用基于特征提取的算法来定位车牌,效果应该会好很多。