|
|
@ -3,7 +3,9 @@ import cv2
|
|
|
|
from matplotlib import pyplot as plt
|
|
|
|
from matplotlib import pyplot as plt
|
|
|
|
import os
|
|
|
|
import os
|
|
|
|
import numpy as np
|
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
|
|
|
from tkinter import ttk
|
|
|
|
|
|
|
|
from PIL import ImageTk, Image
|
|
|
|
|
|
|
|
|
|
|
|
# plt显示彩色图片
|
|
|
|
# plt显示彩色图片
|
|
|
|
def plt_show0(img):
|
|
|
|
def plt_show0(img):
|
|
|
@ -27,11 +29,14 @@ def gray_guss(image):
|
|
|
|
return gray_image
|
|
|
|
return gray_image
|
|
|
|
|
|
|
|
|
|
|
|
# 读取待检测图片
|
|
|
|
# 读取待检测图片
|
|
|
|
origin_image = cv2.imread('../chepai1.jpg')
|
|
|
|
origin_image = cv2.imread('../xiangA.jpg')
|
|
|
|
|
|
|
|
|
|
|
|
# 复制一张图片,在复制图上进行图像操作,保留原图
|
|
|
|
# 复制一张图片,在复制图上进行图像操作,保留原图
|
|
|
|
image = origin_image.copy()
|
|
|
|
image = origin_image.copy()
|
|
|
|
|
|
|
|
|
|
|
|
# 图像去噪灰度处理
|
|
|
|
# 图像去噪灰度处理
|
|
|
|
gray_image = gray_guss(image)
|
|
|
|
gray_image = gray_guss(image)
|
|
|
|
|
|
|
|
|
|
|
|
# x方向上的边缘检测(增强边缘信息)
|
|
|
|
# x方向上的边缘检测(增强边缘信息)
|
|
|
|
Sobel_x = cv2.Sobel(gray_image, cv2.CV_16S, 1, 0)
|
|
|
|
Sobel_x = cv2.Sobel(gray_image, cv2.CV_16S, 1, 0)
|
|
|
|
absX = cv2.convertScaleAbs(Sobel_x)
|
|
|
|
absX = cv2.convertScaleAbs(Sobel_x)
|
|
|
@ -39,27 +44,35 @@ image = absX
|
|
|
|
|
|
|
|
|
|
|
|
# 图像阈值化操作——获得二值化图
|
|
|
|
# 图像阈值化操作——获得二值化图
|
|
|
|
ret, image = cv2.threshold(image, 0, 255, cv2.THRESH_OTSU)
|
|
|
|
ret, image = cv2.threshold(image, 0, 255, cv2.THRESH_OTSU)
|
|
|
|
|
|
|
|
|
|
|
|
# 显示灰度图像
|
|
|
|
# 显示灰度图像
|
|
|
|
plt_show(image)
|
|
|
|
plt_show(image)
|
|
|
|
|
|
|
|
|
|
|
|
# 形态学(从图像中提取对表达和描绘区域形状有意义的图像分量)——闭操作
|
|
|
|
# 形态学(从图像中提取对表达和描绘区域形状有意义的图像分量)——闭操作
|
|
|
|
kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 10))
|
|
|
|
kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 10))
|
|
|
|
image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernelX,iterations = 1)
|
|
|
|
image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernelX,iterations = 1)
|
|
|
|
|
|
|
|
|
|
|
|
# 显示灰度图像
|
|
|
|
# 显示灰度图像
|
|
|
|
plt_show(image)
|
|
|
|
plt_show(image)
|
|
|
|
|
|
|
|
|
|
|
|
# 腐蚀(erode)和膨胀(dilate)
|
|
|
|
# 腐蚀(erode)和膨胀(dilate)
|
|
|
|
kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 1))
|
|
|
|
kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 1))
|
|
|
|
kernelY = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 20))
|
|
|
|
kernelY = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 20))
|
|
|
|
|
|
|
|
|
|
|
|
#x方向进行闭操作(抑制暗细节)
|
|
|
|
#x方向进行闭操作(抑制暗细节)
|
|
|
|
image = cv2.dilate(image, kernelX)
|
|
|
|
image = cv2.dilate(image, kernelX)
|
|
|
|
image = cv2.erode(image, kernelX)
|
|
|
|
image = cv2.erode(image, kernelX)
|
|
|
|
|
|
|
|
|
|
|
|
#y方向的开操作
|
|
|
|
#y方向的开操作
|
|
|
|
image = cv2.erode(image, kernelY)
|
|
|
|
image = cv2.erode(image, kernelY)
|
|
|
|
image = cv2.dilate(image, kernelY)
|
|
|
|
image = cv2.dilate(image, kernelY)
|
|
|
|
|
|
|
|
|
|
|
|
# 中值滤波(去噪)
|
|
|
|
# 中值滤波(去噪)
|
|
|
|
image = cv2.medianBlur(image, 21)
|
|
|
|
image = cv2.medianBlur(image, 21)
|
|
|
|
|
|
|
|
|
|
|
|
# 显示灰度图像
|
|
|
|
# 显示灰度图像
|
|
|
|
plt_show(image)
|
|
|
|
plt_show(image)
|
|
|
|
|
|
|
|
|
|
|
|
# 获得轮廓
|
|
|
|
# 获得轮廓
|
|
|
|
contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
|
|
|
contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
|
|
|
|
|
|
|
|
|
|
@ -77,11 +90,12 @@ for item in contours:
|
|
|
|
#车牌字符分割
|
|
|
|
#车牌字符分割
|
|
|
|
# 图像去噪灰度处理
|
|
|
|
# 图像去噪灰度处理
|
|
|
|
gray_image = gray_guss(image)
|
|
|
|
gray_image = gray_guss(image)
|
|
|
|
|
|
|
|
|
|
|
|
# 图像阈值化操作——获得二值化图
|
|
|
|
# 图像阈值化操作——获得二值化图
|
|
|
|
ret, image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_OTSU)
|
|
|
|
ret, image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_OTSU)
|
|
|
|
plt_show(image)
|
|
|
|
plt_show(image)
|
|
|
|
|
|
|
|
|
|
|
|
#膨胀操作,使“苏”字膨胀为一个近似的整体,为分割做准备
|
|
|
|
#膨胀操作,使“津”字膨胀为一个近似的整体,为分割做准备
|
|
|
|
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
|
|
|
|
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
|
|
|
|
image = cv2.dilate(image, kernel)
|
|
|
|
image = cv2.dilate(image, kernel)
|
|
|
|
plt_show(image)
|
|
|
|
plt_show(image)
|
|
|
@ -90,6 +104,7 @@ plt_show(image)
|
|
|
|
contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
|
|
|
contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
|
|
|
words = []
|
|
|
|
words = []
|
|
|
|
word_images = []
|
|
|
|
word_images = []
|
|
|
|
|
|
|
|
|
|
|
|
#对所有轮廓逐一操作
|
|
|
|
#对所有轮廓逐一操作
|
|
|
|
for item in contours:
|
|
|
|
for item in contours:
|
|
|
|
word = []
|
|
|
|
word = []
|
|
|
@ -98,14 +113,21 @@ for item in contours:
|
|
|
|
y = rect[1]
|
|
|
|
y = rect[1]
|
|
|
|
weight = rect[2]
|
|
|
|
weight = rect[2]
|
|
|
|
height = rect[3]
|
|
|
|
height = rect[3]
|
|
|
|
|
|
|
|
|
|
|
|
word.append(x)
|
|
|
|
word.append(x)
|
|
|
|
|
|
|
|
|
|
|
|
word.append(y)
|
|
|
|
word.append(y)
|
|
|
|
|
|
|
|
|
|
|
|
word.append(weight)
|
|
|
|
word.append(weight)
|
|
|
|
|
|
|
|
|
|
|
|
word.append(height)
|
|
|
|
word.append(height)
|
|
|
|
|
|
|
|
|
|
|
|
words.append(word)
|
|
|
|
words.append(word)
|
|
|
|
|
|
|
|
|
|
|
|
# 排序,车牌号有顺序。words是一个嵌套列表
|
|
|
|
# 排序,车牌号有顺序。words是一个嵌套列表
|
|
|
|
words = sorted(words,key=lambda s:s[0],reverse=False)
|
|
|
|
words = sorted(words,key=lambda s:s[0],reverse=False)
|
|
|
|
i = 0
|
|
|
|
i = 0
|
|
|
|
|
|
|
|
|
|
|
|
#word中存放轮廓的起始点和宽高
|
|
|
|
#word中存放轮廓的起始点和宽高
|
|
|
|
for word in words:
|
|
|
|
for word in words:
|
|
|
|
# 筛选字符的轮廓
|
|
|
|
# 筛选字符的轮廓
|
|
|
@ -113,8 +135,8 @@ for word in words:
|
|
|
|
i = i+1
|
|
|
|
i = i+1
|
|
|
|
splite_image = image[word[1]:word[1] + word[3], word[0]:word[0] + word[2]]
|
|
|
|
splite_image = image[word[1]:word[1] + word[3], word[0]:word[0] + word[2]]
|
|
|
|
word_images.append(splite_image)
|
|
|
|
word_images.append(splite_image)
|
|
|
|
print(i)
|
|
|
|
#print(i)
|
|
|
|
print(words)
|
|
|
|
#print(words)
|
|
|
|
|
|
|
|
|
|
|
|
for i,j in enumerate(word_images):
|
|
|
|
for i,j in enumerate(word_images):
|
|
|
|
plt.subplot(1,7,i+1)
|
|
|
|
plt.subplot(1,7,i+1)
|
|
|
@ -124,9 +146,12 @@ plt.show()
|
|
|
|
#模版匹配
|
|
|
|
#模版匹配
|
|
|
|
# 准备模板(template[0-9]为数字模板;)
|
|
|
|
# 准备模板(template[0-9]为数字模板;)
|
|
|
|
template = ['0','1','2','3','4','5','6','7','8','9',
|
|
|
|
template = ['0','1','2','3','4','5','6','7','8','9',
|
|
|
|
'A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z',
|
|
|
|
'A','B','C','D','E','F','G','H','J','K',
|
|
|
|
'藏','川','鄂','甘','赣','贵','桂','黑','沪','吉','冀','津','晋','京','辽','鲁','蒙','闽','宁',
|
|
|
|
'L','M','N','P','Q','R','S','T','U','V',
|
|
|
|
'青','琼','陕','苏','皖','湘','新','渝','豫','粤','云','浙']
|
|
|
|
'W','X','Y','Z','藏','川','鄂','甘','赣',
|
|
|
|
|
|
|
|
'贵','桂','黑','沪','吉','冀','津','晋','京',
|
|
|
|
|
|
|
|
'辽','鲁','蒙','闽','宁','青','琼','陕','苏',
|
|
|
|
|
|
|
|
'皖','湘','新','渝','豫','粤','云','浙']
|
|
|
|
|
|
|
|
|
|
|
|
# 读取一个文件夹下的所有图片,输入参数是文件名,返回模板文件地址列表
|
|
|
|
# 读取一个文件夹下的所有图片,输入参数是文件名,返回模板文件地址列表
|
|
|
|
def read_directory(directory_name):
|
|
|
|
def read_directory(directory_name):
|
|
|
@ -234,16 +259,18 @@ def template_matching(word_images):
|
|
|
|
|
|
|
|
|
|
|
|
word_images_ = word_images.copy()
|
|
|
|
word_images_ = word_images.copy()
|
|
|
|
# 调用函数获得结果
|
|
|
|
# 调用函数获得结果
|
|
|
|
|
|
|
|
|
|
|
|
result = template_matching(word_images_)
|
|
|
|
result = template_matching(word_images_)
|
|
|
|
print(result)
|
|
|
|
#print(result)
|
|
|
|
# "".join(result)函数将列表转换为拼接好的字符串,方便结果显示
|
|
|
|
# "".join(result)函数将列表转换为拼接好的字符串,方便结果显示
|
|
|
|
print( "".join(result))
|
|
|
|
#print( "".join(result))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from PIL import ImageFont, ImageDraw, Image
|
|
|
|
from PIL import ImageFont, ImageDraw, Image
|
|
|
|
|
|
|
|
|
|
|
|
height,weight = origin_image.shape[0:2]
|
|
|
|
height,weight = origin_image.shape[0:2]
|
|
|
|
print(height)
|
|
|
|
#print(height)
|
|
|
|
print(weight)
|
|
|
|
#print(weight)
|
|
|
|
|
|
|
|
|
|
|
|
image_1 = origin_image.copy()
|
|
|
|
image_1 = origin_image.copy()
|
|
|
|
cv2.rectangle(image_1, (int(0.2*weight), int(0.75*height)), (int(weight*0.9), int(height*0.95)), (0, 255, 0), 5)
|
|
|
|
cv2.rectangle(image_1, (int(0.2*weight), int(0.75*height)), (int(weight*0.9), int(height*0.95)), (0, 255, 0), 5)
|
|
|
@ -257,6 +284,26 @@ draw = ImageDraw.Draw(img_pil)
|
|
|
|
#绘制文字信息
|
|
|
|
#绘制文字信息
|
|
|
|
draw.text((int(0.2*weight)+25, int(0.75*height)), "".join(result), font = font, fill = (255, 255, 0))
|
|
|
|
draw.text((int(0.2*weight)+25, int(0.75*height)), "".join(result), font = font, fill = (255, 255, 0))
|
|
|
|
bk_img = np.array(img_pil)
|
|
|
|
bk_img = np.array(img_pil)
|
|
|
|
print(result)
|
|
|
|
#print(result)
|
|
|
|
print( "".join(result))
|
|
|
|
print( "".join(result))
|
|
|
|
plt_show0(bk_img)
|
|
|
|
plt_show0(bk_img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 使用PIL将numpy数组转换为Image对象
|
|
|
|
|
|
|
|
image_tk = Image.fromarray(cv2.cvtColor(bk_img, cv2.COLOR_BGR2RGB))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 初始化Tkinter窗口
|
|
|
|
|
|
|
|
root = tk.Tk()
|
|
|
|
|
|
|
|
root.title("车牌识别结果")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 将Image对象转换为Tkinter支持的PhotoImage对象
|
|
|
|
|
|
|
|
photo_image = ImageTk.PhotoImage(image_tk)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 创建标签以显示图像
|
|
|
|
|
|
|
|
label = ttk.Label(root, image=photo_image)
|
|
|
|
|
|
|
|
label.pack() # 将标签添加到窗口中并自动调整大小
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 防止Tkinter在图像数据被垃圾回收时删除图像
|
|
|
|
|
|
|
|
label.image = photo_image
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 运行Tkinter事件循环
|
|
|
|
|
|
|
|
root.mainloop()
|