相关文章
项目地址:YOLOv1 VOC 2007
笔者训练的权重地址:阿里云盘分享
10 秒文章速览
本文针对讲解 PASCAL VOC 2007 数据集的结构、信息进行了粗略说明,并演示了数据集加载
PASCAL VOC 项目传送门:The PASCAL Visual Object Classes Homepage
这里,笔者也给出自己整理的 PASCAL VOC 2007 数据集的下载地址:Kaggle-PASCAL VOC 2007
本文讲的数据集针对 PASCAL VOC 2007
数据集介绍
数据集是从现实场景中采集的图片,一共包含20个类别
- 人:人🧔
- 动物:鸟🦜、猫🐈、牛🐄、狗🐕、马🐎、羊🐏
- 车辆:飞机✈️、自行车🚲、船🚢、公共汽车🚌、汽车🚗、摩托车🏍️、火车🚂
- 室内:瓶子🍾、椅子🪑、餐桌、盆栽🪴、沙发🛋️、电视/显示器📺
数据集可以用于主要可以用于检测、分割这2项任务
目标检测
目标分割
数据集文件结构
PASCAL VOC 2007 的训练、验证集文件结构如下
- VOC 2007
- Annotations:放置每张图片的标注,储存为XML格式
- ImageSets
- Layout:train.txt 训练集、val.txt 验证集、trainval.txt 训练验证汇总集
- Main:对各个类别的训练集、验证集分开放置
- Segmentation:放置用于分割任务的数据集
- JPEGImages:放置所有图片
- SegmentationClass:按类别进行图像分割,同一类别的物体会被标注为相同颜色
- SegmentationObject:按对象进行图像分割,即使是同一类别也会被标注为不同颜色
XML 文件
xml文件的内容如下,标注了一张图片中目标的边框、类别等信息
xml
<annotation>
<folder>VOC2007</folder>
<filename>000005.jpg</filename>
<source>
<database>The VOC2007 Database</database>
<annotation>PASCAL VOC2007</annotation>
<image>flickr</image>
<flickrid>325991873</flickrid>
</source>
<owner>
<flickrid>archintent louisville</flickrid>
<name>?</name>
</owner>
<size>
<width>500</width>
<height>375</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>chair</name>
<pose>Rear</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>263</xmin>
<ymin>211</ymin>
<xmax>324</xmax>
<ymax>339</ymax>
</bndbox>
</object>
</annotation>
<filename>
标注了图片名称,在 <size>
中标注了图片的宽(<width>
)、高(<height>
)、通道数(<depth>
)。在 <object>
中标注了目标的名称(<name>
)、边框(<bndbox>
)等信息
读取 XML
在了解了数据集、XML文件之后,就可以正式进入代码💻阶段咯~
下面的代码中,定义了 PASCAL VOC 2007 数据集的类别与 load_data
,load_data
函数能够返回图片的路径与生成图片相对应的标签
python
import os
import tensorflow as tf
from xml.etree import ElementTree as ET
# 文件路径
path_JPEGImages = 'VOCdevkit/VOC2007/JPEGImages'
path_Annotations = 'VOCdevkit/VOC2007/Annotations'
path_ImageSets_Layout_trainval = 'VOCdevkit/VOC2007/ImageSets/Layout/trainval.txt'
# 类别
classes = {'aeroplane': {'code': 0, 'name': 'aeroplane', 'color': (255, 0, 0)},
'bicycle': {'code': 1, 'name': 'bicycle', 'color': (0, 255, 0)},
'bird': {'code': 2, 'name': 'bird', 'color': (0, 0, 255)},
'boat': {'code': 3, 'name': 'boat', 'color': (255, 0, 255)},
'bottle': {'code': 4, 'name': 'bottle', 'color': (0, 255, 255)},
'bus': {'code': 5, 'name': 'bus', 'color': (255, 165, 0)},
'car': {'code': 6, 'name': 'car', 'color': (0, 255, 165)},
'cat': {'code': 7, 'name': 'cat', 'color': (255, 0, 165)},
'chair': {'code': 8, 'name': 'chair', 'color': (0, 255, 0)},
'cow': {'code': 9, 'name': 'cow', 'color': (255, 210, 0)},
'diningtable': {'code': 10, 'name': 'diningtable', 'color': (0, 0, 210)},
'dog': {'code': 11, 'name': 'dog', 'color': (255, 0, 80)},
'horse': {'code': 12, 'name': 'horse', 'color': (0, 80, 255)},
'motorbike': {'code': 13, 'name': 'motorbike', 'color': (255, 80, 0)},
'person': {'code': 14, 'name': 'person', 'color': (0, 255, 80)},
'pottedplant': {'code': 15, 'name': 'pottedplant', 'color': (255, 165, 80)},
'sheep': {'code': 16, 'name': 'sheep', 'color': (80, 0, 255)},
'sofa': {'code': 17, 'name': 'sofa', 'color': (80, 255, 80)},
'train': {'code': 18, 'name': 'train', 'color': (0, 165, 255)},
'tvmonitor': {'code': 19, 'name': 'tvmonitor', 'color': (255, 220, 0)}}
classes_name = list(classes.keys())
def load_data(path):
# 读取训练集验证集汇合文件
with open(path, 'r') as f:
file_set = f.readlines()
file_set = map(lambda x: x.strip(), file_set)
# 保存图片路径
path_set = []
# 保存标签
label_set = []
for file in file_set:
# 创建一个"空"的标签
label = np.zeros((7, 7, 25), dtype='float32')
# 图片路径放入路径集
path_set.append(os.path.join(path_JPEGImages, file + '.jpg'))
# 获取 xml 标签文件的跟路径
root = ET.parse(os.path.join(path_Annotations, file + '.xml')).getroot()
width = int(root.find('size').findtext('width')) # 获取目标的宽度
height = int(root.find('size').findtext('height')) # 获取图片的高度
# 获取一个网格的宽高
w_grid = width/7
h_grid = height/7
# 遍历所有 object 标签
for object_label in root.iter('object'):
cls = classes[object_label.findtext('name')]['code'] # 获取目标的类别
xmin = int(object_label.find('bndbox').findtext('xmin')) # 获取目标的 xmin
ymin = int(object_label.find('bndbox').findtext('ymin')) # 获取目标的 ymin
xmax = int(object_label.find('bndbox').findtext('xmax')) # 获取目标的 xmax
ymax = int(object_label.find('bndbox').findtext('ymax')) # 获取目标的 ymax
x_center = (xmin + xmax) / 2 # 获取目标中心点 x
y_center = (ymin + ymax) / 2 # 获取目标中心点 y
x_idx = int(x_center / w_grid) # 将图片分成 7x7 个区域,获取 x 方向上的索引
y_idx = int(y_center / h_grid) # 将图片分成 7x7 个区域,获取 y 方向上的索引
x = (x_center - x_idx * w_grid) / w_grid # 获取在 (x_idx,y_idx) 区域的中心点 x,并归一化
y = (y_center - y_idx * h_grid) / h_grid # 获取在 (x_idx,y_idx) 区域的中心点 y,并归一化
w = (xmax - xmin) / width # 获取图像长度,并归一化
h = (ymax - ymin) / height # 获取图像宽度,并归一化
# 设置标签
label[y_idx, x_idx, cls] = 1 # 设置类别
label[y_idx, x_idx, 20:25] = [x, y, w, h, 1] # 设置 (x, y, w, h, confidence)
# 标签放入标签集
label_set.append(label)
return path_set, label_set
创建训练集
在上文中,我们已经能够获取图片路径和标签了。接下来,我们需要读取图片信息,并创建训练集
python
# 读取图片
def load_img(path, bbox):
img = tf.io.read_file(path)
img = tf.io.decode_jpeg(img, channels=3)
img = tf.image.resize(img, (448, 448)) / 255
return img, bbox
# 获取图片路径、标签
path_set, label_set = load_data(path_ImageSets_Layout_trainval)
# 创建数据集
data_set = tf.data.Dataset.from_tensor_slices((path_set, label_set))
data_set = data_set.map(load_img) # 读取图片
data_set_num = len(data_set)
train_set_num = int(data_set_num * 0.8)
# 创建训练集
train_set = data_set.take(train_set_num) # 取 80% 作为训练集
train_set = train_set.shuffle(1000) # 打乱训练集
train_set = train_set.batch(16) # batch size 设置为 16
# 读取验证集数据
valid_set = data_set.skip(train_set_num) # 取 20% 作为验证集
valid_set = [i for i in valid_set]
至此,对于数据集方面的内容,结束。还需翻过设计损失函数与模型构建与训练这三座大山⛰️,方可修成正果😇