import cv2
import numpy as np
from PIL import Image
from matplotlib import pyplot as plt
def preprocess(gray):
# # 直方图均衡化
#equ = cv2.equalizeHist(gray)
# 高斯平滑
gaussian = cv2.GaussianBlur(gray, (3, 3), 0, 0, cv2.BORDER_DEFAULT)
# 中值滤波
median = cv2.medianBlur(gaussian, 5)
# Sobel算子,X方向求梯度
sobel = cv2.Sobel(median, cv2.CV_8U, 1, 0, ksize=3)
# 二值化
ret, binary = cv2.threshold(sobel, 170, 255, cv2.THRESH_BINARY)
#cv2.imshow("binary",binary)
# 膨胀和腐蚀操作的核函数
element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))
element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (8, 6))
# 膨胀2次,让轮廓突出
dilation = cv2.dilate(binary, element2, iterations=2)
# 腐蚀一次,去掉细节
erosion = cv2.erode(dilation, element1, iterations=1)
# 再3次膨胀,让轮廓明显一些
dilation2 = cv2.dilate(erosion, element2, iterations=3)
cv2.imshow('dilation2', dilation2)
cv2.waitKey(0)
return dilation2
def findPlateNumberRegion(img):
region = []
# 查找轮廓
binary,contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 筛选面积小的
for i in range(len(contours)):
cnt = contours[i]
# 计算该轮廓的面积
area = cv2.contourArea(cnt)
# 面积小的都筛选掉
if (area < 2000):
continue
# 轮廓近似,作用很小
epsilon = 0.001 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
# 找到最小的矩形,该矩形可能有方向
rect = cv2.minAreaRect(cnt)
print("rect is: ")
print(rect)
# box是四个点的坐标
box = cv2.boxPoints(rect)
box = np.int0(box)
# 计算高和宽
height = abs(box[0][1] - box[2][1])
width = abs(box[0][0] - box[2][0])
# 车牌正常情况下长高比在2.7-5之间
ratio = float(width) / float(height)
print(ratio)
if (ratio > 5 or ratio < 2):
continue
region.append(box)
return region
def detect(img):
# 转化成灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 形态学变换的预处理
dilation = preprocess(gray)
# 查找车牌区域
region = findPlateNumberRegion(dilation)
# 用绿线画出这些找到的轮廓
for box in region:
cv2.drawContours(img, [box], 0, (0, 255, 0), 2)
ys = [box[0, 1], box[1, 1], box[2, 1], box[3, 1]]
xs = [box[0, 0], box[1, 0], box[2, 0], box[3, 0]]
ys_sorted_index = np.argsort(ys)
xs_sorted_index = np.argsort(xs)
x1 = box[xs_sorted_index[0], 0]
x2 = box[xs_sorted_index[3], 0]
y1 = box[ys_sorted_index[0], 1]
y2 = box[ys_sorted_index[3], 1]
img_org2 = img.copy()
img_plate = img_org2[y1:y2, x1:x2]
cv2.imshow('dingwei', img_plate)
cv2.imwrite('dingwei.jpg', img_plate)
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.imshow('img', img)
# 带轮廓的图片
cv2.imwrite('contours.png', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
'''在imagePath中放入你要测试的图片'''
imagePath = '1.jpg'
im3 = Image.open(imagePath)
im3.show(imagePath)
img = cv2.imread(imagePath)
detect(img)
#进一步切割
img1 = Image.open("dingwei.jpg")
#车牌大小统一成440*140
new_img = img1.resize((440,140),Image.BILINEAR)
#车牌再次定位截取统一成([30,390],[20,390])
region = new_img.crop((30, 23, 416, 110))
region.save("dingwei1.jpg")
#对车脾进行倾斜矫正
'''imga = cv2.imread("dingwei1.jpg", 0)
imge = cv2.GaussianBlur(imga,(3,3),0)
edges = cv2.Canny(imge, 50, 150, apertureSize = 3)
lines = cv2.HoughLines(edges,1,np.pi/180,118)
for l in lines[0]:
theta = l[1]
jiao = -(1.57079-theta)*180/3.14159
pil_im = Image.open('dingwei1.jpg')
pil_im = pil_im.rotate(jiao)
pil_im.save('300.jpg')'''
im = Image.open('dingwei1.jpg')
im.show('dingwei1.jpg')
#灰度化
im = im.convert('L')
im.save('001.png')
#自己写的二值化
pixload = im.load()
for x in range(im.size[0]):
for y in range(im.size[1]):
if pixload[x,y]<125:
pixload[x,y] = 255
else:
pixload[x,y] = 0
#去掉车牌的上下的圆孔
im.save('003.png')
#im.show('003.png')
pixload2 = im.load()
print(im.size)
for x in range(im.size[1]):
count =0
for y in range(im.size[0]):
if pixload2[y,x]==0:
count=count+1
if count<50:
for y in range(im.size[0]):
pixload2[y, x] =255
im.save('004.png')
#im.show('004.png')
pixload3 = im.load()
#去掉车牌上的圆点
for x in range(im.size[0]):
count =0
for y in range(im.size[1]):
if pixload3[x,y]==0:
count=count+1
if count<0:
for y in range(im.size[1]):
pixload2[x, y] =255
im.save('005.png')
#im.show('005.png')
img = cv2.imread("005.png") # 读取图片
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换了灰度化
cv2.imshow('gray', img_gray) # 显示图片
cv2.waitKey(0)
# 2、将灰度图像二值化,设定阈值是100
img_thre = img_gray
cv2.threshold(img_gray, 140, 255, cv2.THRESH_BINARY_INV, img_thre)
cv2.imshow('threshold', img_thre)
cv2.waitKey(0)
# 3、保存黑白图片
cv2.imwrite('132.png', img_thre)
# 4、分割字符
white = [] # 记录每一列的白色像素总和
black = [] # ..........黑色.......
height = img_thre.shape[0]
width = img_thre.shape[1]
white_max = 0
black_max = 0
# 计算每一列的黑白色像素总和
for i in range(width):
s = 0 # 这一列白色总数
t = 0 # 这一列黑色总数
for j in range(height):
if img_thre[j][i] == 255:
s += 1
if img_thre[j][i] == 0:
t += 1
white_max = max(white_max, s)
black_max = max(black_max, t)
white.append(s)
black.append(t)
#print(s)
#print(t)
arg = False # False表示白底黑字;True表示黑底白字
if black_max > white_max:
arg = True
# 分割图像
def find_end(start_):
end_ = start_+1
for m in range(start_+1, width-1):
if (black[m] if arg else white[m]) > (0.95 * black_max if arg else 0.95 * white_max): # 0.95这个参数请多调整,对应下面的0.05
end_ = m
break
return end_
n = 1
start = 1
end = 2
aaa =15
bb = 0
while n < width-2:
n += 1
if (white[n] if arg else black[n]) > (0.05 * white_max if arg else 0.05 * black_max):
# 上面这些判断用来辨别是白底黑字还是黑底白字
# 0.05这个参数请多调整,对应上面的0.95
start = n
end = find_end(start)
n = end
if end-start > 9:
aaa += 1
bb = bb+1
cj = img_thre[1:height, start:end]
cv2.imwrite(str(aaa)+'.jpg',cj)
# cv2.imshow('caijian', cj)
cv2.waitKey(0)
#显示分割后的图像
aaa = aaa-bb
b = []
for i in range(bb):
aaa += 1
img = cv2.imread(str(aaa)+'.jpg',0)
b.append(img)
for c in range(bb):
print(c)
c += 1
plt.subplot(1,bb,c)
plt.imshow(b[c-1],'gray')
plt.show()