PASCAL VOC2012数据集
下载的官方网址:http://host.robots.ox.ac.uk/pascal/voc/voc2012/index.html#devkit
一、介绍与下载
PASCAL VOC 挑战赛(The PASCAL Visual Object Classes)是一个世界级的计算机视觉挑战赛。PASCAL全称Pattern Analysis, Statistical modelling and Computational Learning(模式分析、统计建模和计算学习),是一个由欧盟资助的网络组织。PASCAL VOC挑战赛主要包括下面几类:
图像分类(Object Classification)
目标检测(Object Detection)
目标分割(Object Segmentation)
动作识别(Action Classification)
etc
找到Development Kit即可进行下载
一共有20个类别
二、下载数据集的文件结构及详解
1.Annotation
随便打开一个annotation文件:
<annotation> # 主节点
<folder>VOC2012</folder> # 文件夹名字
<filename>2007_000187.jpg</filename> # 图片名称
<source> # 源
<database>The VOC2007 Database</database> # 来自VOC 2007
<annotation>PASCAL VOC2007</annotation> # 标注信息来源 VOC 2007
<image>flickr</image> # 来自网络分享
</source>
<size> # 图片大小节点
<width>500</width> # 宽度
<height>375</height> # 高度
<depth>3</depth> # 深度(通道数)
</size>
<segmented>1</segmented> # 该节点:该图片有没有被分割过(1和0)
<object> # 目标检测节点(可以有多个检测目标)
<name>tvmonitor</name> # 目标所属类别
<pose>Frontal</pose> # 用不到
<truncated>1</truncated> # 目标有没有被截断(如果目标在图片的边界,那么就是被截断的状态)
<difficult>0</difficult> # 目标检测的难易程度(0:容易检测; 1:难以检测)
<bndbox> # bounding box
<xmin>1</xmin> # 左上角x坐标
<ymin>95</ymin> # 左上角y坐标
<xmax>240</xmax> # 右下角x坐标
<ymax>336</ymax> # 右下角y坐标
</bndbox>
</object>
<object> # 第二个检测目标
<name>person</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>137</xmin>
<ymin>78</ymin>
<xmax>497</xmax>
<ymax>375</ymax>
</bndbox>
</object>
<object> # 三个检测目标
<name>person</name>
<pose>Unspecified</pose>
<truncated>1</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>89</xmin>
<ymin>202</ymin>
<xmax>129</xmax>
<ymax>247</ymax>
</bndbox>
</annotation>
flickr 网络 相片分享;
truncated 英[trʌŋˈkeɪtɪd] 美[ˈtrʌŋkeɪtɪd] adj. (版本)缩减的,删节的,截短了的; v. 截短,缩短,删节(尤指掐头或去尾);
一张图片中可以有多个检测目标
2.train.txt
和val.txt
对于目标检测任务,我们主要关注ImageSets\Main
下的train.txt
、val.txt
和trainval.txt
这三个文件。
下面是train.txt
和val.txt
的部分内容展示(trainval.txt
也是下面的样式):
每一行代表图像名称
2008_000008
2008_000015
2008_000019
2008_000023
2008_000028
2008_000033
2008_000036
2008_000037
2008_000041
...
train.txt
和val.txt
包含了训练时图片的名称和验证时图片的名称。
3.trainval.txt
trainval.txt文件包含了训练使用的训练集和验证集。
总所周知,训练集和验证集是互斥的,那么为什么会有 trainval.txt这个文件呢?
因为我们得到结果可以去PASCAL官网进行测试,而PASCAL VOC 2012的测试集是不公开的,所以官方需要知道你在训练时使用了哪些文件,这时我们就需要提交这个文件以此在测试时可以剔除掉我们训练用过的文件。
4.boat_train.txt表示船的训练集
2008_000143 -1
2008_000144 -1
2008_000148 1
2008_000151 -1
2008_000187 -1
2008_000188 -1
2008_000189 -1
2008_000191 0
2008_000192 -1
2008_000193 -1
这个文件中,除了图片的名称外,还有一列,包含三个数-1,0,1,分别表示:
-1
:图片中没有boat这个目标0
:包含boat目标,但该目标检测很困难1
:图片中有boat这个目标
5.文件使用流程
- 先读取
ImageSets/Main
的train.txt
,获取它的每一行信息(每一张图片的名称) - 得到图片名称后,去
Annotation
找到对应的.xml
文件并解析该文件,得到图片标签的信息 - 再去
ImageSet/JPEGImages
找到相应的图片并载入内存
三、标注属于自己的数据集
1. 标注软件介绍与安装
标注图像的软件有很多,在GitHub上有很多开源项目,比如:
https://github.com/tzutalin/labelImg
可以生成 .xml文件
https://github.com/wkentaro/labelme
主要生成json文件
为了保持和PASCAL VOC数据集一致,这里使用labelImg
pip3 install labelImg
labelImg
labelImg ./image[IMAGE_PATH] [PRE-DEFINED CLASS FILE]./class.txt
2.标注软件使用
简单使用流程:
- 准备一个关于类别的文件信息
- 打开软件
- 设置图像文件夹所在目录,以及标注文件保存目录
- 标注图像并保存
- 若要修改源代码,在项目的
libs -> labelFile.py
文件中修改
2.1第一步:准确文件和文件夹并进入目标路径
我们先将文件夹和文件准备好,如:
├── annotation
├── classes.txt
└── images
├── test_1
├── test_1.jpg
├── test_2.jpg
├── test_3.jpg
└── test_4.jpg
其中:
annotation
是标注文件夹,一会儿我们会将软件标注的结果放这里面classes.txt
是类别的信息,内容如下:
dog
person
cat
tv
car
meatballs
marinara sauce
tomato soup
chicken noodle soup
french onion soup
chicken breast
ribs
pulled pork
hamburger
cavity
images
:放图片的文件夹,里面是具体需要标注的图片
第二步:打开软件
# 进入文件夹
ls
annotation classes.txt images
# 打开软件 labelImg [图片文件夹路径] [标签文件]
labelImg ./images/ ./classes.txt
第三步:设置标注文件保存目录
第四步:标注图像并保存
此时Annotation
文件夹下就有一个文件test_1.xml
,内容如下:
<annotation>
<folder>images</folder> # 图片所属文件夹
<filename>test_1.jpg</filename> # 图片的名字
<path>/home/leovin/PyTorchProject/A2_object_detection/faster_rcnn/label_our_datasets/images/test_1.jpg</path>
<source>
<database>Unknown</database>
</source>
<size>
<width>1032</width> # 图片的宽度
<height>795</height> # 图片的高度
<depth>3</depth> # 图片的深度
</size>
<segmented>0</segmented>
<object> # 第一个目标
<name>cat</name> # 目标的真实类别
<pose>Unspecified</pose>
<truncated>0</truncated> # 没有被截断
<difficult>0</difficult>
<bndbox> # BBox的坐标(两个点坐标)
<xmin>362</xmin>
<ymin>122</ymin>
<xmax>1029</xmax>
<ymax>790</ymax>
</bndbox>
</object>
<object> # 第二个目标
<name>dog</name>
<pose>Unspecified</pose>
<truncated>1</truncated> # 被截断
<difficult>0</difficult>
<bndbox>
<xmin>30</xmin>
<ymin>342</ymin>
<xmax>415</xmax>
<ymax>795</ymax>
</bndbox>
</object>
<object>
<name>dog</name>
<pose>Unspecified</pose>
<truncated>0</truncated> # 没有被截断
<difficult>0</difficult>
<bndbox>
<xmin>684</xmin>
<ymin>165</ymin>
<xmax>953</xmax>
<ymax>582</ymax>
</bndbox>
</object>
</annotation>
之后就可以进行其他图片的标注了。
快捷键(Hotkeys)
key | action |
---|---|
Ctrl + u | 选择一个目录(文件夹)加载其中所有图片 |
Ctrl + r | 更改标注的保存目录 |
Ctrl + s | 保存本次标注 |
Ctrl + d | 复制当前的标注及标注框 |
Ctrl + Shift + d | 删除当前的图片 |
Space | 标记当前图片为验证集 |
w | 创建一个新的矩形框 |
d | 下一张图片 |
a | 上一张图片 |
del | 删除所选的矩形框 |
Ctrl + + | 放大 |
Ctrl + - | 缩放 |
↑→↓← | 微调矩形框 |
3. 数据集划分
在得到自己标注好的数据后,如何得到像VOC 2012那样的train.txt文件呢?
import os
import random
def main():
random.seed(0) # 设置随机种子,保证随机结果可复现
# 给定数据集Annotation的路径
files_path = "./VOCdevkit/VOC2012/Annotations"
assert os.path.exists(files_path), "path: '{}' does not exist.".format(files_path)
# 验证集的比例
val_rate = 0.2 # 因为测试集不公开,训练:验证集=8:2
"""
for file in os.listdir(files_path)
其中os.listdir(files_path)遍历该路径下所有的文件
file就是一个一个文件
file.split(".")[0]
分割字符串并取出文件名
sorted()
排序函数
Note: 列表表达式最后得到肯定是一个list
"""
files_name = sorted([file.split(".")[0] for file in os.listdir(files_path)])
files_num = len(files_name) # 得到文件的数量
"""
random.sample(序列,k=采样个数)
可以简单理解为从某个list中随机采样k个点(且k不会重复)
返回值是一个list
>>> import random
>>> random.sample(range(0, 10), 6)
[8, 3, 7, 0, 6, 2]
random.sample(range(0, files_num), k=int(files_num*val_rate))
从0到files_num-1中随机采样files_num*val_rate个点组成一个list并返回
"""
val_index = random.sample(range(0, files_num), k=int(files_num*val_rate))
train_files = []
val_files = []
# files_name是一个list,list可以被enumerate
for index, file_name in enumerate(files_name):
if index in val_index: # 如果这张图片是采样图片,则放入验证集
val_files.append(file_name)
else:
train_files.append(file_name) # 否则放入训练集
try:
# 'x'用于创建并写入新文件
# \n 表示换行符
train_f = open("train.txt", "x")
eval_f = open("val.txt", "x")
train_f.write("\n".join(train_files))
eval_f.write("\n".join(val_files))
except FileExistsError as e:
print(e)
exit(1)
if __name__ == '__main__':
main()