基于图像处理和K近邻的车牌号识别

源码下载
CNN流程:
这里写图片描述
整个流程:
这里写图片描述

generate.py:分离整张字符图像代码
# 将字符图片分离成字符
import os
import cv2
import numpy as np
# 提取字符函数
def extract_chars(img):
    # 使用二值化处理
    ret, bwimg = cv2.threshold(img, 64, 255, cv2.THRESH_BINARY)
    # print(bwimg)
    # 定义一个3*3的十字结构
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    # 对图像进行腐蚀,缩小边缘
    erode = cv2.erode(bwimg, kernel, iterations = 1)
    # 图像非运算,黑白颠倒
    bw_image = cv2.bitwise_not(erode)
    # cv2.imshow("Image", img)
    # cv2.waitKey(0)
    # 检测图像轮廓,返回轮廓属性
    contours = cv2.findContours(bw_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[1]
    # 生成轮廓框
    bounding_boxes = []
    for contour in contours:
        # 轮廓基点和长宽
        x,y,w,h = cv2.boundingRect(contour)
        x,y,w,h = x-2, y-2, w+4, h+4
        bounding_boxes.append((x,y,w,h))
    # 裁出字符图片
    characters = []
    for bbox in bounding_boxes:
        x,y,w,h = bbox
        char_image = img[y:y+h,x:x+w]
        characters.append(char_image)
    return characters
# 存储字符函数
def output_chars(chars, labels):
    for i, char in enumerate(chars):
        # cv2.imshow("Image", char)
        # cv2.waitKey(0)
        filename = "chars/%s.png" % labels[i]
        # 图像长宽放大三倍,邻域双三次插值
        char = cv2.resize(char
            , None
            , fx=3
            , fy=3
            , interpolation=cv2.INTER_CUBIC)
        # char = cv2.resize(char,(90,140))
        cv2.imwrite(filename, char)
# 生成文件夹
if not os.path.exists("chars"):
    os.makedirs("chars")
# 读取灰度数字和字母图片
img_digits = cv2.imread("ch/digit.jpg", 0)
img_letters = cv2.imread("ch/letter.jpg", 0)
# 提取字符
digits = extract_chars(img_digits)
letters = extract_chars(img_letters)
DIGITS = [1, 0, 9, 8 ,7, 6, 5, 4, 3, 2]
# LETTERS = [chr(ord('A') + i) for i in range(25,-1,-1)]
LETTERS = ['N', 'M', 'L', 'K' ,'J', 'I', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A', 'Z', 'Y', 'X', 'W', 'V', 'U', 'T', 'S', 'R', 'Q', 'P', 'O']
# 以字符命名方式存储字符图片
output_chars(digits, DIGITS)
output_chars(letters, LETTERS) 

train.py: 提取字符特征,KNN初步测试
# 将字符图片转成特征,并生成各个特征的label
import cv2
import numpy as np
# 生成车牌号中字符 ord由字符生成Ascii码 chr由Ascii码生成字符
CHARS = [chr(ord('0') + i) for i in range(10)] + [chr(ord('A') + i) for i in range(26)]
# print(CHARS)
# 加载字符图片函数
def load_char_images():
    characters = {}
    for char in CHARS:
        # 以灰度模式读取
        char_img = cv2.imread("chars/%s.png" % char, 0)
        characters[char] = char_img
    return characters
# 加载字符图片
characters = load_char_images()
# 特征长度为100
samples =  np.empty((0,100))
for char in CHARS:
    char_img = characters[char]
    # 将图片缩放成10*10,保持特征长度的一致性
    small_char = cv2.resize(char_img,(10,10))
    # 图片进行切片成1*100,一维向量
    sample = small_char.reshape((1,100))
    # 添加进samples
    samples = np.append(samples,sample,0)
# 生成字符label,用列存储
label = np.array([ord(c) for c in CHARS],np.float32)
label = label.reshape((label.size,1))
# 存储字符特征和字符label
np.savetxt('char_samples.data',samples)
np.savetxt('char_label.data',label)
# 模型训练
# 读取字符特征和标签
samples = np.loadtxt('char_samples.data',np.float32)
label = np.loadtxt('char_label.data',np.float32)
label = label.reshape((label.size,1))
# 使用K近邻进行学习
model = cv2.ml.KNearest_create()
model.train(samples, cv2.ml.ROW_SAMPLE, label)
# 读取一个测试样本
# img = cv2.imread("chars/2.png",0)
total=0
for char in CHARS:
    img = cv2.imread("chars/%s.png" %char,0)
    small_img = cv2.resize(img,(10,10))
    ret, small_img = cv2.threshold(small_img, 64, 255, cv2.THRESH_BINARY)
    # print(small_img)
    small_img = small_img.reshape((1,100))
    small_img = np.float32(small_img)
    # 使用K近邻进行预测
    retval, results, neigh_resp, dists = model.findNearest(small_img, k = 1)
    print(chr(results[0][0]))
    if(chr(results[0][0])==char):
        total += 1
print(1.0*total/len(CHARS))

main.py: 车牌号图像处理并识别
# 主程序,识别车牌号
import cv2
import numpy as np
import sys
import argparse
import os
def reduce_colors(img, n):
    # 图片切片成3列
    Z = img.reshape((-1,3))
    # 转成float32类型,运算快
    Z = np.float32(Z)
    # 使用k均值进行聚类
    # 迭代停止的模式选择:满足精确度+最大迭代次数
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    # K值,分类数
    K = n
    # 重复进行多少次,将返回最好一次结果
    # 紧密度,返回每个点到相应重心的距离的平方和; labels:标志数组;centers:由聚类的中心组成的数组。
ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
    # 图片重新转成uint8数据类型
    center = np.uint8(center)
    res = center[label.flatten()]
    # 返回图片
    res2 = res.reshape((img.shape))
    return res2 
# 图片处理函数
def clean_image(img):
    # RGB转灰度图
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 缩放图片
    resized_img = cv2.resize(gray_img
        , None
        , fx=4.0
        , fy=4.0
        , interpolation=cv2.INTER_CUBIC)
    # 进行高斯滤波
    resized_img = cv2.GaussianBlur(resized_img,(5,5),0)
    # 存储高斯结果
    cv2.imwrite('temp/licence_plate_gauss.png', resized_img)
    # 直方图均衡化
    equalized_img = cv2.equalizeHist(resized_img)
    # 存储均衡化直方图
    cv2.imwrite('temp/licence_plate_equ.png', equalized_img)
    # 图片经过聚类处理
    reduced = cv2.cvtColor(reduce_colors(cv2.cvtColor(equalized_img, cv2.COLOR_GRAY2BGR), 8), cv2.COLOR_BGR2GRAY)
    cv2.imwrite('temp/licence_plate_red.png', reduced)
    # 限定阈值二值化图片
    ret, bwimg = cv2.threshold(reduced, 64, 255, cv2.THRESH_BINARY)
    # 存储二值图片
    cv2.imwrite('temp/licence_plate_bwimg.png', bwimg) 
    # 定义一个3*3的十字结构
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4, 4))
    # 对图像进行腐蚀
    erode = cv2.erode(bwimg, kernel, iterations = 1)
    # 存储腐蚀图片
    cv2.imwrite('temp/licence_plate_erode.png', erode)
    return erode
# 提取字符函数
def extract_characters(img):
    # 非运算,将数字部分转成白颜色
    bw_image = cv2.bitwise_not(img)
    cv2.imwrite("temp/bw_image.png",bw_image)
    # 查找边缘
    contours = cv2.findContours(bw_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[1]
    # print(contours)
    char_mask = np.zeros_like(img)
    bounding_boxes = []
    for contour in contours:
        x,y,w,h = cv2.boundingRect(contour)
        area = w * h
        center = (x + w/2, y + h/2)
        # 对于区域在1000~10000之间的才算字符
        if (area > 1800) and (area < 10000):
            x,y,w,h = x-4, y-4, w+8, h+8
            # 存储图片边框信息
            bounding_boxes.append((center, (x,y,w,h)))
            # 绘画矩形,使用灰度255白色,线宽-1表示填满
            cv2.rectangle(char_mask,(x,y),(x+w,y+h),255,-1)
    # 存储矩形区域
    cv2.imwrite('temp/licence_plate_char_mask.png', char_mask)
    # 将原图和提取的字符图进行与与运算提取出字符图,在进行非运算
    clean = cv2.bitwise_not(cv2.bitwise_and(char_mask, char_mask, mask = bw_image))
    # 根据字符中心进行从左到右排序
    bounding_boxes = sorted(bounding_boxes, key=lambda item: item[0][0])  
    # 裁出字符图片
    characters = []
    for center, bbox in bounding_boxes:
        x,y,w,h = bbox
        char_image = clean[y:y+h,x:x+w]
        characters.append((bbox, char_image))
    # 返回整张字符图和裁剪后字符图
    return clean, characters
# 高亮字符图
def highlight_characters(img, chars, file):
    # 图片转RGB
    # if(file=="CU5600"):
    output_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    for bbox, char_img in chars:
        x,y,w,h = bbox
        # 将所选区域用白色绘制
        cv2.rectangle(output_img,(x,y),(x+w,y+h),255,1)
    # 存储高亮字符图片
    cv2.imwrite('temp/licence_plate_out.png', output_img)
    return output_img
# 开始执行
#命令形式: python main.py --image T1.jpg
# 从命令行获取要读取的车牌号图片   
# ap = argparse.ArgumentParser()
# ap.add_argument("-i", "--image", required = True, help = "输入图片路径")
# args = vars(ap.parse_args())
# # 读取图片
# img = cv2.imread(args["image"])
# 读取字符特征和标签
samples = np.loadtxt('char_samples.data',np.float32)
label = np.loadtxt('char_label.data',np.float32)
label = label.reshape((label.size,1))
# 使用K近邻模型并训练
model = cv2.ml.KNearest_create()
model.train(samples, cv2.ml.ROW_SAMPLE, label)
# 重定向输出流
orig_stdout = sys.stdout
f = open('output.txt','w')
sys.stdout = f
path = "data" #文件夹目录  
files= os.listdir(path)
total=0
for file in files:
    # 读取图片
    img = cv2.imread(path+"/"+file)
    # print(file)
    img = cv2.resize(img,(108,24))
    # 处理图片
    img = clean_image(img)
    # 提取图片中字符
    clean_img, chars = extract_characters(img)
    # 高亮图片中字符
    output_img = highlight_characters(clean_img, chars,file[0:-4])
    plate_chars = ""
    for bbox, char_img in chars:
        # 将提取的char转成字符特征形式
        # print("char_img.shape")
        # print(char_img.shape)
        small_img = cv2.resize(char_img,(10,10))
        small_img = small_img.reshape((1,100))
        small_img = np.float32(small_img)
        retval, results, neigh_resp, dists = model.findNearest(small_img, k = 1)
        plate_chars += str(chr((results[0][0])))
    # 存储识别的车牌号
    print("识别车牌号: %s" % plate_chars)
    print("实际车牌号: %s" % file[0:-4])
    print()
    if(plate_chars==file[0:-4]):
        total = total + 1
sys.stdout = orig_stdout
f.close()
print("准确率",1.00*total/len(files))
  • 4
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值