Pytorch_Coco数据集转换_pre_transform_format

数据集处理-数据集转换格式

   数据为王,而合适的数据格式也非常重要
    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
原文地址:https://www.cnblogs.com/ytwang/p/15741726.html