labelme标注自定义数据集COCO类型

使用labelme制作COCO类型的自定义数据集

一、COCO类型数据集

本文重点介绍COCO类自定义数据集制作,关于COCO数据格式参考以下链接:COCO数据集格式

二、自定义数据集制作步骤

(1)数据集文件夹说明

最终需要的文件夹目录如下图所示,其中data位于mmdetection项目根目录下。

image-20240205150004089

(2)使用labelme标注工具进行标注

具体使用方法参考:LabelMe使用_labelme中所有的create的作用解释-CSDN博客

(3)生成需要训练,验证,测试的图片txt文件

使用create_txt.py生成train2019.txt,val2019.txt,test2019.txt,分别对应需要训练,验证,测试的图片名(仅包括名,无扩展名.jpg)如:10001.jpg即保存为10001。create_txt.py文件代码 以及txt文件内容展示如下

# !/usr/bin/python
# -*- coding: utf-8 -*-
import os
import random

trainval_percent = 0.8  # 验证集+训练集占总比例多少
train_percent = 0.7  # 训练数据集占验证集+训练集比例多少
jsonfilepath = 'labels/total'
txtsavepath = './'
total_xml = os.listdir(jsonfilepath)

num = len(total_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv)
train = random.sample(trainval, tr)

ftrainval = open('./trainval.txt', 'w')
ftest = open('./test.txt', 'w')
ftrain = open('./train.txt', 'w')
fval = open('./val.txt', 'w')

for i in list:
    name = total_xml[i][:-5] + '\n'
    if i in trainval:
        ftrainval.write(name)
        if i in train:
            ftrain.write(name)
        else:
            fval.write(name)
    else:
        ftest.write(name)

ftrainval.close()
ftrain.close()
fval.close()
ftest.close()

image-20240205150820218

(4)通过classify.py程序将json文件与图片分类

此步骤是为了 将所有标注文件与图片文件按照 上一步三个txt文件里的进行分类对应

此步骤需要创建文件夹如下图所示。注意!!!images

import shutil
import cv2 as cv

sets=['train',  'val', 'test']

for image_set in sets:
    #分别读取三个txt文件中内容并拼接出 所有图片名
    image_ids = open('./%s.txt'%(image_set)).read().strip().split()
    #将每一类的图片和对应的json文件存入对应的文件夹
    for image_id in image_ids:
        img = cv.imread('images/total2019/%s.jpg' % (image_id))
        json='labelme/total/%s.json'% (image_id)
        cv.imwrite('images/%s/%s.jpg' % (image_set,image_id), img)
        cv.imwrite('labelme/%s/%s.jpg' % (image_set,image_id), img)
        shutil.copy(json,'labelme/%s/%s.json' % (image_set,image_id))
print("完成")


(5)建立建立labels.txt文件,并通过labelme2coco.py生成 instances_train.json,instances_test.json,instances_val.json

label.txt文件包括你自定义数据集的类别信息,其中第一行为背景 (默认忽略)

image-20240205152050644

labelme2coco.py文件负责将标注的json文件都转换到instances_XXX.json中。

下方代码根据个人需要有部分修改。官方labelme2coco.py项目参考链接:labelme2coco/labelme2coco/labelme2coco.py at master · fcakyon/labelme2coco · GitHub

# -*- coding: utf-8 -*-
#!/usr/bin/env python

import argparse
import collections
import datetime
import glob
import json
import os
import os.path as osp
import sys
import uuid

import imgviz
import numpy as np
import PIL.Image as Image

import labelme

try:
    import pycocotools.mask
except ImportError:
    print("Please install pycocotools:\n\n    pip install pycocotools\n")
    sys.exit(1)


def main():
    # parser = argparse.ArgumentParser(
    #    formatter_class=argparse.ArgumentDefaultsHelpFormatter
    # )
    # parser.add_argument("input_dir", help="input annotated directory")
    # parser.add_argument("output_dir", help="output dataset directory")
    # parser.add_argument("--labels", help="labels file", required=True)
    # parser.add_argument(
    #    "--noviz", help="no visualization", action="store_true"
    # )
    # args = parser.parse_args()

    # 需要变换路径执行三次 分别为train/test/val
    input_dir = './labels/test/'
    output_dir = './annotations/test/'
    labels = 'labels.txt'
    noviz = False

    if osp.exists(output_dir):
        print("Output directory already exists:", output_dir)
        sys.exit(1)
    os.makedirs(output_dir)
    #os.makedirs(osp.join(output_dir, "JPEGImages"))
    #if not noviz:
        #os.makedirs(osp.join(output_dir, "Visualization"))

    print("Creating dataset:", output_dir)

    now = datetime.datetime.now()

    data = dict(
        info=dict(
            description=None,
            url=None,
            version=None,
            year=now.year,
            contributor=None,
            date_created=now.strftime("%Y-%m-%d %H:%M:%S.%f"),
        ),
        licenses=[dict(url=None, id=0, name=None, )],
        images=[
            # license, url, file_name, height, width, date_captured, id
        ],
        type="instances",
        annotations=[
            # segmentation, area, iscrowd, image_id, bbox, category_id, id
        ],
        categories=[
            # supercategory, id, name
        ],
    )

    class_name_to_id = {}
    for i, line in enumerate(open(labels).readlines()):
        class_id = i   # starts with -1
        class_name = line.strip()
        if class_id == 0:
            assert class_name == "__ignore__"
            continue
        class_name_to_id[class_name] = class_id
        data["categories"].append(
            dict(supercategory=None, id=class_id, name=class_name, )
        )
    #out_ann_file 为要保存的最终json文件,注意每次要修改名称
    out_ann_file = osp.join(output_dir, "instances_test.json")
    # label_files 为所有要读取的标注json文件路径列表
    label_files = glob.glob(osp.join(input_dir, "*.json"))
    for image_id, filename in enumerate(label_files):
        print("Generating dataset from:", filename)

        label_file = labelme.LabelFile(filename=filename)

        base = osp.splitext(osp.basename(filename))[0]
        #out_img_file = osp.join(output_dir, "JPEGImages", base + ".jpg")
        # if label_file == "./labels/train/10109.json":
        #     print("123")


        img = labelme.utils.img_data_to_arr(label_file.imageData)
        #若果通道数为4 需要砍掉最后一个通道只保留RGB前三个通道
        if img.shape[-1]==4:
            img=img[:,:,:-1] #i:j,
        #print(img.shape,type(img))
        #imgviz.io.imsave(out_img_file, img)

        data["images"].append(
            dict(
                license=0,
                url=None,
                # file_name=osp.relpath(out_img_file, osp.dirname(out_ann_file)),
                file_name=base + ".jpg",
                height=img.shape[0],
                width=img.shape[1],
                date_captured=None,
                id=image_id,
            )
        )

        masks = {}  # for area
        segmentations = collections.defaultdict(list)  # for segmentation
        for shape in label_file.shapes:
            points = shape["points"]
            label = shape["label"]
            group_id = shape.get("group_id")
            shape_type = shape.get("shape_type", "polygon")
            mask = labelme.utils.shape_to_mask(
                img.shape[:2], points, shape_type
            )

            if group_id is None:
                group_id = uuid.uuid1()

            instance = (label, group_id)

            if instance in masks:
                masks[instance] = masks[instance] | mask
            else:
                masks[instance] = mask

            if shape_type == "rectangle":
                (x1, y1), (x2, y2) = points
                x1, x2 = sorted([x1, x2])
                y1, y2 = sorted([y1, y2])
                points = [x1, y1, x2, y1, x2, y2, x1, y2]
            if shape_type == "circle":
                (x1, y1), (x2, y2) = points
                r = np.linalg.norm([x2 - x1, y2 - y1])
                # r(1-cos(a/2))<x, a=2*pi/N => N>pi/arccos(1-x/r)
                # x: tolerance of the gap between the arc and the line segment
                n_points_circle = max(int(np.pi / np.arccos(1 - 1 / r)), 12)
                i = np.arange(n_points_circle)
                x = x1 + r * np.sin(2 * np.pi / n_points_circle * i)
                y = y1 + r * np.cos(2 * np.pi / n_points_circle * i)
                points = np.stack((x, y), axis=1).flatten().tolist()
            else:
                points = np.asarray(points).flatten().tolist()

            segmentations[instance].append(points)
        segmentations = dict(segmentations)

        for instance, mask in masks.items():
            cls_name, group_id = instance
            if cls_name not in class_name_to_id:
                continue
            cls_id = class_name_to_id[cls_name]

            mask = np.asfortranarray(mask.astype(np.uint8))
            mask = pycocotools.mask.encode(mask)
            area = float(pycocotools.mask.area(mask))
            bbox = pycocotools.mask.toBbox(mask).flatten().tolist()

            data["annotations"].append(
                dict(
                    id=len(data["annotations"]),
                    image_id=image_id,
                    category_id=cls_id,
                    segmentation=segmentations[instance],
                    area=area,
                    bbox=bbox,
                    iscrowd=0,
                )
            )

        if not noviz:
            viz = img
            if masks:

                listdata_labels = []
                listdata_captions = []
                listdata_masks = []

                for (cnm, gid), msk in masks.items():
                    if cnm in class_name_to_id:
                        listdata_labels.append(class_name_to_id[cnm])
                        listdata_captions.append(cnm)
                        listdata_masks.append(msk)

                listdata = zip(listdata_labels, listdata_captions, listdata_masks)
                labels, captions, masks = zip(*listdata)
                # labels, captions, masks = zip(*[(listdata_labels, listdata_captions, listdata_masks)])

                # print(len(masks))

                # labels, captions, masks = zip(
                #    *[
                #        (class_name_to_id[cnm], cnm, msk)
                #        for (cnm, gid), msk in masks.items()
                #        if cnm in class_name_to_id
                #    ]
                # )
                viz = imgviz.instances2rgb(
                    image=img,
                    labels=labels,
                    masks=masks,
                    captions=captions,
                    font_size=15,
                    line_width=2,
                )
            out_viz_file = osp.join(
                output_dir, "Visualization", base + ".jpg"
            )
            imgviz.io.imsave(out_viz_file, viz)

    with open(out_ann_file, "w") as f:
        json.dump(data, f)


if __name__ == "__main__":
    main()

最终得到 需要的三个json文件 即 instances_train.jsoninstances_test.jsoninstances_val.json 将这三个文件存入步骤(1)annotations文件夹中

并将步骤(4)中 分类好的 train、val、test图片文件夹,存入步骤(1)中的文件夹。


上述步骤是关于如何制作COCO类自定义数据集。

  • 12
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值