基于卷积神经网络的交通标志识别(pytorch,opencv,yolov5)

文章目录

本文共包含两部分,
第一部分是用resnet18对交通标志分类,仅仅只是交通标志分类
文末附有yolov5和resnet18结合的源码,yolov5复制检测交通标志位置,然后使用resnet18对交通标志进行分类。

数据集介绍:

本文使用的数据集共有6000多张,共包含58个类别。部分数据集如下:



resnet18模型代码

使用pytorch自带的resnet18模型,代码如下:

python 复制代码
from torchvision import models
import torch.nn as nn

#加载resnet18模型
net=models.resnet18(weights=None)
#因为分类个数为58,所以需要修改模型最后一层全连接层
net.fc=nn.Linear(in_features=512, out_features=58, bias=True)
# print(net)

加载数据集(Dataset与Dataloader)

python 复制代码
from torch.utils.data import Dataset,DataLoader
import numpy as np
import cv2
import imgaug.augmenters as iaa
from imgaug.augmentables.segmaps import SegmentationMapsOnImage
from PIL import Image
import os
from torchvision import transforms
import torch
import random

a=[]
class Mydata(Dataset):
    def __init__(self,lines,train=True):
        super(Mydata, self).__init__()
        self.lines=lines
        random.shuffle(self.lines)
        self.train=train


    def __len__(self):
        return len(self.lines)
    def __getitem__(self, index):

        txts=self.lines[index].strip().split(';')
        src_path='pic/'+txts[0]
        w=int(txts[1])
        h=int(txts[2])
        x1=int(txts[3])
        y1=int(txts[4])
        x2=int(txts[5])
        y2=int(txts[6])

        new_x1=random.randint(0,x1)
        new_y1=random.randint(0,y1)
        new_x2=random.randint(x2,w-1)
        new_y2=random.randint(y2,h-1)

        lab=int(txts[7])
        # if lab in a:
        #     pass
        # else:a.append(lab)
        #
        # a.sort()
        # print(len(a))
        # print(a)
        img = Image.open(src_path)
        img=np.array(img)[...,:3]
        img=img[new_y1:new_y2,new_x1:new_x2]


        #数据增强
        if self.train:
            img=self.get_random_data(img)
        else:
            img = cv2.resize(img, (128, 128))
        # cv2.imshow('img',img[...,::-1])
        # cv2.waitKey(0)

        #归一化
        img=(img/255.0).astype('float32')
        img=np.transpose(img,(2,0,1))

        img=torch.from_numpy(img)
        return img,lab
    def get_random_data(self,img):
        seq = iaa.Sequential([
            # iaa.Flipud(0.5),  # flip up and down (vertical)
            # iaa.Fliplr(0.5),  # flip left and right (horizontal)
            iaa.Multiply((0.8, 1.2)),  # change brightness, doesn't affect BBs(bounding boxes)
            iaa.GaussianBlur(sigma=(0, 1.0)),  # 标准差为0到3之间的值

            iaa.Crop(percent=(0, 0.2)),
            iaa.Affine(
                translate_px={"x": (0,15), "y": (0,15)},  # 平移
                scale=(0.8, 1.2),  # 尺度变换
                rotate=(-20, 20),
                mode='constant',
                cval=(125)
                ),
            iaa.Resize(128)
        ])

        img= seq(image=img)
        return img
if __name__ == '__main__':
    lines=open('data.txt','r').readlines()
    my=Mydata(lines=lines,train=True)
    myloader=DataLoader(dataset=my,batch_size=3,shuffle=False)

    for i,j in myloader:
        print(i.shape,j.shape)

模型训练

经过60个epoch训练后,模型准确率基本上达到百分百

python 复制代码
from mymodel import net
from myDataset import Mydata
import random
from torch.utils.data import DataLoader
import torch.nn as nn
import torch.optim as optim
import torch
from tqdm import tqdm
import matplotlib.pylab as plt

batch_size=32
Epoch=60
lr=0.001

lines=open('data.txt','r').readlines()
random.shuffle(lines)
val_lines=random.sample(lines,int(len(lines)*0.1))
train_lines=list(set(lines)-set(val_lines))


train_data=Mydata(lines=train_lines)
val_data=Mydata(lines=val_lines,train=False)
train_loader=DataLoader(dataset=train_data,batch_size=batch_size,shuffle=True)
val_loader=DataLoader(dataset=val_data,batch_size=batch_size,shuffle=False)

num_train   = len(train_lines)
epoch_step  = num_train // batch_size
BCE_loss     = nn.CrossEntropyLoss()
optimizer  = optim.Adam(net.parameters(), lr=lr, betas=(0.5, 0.999))
lr_scheduler  = optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.99)
#获取学习率函数
def get_lr(optimizer):
    for param_group in optimizer.param_groups:
        return param_group['lr']
#计算准确率函数
def metric_func(pred,lab):
    _,index=torch.max(pred,dim=-1)
    acc=torch.where(index==lab,1.,0.).mean()
    return acc
device=torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
net=net.to(device)
#设置损失函数
loss_fun     = nn.CrossEntropyLoss()

if __name__ == '__main__':

    T_acc=[]
    V_acc=[]
    T_loss=[]
    V_loss=[]

    # 设置迭代次数200次
    epoch_step = num_train // batch_size
    for epoch in range(1, Epoch + 1):
        net.train()

        total_loss = 0
        loss_sum = 0.0
        train_acc_sum=0.0

        with tqdm(total=epoch_step, desc=f'Epoch {epoch}/{Epoch}', postfix=dict, mininterval=0.3) as pbar:
            for step, (features, labels) in enumerate(train_loader, 1):
                features = features.to(device)
                labels = labels.to(device)
                batch_size = labels.size()[0]

                optimizer.zero_grad()
                predictions = net(features)
                loss = loss_fun(predictions, labels)
                loss.backward()
                optimizer.step()
                total_loss += loss
                train_acc = metric_func(predictions, labels)
                train_acc_sum+=train_acc
                pbar.set_postfix(**{'loss': total_loss.item() / (step),
                                    "acc":train_acc_sum.item()/(step),
                                    'lr': get_lr(optimizer)})
                pbar.update(1)
        T_acc.append(train_acc_sum.item()/(step))
        T_loss.append(total_loss.item() / (step))
        # 验证
        net.eval()
        val_acc_sum = 0
        val_loss_sum=0
        for val_step, (features, labels) in enumerate(val_loader, 1):
            with torch.no_grad():
                features = features.to(device)
                labels = labels.to(device)
                predictions = net(features)

                val_metric = metric_func(predictions, labels)
                loss=loss_fun(predictions,labels)
            val_acc_sum += val_metric.item()
            val_loss_sum+=loss.item()
        print('val_acc=%.4f' % (val_acc_sum / val_step))
        V_acc.append(round(val_acc_sum / val_step,2))
        V_loss.append(val_loss_sum/val_step)

        # 保存模型
        if (epoch) % 2 == 0:
            torch.save(net.state_dict(), 'logs/Epoch%d-Loss%.4f_.pth' % (
                epoch, total_loss / (epoch_step + 1)))

        lr_scheduler.step()

    plt.figure()
    plt.plot(T_acc,'r')
    plt.plot(V_acc,'b')
    plt.title('Training and validation Acc')
    plt.xlabel("Epochs")
    plt.ylabel("Acc")
    plt.legend(["Train_acc", "Val_acc"])
    # plt.show()
    plt.savefig("ACC.png")

    plt.figure()
    plt.plot(T_loss, 'r')
    plt.plot(V_loss, 'b')
    plt.title('Training and validation loss')
    plt.xlabel("Epochs")
    plt.ylabel("loss")
    plt.legend(["Train_loss", "Val_loss"])

    plt.savefig("LOSS.png")
    plt.show()

训练准确率及损失函数:

准确率:

损失函数:

resnet18交通标志分类源码

(包含训练,预测代码,准确率,损失函结果图像,数据集等):

下载地址:

yolov5检测与识别(交通标志)

前面是使用resnet18网络对交通标志分类,只是单单的分类,无法从一张完整的全局图像中检测交通标志位置。对此,首先使用yolov5从全局图像中检测交通标志的位置,只是检测没有分类,然后再使用前面训练好的resnet18模型对交通标志分类。其效果如下:

相关推荐
程序猿编码4 小时前
不用GPU,不用多线程,我用C++20手写了一个Gemma 3推理引擎
pytorch·语言模型·大模型·c++20·推荐算法
AndrewHZ11 小时前
图像处理入门(第005期):颜色空间入门——RGB/HSV/CMYK/Lab
图像处理·python·opencv·hsv·rgb·色彩空间
就是一顿骚操作14 小时前
VGG:用小卷积块把 CNN 做深的经典解读
人工智能·深度学习·神经网络·cnn·论文解读
hhzz17 小时前
《深度学习框架PyTorch入门与实践》系列:09-分布式与并行训练之DataParallel、DDP与Horovod
pytorch·分布式·深度学习
极创信息1 天前
系统安全隐患全方位排查方案:标准化渗透测试全流程
java·opencv·struts·数据挖掘·eclipse·语音识别·hibernate
reset20211 天前
OpenCV 图像算法梳理分析
人工智能·opencv·算法
别动我齐刘海2 天前
机器学习基础3——C++、OpenCV、点云、Open3D
c++·人工智能·opencv·目标检测·机器学习·机器人·ros2
GoCodingInMyWay2 天前
PaddleOCR 开始
pytorch·ai·ocr
欧特克_Glodon2 天前
OpenCV计算机视觉开发入门与实践<七>:OpenCV 界面编程之窗口
c++·人工智能·opencv·计算机视觉
m0_617493942 天前
OpenCV cv2.circle() 坐标类型错误排查与修复指南
人工智能·opencv·计算机视觉