本文主要介绍如何标注、存放和划分 VOC
格式的自定义数据集。
目录:
- MMDetection v2 目标检测(1):环境搭建
- MMDetection v2 目标检测(2):数据准备
- MMDetection v2 目标检测(3):配置修改
- MMDetection v2 目标检测(4):模型训练和测试
服务器的环境配置:
-
Ubuntu
:18.04.5 -
CUDA
:10.1.243 -
Python
:3.7.9 -
PyTorch
:1.5.1 -
MMDetection
:2.16.0
1 标注数据
MMDetection
目前支持 Pascal VOC
、MS COCO
、Cityscapes
、LVIS
、Wider Face
、Deep Fashion
等多个公开数据集。
而其他公开数据集,例如:KITTI
等,可在网上搜索脚本,将标注文件转化成 VOC
或 COCO
格式。
如果是自定义数据集,则可使用数据标注工具 LabelImg
,来生成 VOC
格式的标注文件。
下面介绍如何在 Win 10
上安装和使用 LabelImg
。
1.1 安装 LabelImg
pip
安装:
pip install labelimg
1.2 使用 LabelImg
- 将数据集按照以下格式存放:
data
├─ Annotations
├─ JPEGImages
└─ predefined_classes.txt
-
Annotations
:存放标注文件 -
JPEGImages
:存放图像文件 -
predefined_classes.txt
:定义标签类别
- 在
predefined_classes.txt
中,定义标签类别,例如:
Car
Pedestrian
Cyclist
- 打开
data
目录:
cd data
- 运行
LabelImg
:
labelimg JPEGImages predefined_classes.txt
选择图像文件夹
JPEGImages
。进入
LabelImg
界面:
-
Open Dir
:打开存放图像文件的目录路径,选择JPEGImages
-
Change Save Dir
:更换存放标注文件的目录路径,选择Annotations
-
PascalVOC
/YOLO
:切换标注保存的格式 -
Create\nRectBox
:创建标注 -
Save
:保存标注
- 其他设置:
-
Auto Save mode
:自动保存模式,不用每标注一张图像,都要点击一次保存标注 -
Display Labels
:显示标签,标注好的标签会自动显示出来 -
Advanced Mode
:高级模式,不用每标注一个目标,都要点击一次创建标注
2 存放数据
- 将数据集上传到服务器,并将图像和标注文件按照
VOC
格式存放:
data
└─ VOCdevkit
└─ MyDataset
├─ Annotations
├─ ImageSets
│ └─ Main
│ ├─ test.txt
│ ├─ train.txt
│ ├─ trainval.txt
│ └─ val.txt
└─ JPEGImages
-
Annotations
:存放标注文件 -
ImageSets
:存放划分文件 -
JPEGImages
:存放图像文件
Tips:
目录中的MyDataset
可改为任意自定义数据集的名字。
- 推荐使用符号链接,将数据集放到
mmdetection
目录下:
ln -s ~/data ~/mmdetection
mmdetection
的目录结构:
mmdetection
├─ mmdet
├─ tools
├─ configs
├─ checkpoints
├─ data
3 划分数据
打开 MyDataset
目录:
cd data/VOCdevkit/MyDataset
3.1 划分数据集
运行 split_dataset.py
:
python split_dataset.py
具体代码如下:
import os
import random
trainval_percent = 0.9
train_percent = 0.9
total_xml = os.listdir('./Annotations')
num = len(total_xml)
nums = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(nums, tv)
train = random.sample(trainval, tr)
ftrainval = open('./ImageSets/Main/trainval.txt', 'w')
ftrain = open('./ImageSets/Main/train.txt', 'w')
fval = open('./ImageSets/Main/val.txt', 'w')
ftest = open('./ImageSets/Main/test.txt', 'w')
for i in nums:
name = total_xml[i][:-4] + '\n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftrain.write(name)
else:
fval.write(name)
else:
ftest.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
在 ./ImageSets/Main
目录下,生成四个 txt
文件:
-
test.txt
:测试集 -
train.txt
:训练集 -
trainval.txt
:训练和验证集 -
val.txt
:验证集
每个文件分别记录了对应划分数据集包含的图像文件名(不含后缀名)。
3.2 统计数据个数
运行 cal_data_num.py
:
python cal_data_num.py
具体代码如下:
import os
names_txt = os.listdir('./ImageSets/Main')
print(f'共有文件:{len(names_txt)} 个')
for name_txt in names_txt:
with open(os.path.join('./ImageSets/Main', name_txt)) as f:
lines = f.readlines()
print(f'{name_txt} 共有数据:{len(lines)} 个')
得到每个划分数据集的数据个数。
4 转换数据
另外,还可以将 VOC
格式转换成 COCO
格式。
- 打开
./tools/convert_datasets/pascal_voc.py
如果标注文件中不存在 difficult
标签,需要将 difficult
设为 None
:
def parse_xml(args):
xml_path, img_path = args
tree = ET.parse(xml_path)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.findall('object'):
name = obj.find('name').text
label = label_ids[name]
try:
difficult = int(obj.find('difficult').text)
except AttributeError:
difficult = None
# difficult = int(obj.find('difficult').text)
如果是自定义数据集的名字,需要修改数据集的路径 filelist
、xml_paths
、img_paths
:
def cvt_annotations(devkit_path, years, split, out_file):
if not isinstance(years, list):
years = [years]
annotations = []
for year in years:
filelist = osp.join(devkit_path,
f'{year}/ImageSets/Main/{split}.txt')
# filelist = osp.join(devkit_path,
# f'VOC{year}/ImageSets/Main/{split}.txt')
if not osp.isfile(filelist):
print(f'filelist does not exist: {filelist}, '
f'skip {year} {split}')
# print(f'filelist does not exist: {filelist}, '
# f'skip voc{year} {split}')
return
img_names = mmcv.list_from_file(filelist)
xml_paths = [
osp.join(devkit_path, f'{year}/Annotations/{img_name}.xml')
for img_name in img_names
]
# xml_paths = [
# osp.join(devkit_path, f'VOC{year}/Annotations/{img_name}.xml')
# for img_name in img_names
# ]
img_paths = [
f'{year}/JPEGImages/{img_name}.png' for img_name in img_names
]
# img_paths = [
# f'VOC{year}/JPEGImages/{img_name}.jpg' for img_name in img_names
# ]
part_annotations = mmcv.track_progress(parse_xml,
list(zip(xml_paths, img_paths)))
annotations.extend(part_annotations)
mmcv.dump(annotations, out_file)
return annotations
如果是自定义数据集的名字,需要添加 mydataset
:
def main():
args = parse_args()
devkit_path = args.devkit_path
out_dir = args.out_dir if args.out_dir else devkit_path
mmcv.mkdir_or_exist(out_dir)
years = []
if osp.isdir(osp.join(devkit_path, 'VOC2007')):
years.append('VOC2007')
if osp.isdir(osp.join(devkit_path, 'VOC2012')):
years.append('VOC2012')
if 'VOC2007' in years and 'VOC2012' in years:
years.append(['VOC2007', 'VOC2012'])
# ------------------------------
if osp.isdir(osp.join(devkit_path, 'MyDataset')):
years.append('mydataset')
# ------------------------------
if not years:
raise IOError(f'The devkit path {devkit_path} contains neither '
'"VOC2007" nor "VOC2012" subfolder')
for year in years:
if year == 'VOC2007':
prefix = 'voc07'
elif year == 'VOC2012':
prefix = 'voc12'
elif year == ['VOC2007', 'VOC2012']:
prefix = 'voc0712'
# ------------------------------
elif year = 'mydataset':
prefix = 'mydataset'
# ------------------------------
for split in ['train', 'val', 'trainval']:
dataset_name = prefix + '_' + split
print(f'processing {dataset_name} ...')
cvt_annotations(devkit_path, year, split,
osp.join(out_dir, dataset_name + '.pkl'))
if not isinstance(year, list):
dataset_name = prefix + '_test'
print(f'processing {dataset_name} ...')
cvt_annotations(devkit_path, year, 'test',
osp.join(out_dir, dataset_name + '.pkl'))
print('Done!')
- 运行
./tools/convert_datasets/pascal_voc.py
命令格式:
python tools/convert_datasets/pascal_voc.py ${DEVKIT_PATH} [--out-dir ${OUT_DIR}]
命令参数:
-
devkit_path
:VOC
格式数据集的目录路径 -
--out-dir
:输出COCO
格式标注的目录路径
示例:
python tools/convert_datasets/pascal_voc.py data/VOCdevkit data/coco
5 结语
有帮助的话,点个赞再走吧,谢谢~
参考:
- 最新版本的mmdetection2.0 (v2.0.0版本)环境搭建、训练自己的数据集、测试以及常见错误集合
- 目标检测使用LabelImg标注VOC数据格式和YOLO数据格式——LabelImg使用详细教程
- Test existing models on standard datasets