(三)Google Open Images Dataset V5 下载
第一行:是指源图片本身下载,就是一张张图,不包含边界框等信息,主要两个地方可下,CVDF是指通用视觉数据基金会。
第二行:train-annotations-bbox.csv、validation-annotations-bbox.csv、test-annotations-bbox.csv
指边界框等信息。我们试着下载一个下来,是个csv文件,我们暂称它为边界框表,打开以后像这样:
第五行:就是标签类别,一幅图上有几个对象,就给你打几个标签,我们暂称它为分类标签表,可做图像分类用。
train-annotations-human-imagelabels-boxable.csv、validation-annotations-human-imagelabels-boxable.csv、test-annotations-human-imagelabels-boxable.csv
第六行:就是图像的相关信息,它包含图片网址,OpenImages ID,轮换信息,标题,作者和许可证信息,我们暂称它为图片表,可以看得出来,几乎所有的图像都来自flickr网站
train-images-boxable-with-rotation.csv、validation-images-with-rotation.csv、test-images-with-rotation.csv
第七行就是元数据了,比较简单,就是分类实际名称,我们暂称它为标签表。可以将MID格式的类名转换为简短描述
class-descriptions-boxable.csv
表格之间的关系
从上面四个表可以看出,它们形成了一个小小的数据库表关系:
非常简单的外键关系,图片表描述图片信息,最重要是下载地址,边界框表主要描述一张图有几个边框,它与图片表通过外键ImageID关联,同时每个边框具体属于哪个分类,又要通过LabelName外键和标签表关联。
使用open image v5 进行目标检测训练,训练单类目标检测器,比如雪人检测器。
下载snowman图片的代码:
下载数据[约1小时]
首先,我们需要安装awscli
sudo pip3 install awscli
然后,我们需要获得相关的openImages文件、class-descriptions-boxable.csv and train-annotations-bbox.csv(1.11GB),这些文件用于定位包含我们感兴趣的对象的文件。
wget https://storage.googleapis.com/openimages/2018_04/class-descriptions-boxable.csv
wget https://storage.googleapis.com/openimages/2018_04/train/train-annotations-bbox.csv
接下来,将上面的.csv文件移动到与脚本 getDataFromOpenImages_snowman.py 相同的文件夹中,然后使用下面的脚本下载数据
python3 getDataFromOpenImages_snowman.py
图像被下载到JPEGImages文件夹中,相应的标签文件被写入到labels文件夹中。下载将获得539张图片上的770个雪人实例。下载大约需要一个小时,这取决于互联网的速度。JPEGImages 和 labels 加在一起应该小于136 MB。
import csv
import subprocess
import os
#下载训练集图片
runMode = "train"
#只下载snowman图片
classes = ["Snowman"]
#class-descriptions-boxable.csv文件可以将LabelName转换为简短描述,现在用其创建一个字典,
#通过简短描述查询其LabelName,例如:Snowman-->/m/0152hh
with open('class-descriptions-boxable.csv', mode='r') as infile:
reader = csv.reader(infile)
dict_list = {rows[1]:rows[0] for rows in reader}
#如果之前创建了JPEGImages文件夹,将其删除,并重新创建
subprocess.run(['rm', '-rf', 'JPEGImages'])
subprocess.run([ 'mkdir', 'JPEGImages'])
#如果之前创建了labels文件夹,将其删除,并重新创建
subprocess.run(['rm', '-rf', 'labels'])
subprocess.run([ 'mkdir', 'labels'])
#循环下载所需的每个类别的图片
for ind in range(0, len(classes)):
#Class 0 : snowman
className = classes[ind]
print("Class " + str(ind) + " : " + className)
#"grep /m/0152hh train-annotations-bbox.csv",查找含有/m/0152hh的行
commandStr = "grep " + dict_list[className] + " " + runMode + "-annotations-bbox.csv"
print(commandStr)
class_annotations = subprocess.run(commandStr.split(), stdout=subprocess.PIPE).stdout.decode('utf-8')
#splitlines()返回包含各行作为元素的列表,总共有770个类标注(class annotations)
#总共有538张图片,边界框共有770个
class_annotations = class_annotations.splitlines()
totalNumOfAnnotations = len(class_annotations)
print("Total number of annotations : "+str(totalNumOfAnnotations))
cnt = 0
for line in class_annotations[0:totalNumOfAnnotations]:
cnt = cnt + 1
print("annotation count : " + str(cnt))
lineParts = line.split(',')
#使用aws命令下载图片:aws s3 --no-sign-request --only-show-errors cp s3://open-images-dataset/train/lineParts[0].jpg JPEGImages/lineParts[0].jpg
#lineParts[0]是每张图片的名称,即ImageID
subprocess.run([ 'aws', 's3', '--no-sign-request', '--only-show-errors', 'cp', 's3://open-images-dataset/'+runMode+'/'+lineParts[0]+".jpg", 'JPEGImages/'+lineParts[0]+".jpg"])
#将每个标注(框的坐标标注)写入labels文件夹中的与图片同名,后缀为.txt的文件中,一张图片有多个框,就将每个标注都写入同一个文件
#第一个值表示该标注所属类别的索引,在此都是0,只有一个类别
#转换box的坐标,原来的是用左上角和右下角的两个点的坐标表示一个框,现在转换为用框的中心点坐标,框的宽,框的高这四个值来表示一个框
with open('labels/%s.txt'%(lineParts[0]),'a') as f:
f.write(' '.join([str(ind),str((float(lineParts[5]) + float(lineParts[4]))/2), str((float(lineParts[7]) + float(lineParts[6]))/2), str(float(lineParts[5])-float(lineParts[4])),str(float(lineParts[7])-float(lineParts[6]))])+'\n')
对于多类对象检测器,您将需要为每个类提供更多的示例,您可能希望获得test-annotations-bbox.csv和validation-annotations-bbox.csv文件,然后修改python脚本中的runMode并重新运行它,以便为每个类获得更多的图像。但是在我们当前的雪人案例中,770个实例就足够了。
训练集-测试集划分
我们将JPEGImages文件夹中的图像分割为训练和测试集。您可以使用以下splitTrainAndTest.py脚本来实现这一点,并将JPEGImages文件夹的完整路径作为参数传递。
python3 splitTrainAndTest.py /full/path/to/snowman/JPEGImages/
上面的脚本将数据分割为一个训练(90%)和一个测试集(10%),并生成两个文件 snowman_train.txt 和 snowman_test.txt
import random
import os
import subprocess
import sys
def split_data_set(image_dir):
f_val = open("snowman_test.txt", 'w')
f_train = open("snowman_train.txt", 'w')
path, dirs, files = next(os.walk(image_dir))
data_size = len(files)
ind = 0
#10%的数据用作测试集
data_test_size = int(0.1 * data_size)
#从整数序列(这里range返回的是可迭代对象)[0, 1, 2, 3,...,data_size]中选择n个随机且独立的元素,返回列表
test_array = random.sample(range(data_size), k=data_test_size)
for f in os.listdir(image_dir):
if(f.split(".")[1] == "jpg"):
ind += 1
if ind in test_array:
f_val.write(image_dir+'/'+f+'\n')
else:
f_train.write(image_dir+'/'+f+'\n')
split_data_set(sys.argv[1])