coco2017格式数据集制作

这篇文章提供了一个比较好的思路。总体做法还是离不开这个文章的做法。
上面文章作者提供的思路比较正统开始说明之前我们先说明一下coco2017的格式类型,这些网络上也说了很多了,这里再提及一下加深理解。
coco/
annotations/
instances_train2017.json
instances_val2017.json
images/
train2017/
0d4c5e4f-fc3c-4d5a-906c-105.jpg
val2017
0ddfc5aea-fcdac-421-92dad-144.jpg
以上格式摘自上面提到的文章,并且最后我们也是按这种方式生成的。
这里我们用到的格式也可以这么做,当然也可以适配自己的文件,比如要是每个视频下拆除的单张图,那么可以再多加一级目录出来。
具体的做法按照启发写到我的github项目里了,这里简要说明一下,当然github上后续也会更新。

csv格式制作

这里用csv也可以,用txt也可以,数据的格式并不是一个问题,而如何转换到我们想要的格式则有多种解决方式。
这里只展示csv的用法。

import os
import json
import cv2
import time
import argparse
import csv
parser = argparse.ArgumentParser(description='convert object label')
parser.add_argument('data', metavar='DIR',
                    help='path to dataset')
parser.add_argument('keyframe_dir', metavar='DIR',
                    help='path to frame dir')
parser.add_argument('--mode', type=str, choices=['train', 'val', 'test'])

args = parser.parse_args()

root = os.path.join(args.data, args.mode) 

video_list = open(os.path.join(root, 'videolist.txt'),'r')

output_list = open('%s_list.txt' % args.mode,'w')

obj_name = open('objects_en.txt','r')
obj_list = [line.rstrip() for line in obj_name]
print(obj_list)
train_category = []
video_count = 0
start = time.time()
key_frame_count = 0
#output_folder = '%s_label' % args.mode
#if not os.path.exists(output_folder):
 #   os.makedirs(output_folder)
with open('val.csv','w') as f1:
 for vid in video_list:
    label = json.load(open(os.path.join(root, 'label', 'sample_' + vid.rstrip().split('.')[0] + '.json'), 'r'))
    writer = csv.writer(f1)
    for shot in label['shots']:
        keyframe = shot['keyframe']
        image_path = os.path.join(args.keyframe_dir, args.mode, vid[:-1], '%05d.jpg'% keyframe)
        for target in shot['targets'] :
          if target['category'] == 0:
           if os.path.isfile(image_path):
                        xmin = target['bbox']['x']
                        xmax = xmin + target['bbox']['width']
                        ymin = target['bbox']['y']
                        ymax = ymin + target['bbox']['height']
                        cls_id = obj_list[int(target['tag'])]
                        writer.writerow([image_path,xmin,xmax,ymin,ymax,cls_id])#用write方法写入我们的csv文件里即可。

这里因为是适配了videonet比赛的数据格式,videonet数据集是一个视频数据集,目标检测也是其中一个任务,这里目标检测对应信息由官方给出的json来标注xyhw四个信息。我们csv的格式这里也是按

path xmin ymin xmax ymax id

上述格式生成csv文件,参考给出的代码也很好理解。通过csv文件将对应cocotrian或者validation格式的数据生成,经测试在maskrcnn-benchmark上是可以使用的。
以下给出train的coco形式的代码生成

# -*- coding: utf-8 -*-
'''
@time: 2019/01/11 11:28
spytensor
'''

import os
import json
import numpy as np
import pandas as pd
import glob
import cv2
import os
import shutil
from IPython import embed
from tqdm import tqdm
#from sklearn.model_selection import train_test_split
np.random.seed(41)

#0为背景
obj_name = open('objects_en.txt','r')
obj_list = [line.rstrip() for line in obj_name]
classname_to_id = {}
for i in range(len(obj_list)):
    classname_to_id.setdefault(obj_list[i],i)
print(classname_to_id)

class Csv2CoCo:

    def __init__(self,image_dir,total_annos):
        self.images = []
        self.annotations = []
        self.categories = []
        self.img_id = 0
        self.ann_id = 0
        self.image_dir = image_dir
        self.total_annos = total_annos

    def save_coco_json(self, instance, save_path):
        json.dump(instance, open(save_path, 'w'), ensure_ascii=False, indent=2)  # indent=2 更加美观显示

    # 由txt文件构建COCO
    def to_coco(self, keys):
        self._init_categories()
        for key in keys:
            self.images.append(self._image(key))
            shapes = self.total_annos[key]
            for shape in shapes:
                bboxi = []
                for cor in shape[:-1]:
                    bboxi.append(int(cor))
                label = shape[-1]
                #print('label',label)
                annotation = self._annotation(bboxi,label)
                print('annotation',annotation)
                self.annotations.append(annotation)
                self.ann_id += 1
            self.img_id += 1
        instance = {}
        instance['info'] = 'spytensor created'
        instance['license'] = ['license']
        instance['images'] = self.images
        instance['annotations'] = self.annotations
        instance['categories'] = self.categories
        return instance

    # 构建类别
    def _init_categories(self):
        for k, v in classname_to_id.items():
            category = {}
            category['id'] = v
            category['name'] = k
            self.categories.append(category)

    # 构建COCO的image字段
    def _image(self, path):
        image = {}
        print(path)
        img = cv2.imread(self.image_dir + path)
        image['height'] = img.shape[0]
        image['width'] = img.shape[1]
        image['id'] = self.img_id
        image['file_name'] = path
        return image

    # 构建COCO的annotation字段
    def _annotation(self, shape,label):
        # label = shape[-1]
        points = shape[:4]
        annotation = {}
        annotation['id'] = self.ann_id
        annotation['image_id'] = self.img_id
        annotation['category_id'] = int(classname_to_id[label])
        #annotation['segmentation'] = self._get_seg(points)
        annotation['bbox'] = self._get_box(points)
        annotation['iscrowd'] = 0
        annotation['area'] = 1.0
        return annotation

    # COCO的格式: [x1,y1,w,h] 对应COCO的bbox格式
    def _get_box(self, points):
        min_x = points[0]
        min_y = points[1]
        max_x = points[2]
        max_y = points[3]
        return [min_x, min_y, max_x - min_x, max_y - min_y]
    # segmentation
    def _get_seg(self, points):
        min_x = points[0]
        min_y = points[1]
        max_x = points[2]
        max_y = points[3]
        h = max_y - min_y
        w = max_x - min_x
        a = []
        a.append([min_x,min_y, min_x,min_y+0.5*h, min_x,max_y, min_x+0.5*w,max_y, max_x,max_y, max_x,max_y-0.5*h, max_x,min_y, max_x-0.5*w,min_y])
        return a
   

if __name__ == '__main__':
    csv_file = "train.csv"
    image_dir = "/home/sda/videonet/train/image/train/"
    saved_coco_path = "./"
    # 整合csv格式标注文件
    total_csv_annotations = {}
    annotations = pd.read_csv(csv_file,header=None).values
    for annotation in annotations:
        #print(annotation[0].split(os.sep)[-2]+'/'+annotation[0].split(os.sep)[-1])
        key = annotation[0].split(os.sep)[-2]+'/'+annotation[0].split(os.sep)[-1]
        value = np.array([annotation[1:]])
        if key in total_csv_annotations.keys():
            total_csv_annotations[key] = np.concatenate((total_csv_annotations[key],value),axis=0)
        else:
            total_csv_annotations[key] = value
    for k,v in total_csv_annotations.items():
        print(k,v)
    # 按照键值划分数据
    total_keys = list(total_csv_annotations.keys())
    train_keys = total_keys
    #val_keys = total_keys
    #train_keys, val_keys = train_test_split(total_keys, test_size=0.2)
    print("train_n:", len(train_keys))#, 'val_n:', len(val_keys))
    # 创建必须的文件夹
    if not os.path.exists('%scoco/annotations/'%saved_coco_path):
        os.makedirs('%scoco/annotations/'%saved_coco_path)
    if not os.path.exists('%scoco/images/train2017/'%saved_coco_path):
        os.makedirs('%scoco/images/train2017/'%saved_coco_path)
    if not os.path.exists('%scoco/images/val2017/'%saved_coco_path):
        os.makedirs('%scoco/images/val2017/'%saved_coco_path)
    # 把训练集转化为COCO的json格式
    for file in train_keys:
      if not os.path.exists('{}coco/images/train2017/{}'.format(saved_coco_path,file.split('/')[0])):
        print(file.split('/')[0])
        os.makedirs('{}coco/images/train2017/{}'.format(saved_coco_path,file.split('/')[0]))
        if not os.path.exists("{}coco/images/train2017/{}".format(saved_coco_path,file)):
          shutil.copy(image_dir+file,"{}coco/images/train2017/{}".format(saved_coco_path,file))
      elif os.path.exists('{}coco/images/train2017/{}'.format(saved_coco_path,file.split('/')[0])):
        if not os.path.exists("{}coco/images/train2017/{}".format(saved_coco_path,file)):
          shutil.copy(image_dir+file,"{}coco/images/train2017/{}".format(saved_coco_path,file))
    l2c_train = Csv2CoCo(image_dir=image_dir,total_annos=total_csv_annotations)
    train_instance = l2c_train.to_coco(train_keys)
    l2c_train.save_coco_json(train_instance, '%scoco/annotations/instances_train2017.json'%saved_coco_path)
    #for file in val_keys:
     #   shutil.copy(image_dir+file,"%scoco/images/val2017/"%saved_coco_path)
    # 把验证集转化为COCO的json格式
    #l2c_val = Csv2CoCo(image_dir=image_dir,total_annos=total_csv_annotations)
    #val_instance = l2c_val.to_coco(val_keys)
    #l2c_val.save_coco_json(val_instance, '%scoco/annotations/instances_val2017.json'%saved_coco_path)

和开头作者提到的方法不一样,我这里适配了自己的路径写到绝对路径,一定程度上保证了路径问题不会产生,新添加的多个if语句主要是有以下功能保证:

  1. 因为一张图片会包含多个目标物体,因此会可能有多个xyhw,当我们按上面生成csv代码时,因为一张图包含的多个xyhw,都会让所在的这张图重复写一遍,所以说我们用if先判断一遍看看是否是重复的,重复的我们跳过。
  2. 因为我们这里标注的是关键帧,所以说上一级目录是一个视频名,如果要把这个写到filename里,相当于我们还要再遍历一遍文件夹是否重复,所以再用到一次if判断。
    对于train和validaiton是可以用一种方式生成的,而test会有一些变化,主要是test没有标注,我们只需要遍历后把filename写进去即可。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容