通过对车牌的颜色、面积、倾斜度进行识别。
代码如下:
在识别图片时,首先要调整图片的比例,也就是n,图片的大小,决定了车牌面积的大小,决定了能不能识别出来,一般图片要占到屏幕面积的1/4左右。
车牌的相应信息,储存在box中,可以选择输出,此程序输出了面积,角度和比例。
from cv2 import cv2
import numpy as np
import os
lower_blue = np.array([90,90,0])
upper_blue = np.array([120,210,250])
img = cv2.imread('d:/Python/license plate/chepai/2.jfif')
# 设置图片的比例,只有图片的显示面积合适,才能定位出车牌,需要调节
n = 0.8
sp = img.shape
height = round(n*sp[0])
weight = round(n*sp[1])
new_img = cv2.resize(img,(weight,height))
cv2.imshow('img', new_img)
hsv = cv2.cvtColor(new_img, cv2.COLOR_BGR2HSV)
mark = cv2.inRange(hsv, lower_blue, upper_blue)
# 形态学分割是识别的白色区域。如果在mark中车牌的颜色是黑色,需要翻转
# mark = cv2.bitwise_not(mark)
cv2.imshow("mark", mark)
# 腐蚀和膨胀
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(4,5)) #定义矩形结构元素
# 腐蚀和膨胀的次数也可以根据情况调节
img_erode = cv2.erode(mark, kernel, iterations=1)
img_dilated = cv2.dilate(mark, kernel, iterations=3)
cv2.imshow('erode', img_dilated)
# 寻找轮廓
contours, hierarchy = cv2.findContours(img_dilated,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):
area = cv2.contourArea(contours[i])
if area > 4000:
rect = cv2.minAreaRect(contours[i]) #提取矩形坐标
box = cv2.boxPoints(rect)
box = np.int0(box)
angle =abs(abs(rect[2])-45)
length = max(rect[1])
wideth = min(rect[1])
bili = length / (wideth + 0.01)
area = rect[1][0] * rect[1][1]
if area > 20000 or angle 3.3 or bili < 2.5 :
continue
print(area)
print(bili)
print(rect[2])
cv2.drawContours(new_img, [box], 0, (0, 0, 255), 2)
cv2.imshow('result', new_img)
cv2.waitKey(0)
核心是函数 cv2.minAreaRect(),下面的介绍引自:引用链接
函数 cv2.minAreaRect() 返回一个Box2D结构rect:(最小外接矩形的中心(x,y),(宽度,高度),旋转角度),但是要绘制这个矩形,我们需要矩形的4个顶点坐标box, 通过函数 cv2.cv.BoxPoints() 获得,返回形式[ [x0,y0], [x1,y1], [x2,y2], [x3,y3] ]。得到的最小外接矩形的4个顶点顺序、中心坐标、宽度、高度、旋转角度(是度数形式,不是弧度数)的对应关系如下:
注意:
旋转角度θ是水平轴(x轴)逆时针旋转,直到碰到矩形的第一条边停住,此时该边与水平轴的夹角。并且这个边的边长是width,另一条边边长是height。也就是说,在这里,width与height不是按照长短来定义的。
在opencv中,坐标系原点在左上角,相对于x轴,逆时针旋转角度为负,顺时针旋转角度为正。所以,θ∈(-90度,0]。程序中也根据角度大小进行排除区域,如果太斜的话,识别不出来。
最后还输出了相应的面积,角度和车牌比例。
效果如下:
后续的操作参见:提取分割