【深度神经网络(DNN)】实现车牌识别

news2024/9/28 4:37:14

文章目录

  • 前言
  • 一、数据集介绍
  • 二、步骤
    • 1.导包
    • 2.参数配置
    • 3.数据处理
    • 4.模型定义
    • 5.模型训练
    • 6.模型预测
  • 总结


前言

课内实践作业 车牌识别


一、数据集介绍

1.车牌识别数据集:VehicleLicense车牌识别数据集包含16151张单字符数据,所有的单字符均为严格切割且都转换为黑白二值图像(如下第一行:训练数据所示)。
2.characterData:车牌识别数据集

二、步骤

1.导包

代码如下(示例):


#导入需要的包
import os
import zipfile
import random
import json
import cv2
import numpy as np
from PIL import Image
import paddle
import matplotlib.pyplot as plt
print(cv2.__version__)

在这里插入图片描述

2.参数配置

'''
参数配置
'''
train_parameters = {
    "input_size": [1, 20, 20],                           #输入图片的shape
    "class_dim": -1,                                     #分类数
    "src_path":"data/data47799/characterData.zip",       #原始数据集路径
    "target_path":"/home/aistudio/data/dataset",        #要解压的路径 
    "train_list_path": "/home/aistudio/train_data.txt",              #train_data.txt路径
    "eval_list_path": "/home/aistudio/val_data.txt",                  #eval_data.txt路径
    "label_dict":{},                                    #标签字典
    "readme_path": "/home/aistudio/data/readme.json",   #readme.json路径
    "train_batch_size": 32                           #训练的轮数
}

3.数据处理

def unzip_data(src_path,target_path):
    '''
    解压原始数据集,将src_path路径下的zip包解压至data/dataset目录下
    '''
    if(not os.path.isdir(target_path)):    
        z = zipfile.ZipFile(src_path, 'r')
        z.extractall(path=target_path)
        z.close()
    else:
        print("文件已解压")
``
```py
def get_data_list(target_path,train_list_path,eval_list_path):
    '''
    生成数据列表
    '''
    #存放所有类别的信息
    class_detail = []
    #获取所有类别保存的文件夹名称
    data_list_path=target_path 
   
    class_dirs = os.listdir(data_list_path)

   
    if '__MACOSX' in class_dirs:
        class_dirs.remove('__MACOSX')
    # #总的图像数量
    all_class_images = 0
    # #存放类别标签
    class_label=0
    # #存放类别数目
    class_dim = 0
    # #存储要写进eval.txt和train.txt中的内容
    trainer_list=[]
    eval_list=[]
    #读取每个类别
    for class_dir in class_dirs:
        if class_dir != ".DS_Store":
            class_dim += 1
            #每个类别的信息
            class_detail_list = {}
            eval_sum = 0
            trainer_sum = 0
            #统计每个类别有多少张图片
            class_sum = 0
            #获取类别路径 
            path = os.path.join(data_list_path,class_dir)
            # print(path)
            # 获取所有图片
            img_paths = os.listdir(path)
            for img_path in img_paths:                                  # 遍历文件夹下的每个图片
                if img_path =='.DS_Store':
                    continue
                name_path = os.path.join(path,img_path)                       # 每张图片的路径
                if class_sum % 10 == 0:                                 # 每10张图片取一个做验证数据
                    eval_sum += 1                                       # eval_sum为测试数据的数目
                    eval_list.append(name_path + "\t%d" % class_label + "\n")
                else:
                    trainer_sum += 1 
                    trainer_list.append(name_path + "\t%d" % class_label + "\n")#trainer_sum测试数据的数目
                class_sum += 1                                          #每类图片的数目
                all_class_images += 1                                   #所有类图片的数目
            
            # 说明的json文件的class_detail数据
            class_detail_list['class_name'] = class_dir             #类别名称
            class_detail_list['class_label'] = class_label          #类别标签
            class_detail_list['class_eval_images'] = eval_sum       #该类数据的测试集数目
            class_detail_list['class_trainer_images'] = trainer_sum #该类数据的训练集数目
            class_detail.append(class_detail_list)  
            #初始化标签列表
            train_parameters['label_dict'][str(class_label)] = class_dir
            class_label += 1
            
    #初始化分类数
    train_parameters['class_dim'] = class_dim
    print(train_parameters)
    #乱序  
    random.shuffle(eval_list)
    with open(eval_list_path, 'a') as f:
        for eval_image in eval_list:
            f.write(eval_image) 
    #乱序        
    random.shuffle(trainer_list) 
    with open(train_list_path, 'a') as f2:
        for train_image in trainer_list:
            f2.write(train_image) 

    # 说明的json文件信息
    readjson = {}
    readjson['all_class_name'] = data_list_path                  #文件父目录
    readjson['all_class_images'] = all_class_images
    readjson['class_detail'] = class_detail
    jsons = json.dumps(readjson, sort_keys=True, indent=4, separators=(',', ': '))
    with open(train_parameters['readme_path'],'w') as f:
        f.write(jsons)
    print ('生成数据列表完成!')
'''
参数初始化
'''
src_path=train_parameters['src_path']
target_path=train_parameters['target_path']
train_list_path=train_parameters['train_list_path']
eval_list_path=train_parameters['eval_list_path']
batch_size=train_parameters['train_batch_size']
'''
解压原始数据到指定路径
'''

unzip_data(src_path,target_path)

#每次生成数据列表前,首先清空train.txt和eval.txt
with open(train_list_path, 'w') as f: 
    f.seek(0)
    f.truncate() 
with open(eval_list_path, 'w') as f: 
    f.seek(0)
    f.truncate() 
    
#生成数据列表   
get_data_list(target_path,train_list_path,eval_list_path)

在这里插入图片描述

'''
自定义数据集
'''
import paddle
from paddle.io import Dataset
class MyDataset(Dataset):
    """
    步骤一:继承paddle.io.Dataset类
    """
    def __init__(self, mode='train'):
        """
        步骤二:实现构造函数,定义数据集大小
        """
        self.data = []
        self.label = []
        super(MyDataset, self).__init__()
        if mode == 'train':
            #批量读入数据
            print(train_list_path)
            with open(train_list_path, 'r') as f:
                lines = [line.strip() for line in f]
                for line in lines:
                    #分割数据和标签
                    img_path, lab = line.strip().split('\t')
                    #读入图片
                    img = cv2.imread(img_path)
                    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
                    img = np.array(img).astype('float32')
                    #图片归一化处理
                    img = img/255.0
                    #将数据同一添加到data和label中
                    self.data.append(img)
                    self.label.append(np.array(lab).astype('int64'))
        else:
            #测试集同上
            with open(eval_list_path, 'r') as f:
                lines = [line.strip() for line in f]
                for line in lines:
                    img_path, lab = line.strip().split('\t')
                    img = cv2.imread(img_path)
                    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
                    img = np.array(img).astype('float32')
                    img = img/255.0
                    self.data.append(img)
                    self.label.append(np.array(lab).astype('int64'))
    def __getitem__(self, index):
        """
        步骤三:实现__getitem__方法,定义指定index时如何获取数据,并返回单条数据(训练数据,对应的标签)
        """
        #返回单一数据和标签
        data = self.data[index]
        label = self.label[index]
        #注:返回标签数据时必须是int64
        # print(data)
        return data, np.array(label, dtype='int64')
    def __len__(self):
        """
        步骤四:实现__len__方法,返回数据集总数目
        """
        #返回数据总数
        return len(self.label)

# 测试定义的数据集
train_dataset = MyDataset(mode='train')
eval_dataset = MyDataset(mode='val')
print('=============train_dataset =============')
#输出数据集的形状和标签
print(train_dataset.__getitem__(1)[0].shape,train_dataset.__getitem__(1)[1])
#输出数据集的长度
print(train_dataset.__len__())
print('=============eval_dataset =============')
#输出数据集的形状和标签
for data, label in eval_dataset:
    print(data.shape, label)
    break
#输出数据集的长度
print(eval_dataset.__len__())

在这里插入图片描述

4.模型定义

import paddle.fluid as fluid
from paddle.fluid.dygraph import Linear

class MyDNN(fluid.dygraph.Layer):
    def __init__(self):
        super(MyDNN,self).__init__()
        ####请完善网络模型定义
        # self.hidden1 = paddle.nn.Linear(in_features=20*20,out_deatures=200)
        # self.hidden2 = paddle.nn.Linear(in_features=200,out_deatures=100)
        # self.hidden3 = paddle.nn.Linear(in_features=100,out_deatures=100)
        # self.out = paddle.nn.Linear(in_features=100,out_deatures=65)
        self.hidden1 = Linear(20*20,200,act='relu')
        self.hidden2 = Linear(200,100,act='relu')
        self.hidden3 = Linear(100,100,act = 'relu')
        self.hidden4 = Linear(100,65,act='softmax')

    # forward 定义执行实际运行时网络的执行逻辑
    def forward(self,input):       
        #-1 表示这个维度的值是从x的元素总数和剩余维度推断出来的,有且只能有一个维度设置为-1
        x = fluid.layers.reshape(input, shape=[-1,20*20]) 

        x=self.hidden1(x)
        x=self.hidden2(x)
        x=self.hidden3(x)
        y=self.hidden4(x)
        return y

5.模型训练

#step3:训练模型
# 用Model封装模型
model = paddle.Model(MyDNN())
# 定义损失函数


model.prepare(paddle.optimizer.Adam(parameters=model.parameters()),paddle.nn.CrossEntropyLoss(),paddle.metric.Accuracy(topk=(1,5)))
# model.prepare(paddle.optimizer.SGD(parameters=model.parameters()),paddle.nn.CrossEntropyLoss(),paddle.metric.Accuracy(topk=(1,5)))

# 训练可视化VisualDL工具的回调函数
visualdl = paddle.callbacks.VisualDL(log_dir='visualdl_log')
# 启动模型全流程训练
model.fit(train_dataset,            # 训练数据集
           eval_dataset,            # 评估数据集
          epochs=100,            # 总的训练轮次
          batch_size = batch_size,    # 批次计算的样本量大小
          shuffle=True,             # 是否打乱样本集
          verbose=1,                # 日志展示格式
          save_dir='./chk_points/', # 分阶段的训练模型存储路径
          callbacks=[visualdl])     # 回调函数使用
#保存模型
model.save('model_save_dir')

在这里插入图片描述

license_plate = cv2.imread('work/车牌.png')
print(license_plate.shape)
gray_plate = cv2.cvtColor(license_plate, cv2.COLOR_RGB2GRAY) 
ret, binary_plate = cv2.threshold(gray_plate, 175, 255, cv2.THRESH_BINARY) #ret:阈值,binary_plate:根据阈值处理后的图像数据
# 按列统计像素分布
result = []
for col in range(binary_plate.shape[1]):
    result.append(0)
    for row in range(binary_plate.shape[0]):
        result[col] = result[col] + binary_plate[row][col]/255
# print(result) 
#记录车牌中字符的位置
character_dict = {}
num = 0
i = 0
while i < len(result):
    if result[i] == 0:
        i += 1
    else:
        index = i + 1
        while result[index] != 0:
            index += 1
        character_dict[num] = [i, index-1]
        num += 1
        i = index
# print(character_dict)        
#将每个字符填充,并存储
characters = []
for i in range(8):
    if i==2:
        continue
    padding = (170 - (character_dict[i][1] - character_dict[i][0])) / 2
    #将单个字符图像填充为170*170
    ndarray = np.pad(binary_plate[:,character_dict[i][0]:character_dict[i][1]], ((0,0), (int(padding), int(padding))), 'constant', constant_values=(0,0))
    ndarray = cv2.resize(ndarray, (20,20))
    cv2.imwrite('work/' + str(i) + '.png', ndarray)
    characters.append(ndarray)
    
def load_image(path):
    img = paddle.dataset.image.load_image(file=path, is_color=False)
    img = img.astype('float32')
    img = img[np.newaxis, ] / 255.0
    return img

在这里插入图片描述

将标签进行转换
print('Label:',train_parameters['label_dict'])
match = {'A':'A','B':'B','C':'C','D':'D','E':'E','F':'F','G':'G','H':'H','I':'I','J':'J','K':'K','L':'L','M':'M','N':'N',
        'O':'O','P':'P','Q':'Q','R':'R','S':'S','T':'T','U':'U','V':'V','W':'W','X':'X','Y':'Y','Z':'Z',
        'yun':'云','cuan':'川','hei':'黑','zhe':'浙','ning':'宁','jin':'津','gan':'赣','hu':'沪','liao':'辽','jl':'吉','qing':'青','zang':'藏',
        'e1':'鄂','meng':'蒙','gan1':'甘','qiong':'琼','shan':'陕','min':'闽','su':'苏','xin':'新','wan':'皖','jing':'京','xiang':'湘','gui':'贵',
        'yu1':'渝','yu':'豫','ji':'冀','yue':'粤','gui1':'桂','sx':'晋','lu':'鲁',
        '0':'0','1':'1','2':'2','3':'3','4':'4','5':'5','6':'6','7':'7','8':'8','9':'9'}
L = 0
LABEL ={}
for V in train_parameters['label_dict'].values():
    LABEL[str(L)] = match[V]
    L += 1
print(LABEL)

6.模型预测

with fluid.dygraph.guard():
    model=MyDNN()#模型实例化
    model_dict,_=fluid.load_dygraph('model_save_dir.pdparams')
    model.load_dict(model_dict)#加载模型参数
    model.eval()#评估模式
    lab=[]
    for i in range(8):
        if i==2:
            continue
        infer_imgs = []
        infer_imgs.append(load_image('work/' + str(i) + '.png'))
        infer_imgs = np.array(infer_imgs)
        infer_imgs = fluid.dygraph.to_variable(infer_imgs)
        result=model(infer_imgs)
        lab.append(np.argmax(result.numpy()))
print(lab)
display(Image.open('work/车牌.png'))
for i in range(len(lab)):
    print(LABEL[str(lab[i])],end='')

在这里插入图片描述

总结

通过对实现车牌识别让我对深度神经网络(DNN)有了更深的认识

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1181575.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣:67.二进制求和

class Solution { public:string addBinary(string a, string b) {string ans;reverse(a.begin(), a.end()); // 将字符串a反转reverse(b.begin(), b.end()); // 将字符串b反转int n max(a.size(), b.size()), carry 0; // 获取a和b的最大长度&#xff0c;并初始化进位为0for…

Python合并拼接图片

目录 图片二维合并拼接&#xff08;类似九宫格&#xff09;图片纵向合并拼接举例18张图片合并为2张九宫格图片18张图片合并为2张纵向图片 使用前需要安装PIL库&#xff0c;以下代码使用的Pillow(10.1.0) pip install pillow图片二维合并拼接&#xff08;类似九宫格&#xff09…

趣玩行为商城:用智能消费行为开启财富新生活!

随着当前的消费主力转移至90后和Z时代&#xff0c;购物和消费习惯已经发生了翻天覆地的变化。以往那种大超市&#xff0c;线下大卖场、超级Mall综合体逐渐式微&#xff0c;以“健康生活”、“智能消费”“社区直达”为主的消费理念逐渐兴盛&#xff0c;消费者开始更多地关注此类…

sqli-labs-1

文章目录 Less-01Less-02Less-03Less-04 Less-01 1.输入不同的id值&#xff0c;可以获取不同的用户信息&#xff1a; 2.在sql后拼接’or11–&#xff0c;并没有获取到所有用户的信息&#xff0c;猜测可能用了limit语句 3.构造错误的sql语句&#xff0c;果然有limit报错: …

简历考察点1_《基于 VUE2.0 前后端分离的个人博客系统》

项目名称&#xff1a;《基于 Vue2.0①前后端分离的个人博客系统》 项目描述&#xff1a;提供最新技术资讯、开发知识和分享的博客平台&#xff0c;功能模块包括&#xff1a;支持不同用户登录注册、编辑并发布博客、上传图片、评论留言、根据访问量查询最热文章和标签、根据日期…

VM虚拟机逆向---[羊城杯 2021]Babyvm 复现【详解】

文章目录 前言题目分析汇编脚本分析汇编exp 后言 前言 无 题目分析 &unk_804B0C0里面是opcode&#xff0c;sub_1C8里面有个mprotect&#xff0c;用了一个SMC加密。 我使用的是动态调试&#xff0c;因为是ELF文件&#xff0c;链接一下linux&#xff0c;进行动调&#xff…

Android11修改连接WiFi后AP端显示的设备名

修改build.prop文件 1.修改 /system/build.prop 最后添加&#xff0c;xxx 为自己设置的设备名&#xff1a; net.hostnamexxx 2. 重启、重连wifi&#xff0c;从热点或路由器后台查看设备名即为修改后的名称 代码里动态配置 暴力手段&#xff1a;grep -rn “net.hostname” *…

matlab中的iddata函数的初步理解和使用程序举例

matlab中的iddata函数的初步理解和程序举例 一、iddata函数功能 iddata函数常用于系统识别分析领域数据分析方面。该函数在时域或频域中&#xff0c;将用于系统识别的输入输出数据及其特性数据的生成对象数据类型。即&#xff0c;可以使用iddata函数封装要标识的系统的输入和…

【Transformer从零开始代码实现】(一)输入部件:embedding+positionalEncoding

Transformer总架构图 输入相关组件 输入部分&#xff1a; 源文本嵌入层位置编码器目标文本嵌入层位置编码器 &#xff08;1&#xff09;Embedding 首先&#xff0c;需要对输入的内容进行向量化。 1&#xff09;先导示例 nn.Embedding示例&#xff1a; # 10代表嵌入的数…

即插即用篇 | YOLOv8 引入反向残差注意力模块 iRMB | 《ICCV 2023 最新论文》

论文地址:https://arxiv.org/abs/2301.01146 代码地址:https://github.com/zhangzjn/EMO 本论文着重于开发现代、高效、轻量级的模型,用于进行密集预测,同时在参数、FLOPs和性能之间进行权衡。倒置残差块(IRB)作为轻量级CNN的基础设施,但在基于注意力的研究中尚未找到对…

目标检测中的评价指标

目标检测中的评价指标 将检测目标分为正样本和负样本。 真阳性&#xff08;true positives , TP&#xff09; : 正样本被正确识别为正样本。 假阳性&#xff08;false positives, FP&#xff09;: 负样本被错误识别为正样本。 假阴性&#xff08;false negatives, FN&#…

技术分享 | app自动化测试(Android)-- 参数化用例

参数化是自动化测试的一种常用技巧&#xff0c;可以将测试代码中的某些输入使用参数来代替。以百度搜索功能为例&#xff0c;每次测试搜索场景&#xff0c;都需要测试不同的搜索内容&#xff0c;在这个过程里面&#xff0c;除了数据在变化&#xff0c;测试步骤都是重复的&#…

Java附件和base64相互转换

1 文件转base64 声明&#xff1a;我用的是Hutool的Base64下的api package cn.hutool.core.codec; 首先找一张图片 很简单&#xff0c;直接使用Base64的encode方法就可以拿到文件的base64码&#xff1a; File file new File("D:\\Tools\\Images\\北极熊.jpg");String…

软件测试面试题汇总,(测试技术+人力资源+进阶规划)含2023面试题和答案总结

什么是兼容性测试&#xff1f;单元测试的策略有哪些&#xff1f;当开发人员说不是BUG时&#xff0c;你如何应付&#xff1f;等&#xff0c;尾部有最新BAT的Python高级自动化工程师面试题目和答案福利&#xff0c;想要的就快来领走吧&#xff01;&#xff08;领取方式见文末&…

【机器学习3】有监督学习经典分类算法

1 支持向量机 在现实世界的机器学习领域&#xff0c; SVM涵盖了各个方面的知识&#xff0c; 也是面试题目中常见的基础模型。 SVM的分类结果仅依赖于支持向量&#xff0c;对于任意线性可分的两组点&#xff0c;它 们在SVM分类的超平面上的投影都是线性不可分的。 2逻辑回归 …

安装 MinGW

实际上是将 GCC&#xff08;C语言编译器&#xff09; 移植到了 Windows 平台下。 1、网上下载 下载安装器 mingw-get-setup.exe&#xff0c;路径https://osdn.net/projects/mingw/ 2、打开点击install 3、选择路径continue 4、文件加载完成之后选择continue 5、勾选这两个 6…

数据结构与算法之美学习笔记:17 | 跳表:为什么Redis一定要用跳表来实现有序集合?

目录 前言如何理解“跳表”&#xff1f;用跳表查询到底有多快&#xff1f;跳表是不是很浪费内存&#xff1f;高效的动态插入和删除跳表索引动态更新解答开篇内容小结 前言 本节课程思维导图&#xff1a; 二分查找底层依赖的是数组随机访问的特性&#xff0c;所以只能用数组来实…

润色论文Prompt

你好&#xff0c;我现在开始写论文了&#xff0c;我希望你可以扮演帮我润色论文的角色我写的论文是关于xxxxx领域的xxxxx&#xff0c;我希望你能帮我检查段落中语句的逻辑、语法和拼写等问题我希望你能帮我检查以下段落中语句的逻辑、语法和拼写等问题同时提供润色版本以符合学…

freeswich学习

写在前面 因为所在部分主要负责公司客服业务&#xff0c;需要了解freeswich相关内容&#xff0c;所以这里将学习内容记录下。 1&#xff1a;安装freesswich freeswich是一个实现了软交换协议的开源软件&#xff0c;可以对对接运营上的通话线路&#xff0c;实现拨打电话。 安…

编程未来规划笔记

编程思考 Python 自动化办公、深度学习、自然语言处理&#xff08;调用各种库&#xff09; Html Css 写网页 学习不要怕忘 为什么学的快、忘得快 Google、写代码、放文档 高度提炼 学什么&#xff1b;存在的意义是什么 更好的拓展性&#xff1b;可维护性 实践 原理 顶层设计…