基于python和cv2、pytorch实现的车牌定位、字符分割、字符识别项目

news2024/12/23 0:43:02

问题描述


车牌的检测和识别的应用非常广泛,比如交通违章车牌追踪,小区或地下车库门禁。在对车牌识别和检测的过程中,因为车牌往往是规整的矩形,长宽比相对固定,色调纹理相对固定,常用的方法有:基于形状、基于色调、基于纹理、基于文字特征等方法,近年来随着深度学习的发展也会使用目标检测的一些深度学习方法。

实现思路


车牌定位

车牌分割

文字识别

工程和算法


目录结构

源码和数据位于 src 文件夹中,src 文件夹中各个子文件功能如下:

  • characterData:内含有所有简体中文车牌包含的字符图片数据集(包括省份汉字、字母、数字)

  • singledigit:(请自己创建该空文件夹),用于存储提取出的单个字符图片

  • Car.jpg:示例图片,可以用来测试模型识别效果

  • getplate.py:车牌定位、字符分割源码

  • main.py:模型训练,字符识别源码

运行

  • clone 到本地

  • 在 src 文件夹下添加空文件夹,名为 singledigit

  • 先运行 getplate.py

  • 再运行 main.py,控制台输出结果

车牌定位

importmatplotlib.pyplotaspltimportnumpyasnpimporttorchimportcv2importosdeffind_card(I):# 识别出车牌区域并返回该区域的图像[y,x,z]=I.shape# y取值范围分析Blue_y=np.zeros((y,1))foriinrange(y):forjinrange(x):# 蓝色rgb范围temp=I[i,j,:]if(I[i,j,2]<=30)and(I[i,j,0]>=119):Blue_y[i][0]+=1MaxY=np.argmax(Blue_y)PY1=MaxYwhile(Blue_y[PY1,0]>=5)and(PY1>0):PY1-=1PY2=MaxYwhile(Blue_y[PY2,0]>=5)and(PY2<y-1):PY2+=1# x取值Blue_x=np.zeros((1,x))foriinrange(x):forjinrange(PY1,PY2):if(I[j,i,2]<=30)and(I[j,i,0]>=119):Blue_x[0][i]+=1PX1=0while(Blue_x[0,PX1]<3)and(PX1<x-1):PX1+=1PX2=x-1while(Blue_x[0,PX2]<3)and(PX2>PX1):PX2-=1# 对车牌区域的修正PX1-=2PX2+=2returnI[PY1:PY2,PX1-2:PX2,:]defdivide(I):[y,x,z]=I.shapeWhite_x=np.zeros((x,1))foriinrange(x):forjinrange(y):ifI[j,i,1]>176:White_x[i][0]+=1returnWhite_x

车牌分割

def divide_each_character(I):
    [y, x, z] = I.shape
    White_x = np.zeros((x, 1))
    for i in range(x):
        for j in range(y):
            if I[j, i, 1] > 176:
                White_x[i][0] += 1
    res = []
    length = 0
    for i in range(White_x.shape[0]):
        # 使用超参数经验分割
        t = I.shape[1] / 297
        num = White_x[i]
        if num > 8:
            length += 1
        elif length > 20 * t:
            res.append([i - length - 2, i + 2])
            length = 0
        else:
            length = 0
    return res

定位和分割主函数

if__name__=='__main__':I=cv2.imread('Car.jpg')Plate=find_card(I)# White_x = divide(Plate)plt.imshow(Plate)plt.show()# plt.plot(np.arange(Plate.shape[1]), White_x)res=divide_each_character(Plate)plate_save_path='./singledigit/'fortinrange(len(res)):plt.subplot(1,7,t+1)temp=res[t]save_img=cv2.cvtColor(Plate[:,temp[0]:temp[1],:],cv2.COLOR_BGR2GRAY)ma=max(save_img.shape[0],save_img.shape[1])mi=min(save_img.shape[0],save_img.shape[1])ans=np.zeros(shape=(ma,ma,3),dtype=np.uint8)start=int(ma/2-mi/2)foriinrange(mi):forjinrange(ma):ifsave_img[j,i]>125:forkinrange(3):ans[j,start+i,k]=255ans=cv2.merge([ans[:,:,0],ans[:,:,1],ans[:,:,2]])ans=cv2.resize(ans,(25,25))dir_name=plate_save_path+str(t)os.mkdir(dir_name)cv2.imwrite(dir_name+'/'+str(t)+'.jpg',ans)plt.imshow(ans)plt.show()

文字识别

from torchvision.datasets import ImageFolder
from torchvision import transforms
from torch.utils.data import DataLoader,SubsetRandomSampler
from torch import nn, optim
import numpy as np
import torch
import time
import sys
import cv2
import os

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


data_path = './characterData/data'
data_transform=transforms.Compose([
    transforms.Grayscale(),
    transforms.ToTensor()
])
dataset=ImageFolder(data_path,transform=data_transform)



validation_split=.1
shuffle_dataset = True
random_seed= 42
batch_size=100
dataset_size = len(dataset)
indices = list(range(dataset_size))
split = int(np.floor(validation_split * dataset_size))
if shuffle_dataset :
    np.random.seed(random_seed)
    np.random.shuffle(indices)
train_indices, val_indices = indices[split:], indices[:split]

train_sampler = SubsetRandomSampler(train_indices)
test_sampler = SubsetRandomSampler(val_indices)

train_iter = DataLoader(dataset, batch_size=batch_size,
                                           sampler=train_sampler)
test_iter = DataLoader(dataset, batch_size=batch_size,
                                                sampler=test_sampler)


# lenet训练
sys.path.append("..")
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(1, 6, 5), # in_channels, out_channels, kernel_size
            nn.Sigmoid(),
            nn.MaxPool2d(2, 2), # kernel_size, stride
            nn.Conv2d(6, 16, 5),
            nn.Sigmoid(),
            nn.MaxPool2d(2, 2)
        )
        self.fc = nn.Sequential(
            nn.Linear(16*4, 120),
            nn.Sigmoid(),
            nn.Linear(120, 84),
            nn.Sigmoid(),
            nn.Linear(84, 65)
        )

    def forward(self, img):
        feature = self.conv(img)
        output = self.fc(feature.view(img.shape[0], -1))
        return output

def evaluate_accuracy(data_iter, net, device=None):
    if device is None and isinstance(net, torch.nn.Module):
        # 如果没指定device就使用net的device
        device = list(net.parameters())[0].device
    acc_sum, n = 0.0, 0
    with torch.no_grad():
        for X, y in data_iter:
            if isinstance(net, torch.nn.Module):
                net.eval() # 评估模式, 这会关闭dropout
                acc_sum += (net(X.to(device)).argmax(dim=1) == y.to(device)).float().sum().cpu().item()
                net.train() # 改回训练模式
            else: # 自定义的模型, 3.13节之后不会用到, 不考虑GPU
                if('is_training' in net.__code__.co_varnames): # 如果有is_training这个参数
                    # 将is_training设置成False
                    acc_sum += (net(X, is_training=False).argmax(dim=1) == y).float().sum().item()
                else:
                    acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()
            n += y.shape[0]
    return acc_sum / n

def predict(img,net,device=None):
    if device is None and isinstance(net, torch.nn.Module):
        # 如果没指定device就使用net的device
        device = list(net.parameters())[0].device
    res=''
    with torch.no_grad():
        for X,y in img:
            if isinstance(net, torch.nn.Module):
                net.eval() # 评估模式, 这会关闭dropout
                temp=net(X.to(device)).argmax(dim=1)
                x=np.array(X)
                temp=np.array(temp).tolist()
                for i in temp:
                    res+=str(match[i])
                net.train() # 改回训练模式
    return res

# 本函数已保存在d2lzh_pytorch包中方便以后使用
def train_ch5(net, train_iter, test_iter, batch_size, optimizer, device, num_epochs):
    net = net.to(device)
    print("training on ", device)
    loss = torch.nn.CrossEntropyLoss()
    for epoch in range(num_epochs):
        train_l_sum, train_acc_sum, n, batch_count, start = 0.0, 0.0, 0, 0, time.time()
        for X, y in train_iter:
            x=np.array(X)
            Y=np.array(y)
            X = X.to(device)
            y = y.to(device)
            y_hat = net(X)
            l = loss(y_hat, y)
            optimizer.zero_grad()
            l.backward()
            optimizer.step()
            train_l_sum += l.cpu().item()
            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()
            n += y.shape[0]
            batch_count += 1
        test_acc = evaluate_accuracy(test_iter, net)
        print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f, time %.1f sec'
              % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n, test_acc, time.time() - start))


net = LeNet()
print(net)
lr, num_epochs = 0.001, 40
batch_size=256
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
checkpoint_save_path = "./LeNet5.pth"
if os.path.exists(checkpoint_save_path ):
    print('load the model')
    net.load_state_dict(torch.load(checkpoint_save_path))
else:
    train_ch5(net, train_iter, test_iter, batch_size, optimizer, device, num_epochs)
    torch.save(net.state_dict(),checkpoint_save_path)

# 识别车牌内容
# plate_paths=os.listdir('./singledigit')
# ans=''
# for plate in plate_paths:
#     #ans+=predict(cv2.imread(plate),net)
#     img=cv2.imread('./singledigit/'+plate)
#     img2=np.zeros(shape=(3,20,20),dtype=torch.float32)
# 
#     a=net(torch.from_numpy(img))
# print(ans)

pre_path = './singledigit'
pre_transform=transforms.Compose([
    transforms.Grayscale(),
    transforms.CenterCrop(size=(20,20)),
    transforms.ToTensor()
])
preset=ImageFolder(pre_path,transform=pre_transform)
pre_iter = DataLoader(preset)
ans=predict(pre_iter,net)
print(ans)

实现效果

runfile('E:/大数据分析方法/workspace/week1/数字图像处理/test05.py', wdir='E:/大数据分析方法/workspace/week1/数字图像处理')

LeNet(
  (conv): Sequential(
    (0): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
    (1): Sigmoid()
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (3): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
    (4): Sigmoid()
    (5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (fc): Sequential(
    (0): Linear(in_features=64, out_features=120, bias=True)
    (1): Sigmoid()
    (2): Linear(in_features=120, out_features=84, bias=True)
    (3): Sigmoid()
    (4): Linear(in_features=84, out_features=65, bias=True)
  )
)

training on  cpu

epoch 1, loss 3.7474, train acc 0.069, test acc 0.074, time 75.7 sec
epoch 2, loss 3.7088, train acc 0.071, test acc 0.074, time 7.4 sec
epoch 3, loss 3.3383, train acc 0.194, test acc 0.358, time 7.2 sec
epoch 4, loss 2.4473, train acc 0.420, test acc 0.473, time 7.0 sec
epoch 5, loss 1.9042, train acc 0.488, test acc 0.565, time 7.0 sec
epoch 6, loss 1.5477, train acc 0.583, test acc 0.639, time 7.1 sec
epoch 7, loss 1.3139, train acc 0.656, test acc 0.698, time 6.8 sec
epoch 8, loss 1.1450, train acc 0.705, test acc 0.737, time 8.0 sec
epoch 9, loss 1.0151, train acc 0.743, test acc 0.770, time 7.6 sec
epoch 10, loss 0.9199, train acc 0.769, test acc 0.788, time 7.2 sec
epoch 11, loss 0.8415, train acc 0.789, test acc 0.804, time 7.2 sec
epoch 12, loss 0.7789, train acc 0.804, test acc 0.817, time 7.4 sec
epoch 13, loss 0.7240, train acc 0.817, test acc 0.830, time 7.4 sec
epoch 14, loss 0.6803, train acc 0.825, test acc 0.834, time 7.2 sec
epoch 15, loss 0.6408, train acc 0.833, test acc 0.838, time 7.2 sec
epoch 16, loss 0.6064, train acc 0.838, test acc 0.845, time 7.5 sec
epoch 17, loss 0.5785, train acc 0.842, test acc 0.854, time 7.3 sec
epoch 18, loss 0.5502, train acc 0.850, test acc 0.856, time 7.4 sec
epoch 19, loss 0.5278, train acc 0.855, test acc 0.857, time 7.3 sec
epoch 20, loss 0.5028, train acc 0.860, test acc 0.875, time 7.2 sec
epoch 21, loss 0.4820, train acc 0.867, test acc 0.877, time 7.3 sec
epoch 22, loss 0.4622, train acc 0.872, test acc 0.883, time 7.4 sec
epoch 23, loss 0.4424, train acc 0.877, test acc 0.885, time 7.4 sec
epoch 24, loss 0.4264, train acc 0.882, test acc 0.881, time 7.5 sec
epoch 25, loss 0.4106, train acc 0.885, test acc 0.890, time 7.3 sec
epoch 26, loss 0.3957, train acc 0.888, test acc 0.893, time 7.3 sec
epoch 27, loss 0.3803, train acc 0.894, test acc 0.900, time 8.3 sec
epoch 28, loss 0.3695, train acc 0.897, test acc 0.900, time 8.3 sec
epoch 29, loss 0.3538, train acc 0.903, test acc 0.903, time 7.9 sec
epoch 30, loss 0.3421, train acc 0.906, test acc 0.907, time 8.1 sec

预测结果为:苏E05EV8

改进方向


1、车牌定位仅使用了颜色特征

2、车牌分割仅使用了 x 轴投影波峰波谷

3、卷积神经网络准确率有待提高

完整代码:

https://download.csdn.net/download/qq_38735017/87381154

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

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

相关文章

linux C -- 内存管理

链接: linux C学习目录 linux C 共享内存机制共享内存物理位置shared memory常用函数编程模型范例write.cread.c修改参数实验共享内存 二个或者多个进程,共享同一块由系统内核负责维护的内部内存区域其地址空间通常被映射到堆和栈之间无需复制信息,最快的一种IPC机制需要考虑同…

web应用 —— HTML

web应用 一、HTML 1.插件 1.Live Server 模拟网站服务器 2.Auto Rename Tag 自动修改标签对 3.设置settings-format-勾选Format On Save &#xff08;创建文件&#xff1a;File-Open Folder-新建文件夹-命名文件&#xff09; 2.html文档结构 html所有标签为树形结构&…

基于YOLOv5+C3CBAM+CBAM注意力的海底生物[海参、海胆、扇贝、海星]检测识别分析系统

在我前面的一些文章中也有用到过很多次注意力的集成来提升原生检测模型的性能&#xff0c;这里同样是加入了注意力机制&#xff0c;区别在于&#xff0c;这里同时在两处加入了注意力机制&#xff0c;第一处是讲CBAM集成进入原生的C3模块中&#xff0c;在特征提取部分就可以发挥…

Microsoft系统漏洞修复

近期收到服务器系统漏洞扫描&#xff0c;发现很多关于Microsoft本身的系统漏洞。 有很多新手不知道怎么去修复系统漏洞&#xff0c;害怕一旦修复出问题&#xff0c;自己要担责。 我这里讲解下怎么准备的去寻找漏洞&#xff0c;并把它修复的过程。 我已下列的漏洞为例&#x…

RK3588平台开发系列讲解(日志篇)syslog介绍

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、syslog介绍二、syslog的架构三、syslog日志组成四、syslog接口说明1、openlog2、syslog3、closelog五、syslog.conf接口说明1、selector2、level3、action4、示例沉淀、分享、成长,让自己和他人都能有所收获!&am…

计算机网络第三章

目录 1.数据链路层 1.数据链路层的基本概述 2.数据链路层的功能概述 3.封装成帧 4.差错控制 1.检错编码 2.纠错编码 5.流量控制 1.停止-等待协议 2.选择重传协议(SR) 3.后退N帧协议(GBN) 6.介质访问控制 1.静态划分信道(信道划分介质访问控制) 2.动态分配信道 7.局域网 8.链路…

【经验分享】美赛报名以及注册方法-以2023年美赛为例

首先点击COMAP的官网链接&#xff1a; https://www.comap.com/ 然后选择Contests目录下的MCM/ICM 选择 Learn More and Register 然后选择 Click here to register for the 2023 MCM/ICM contest 注册分为两个步骤&#xff1a;顾问&#xff08;指导教师&#xff09;注册和填…

uni-app中自定义TabBar

1.由于原生的tabBar不能做到事件的拦截处理所以才自定义 注意点&#xff1a;自定义tabBar后则原生的uni.switchTab(OBJECT)不能再使用了 第一步&#xff1a;需要把原生的tabBar注释掉 第二步&#xff1a;在components下新建TabBar.vue文件&#xff08;那个页面用那个页面引入…

RHCE-Web服务器在linux上的部署,了解hash算法以及常见的加密方式

目录 1.WEB服务器&#xff08;Web Server&#xff09; 浏览器 工作原理 常见状态码&#xff1a; www服务器的基本配置 2.web服务配置样例 3.了解hash算法以及常见的加密方式 hash算法&#xff1a; 常用HASH函数 处理冲突方法 常用hash算法的介绍&#xff1a; ssh协议…

Composition步骤

纲要&#xff1a; SWC属于AUTOSAR的Component文件夹下&#xff0c;而Composition属于Composition文件夹下。 AUTOSAR Project Structure Sample目录 1. Create Software Composition 2. Add SWC into Composition 3. Create AssemblyConnector between SWCs 1. Create Sof…

优化SpringBoot程序启动速度

Spring Boot 程序优化 一、延迟初始化Bean 一般在 SpringBoot 中都拥有很多的耗时任务&#xff0c;比如数据库建立连接、初始线程池的创建等等&#xff0c;我们可以延迟这些操作的初始化&#xff0c;来达到优化启动速度的目的。Spring Boot 2.2 版本后引入 spring.main.lazy-i…

【大数据hadoop】基于centos7搭建haoop与hive

一、前言 hadoop是大数据生态中的基础服务&#xff0c;也是其他大数据框架的基础运行环境&#xff0c;尤其是hdfs&#xff0c;是其他大数据框架的基础存储载体&#xff0c;因此系统学习和掌握hadoop对学习大数据很有必要&#xff1b; 而Hive则是Hadop生态系统中必不可少的一个数…

分布式任务介绍

分布式任务解决方案 Elastic-Job介绍 官网&#xff1a;http://elasticjob.io/index_zh.html 由当当网基于Quartz Zookeeper的二次开放产品 基于Zookeeper分布式锁&#xff0c;保证只有一个服务去执行定时任务。 基于Zookeeper实现了注册中心&#xff0c;自动帮助我们去调度指…

pgCluu 的安装、使用与实践

文章目录前言一、什么是 pgCluu二、pgCluu的安装流程静态模式动态模式三、pgCluu的用法pgCluu 用法pgCluu_collectd 用法&#xff1a;四、pgCluu的实操分享实操示例一&#xff1a;实操示例二&#xff1a;前言 PostgreSQL 的监控方法很多&#xff0c;数量越来越多的 PG 的监控再…

MFC输出普朗克常数

在量子力学中可以计算德布罗意波长&#xff0c;其公式如下&#xff1b; 德布罗意波长 h / (质量 * 速度&#xff09;&#xff1b; 其中h是普朗克常数&#xff1b; 先看一下普朗克常数&#xff1b;6.62 乘以10的负34次方&#xff1b; 输出一下此常数看一下&#xff1b; #de…

SpringCloud之Spring Cloud Config 分布式配置

Spring Cloud Config 分布式配置1. 分布式系统面临的配置文件问题2. Spring Cloud Config 分布式配置中心的概念3. Spring Cloud Config 分布式配置中心的作用4. Spring Cloud Config 分布式配置中心和 GitHub 整合5. 小案例Dalston.RELEASE Spring Cloud Config 为分布式系统…

Web3中文|Web3注定会成为元宇宙的一部分

“Web3”和“元宇宙”或许是2022年最热门的流行语了。在营销行话中、在广告中、在新闻报道中&#xff0c;Web3和元宇宙这两个概念总是被捆绑在一起。 但不得不说&#xff0c;二者经常被混为一谈是有原因的。因为它们都是定义模糊的新技术&#xff0c;都被认为是互联网的未来&a…

20230112在Ubuntu下看笔记本电脑电池的电量

20230112在Ubuntu下看笔记本电脑电池的电量 2023/1/12 17:24 ubuntu20.04 Xshell 7 (Build 0108) Copyright (c) 2020 NetSarang Computer, Inc. All rights reserved. Type help to learn how to use Xshell prompt. [C:\~]$ Connecting to 192.168.186.228:22... Connecti…

知物由学 | 多级建模方法提升汉语语音识别效果,获ISCSLP大赛认可

导读&#xff1a;语音是人类信息沟通的重要途径&#xff0c;同时也是人机交互的重要桥梁&#xff0c;自动语音识别可以表述为通过计算机将人类语音信号转录为书面形式的文字输出的过程。本文分享了网易易盾提出的多级建模单元的端到端汉语语音识别方法及具体的落地实践。 1.语…

什么是虹科weeve边缘计算软件平台?

一、前言 随着越来越多的企业希望进入物联网领域&#xff0c;他们在构建和部署物联网项目时面临着前所未有的挑战。根据思科的一项调查表明&#xff0c;超过60&#xff05;的受访者承认他们严重低估了管理自己的物联网计划的复杂性。更令人震惊的是&#xff0c;同一调查还发现…