car plate

code

产生数据

import os
import cv2 as cv
import numpy as np
from math import *
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw

index = {"京": 0, "沪": 1, "津": 2, "渝": 3, "冀": 4, "晋": 5, "蒙": 6, "辽": 7, "吉": 8, "黑": 9,
         "苏": 10, "浙": 11, "皖": 12, "闽": 13, "赣": 14, "鲁": 15, "豫": 16, "鄂": 17, "湘": 18, "粤": 19,
         "桂": 20, "琼": 21, "川": 22, "贵": 23, "云": 24, "藏": 25, "陕": 26, "甘": 27, "青": 28, "宁": 29,
         "新": 30, "0": 31, "1": 32, "2": 33, "3": 34, "4": 35, "5": 36, "6": 37, "7": 38, "8": 39,
         "9": 40, "A": 41, "B": 42, "C": 43, "D": 44, "E": 45, "F": 46, "G": 47, "H": 48, "J": 49,
         "K": 50, "L": 51, "M": 52, "N": 53, "P": 54, "Q": 55, "R": 56, "S": 57, "T": 58, "U": 59,
         "V": 60, "W": 61, "X": 62, "Y": 63, "Z": 64}

chars = ["京", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑",
         "苏", "浙", "皖", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤",
         "桂", "琼", "川", "贵", "云", "藏", "陕", "甘", "青", "宁",
         "新", "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"]


def AddSmudginess(img, Smu):
    """
    模糊处理
    :param img: 输入图像
    :param Smu: 模糊图像
    :return: 添加模糊后的图像
    """
    rows = r(Smu.shape[0] - 50)
    cols = r(Smu.shape[1] - 50)
    adder = Smu[rows:rows + 50, cols:cols + 50]
    adder = cv.resize(adder, (50, 50))
    img = cv.resize(img, (50, 50))
    img = cv.bitwise_not(img)
    img = cv.bitwise_and(adder, img)
    img = cv.bitwise_not(img)
    return img


def rot(img, angel, shape, max_angel):
    """
    添加透视畸变
    """
    size_o = [shape[1], shape[0]]
    size = (shape[1] + int(shape[0] * cos((float(max_angel) / 180) * 3.14)), shape[0])
    interval = abs(int(sin((float(angel) / 180) * 3.14) * shape[0]))
    pts1 = np.float32([[0, 0], [0, size_o[1]], [size_o[0], 0], [size_o[0], size_o[1]]])
    if angel > 0:
        pts2 = np.float32([[interval, 0], [0, size[1]], [size[0], 0], [size[0] - interval, size_o[1]]])
    else:
        pts2 = np.float32([[0, 0], [interval, size[1]], [size[0] - interval, 0], [size[0], size_o[1]]])
    M = cv.getPerspectiveTransform(pts1, pts2)
    dst = cv.warpPerspective(img, M, size)
    return dst


def rotRandrom(img, factor, size):
    """
    添加放射畸变
    :param img: 输入图像
    :param factor: 畸变的参数
    :param size: 图片目标尺寸
    :return: 放射畸变后的图像
    """
    shape = size
    pts1 = np.float32([[0, 0], [0, shape[0]], [shape[1], 0], [shape[1], shape[0]]])
    pts2 = np.float32([[r(factor), r(factor)], [r(factor), shape[0] - r(factor)], [shape[1] - r(factor), r(factor)],
                       [shape[1] - r(factor), shape[0] - r(factor)]])
    M = cv.getPerspectiveTransform(pts1, pts2)
    dst = cv.warpPerspective(img, M, size)
    return dst


def tfactor(img):
    """
    添加饱和度光照的噪声
    """
    hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
    hsv[:, :, 0] = hsv[:, :, 0] * (0.8 + np.random.random() * 0.2)
    hsv[:, :, 1] = hsv[:, :, 1] * (0.3 + np.random.random() * 0.7)
    hsv[:, :, 2] = hsv[:, :, 2] * (0.2 + np.random.random() * 0.8)
    img = cv.cvtColor(hsv, cv.COLOR_HSV2BGR)
    return img


def random_envirment(img, noplate_bg):
    """
    添加自然环境的噪声, noplate_bg为不含车牌的背景图
    """
    bg_index = r(len(noplate_bg))
    env = cv.imread(noplate_bg[bg_index])
    env = cv.resize(env, (img.shape[1], img.shape[0]))
    bak = (img == 0)
    bak = bak.astype(np.uint8) * 255
    inv = cv.bitwise_and(bak, env)
    img = cv.bitwise_or(inv, img)
    return img


def GenCh(f, val):
    """
    生成中文字符
    """
    img = Image.new("RGB", (45, 70), (255, 255, 255))
    draw = ImageDraw.Draw(img)
    draw.text((0, 3), val, (0, 0, 0), font=f)
    img = img.resize((23, 70))
    A = np.array(img)
    return A


def GenCh1(f, val):
    """
    生成英文字符
    """
    img = Image.new("RGB", (23, 70), (255, 255, 255))
    draw = ImageDraw.Draw(img)
    draw.text((0, 2), val, (0, 0, 0), font=f)  # val.decode('utf-8')
    A = np.array(img)
    return A


def AddGauss(img, level):
    """
    添加高斯模糊
    """
    return cv.blur(img, (level * 2 + 1, level * 2 + 1))


def r(val):
    return int(np.random.random() * val)


def AddNoiseSingleChannel(single):
    """
    添加高斯噪声
    """
    diff = 255 - single.max()
    noise = np.random.normal(0, 1 + r(6), single.shape)
    noise = (noise - noise.min()) / (noise.max() - noise.min())
    noise *= diff
    # noise= noise.astype(np.uint8)
    dst = single + noise
    return dst


def addNoise(img):  # sdev = 0.5,avg=10
    img[:, :, 0] = AddNoiseSingleChannel(img[:, :, 0])
    img[:, :, 1] = AddNoiseSingleChannel(img[:, :, 1])
    img[:, :, 2] = AddNoiseSingleChannel(img[:, :, 2])
    return img


class GenPlate:
    def __init__(self, fontCh, fontEng, NoPlates):
        self.fontC = ImageFont.truetype(fontCh, 43, 0)
        self.fontE = ImageFont.truetype(fontEng, 60, 0)
        self.img = np.array(Image.new("RGB", (226, 70), (255, 255, 255)))
        self.bg = cv.resize(cv.imread("images/template.bmp"), (226, 70))  # template.bmp:车牌背景图
        self.smu = cv.imread("images/smu2.jpg")  # smu2.jpg:模糊图像
        self.noplates_path = []
        for parent, parent_folder, filenames in os.walk(NoPlates):
            for filename in filenames:
                path = parent + "/" + filename
                self.noplates_path.append(path)

    def draw(self, val):
        offset = 2
        self.img[0:70, offset + 8:offset + 8 + 23] = GenCh(self.fontC, val[0])
        self.img[0:70, offset + 8 + 23 + 6:offset + 8 + 23 + 6 + 23] = GenCh1(self.fontE, val[1])
        for i in range(5):
            base = offset + 8 + 23 + 6 + 23 + 17 + i * 23 + i * 6
            self.img[0:70, base:base + 23] = GenCh1(self.fontE, val[i + 2])
        return self.img

    def generate(self, text):
        if len(text) == 7:
            fg = self.draw(text)  # decode(encoding="utf-8")
            fg = cv.bitwise_not(fg)
            com = cv.bitwise_or(fg, self.bg)
            com = rot(com, r(60) - 30, com.shape, 30)
            com = rotRandrom(com, 10, (com.shape[1], com.shape[0]))
            com = tfactor(com)
            com = random_envirment(com, self.noplates_path)
            #com = AddGauss(com, 1 + r(4))
            com = addNoise(com)
            return com

    @staticmethod
    def genPlateString(pos, val):
        """
          生成车牌string,存为图片
        生成车牌list,存为label
        """
        plateStr = ""
        plateList = []
        box = [0, 0, 0, 0, 0, 0, 0]
        if pos != -1:
            box[pos] = 1
        for unit, cpos in zip(box, range(len(box))):
            if unit == 1:
                plateStr += val
                plateList.append(val)
            else:
                if cpos == 0:
                    plateStr += chars[r(31)]
                    plateList.append(plateStr)
                elif cpos == 1:
                    plateStr += chars[41 + r(24)]
                    plateList.append(plateStr)
                else:
                    plateStr += chars[31 + r(34)]
                    plateList.append(plateStr)
        plate = [plateList[0]]
        b = [plateList[i][-1] for i in range(len(plateList))]
        plate.extend(b[1:7])
        return plateStr, plate

    @staticmethod
    def genBatch(batchsize, outputPath, size):
        """
        将生成的车牌图片写入文件夹,对应的label写入label.txt
        :param batchsize: 批次大小
        :param outputPath: 输出图像的保存路径
        :param size: 输出图像的尺寸
        :return: None
        """
        if not os.path.exists(outputPath):
            os.mkdir(outputPath)
        outfile = open('label.txt', 'w', encoding='utf-8')
        for i in range(batchsize):
            plateStr, plate = G.genPlateString(-1, -1)
            print(plateStr, plate)
            img = G.generate(plateStr)
            img = cv.resize(img, size)
            cv.imwrite(outputPath + "/" + str(i).zfill(2) + ".jpg", img)
            outfile.write(str(plate) + "\n")


if __name__ == '__main__':
    G = GenPlate("font/platech.ttf", 'font/platechar.ttf', "NoPlates")
    G.genBatch(201, 'plate', (272, 72))

训练

import os
import time
import datetime
import numpy as np
import tensorflow as tf
from input_data import OCRIter
import model

os.environ["TF_CPP_MIN_LOG_LEVEL"] = '3'

img_h = 72
img_w = 272
num_label = 7
batch_size = 32
epoch = 10000
learning_rate = 0.0001

logs_path = 'logs '
model_path = 'saved_model'

image_holder = tf.compat.v1.placeholder(tf.float32, [batch_size, img_h, img_w, 3])
label_holder = tf.compat.v1.placeholder(tf.int32, [batch_size, 7])
keep_prob = tf.compat.v1.placeholder(tf.float32)


def get_batch():
    data_batch = OCRIter(batch_size, img_h, img_w)
    image_batch, label_batch = data_batch.iter()
    return np.array(image_batch), np.array(label_batch)


logit1, logit2, logit3, logit4, logit5, logit6, logit7 = model.cnn_inference(
    image_holder, keep_prob)

loss1, loss2, loss3, loss4, loss5, loss6, loss7 = model.calc_loss(
    logit1, logit2, logit3, logit4, logit5, logit6, logit7, label_holder)

train_op1, train_op2, train_op3, train_op4, train_op5, train_op6, train_op7 = model.train_step(
    loss1, loss2, loss3, loss4, loss5, loss6, loss7, learning_rate)

accuracy = model.pred_model(logit1, logit2, logit3, logit4, logit5, logit6, logit7, label_holder)

input_image = tf.compat.v1.summary.image('input', image_holder)

summary_op = tf.compat.v1.summary.merge(tf.compat.v1.get_collection(tf.compat.v1.GraphKeys.SUMMARIES))

init_op = tf.compat.v1.global_variables_initializer()

with tf.compat.v1.Session() as sess:
    sess.run(init_op)

    train_writer = tf.compat.v1.summary.FileWriter(logs_path, sess.graph)
    saver = tf.compat.v1.train.Saver()

    start_time1 = time.time()
    for step in range(epoch):
        # 生成车牌图像以及标签数据
        img_batch, lbl_batch = get_batch()

        start_time2 = time.time()
        time_str = datetime.datetime.now().isoformat()

        feed_dict = {image_holder: img_batch, label_holder: lbl_batch, keep_prob: 0.6}
        _1, _2, _3, _4, _5, _6, _7, ls1, ls2, ls3, ls4, ls5, ls6, ls7, acc = sess.run(
            [train_op1, train_op2, train_op3, train_op4, train_op5, train_op6, train_op7,
             loss1, loss2, loss3, loss4, loss5, loss6, loss7, accuracy], feed_dict)
        summary_str = sess.run(summary_op, feed_dict)
        train_writer.add_summary(summary_str, step)
        duration = time.time() - start_time2
        loss_total = ls1 + ls2 + ls3 + ls4 + ls5 + ls6 + ls7
        if step % 10 == 0:
            sec_per_batch = float(duration)
            print('%s: Step %d, loss_total = %.2f, acc = %.2f%%, sec/batch = %.2f' %
                  (time_str, step, loss_total, acc * 100, sec_per_batch))
        if step % 5000 == 0 or (step + 1) == epoch:
            checkpoint_path = os.path.join(model_path, 'model.ckpt')
            saver.save(sess, checkpoint_path, global_step=step)
    end_time = time.time()
    print("Training over. It costs {:.2f} minutes".format((end_time - start_time1) / 60))

测试

import os
import cv2 as cv
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from PIL import Image
import model

os.environ["TF_CPP_MIN_LOG_LEVEL"] = '3'  # 只显示 Error

index = {"京": 0, "沪": 1, "津": 2, "渝": 3, "冀": 4, "晋": 5, "蒙": 6, "辽": 7, "吉": 8, "黑": 9,
         "苏": 10, "浙": 11, "皖": 12, "闽": 13, "赣": 14, "鲁": 15, "豫": 16, "鄂": 17, "湘": 18, "粤": 19,
         "桂": 20, "琼": 21, "川": 22, "贵": 23, "云": 24, "藏": 25, "陕": 26, "甘": 27, "青": 28, "宁": 29,
         "新": 30, "0": 31, "1": 32, "2": 33, "3": 34, "4": 35, "5": 36, "6": 37, "7": 38, "8": 39,
         "9": 40, "A": 41, "B": 42, "C": 43, "D": 44, "E": 45, "F": 46, "G": 47, "H": 48, "J": 49,
         "K": 50, "L": 51, "M": 52, "N": 53, "P": 54, "Q": 55, "R": 56, "S": 57, "T": 58, "U": 59,
         "V": 60, "W": 61, "X": 62, "Y": 63, "Z": 64}

chars = ["京", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑",
         "苏", "浙", "皖", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤",
         "桂", "琼", "川", "贵", "云", "藏", "陕", "甘", "青", "宁",
         "新", "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"]


def get_one_image(test):
    """ 随机获取单张车牌图像 """
    n = len(test)
    rand_num = np.random.randint(0, n)
    img_dir = test[rand_num]
    image_show = Image.open(img_dir)
    plt.imshow(image_show)  # 显示车牌图片
    image = cv.imread(img_dir)
    image = image.reshape(1,72, 272, 3)
    image = np.multiply(image, 1 / 255.0)
    return image


batch_size = 1
x = tf.compat.v1.placeholder(tf.float32, [batch_size, 72, 272, 3])
keep_prob = tf.compat.v1.placeholder(tf.float32)

test_dir = 'plate/'
test_image = []
for file in os.listdir(test_dir):
    test_image.append(test_dir + file)
test_image = list(test_image)

image_array = get_one_image(test_image)

logit1, logit2, logit3, logit4, logit5, logit6, logit7 = model.cnn_inference(x, keep_prob)

model_path = 'saved_model/'

saver = tf.compat.v1.train.Saver()

with tf.compat.v1.Session() as sess:
    print("Reading checkpoint...")
    ckpt = tf.train.get_checkpoint_state(model_path)
    if ckpt and ckpt.model_checkpoint_path:
        global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
        saver.restore(sess, ckpt.model_checkpoint_path)
        print('Loading success, global_step is %s' % global_step)
    else:
        print('No checkpoint file found')

    pre1, pre2, pre3, pre4, pre5, pre6, pre7 = sess.run(
        [logit1, logit2, logit3, logit4, logit5, logit6, logit7],
        feed_dict={x: image_array, keep_prob: 1.0})
    prediction = np.reshape(np.array([pre1, pre2, pre3, pre4, pre5, pre6, pre7]), [-1, 65])

    max_index = np.argmax(prediction, axis=1)
    print(max_index)
    line = ''
    result = np.array([])
    for i in range(prediction.shape[0]):
        if i == 0:
            result = np.argmax(prediction[i][0:31])
        if i == 1:
            result = np.argmax(prediction[i][41:65]) + 41
        if i > 1:
            result = np.argmax(prediction[i][31:65]) + 31
        line += chars[result] + " "
    print('predicted: ' + line)
plt.show()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容