1.研究背景与意义
项目参考AAAI Association for the Advancement of Artificial Intelligence
研究背景与意义
随着城市化进程的加快和汽车拥有量的不断增加,停车位的需求量也在不断增加。然而,停车位的有限性和分布不均匀性给城市居民的停车带来了很大的困扰。为了解决这一问题,许多城市已经开始使用停车位实时检测系统,以提供准确的停车位信息和推荐合适的停车位给驾驶员。
然而,传统的停车位实时检测系统存在一些问题。首先,传统的检测算法通常需要大量的计算资源和时间,导致实时性不足。其次,传统的检测算法对于遮挡、光照变化等复杂场景的适应性较差,导致检测结果的准确性不高。此外,传统的检测算法对于小尺寸的停车位检测效果较差,无法满足实际需求。
为了解决这些问题,本研究提出了一种基于RegNet-Backbone改进YOLOv5的停车位实时检测推荐系统。RegNet-Backbone是一种轻量级的神经网络模型,具有较高的计算效率和较低的模型大小。YOLOv5是一种流行的目标检测算法,具有较高的检测速度和较好的检测精度。通过将RegNet-Backbone与YOLOv5相结合,我们可以在保证实时性的同时提高检测的准确性和适应性。
本研究的主要目标是设计和实现一个高效准确的停车位实时检测推荐系统,以提供准确的停车位信息和推荐合适的停车位给驾驶员。具体来说,本研究的主要研究内容包括以下几个方面:
首先,我们将研究RegNet-Backbone在停车位检测任务中的适应性和性能。通过对RegNet-Backbone进行优化和改进,我们可以提高其在停车位检测任务中的准确性和实时性。
其次,我们将研究如何将RegNet-Backbone与YOLOv5相结合,以进一步提高停车位检测的准确性和实时性。通过将RegNet-Backbone作为YOLOv5的骨干网络,我们可以充分利用RegNet-Backbone的计算效率和模型大小优势,同时保持YOLOv5的检测速度和精度。
最后,我们将设计和实现一个完整的停车位实时检测推荐系统,并进行实验评估。通过大量的实验和对比分析,我们可以验证所提出的系统在准确性、实时性和适应性方面的优势,并为实际应用提供可行的解决方案。
本研究的意义主要体现在以下几个方面:
首先,本研究提出的基于RegNet-Backbone改进YOLOv5的停车位实时检测推荐系统可以提供准确的停车位信息和推荐合适的停车位给驾驶员,从而提高停车位的利用率和停车效率,减少城市交通拥堵和环境污染。
其次,本研究所提出的RegNet-Backbone在停车位检测任务中的适应性和性能研究可以为其他相关领域的研究提供借鉴和参考,如交通管理、智能城市等。
最后,本研究所设计和实现的停车位实时检测推荐系统可以为停车位管理部门和驾驶员提供实用的工具和解决方案,为城市停车管理和交通规划提供科学依据和决策支持。
综上所述,本研究的背景和意义在于通过基于RegNet-Backbone改进YOLOv5的停车位实时检测推荐系统,提高停车位检测的准确性、实时性和适应性,从而提高停车位的利用率和停车效率,减少城市交通拥堵和环境污染,为城市停车管理和交通规划提供科学依据和决策支持。
2.图片演示
3.视频演示
基于RegNet-Backbone改进YOLOv5的停车位实时检测推荐系统_哔哩哔哩_bilibili
4.数据集的采集&标注和整理
图片的收集
首先,我们需要收集所需的图片。这可以通过不同的方式来实现,例如使用现有的公开数据集TrafficDatasets。
labelImg是一个图形化的图像注释工具,支持VOC和YOLO格式。以下是使用labelImg将图片标注为VOC格式的步骤:
(1)下载并安装labelImg。
(2)打开labelImg并选择“Open Dir”来选择你的图片目录。
(3)为你的目标对象设置标签名称。
(4)在图片上绘制矩形框,选择对应的标签。
(5)保存标注信息,这将在图片目录下生成一个与图片同名的XML文件。
(6)重复此过程,直到所有的图片都标注完毕。
由于YOLO使用的是txt格式的标注,我们需要将VOC格式转换为YOLO格式。可以使用各种转换工具或脚本来实现。
下面是一个简单的方法是使用Python脚本,该脚本读取XML文件,然后将其转换为YOLO所需的txt格式。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import os
classes = [] # 初始化为空列表
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
def convert(size, box):
dw = 1. / size[0]
dh = 1. / size[1]
x = (box[0] + box[1]) / 2.0
y = (box[2] + box[3]) / 2.0
w = box[1] - box[0]
h = box[3] - box[2]
x = x * dw
w = w * dw
y = y * dh
h = h * dh
return (x, y, w, h)
def convert_annotation(image_id):
in_file = open('./label_xml\%s.xml' % (image_id), encoding='UTF-8')
out_file = open('./label_txt\%s.txt' % (image_id), 'w') # 生成txt格式文件
tree = ET.parse(in_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
cls = obj.find('name').text
if cls not in classes:
classes.append(cls) # 如果类别不存在,添加到classes列表中
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox')
b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
float(xmlbox.find('ymax').text))
bb = convert((w, h), b)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
xml_path = os.path.join(CURRENT_DIR, './label_xml/')
# xml list
img_xmls = os.listdir(xml_path)
for img_xml in img_xmls:
label_name = img_xml.split('.')[0]
print(label_name)
convert_annotation(label_name)
print("Classes:") # 打印最终的classes列表
print(classes) # 打印最终的classes列表
整理数据文件夹结构
我们需要将数据集整理为以下结构:
-----data
|-----train
| |-----images
| |-----labels
|
|-----valid
| |-----images
| |-----labels
|
|-----test
|-----images
|-----labels
确保以下几点:
所有的训练图片都位于data/train/images目录下,相应的标注文件位于data/train/labels目录下。
所有的验证图片都位于data/valid/images目录下,相应的标注文件位于data/valid/labels目录下。
所有的测试图片都位于data/test/images目录下,相应的标注文件位于data/test/labels目录下。
这样的结构使得数据的管理和模型的训练、验证和测试变得非常方便。
模型训练
Epoch gpu_mem box obj cls labels img_size
1/200 20.8G 0.01576 0.01955 0.007536 22 1280: 100%|██████████| 849/849 [14:42<00:00, 1.04s/it]
Class Images Labels P R mAP@.5 mAP@.5:.95: 100%|██████████| 213/213 [01:14<00:00, 2.87it/s]
all 3395 17314 0.994 0.957 0.0957 0.0843
Epoch gpu_mem box obj cls labels img_size
2/200 20.8G 0.01578 0.01923 0.007006 22 1280: 100%|██████████| 849/849 [14:44<00:00, 1.04s/it]
Class Images Labels P R mAP@.5 mAP@.5:.95: 100%|██████████| 213/213 [01:12<00:00, 2.95it/s]
all 3395 17314 0.996 0.956 0.0957 0.0845
Epoch gpu_mem box obj cls labels img_size
3/200 20.8G 0.01561 0.0191 0.006895 27 1280: 100%|██████████| 849/849 [10:56<00:00, 1.29it/s]
Class Images Labels P R mAP@.5 mAP@.5:.95: 100%|███████ | 187/213 [00:52<00:00, 4.04it/s]
all 3395 17314 0.996 0.957 0.0957 0.0845
5.核心代码讲解
5.1 anynet.py
class AnyNetX(nn.Module):
def __init__(self, ls_num_blocks, ls_block_width, ls_bottleneck_ratio, ls_group_width, stride, se_ratio):
super(AnyNetX, self).__init__()
# For each stage, at each layer, number of channels (block width / bottleneck ratio) must be divisible by group width
for block_width, bottleneck_ratio, group_width in zip(ls_block_width, ls_bottleneck_ratio, ls_group_width):
assert block_width % (bottleneck_ratio * group_width) == 0
self.net = nn.Sequential()
prev_block_width = 32
self.net.add_module("stem", Stem(prev_block_width))
for i, (num_blocks, block_width, bottleneck_ratio, group_width) in enumerate(zip(ls_num_blocks, ls_block_width,
ls_bottleneck_ratio,
ls_group_width)):
self.net.add_module("stage_{}".format(i),
Stage(num_blocks, prev_block_width, block_width, bottleneck_ratio, group_width, stride, se_ratio))
prev_block_width = block_width
self.net.add_module("head", Head(ls_block_width[-1], NUM_CLASSES))
self.initialize_weight()
def initialize_weight(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
fan_out = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
m.weight.data.normal_(mean=0.0, std=sqrt(2.0 / fan_out))
elif isinstance(m, nn.BatchNorm2d):
m.weight.data.fill_(1.0)
m.bias.data.zero_()
elif isinstance(m, nn.Linear):
m.weight.data.normal_(mean=0.0, std=0.01)
m.bias.data.zero_()
def forward(self, x):
x = self.net(x)
return x
该工程中的程序文件是anynet.py
,该文件实现了一个名为AnyNet的神经网络模型。
AnyNetX类继承自nn.Module类,它是AnyNet模型的基础版本。构造函数__init__
接受一系列参数,包括ls_num_blocks(每个阶段的块数)、ls_block_width(每个块的宽度)、ls_bottleneck_ratio(瓶颈比例)、ls_group_width(组宽度)、stride(步幅)和se_ratio(SE模块的比例)。在构造函数中,首先对ls_block_width、ls_bottleneck_ratio和ls_group_width进行了一些断言,确保它们满足一定的条件。然后通过调用Stem、Stage和Head模块的构造函数,构建了整个网络结构。最后调用initialize_weight函数,对网络的权重进行初始化。for