草庐IT

基于YOLOv4的车辆检测 MATLAB实现

派大星先生c 2023-06-30 原文

需要源程序的可以关注评论我 我会给大家邮箱的形式发送~

目录

摘要

研究背景

算法设计及实现过程

车辆目标数据集的构建

基于YOLOv4的目标检测

对YOLOv4模型进行改进

实验结果及分析

结论与展望

代码实现


摘要

       针对车辆检测,本文提出了一种基于YOLOv4车辆检测算法。制作了一个多天侯、多时段、多场景的车辆目标数据集,对车辆数据集进行手工标注,将其划分为训练集和测试集以便模型使用,经过DarkNet53网络框架进行训练,发现实验结果良好,可满足实际应用的需求。

研究背景

       随着经济的发展,交通拥堵问题凸显,严重影响人民生活水平的提高,构建智能化的交通监测系统对减少交通拥堵、 提高交通运输效率具有重要意义。对车辆目标进行准确、实时的检测是智能交通系统的核心,在现有车辆检测算法研究中,基于深度学习的检测算法成功引起了学者们的关注,特别是针对复杂场景中多个车辆的检测更具挑战性。

算法设计及实现过程

图1  算法设计框图

       深度学习技术主要是对输入的图像进行卷积处理,对特征进行提取并确定目标位置,其在目标识别领取有很好的成效。基于深度学习的目标识别算法主要代表算法有R-CNN、SSD、YOLO等,本文采用的是YOLOv4算法,该算法是one-stage检测中是典型代表,实时性表现良好,且检测速度较快,综合以上优点,我们最终选用它。

车辆目标数据集的构建

       我们考虑到道路上的车辆以及所处的环境均比较复杂,会影响车辆检测的正确率,所以

       我们认为构建一个合适的实时监测数据集是非常重要的。在网上收集到COCO的车辆数据集,并从中找到车辆数据集,储存之后进行图像组合和边界框的创建,框标签数据一同储存。

图2 车辆数据集

基于YOLOv4的目标检测

       YOLOv4算法是在YOLO系列先前版本的目标检测算法的基础上面优化而来且在目标识别领域中比较热门,主要采用的是CSPDarknet53作为主干特征提取网络,其中共有五个大残差块,每个大残差块中所包含的小残差单元个数为1、2、8、8、4,而SPP网络用在YOLOv4中的目的是增强网络的感受野,PANet是在上采样过程之后又加入了下采样的操作,YOLOv3作为Head,最终实现整个YOLOv4算法。

图3  YOLOv4 网络结构图

设置训练超参数如下,numEpochs = 90;miniBatchSize = 4;learningRate = 0.001;warmupPeriod = 1000;l2Regularization = 0.001;penaltyThreshold = 0.5;

采用随机梯度下降法(Stochastic Gradient Descent, SGD)。训练过程是在 YOLOv4 权重下进行微调,对其迭代100次完成训练过程。

之后运行测试集中的图像运行检测器,并收集结果,使用平均精度度量评估对象检测器,得到测试集训练后的平均精准度为86%,并保存训练模型和训练后的参数。

最后创建一个检测文件,下载预先下载好的网络,获取COCO数据集的类名和用于训练和预训练模型的anchors,然后进行检测和可视化,结果如下。

图4 检测结果1

       在我们得到结果之后,我们发现在检测过程中检测的速度较慢,在运行程序后30s左右才会出现检测结果,且后面的小型车辆在检测过程中并不能被框选并识别,不能够识别车辆视频流。我们针对发现的问题把模型进行改进。

对YOLOv4模型进行改进

       我们通过第一轮的训练之后,发现在小目标识别的准确率和检测的速度这两个地方,我们的模型会有一些缺陷。所以我们对YOLOv4模型进行优化改进。

      首先是在检测速度这方面,我们想要使YOLOv4模型轻量化来解决。CSPDarknet53是YOLOv4主干特征提取网络,轻量化该结构中两个卷积层的计算结果直接进行通道融合,再共用一BN层和激活函数,这样可以减少网络的计算量,避免这两个卷积模块都单独的计算激活值和批量归一化。使模型轻量化的同时,不会影响最终的实验结果。

       在小目标识别的过程中,我们考虑到可能是在数据集中更多的是单个车辆或者单个环境下导致的,所以我们采用数据增强的方法来进行数据扩充,数据增强是指在图片送入网络前的预处理阶段,通过对输入图片进行一些微小的改变操作如随机擦除、调整饱和度等,使得神经网络认为这是一张全新的图片达到增加数据量的效果。这样做不仅可以增大目标检测的数据量,还能够丰富数据集中检测目标的背景,减少背景被误判为检测目标的概率。 

图5 数据增强过程图

实验结果及分析

       经过我们的改进,我们在运行程序之后得到测试集的准确率为91%,20s左右即可得到检测结果,并且小型车辆也可以进行较好的识别检测,并且我们将视频按照每帧分开,同样也实现了视频流的识别。通过对模型进行训练并验证发现,改进的模型在精准度和检测速度方面比原模型都要好。

图6 检测结果2

结论与展望

       我们完成了对交通视频图片的车辆的识别,对车辆识别原理进行了分析,对车辆检测算法进行了改进,改良后的 YOLOv4 模型 的性能得到了大幅提升,车辆检测准确性较高。通过试验测试发现可以满足实时检测的要求,但是该车辆检测模型还有改进优化的空间。还可以对以下几个方面进行优化:

       用于车辆识别的图片大多为白天拍摄的,对白天车辆统计效果较好, 后续研究方向会将下雪天、雨天、夜晚等环境进行比较分析。

       我们在识别过程中发现,很多小型车辆仍有检测不到的情况,需要对模型继续进行优化,训练精度更好的模型才能避免这种情况的发生。

代码实现

clc;
clear;
close all;
warning off;
addpath(genpath(pwd));

%% 下载预训练网络
% 设置上述模型名称以下载该预训练模型。
modelName = 'YOLOv4-coco';
model = helper.downloadPretrainedYOLOv4(modelName);
net = model.net;

%% 加载数据
%解压缩车辆图像并加载车辆地面实况数据。
unzip vehicleDatasetImages.zip
data = load('vehicleDatasetGroundTruth.mat');
vehicleDataset = data.vehicleDataset;

% 将完整路径添加到本地车辆数据文件夹。
vehicleDataset.imageFilename = fullfile(pwd, vehicleDataset.imageFilename);


rng('default')
shuffledIndices = randperm(height(vehicleDataset));
idx = floor(0.6 * length(shuffledIndices));
trainingDataTbl = vehicleDataset(shuffledIndices(1:idx), :);
testDataTbl = vehicleDataset(shuffledIndices(idx+1:end), :);

% 创建用于加载图像的图像数据存储.
imdsTrain = imageDatastore(trainingDataTbl.imageFilename);
imdsTest = imageDatastore(testDataTbl.imageFilename);
 
% 为地面真相边界框创建数据存储。
bldsTrain = boxLabelDatastore(trainingDataTbl(:, 2:end));
bldsTest = boxLabelDatastore(testDataTbl(:, 2:end));

% 组合图像和框标签数据存储。
trainingData = combine(imdsTrain, bldsTrain);
testData = combine(imdsTest, bldsTest);

helper.validateInputData(trainingData);
helper.validateInputData(testData);

%% 数据扩充
augmentedTrainingData = transform(trainingData, @helper.augmentData);
 
% 增强后的图片
augmentedData = cell(4,1);
for k = 1:4
    data = read(augmentedTrainingData);
    augmentedData{k} = insertShape(data{1,1}, 'Rectangle', data{1,2});
    reset(augmentedTrainingData);
end
figure
montage(augmentedData, 'BorderSize', 10)

%% 预处理训练数据
% 指定网络输入大小。 
networkInputSize = net.Layers(1).InputSize;
 

preprocessedTrainingData = transform(augmentedTrainingData, @(data)helper.preprocessData(data, networkInputSize));
 
% 读取预处理的训练数据。
data = read(preprocessedTrainingData);

% 显示带有边界框的图像。
I = data{1,1};
bbox = data{1,2};
annotatedImage = insertShape(I, 'Rectangle', bbox);
annotatedImage = imresize(annotatedImage,2);
figure
imshow(annotatedImage)

% 重置数据存储。
reset(preprocessedTrainingData);

%% 修改预训练YOLO v4网络

rng(0)
trainingDataForEstimation = transform(trainingData, @(data)helper.preprocessData(data, networkInputSize));
numAnchors = 9;
[anchorBoxes, meanIoU] = estimateAnchorBoxes(trainingDataForEstimation, numAnchors);

% 指定培训中要使用的className。
classNames = {'vehicle'};


[lgraph, networkOutputs, anchorBoxes, anchorBoxMasks] = configureYOLOv4(net, classNames, anchorBoxes, modelName);

%% 指定超参数
numEpochs = 200;
miniBatchSize = 4;
learningRate = 0.01;
warmupPeriod = 1000;
l2Regularization = 0.001;
penaltyThreshold = 0.5;
velocity = [];

%% 训练模型
if canUseParallelPool
   dispatchInBackground = true;
else
   dispatchInBackground = false;
end

mbqTrain = minibatchqueue(preprocessedTrainingData, 2,...
        "MiniBatchSize", miniBatchSize,...
        "MiniBatchFcn", @(images, boxes, labels) helper.createBatchData(images, boxes, labels, classNames), ...
        "MiniBatchFormat", ["SSCB", ""],...
        "DispatchInBackground", dispatchInBackground,...
        "OutputCast", ["", "double"]);



% 将层图转换为dlnetwork。
net = dlnetwork(lgraph);

% 学习率和batch_size子图。
fig = figure;
[lossPlotter, learningRatePlotter] = helper.configureTrainingProgressPlotter(fig);

iteration = 0;
% 自定义训练循环。
for epoch = 1:numEpochs
      
    reset(mbqTrain);
    shuffle(mbqTrain);
    
    while(hasdata(mbqTrain))
        iteration = iteration + 1;
       
        [XTrain, YTrain] = next(mbqTrain);
        
        % 使用dlfeval和modelGradients函数评估模型梯度和损失。
        [gradients, state, lossInfo] = dlfeval(@modelGradients, net, XTrain, YTrain, anchorBoxes, anchorBoxMasks, penaltyThreshold, networkOutputs);

        % 应用L2正则化。
        gradients = dlupdate(@(g,w) g + l2Regularization*w, gradients, net.Learnables);

        % 确定当前学习率
        currentLR = helper.piecewiseLearningRateWithWarmup(iteration, epoch, learningRate, warmupPeriod, numEpochs);
        
        % 使用SGDM优化器更新网络可学习参数。
        [net, velocity] = sgdmupdate(net, gradients, velocity, currentLR);

        % 更新dlnetwork的状态参数。
        net.State = state;
        
        % 显示进度。
        if mod(iteration,10)==1
            helper.displayLossInfo(epoch, iteration, currentLR, lossInfo);
        end
            
        % 更新训练图。
        helper.updatePlots(lossPlotter, learningRatePlotter, iteration, currentLR, lossInfo.totalLoss);
    end
end

% 保存训练模型。
anchors.anchorBoxes = anchorBoxes;
anchors.anchorBoxMasks = anchorBoxMasks;

save('yolov4_trained', 'net', 'anchors');

%% 评估模型
confidenceThreshold = 0.5;
overlapThreshold = 0.5;

%创建一个表以保存返回的边界框、分数和标签检测器。
numImages = size(testDataTbl, 1);
results = table('Size', [0 3], ...
    'VariableTypes', {'cell','cell','cell'}, ...
    'VariableNames', {'Boxes','Scores','Labels'});

% 对测试集中的图像运行检测器并收集结果。
reset(testData)
while hasdata(testData)
    % 读取数据存储并获取图像。
    data = read(testData);
    image = data{1};
    
    % 运行预测器
    executionEnvironment = 'auto';
    [bboxes, scores, labels] = detectYOLOv4(net, image, anchors, classNames, executionEnvironment);
    
    % 收集结果。
    tbl = table({bboxes}, {scores}, {labels}, 'VariableNames', {'Boxes','Scores','Labels'});
    results = [results; tbl];
end

% 使用平均精度度量评估对象检测器。
[ap, recall, precision] = evaluateDetectionPrecision(results, testData);

%精确召回(PR)曲线显示了检测器在变化时的精度召回水平。理想情况下,所有召回级别的精度均为1。

% 绘制精度召回曲线。
figure
plot(recall, precision)
xlabel('Recall')
ylabel('Precision')
grid on
title(sprintf('Average Precision = %.2f', ap))

%% 使用经过训练的YOLO v4检测对象
reset(testData)
data = read(testData);

% 选取图片
I = data{1};

% 运行预测
executionEnvironment = 'auto';
[bboxes, scores, labels] = detectYOLOv4(net, I, anchors, classNames, executionEnvironment);

% 预测图片
if ~isempty(scores)
    I = insertObjectAnnotation(I, 'rectangle', bboxes, scores);
end
figure
imshow(I)

有关基于YOLOv4的车辆检测 MATLAB实现的更多相关文章

  1. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  2. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  3. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  4. Matlab imread()读到了什么 (浅显 当复习文档了) - 2

    matlab打开matlab,用最简单的imread方法读取一个图像clcclearimg_h=imread('hua.jpg');返回一个数组(矩阵),往往是a*b*cunit8类型解释一下这个三维数组的意思,行数、数和层数,unit8:指数据类型,无符号八位整形,可理解为0~2^8的数三个层数分别代表RGB三个通道图像rgb最常用的是24-位实现方法,即RGB每个通道有256色阶(2^8)。基于这样的24-位RGB模型的色彩空间可以表现256×256×256≈1670万色当imshow传入了一个二维数组,它将以灰度方式绘制;可以把图像拆分为rgb三层,可以以灰度的方式观察它figure(1

  5. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  6. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  7. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  8. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  9. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  10. ruby - Arrays Sets 和 SortedSets 在 Ruby 中是如何实现的 - 2

    通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复

随机推荐