主要记录一下数据集的制作,看了很多的文章和参考,数据集的制作,因为没有找到一个现成的YOLOV3格式的数据集,就打算自己搞一下,学习一下如何训练数据集的。
1.虚拟机: vmware14+ubuntu16.04
2.darknet :github 下载darknet-master源码
学习了解到,数据集之前的都是VOC格式的,darknet yolov3需要的是TXT的。安装参考的各种说法:
第一步:因为是普通用户,肯定我需要东西都放到home 的目录底下, ../home/darknet/darknetMaster
backup一般放的是训练后的权重,cfg存放的是网络配置文件,data放的是data文件主要是分类的名称 scrips 脚本文件,后面用的voc转换,voc_lable.py就在里面 另外一个主要文件就是Makefile
第二步 下载好的nwpu 10的数据集 ,这个数据集一共有10类标注目标,类ID在readme里面有解释,ground是标注文件,positive 是图片集
但是这个格式和VOC格式不一样,我的思路是先转换成VOCXML的格式,然后利用voc_lable.py文件再转换为darknet需要的txt格式,主要python刚上手,怕中间有错误,对于数据集怎么训练还不懂,就按部就班了:
1. NWPU->VOC XML 参考了一个PY的脚本,可以完美的转换。这样完成了类似lableimage工具的工作,标注并生成了xml文件。
2. 训练集的图和XML文件有了,就可以制作自己的voc数据集了,创建VOCdevkit目录,这个文件最好房子和darknet下面和darknetMaster同一层,方便后续的使用, vocdevkit下需要创建三个文件夹:
├── Annotations/刚生成的XML数据放这个里面
├── ImageSets
├── Main 创建三个文件:test.txt trail.txt val.txt trainval.txt 四个文件,主要是为后面的训练集 测试集, 验证集,这个地方用了一个maketxt.py的脚本文件,随机生成了这些集合,非常的方便, 里面是xml的文件名和图片集的名称都是一样的
├── Layout
├── JPEGImages 存放数据集的图片
这部分主要是保证生成的是VOC的数据集,包括XML标注,图片,以及生成的训练用的四种集合,这部分还是属于voc格式的标注数据集。
3. 用于darknet的数据集需要用voc_lable.py进行将xml变成txt的格式,主要是一种归一化的操作,需要修改这个py变成适合自己的:
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
sets=[('2012', 'train'), ('2012', 'val'), ('2007', 'train'), ('2007', 'val'), ('2007', 'test')]
classes = ["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"]
def convert(size, box):
dw = 1./(size[0])
dh = 1./(size[1])
x = (box[0] + box[1])/2.0 - 1
y = (box[2] + box[3])/2.0 - 1
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(year, image_id):
in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id))
out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, image_id), 'w')
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'):
difficult = obj.find('difficult').text
cls = obj.find('name').text
if cls not in classes or int(difficult)==1:
continue
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')
wd = getcwd()
for year, image_set in sets:
if not os.path.exists('VOCdevkit/VOC%s/labels/'%(year)):
os.makedirs('VOCdevkit/VOC%s/labels/'%(year))
image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split()
list_file = open('%s_%s.txt'%(year, image_set), 'w')
for image_id in image_ids:
list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id))
convert_annotation(year, image_id)
list_file.close()
os.system("cat 2007_train.txt 2007_val.txt 2012_train.txt 2012_val.txt > train.txt")
os.system("cat 2007_train.txt 2007_val.txt 2007_test.txt 2012_train.txt 2012_val.txt > train.all.txt")
修改后的:
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
sets=[('2019', 'train'), ('2019', 'val'), ('2019', 'test')] 需要转换的数据集
classes = ["airplane", "ship", "storage", "baseball", "tennis court", "basketball court", "ground track field", "habor", "bridge", "vehicle"] 数据类
def convert(size, box):
dw = 1./(size[0])
dh = 1./(size[1])
x = (box[0] + box[1])/2.0 - 1
y = (box[2] + box[3])/2.0 - 1
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(year, image_id):
in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id))
out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, image_id), 'w')
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'):
difficult = obj.find('difficult').text
cls = obj.find('name').text
if cls not in classes or int(difficult)==1:
continue
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')
wd = getcwd()
for year, image_set in sets:
if not os.path.exists('VOCdevkit/VOC%s/labels/'%(year)):
os.makedirs('VOCdevkit/VOC%s/labels/'%(year))
image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split()
list_file = open('%s_%s.txt'%(year, image_set), 'w')
for image_id in image_ids:
list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id))
convert_annotation(year, image_id)
list_file.close()
os.system("cat 2019_train.txt 2019_val.txt > train.txt") 生成训练集
os.system("cat 2019_train.txt 2019_val.txt 2019_test.txt > train.all.txt") 生成全部的数据集合
这个文件必须放到vocdevkit 一层目录,这样里面的路径文件才能和实际的对应起来,文件内容就是根据数据集合四类数据集合选择的文件名称 生成对应TXT文件,内容变换为绝对路径,同时生成了关键的归一后的lables文件夹(位置在voc的imageSets同一层),里面存放的就是转换后的全部txt文件。数据转换就制作完成了。