步骤:
读入图片——转灰度图——高斯过滤——均值过滤——sobel提取边缘——图像二值化——膨胀——腐蚀——膨胀——提取轮廓——遍历所有轮廓——对轮廓拟合多边形——求出最小矩形——对矩形进行筛选——在图像中截取矩形框——通过连通区域分割提取车牌字符
代码如下:
import numpy as np
import cv2
import skimage
import pytesseract
from PIL import Image
def image_threshold(image):
image = cv2.GaussianBlur(image,(3,3),0,0,cv2.BORDER_DEFAULT)
image = cv2.medianBlur(image,5)
image = cv2.Sobel(image,cv2.CV_8U,1,0,ksize=3)
#image = cv2.Canny(image,50,150)
image = cv2.threshold(image,150,255,cv2.THRESH_TOZERO_INV)
image = cv2.threshold(image[1],120,255,cv2.THRESH_BINARY)
return image[1]
def image_thresh(image):
element1 = cv2.getStructuringElement(cv2.MORPH_RECT,(9,1))
element2 = cv2.getStructuringElement(cv2.MORPH_RECT,(11,3))
dilation = cv2.dilate(image,element2,iterations=1)
erosion = cv2.erode(dilation,element1,iterations=1)
image = cv2.dilate(erosion,element2,iterations=2)
return image
def get_car_cart(image):
regoins = []
contours,hierarchy = cv2.findContours(image,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# img = cv2.drawContours(image,contours,-1,(0,255,0),2)
# see_image(img)
for contour in contours:
area = cv2.contourArea(contour)
if (area<2000):
continue
#contour = cv2.convexHull(contour)
eps = 1e-3 * cv2.arcLength(contour,True)
approx = cv2.approxPolyDP(contour,eps,True)
rect = cv2.minAreaRect(approx)
box = cv2.boxPoints(rect)
box = np.int0(box)
#print(box)
height = abs(box[0][1] - box[2][1])
width = abs(box[0][0] - box[2][0])
raio = float(width)/float(height)
#print(raio)
if (raio<5 and raio>1.8):
regoins.append(box)
return regoins
def get_rect(image,regoins):
old_image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
img_list = []
for index,box in enumerate(regoins):
if not (box[0][1]>0 and box[2][1]>0 and box[0][0]>0 and box[2][0]>0):
continue
img = np.zeros((abs(box[0][1] - box[2][1]),abs(box[0][0]-box[2][0])))
#cv2.drawContours(image,[box],0,(0,255,0),2)
if (box[0][1]>box[2][1] and box[0][0]>box[2][0]):
img[:,:] = old_image[box[2][1]:box[0][1],box[2][0]:box[0][0]]
img_list.append(img)
if (box[2][1]>box[0][1] and box[0][0]>box[2][0]):
img[:,:] = old_image[box[0][1]:box[2][1],box[2][0]:box[0][0]]
img_list.append(img)
if (box[0][1]>box[2][1] and box[2][0]>box[0][0]):
img[:,:] = old_image[box[2][1]:box[0][1],box[0][0]:box[2][0]]
img_list.append(img)
if (box[2][1]>box[0][1] and box[2][0]>box[0][0]):
img[:,:] = old_image[box[0][1]:box[2][1],box[0][0]:box[2][0]]
img_list.append(img)
return img_list
def see_image():
cv2.waitKey(0)
cv2.destroyAllWindows()
def remove_back(image):
label_list = skimage.measure.label(image)
reg_list = skimage.measure.regionprops(label_list)
labels = []
for reg in reg_list:
if reg.area<50000:
labels.append(reg.label)
current = np.in1d(label_list,list(labels)).reshape(label_list.shape)
current = np.asarray(current).astype(np.uint8)
image = image*current
return image
def see_cart(image_list):
for image in image_list:
image = cv2.threshold(image,127,255,cv2.THRESH_BINARY)
cv2.imwrite('car_test.jpg',image[1].astype(np.uint8))
image = Image.open('car_test.jpg')
code = pytesseract.image_to_string(image)
print(code)
def main():
path = 'car1.jpg'
image = cv2.imread(path)
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
image_thre = image_threshold(gray)
image_thre = image_thresh(image_thre)
regoins = get_car_cart(image_thre)
image_list = get_rect(image,regoins)
see_cart(image_list)
for i,image in enumerate(image_list):
cv2.imshow('test1'+str(i),image.astype(np.uint8))
h,w = image.shape
image = cv2.threshold(image,150,255,cv2.THRESH_BINARY)
#创建连通区域列表
labels = skimage.measure.label(image[1],connectivity=2)
#image = skimage.color.label2rgb(labels)
#获取连通区域属性
labels = skimage.measure.regionprops(labels)
#切割合适的连通区域
for index,label in enumerate(labels):
radio = label.area/(h*w)
if (radio>0.007 and radio<0.02):
print(radio)
box = label.bbox
img = np.zeros((box[2]-box[0]+9,box[3]-box[1]+2))
if (box[0]-7<0):
a = box[0]
else:
a = box[0] -7
img[:box[2]+2-a,:] = image[1][a:box[2]+2,box[1]-1:box[3]+1]
cv2.imshow('test'+str(index),img.astype(np.uint8))
see_image()
if __name__=='__main__':
main()
效果图如下分割效果复现性不太好: