数据集处理-数据集转换格式
数据为王,而合适的数据格式也非常重要
labelMe的标注数据集格式
ImageNet coco kitti apollo
数据集处理
1.将自己的数据集转化为COCO数据集的格式-COCO的 全称是Common Objects in COntext
2.将自己的数据集--自定义dataset 和dataloader--然后训练
制作训练和验证数据的.txt文件
自定义Dataset,继承Dataset, 重写抽象方法:__init__, __len()__, __getitem()__
coco数据集
Dataset之COCO数据集--
1.各个类型包含了训练和验证-文件夹格式-目标检测为例
01.图片数据
data/coco/images/train2017
data/coco/images/val2017
02.标注数据
/data/coco/annotations
instances_train2017.json
instances_val2017.json
2.coco数据集的格式
MS COCO数据集是微软构建的一个大规模图像数据集,包含目标检测、像素分割及看图说话等任务数据
object instances(目标实例),
object keypoints(目标上的关键点),
image captions(看图说话)
该数据集的标注信息主要存放为JSON格式,
info、licenses、images这三个结构体/类型 在不同的JSON文件中这三个类型是一样的,定义是共享的。
annotation和category这两种结构体,他们在不同类型的JSON文件中是不一样,不共享。
注释类型包含五大类,
分别为目标检测、关键点检测、素材分割、全景分割及看图说话,
其中五大注释类型共用基础数据结构
{
"info" : info, # 数据集描述信息
"images" : [image], # 图像字典段列表信息
"annotations" : [annotation], # 注释类型字典段列表
"categories" : [category], # 注释类型字典段列表
"licenses" : [license], # 许可协议字典段列表
}
info{
"year" : int, # 年份
"version" : str, # 版本
"description" : str, # 详细描述信息
"contributor" : str, # 作者
"url" : str, # 协议链接
"date_created" : datetime, # 生成日期
}
image{
"id" : int, # 图像id,可从0开始
"width" : int, # 图像的宽
"height" : int, # 图像的高
"file_name" : str, # 文件名
"license" : int, # 遵循哪个协议
"flickr_url" : str, # flickr图片链接url
"coco_url" : str, # COCO图片链接url
"date_captured" : datetime, # 获取数据的日期
}
license{
"id" : int, # 协议id编号
"name" : str, # 协议名
"url" : str, # 协议链接
}
按照不同的任务
01.目标检测和素材分割任务中,annotation和categories字典段的形式如下
annotation{
"id" : int, # 注释id编号
"image_id" : int, # 图像id编号
"category_id" : int, # 类别id编号
"segmentation" : RLE or [polygon], # 分割具体数据
"area" : float, # 目标检测的区域大小
"bbox" : [x,y,width,height], # 目标检测框的坐标详细位置信息
"iscrowd" : 0 or 1, # 目标是否被遮盖,默认为0
}
categories[{
"id" : int, # 类别id编号
"name" : str, # 类别名字
"supercategory" : str, # 类别所属的大类,如哈巴狗和狐狸犬都属于犬科这个大类
}]
02.关键点检测任务中,annotation和categories字典段的形式如下:
annotation{
"keypoints" : [x1,y1,v1,...], # 关键点坐标,其中V字段表示关键点属性,0表示未标注,1表示已标注但不可见,2表示已标注且可见
"num_keypoints" : int, # 多少个关键点
"[cloned]" : ..., # 当同时存在多个任务时其他任务格式的annotation字典段信息直接放在这个位置,不分先后组合
}
categories[{
"keypoints" : [str], # 关键点名字,注意要与num_keypoints对应起来
"skeleton" : [edge], # 概略描述
"[cloned]" : ..., # 当同时存在多个任务时其他任务格式的categories字典段信息直接放在这个位置,不分先后组合
}]
03.分割任务中,annotation和categories字典段的形式如下:
annotation{
"image_id" : int, # 图像id编号
"file_name" : str, # 文件名
"segments_info" : [segment_info], # 分割数据字典段列表
}
segment_info{
"id" : int, # 分割id编号
"category_id" : int, # 类别id编号
"area" : int, # 分割区域面积大小
"bbox" : [x,y,width,height], # 检测框的坐标详细位置信息
"iscrowd" : 0 or 1, # 该实例是否被遮挡
}
categories[{
"id" : int, # 类别id编号
"name" : str, # 类别名
"supercategory" : str, # 该类别所属的大类
"isthing" : 0 or 1, # 是否为物体
"color" : [R,G,B], # 分割标示的像素颜色
}]
annotations字段是包含多个annotation实例的一个数组,
annotation类型本身又包含了一系列的字段,
如这个目标的category id和segmentation mask。
segmentation格式取决于这个实例是一个单个的对象(即iscrowd=0,将使用polygons格式)还是一组对象(即iscrowd=1,将使用RLE格式)
3.支持的标注
COCO 支持两种类型的标注,其格式取决于标注的是单个物体 还是密集物体.
单个物体的标注是沿着物体边界的点列表进行编码的.
密集物体的标注是采用column-major RLE 进行标注的. RLE:Run Length Encoding(行程长度压缩算法)-把RLE格式的文件转变为图像格式
iscrowd=0 那么segmentation就是polygon格式
iscrowd=1 那么segmentation就是RLE格式
定制的数据格式说明
原有的数据标签形式如下:
文件名 标注框 关键点 类别
转换步骤和代码
01.转换的数据集方式
数据放置方式
02.转换的步骤
脚本一开始先将info、licenses及categories进行定义,
遍历图像信息将其转换为对应的coco格式,最终生成相应的json文件
03.转换的代码
04.数据集可视化
05.数据集使用
代码示例-转换代码
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import os
import os.path
import json
import pyhdfs
import cv2
import numpy as np
def copy_2_local_multi_dir(stat_file_nm,local_dir):
""" 根据标注文件内容-下载数据到本地 """
client = pyhdfs.HdfsClient(hosts="1.1.1.1",user_name="1")
if not os.path.exists(local_dir):
os.makedirs(local_dir)
print("创建",local_dir)
with open(file=stat_file_nm,mode='r',encoding="utf8") as f:
for file_num, data in enumerate(f):
strdict = json.loads(data)
hdfs_src_img = strdict.get("pict_nm")
img_file_nm = hdfs_src_img.strip().replace("\r","").replace("\n","").split("/")[-1]
local_src_jpg = os.path.join(local_dir,img_file_nm)
if client.exists(hdfs_src_img) and not os.path.exists(local_src_jpg):
print((file_num,hdfs_src_img, local_src_jpg))
client.copy_to_local(hdfs_src_img, local_src_jpg)
print(local_src_jpg)
#def gene_coco_format(orig_anno_json,dest_dir_path,dest_json):
def gene_coco_format():
orig_anno_json = r"F:\dataset\origin\test_2017_data.json"
dest_dir_path = r"F:\dataset\coco\annotations"
dest_json ="train2021"
local_img_dir = r"F:\dataset\coco\images\train2021"
coco_dataset = {'info':[], 'images':[], 'annotations':[], 'categories':[], 'licenses':[]}
if not os.path.exists(dest_dir_path):
os.makedirs(dest_dir_path)
print("创建",dest_dir_path)
classname_to_id = {"person": 1}
coco_dataset['info'] = 'coco_created'
coco_dataset['licenses'] = ['mylicense']
with open(file=orig_anno_file,mode='r',encoding="utf8") as f:
for f_num, data in enumerate(f):
strdict = json.loads(data)
hdfs_src_img = strdict.get("pict_nm")
img_file_nm = hdfs_src_img.strip().replace("\r","").replace("\n","").split("/")[-1]
local_src_jpg = os.path.join(local_img_dir,img_file_nm)
# 构建COCO的image字段
coco_dataset["images"].append(
{
"id" : f_num, # 图像id,可从0开始
"width" : 90, # 图像的宽
"height" : 180, # 图像的高
"file_name" : local_src_jpg, # 文件名
"license" : None, # 遵循哪个协议
"flickr_url" : None, # flickr图片链接url
"coco_url" : None, # COCO图片链接url
"date_captured" : "2017/05/21", # 获取数据的日期
}
)
mark_info = strdict.get("oriAn").get("res")
for mark_num,elem in enumerate(mark_info[0].get("elems")):
print(f_num,mark_num,elem)
print(elem.get("markType"))
if elem.get("markType")=="rect":
print(elem.get('attribute').get("type"))
coco_dataset["annotations"].append(
{
"id" : mark_num, # 注释id编号
"image_id" : f_num, # 图像id编号
"category_id" : 1, # 类别id编号
"segmentation" : elem.get('points'), # 分割具体数据
"area" : 1, # 目标检测的区域大小
"bbox" : [elem.get('X'),elem.get('Y'),elem.get('W'),elem.get('H')], # 目标检测框的坐标详细位置信息
"iscrowd" : 0 , # 目标是否被遮盖,默认为0
})
coco_dataset["categories"].append( {
"id" : f_num, # 图像id,可从0开始
"name" : "person",
"supercategory" : "mark"
})
print(coco_dataset)
return coco_dataset
def save_coco_json( instance, save_path):
json.dump(instance, open(save_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
# COCO的格式: [x1,y1,w,h] 对应COCO的bbox格式
def get_box(points):
min_x = min_y = np.inf
max_x = max_y = 0
for x, y in points:
min_x = min(min_x, x)
min_y = min(min_y, y)
max_x = max(max_x, x)
max_y = max(max_y, y)
return [min_x, min_y, max_x - min_x, max_y - min_y]
if __name__ == "__main__":
# 原始的json标注文件
orig_anno_file = r"F:\dataset\origin\test_2017_data.json"
local_dir_path = r"F:\dataset\coco\images\train2021"
#1.将图片copy到对应文件夹
#copy_2_local_multi_dir(orig_anno_file,local_dir_path)
# 生成coco的标注数据集
instance_info = gene_coco_format()
json_save_path = r"F:\dataset\coco\annotations\new_coco_data.json"
save_coco_json(instance_info,json_save_path)
类的方式
参考github上的代码 prepare_detection_dataset/labelme2coco.py 进行改写
import json
import os
import os.path
import numpy as np
#构建类别-名称对应的ID以及大类
classname_to_id = {"person": [1,"person"],"cyc":[2,"cyc"],"vertical":[3,"myareaobj"]}
class Lable2CoCo:
def __init__(self):
self.images = []
self.annotations = []
self.categories = []
self.img_id = 0
self.ann_id = 0
def save_coco_json(self, instance, save_path):
json.dump(instance, open(save_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=1) # indent=2 更加美观显示
# 由json文件构建COCO
def to_coco(self, json_path):
self._init_categories()
with open(file=json_path,mode='r',encoding="utf8") as f:
for f_num, data in enumerate(f):
obj = json.loads(data)
print("Deal image ",f_num)
self.images.append(self._image(obj))
if "myareaobj" in obj:
shapes = obj["myareaobj"]
for shape in shapes:
annotation = self._annotation(shape)
self.annotations.append(annotation)
self.ann_id += 1
self.img_id += 1
instance = {}
instance['info'] = 'my 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['supercategory'] = v[1]
category['id'] = v[0]
category['name'] = k
self.categories.append(category)
# 构建COCO的image字段
def _image(self, obj):
image = {}
image['height'] =obj["height"]
image['width'] = obj["width"]
image['id'] = self.img_id
image['file_name'] = obj["pict_id"]
return image
# 构建COCO的annotation字段
def _annotation(self, shape):
label = shape['ats']['fly']
points = shape["pointsdata"]
annotation = {}
annotation['id'] = self.ann_id
annotation['image_id'] = self.img_id
annotation['category_id'] = int(classname_to_id[label][0])
# annotation['segmentation'] = [np.asarray(points).flatten().tolist()]
annotation['segmentation'] = [[0,0]]
#annotation['bbox'] = self._get_box(points)
annotation['bbox'] = points
annotation['iscrowd'] = 0
annotation['area'] = 1.0
return annotation
# COCO的格式: [x1,y1,w,h] 对应COCO的bbox格式
def _get_box(self, points):
min_x = min_y = np.inf
max_x = max_y = 0
for x, y in points:
min_x = min(min_x, x)
min_y = min(min_y, y)
max_x = max(max_x, x)
max_y = max(max_y, y)
return [min_x, min_y, max_x - min_x, max_y - min_y]
if __name__ == '__main__':
saved_coco_path = "F:\data\instances_train2017.json"
train_path = r"F:\data\orgin\orign_data.json"
# 把训练集转化为COCO的json格式
l2c_train = Lable2CoCo()
train_instance = l2c_train.to_coco(train_path)
l2c_train.save_coco_json(train_instance, saved_coco_path)
参考
在目标检测和关键点检测任务中如何将自己的数据集转为coco格式 https://zhuanlan.zhihu.com/p/56881826
COCO 数据集的使用 https://www.cnblogs.com/q735613050/p/8969452.html
prepare_detection_dataset https://github.com/spytensor/prepare_detection_dataset