YOLO v8 使用cityscapes数据集进行实例分割任务

一、数据集下载

Dataset之Cityscapes:Cityscapes数据集的简介、安装、使用方法之详细攻略_cityscapes dataset-CSDN博客

二、转为COCO格式

1、下载官方脚本地址:GitHub - mcordts/cityscapesScripts: README and scripts for the Cityscapes Dataset

2、cityscapesscripts/helpers/labels.py文件,找到需要的实例分割的类别。注意 hasInstances=Ture 的类别才能够用于实例分割,也就是说只有10类。

3、了解COCO格式

详解COCO数据格式的json文件内容_coco数据集json标注-CSDN博客

4、下面以其中的8类为例:

import cv2
import numpy as np
import os, glob
from shutil import copyfile
import datetime
import json
import os
import re
import fnmatch
from PIL import Image
import numpy as np
import pycococreatortools
 
ROOT_DIR = 'E:/Datesets/cityscapes/cityscapes_val'
IMAGE_DIR = os.path.join(ROOT_DIR, "images")
ANNOTATION_DIR = os.path.join(ROOT_DIR, "gt")
ANNOTATION_SAVE_DIR = os.path.join(ROOT_DIR, "annotations")
INSTANCE_DIR = os.path.join(ROOT_DIR, "instances") 
IMAGE_SAVE_DIR = os.path.join(ROOT_DIR, "val_images")

INFO = {
    "description": "Cityscapes_Instance Dataset",
    "url": "https://github.com/waspinator/pycococreator",
    "version": "0.1.0",
    "year": "2020",
    "contributor": "Kevin_Jia",
    "date_created": "2020-1-23 19:19:19.123456"
}
 
LICENSES = [
    {
        "id": 1,
        "name": "Attribution-NonCommercial-ShareAlike License",
        "url": "http://creativecommons.org/licenses/by-nc-sa/2.0/"
    }
]

CATEGORIES = [
    {
        'id': 1,
        'name': 'person',
        'supercategory': 'cityscapes',
    },
    {
        'id': 2,
        'name': 'rider',
        'supercategory': 'cityscapes',
    },
    {
        'id': 3,
        'name': 'car',
        'supercategory': 'cityscapes',
    },
    {
        'id': 4,
        'name': 'truck',
        'supercategory': 'cityscapes',
    },
    {
        'id': 5,
        'name': 'bus',
        'supercategory': 'cityscapes',
    },
    {
        'id': 6,
        'name': 'train',
        'supercategory': 'cityscapes',
    },
    {
        'id': 7,
        'name': 'motorcycle',
        'supercategory': 'cityscapes',
    },
    {
        'id': 8,
        'name': 'bicycle',
        'supercategory': 'cityscapes',
    }
]

background_label = list(range(-1, 24, 1)) + list(range(29, 31, 1))
idx=0
pic_scale = 1.0
h_bias = 1.0

def image_trans():
    img_subfolders = os.listdir(IMAGE_DIR)
    image_count = 0
    for sub in img_subfolders:
        # sub_path = sub + '/' + sub
        image_sub_path = os.path.join(IMAGE_DIR, sub)
        for image in os.listdir(image_sub_path):
            img_path = os.path.join(image_sub_path, image)
            ann_name = image.split('_')[0] + '_' + image.split('_')[1] + '_' + image.split('_')[2] + '_gtFine_instanceIds.png'
            ann_sub_path = os.path.join(ANNOTATION_DIR, sub)
            ann_path = os.path.join(ann_sub_path, ann_name)
            if os.path.exists(ann_path): 
                pic = cv2.imread(img_path)
                h, w = pic.shape[:2]
                new_w = w * pic_scale
                new_h = new_w / 2
                top = int((h_bias*h-new_h)/2)
                bottom = int((h_bias*h+new_h)/2)
                left = int((w-new_w)/2)
                right = int((w+new_w)/2)
                roi = pic[top:bottom, left:right]
                img_save_path = os.path.join(IMAGE_SAVE_DIR, image)
                cv2.imwrite(img_save_path, roi) 
                annotation = cv2.imread(ann_path, -1)
                ann_roi = annotation[top:bottom, left:right]
                ann_save_path = os.path.join(ANNOTATION_SAVE_DIR, ann_name)
                cv2.imwrite(ann_save_path, ann_roi)
            else:
                print(image + '  do not have instance annotation')
            print(image_count)
            image_count += 1

def data_loader():
    imgs = os.listdir(IMAGE_SAVE_DIR)
    masks_generator(imgs, ANNOTATION_SAVE_DIR)

def masks_generator(imges, ann_path):
    global idx
    pic_count = 0
    for pic_name in imges:
        image_name = pic_name.split('.')[0]
        ann_folder = os.path.join(INSTANCE_DIR, image_name)
        os.mkdir(ann_folder)
        annotation_name = pic_name.split('_')[0] + '_' + pic_name.split('_')[1] + '_' + pic_name.split('_')[2] + '_gtFine_instanceIds.png'
        # annotation_name = image_name + '_instanceIds.png'
        print(annotation_name)
        annotation = cv2.imread(os.path.join(ann_path, annotation_name), -1)
        h, w = annotation.shape[:2]
        ids = np.unique(annotation)
        for id in ids:
            if id in background_label:
                continue
            else:
                class_id = id // 1000
                if class_id == 24:
                    instance_class = 'person'
                elif class_id == 25:
                    instance_class = 'rider'
                elif class_id == 26:
                    instance_class = 'car'
                elif class_id == 27:
                    instance_class = 'truck'
                elif class_id == 28:
                    instance_class = 'bus'
                elif class_id == 31:
                    instance_class = 'train'
                elif class_id == 32:
                    instance_class = 'motorcycle'
                elif class_id == 33:
                    instance_class = 'bicycle'
                else:
                    continue    
            instance_mask = np.zeros((h, w, 3),dtype=np.uint8)
            mask = annotation == id
            instance_mask[mask] = 255
            mask_name = image_name + '_' + instance_class + '_' + str(idx) + '.png'
            cv2.imwrite(os.path.join(ann_folder, mask_name), instance_mask)
            idx += 1
        pic_count += 1
        print(pic_count)
 
def json_generate():
    person = 0
    rider =0
    car = 0
    truck = 0
    bus = 0
    train = 0
    motorcycle = 0
    bicycle = 0
    files = os.listdir(IMAGE_SAVE_DIR)

    coco_output = {
        "info": INFO,
        "licenses": LICENSES,
        "categories": CATEGORIES,
        "images": [],
        "annotations": []
    }

    image_id = 1
    segmentation_id = 1

    # go through each image
    for image_filename in files:
        image_name = image_filename.split('.')[0]
        image_path = os.path.join(IMAGE_SAVE_DIR, image_filename)
        
        annotation_sub_path = os.path.join(INSTANCE_DIR, image_name)
        ann_files = os.listdir(annotation_sub_path)
        if len(ann_files) == 0:
            print("ao avaliable annotation")
            continue
        else:

            image = Image.open(image_path)
            image_info = pycococreatortools.create_image_info(
               image_id, os.path.basename(image_filename), image.size)
            coco_output["images"].append(image_info)
            print(image_filename)            

            for annotation_filename in ann_files:
                annotation_path = os.path.join(annotation_sub_path, annotation_filename)
                for x in CATEGORIES:
                    if x['name'] in annotation_filename:
                        class_id = x['id']
                        break
                # class_id = [x['id'] for x in CATEGORIES if x['name'] in annotation_filename][0]
                if class_id == 1:
                    person += 1
                elif class_id == 2:
                    rider += 1
                elif class_id == 3:
                    car += 1
                elif class_id == 4:
                    truck += 1
                elif class_id == 5:
                    bus += 1
                elif class_id == 6:
                    train += 1
                elif class_id == 7:
                    motorcycle += 1
                elif class_id == 8:
                    bicycle += 1
                else:
                    print('illegal class id')
                category_info = {'id': class_id, 'is_crowd': 'crowd' in image_filename}
                binary_mask = np.asarray(Image.open(annotation_path)
                                            .convert('1')).astype(np.uint8)

                annotation_info = pycococreatortools.create_annotation_info(
                        segmentation_id, image_id, category_info, binary_mask,
                        image.size, tolerance=2)

                if annotation_info is not None:
                    coco_output["annotations"].append(annotation_info)

                    segmentation_id = segmentation_id + 1

            image_id = image_id + 1
            print(image_id)
 
    with open('{}/val_modified.json'.format(ROOT_DIR), 'w') as output_json_file:
        json.dump(coco_output, output_json_file)
    print(person, rider, car, truck, bus,train,motorcycle,bicycle)

 
 
if __name__ == "__main__":
    #依次使用以下三个函数
    image_trans()
    #data_loader()
    #json_generate()
    

 在运行代码的时候可能会遇到一个错误(对于mask存在多部分时候报错):

File ".......pycococreator-master\pycococreatortools\pycococreatortools.py", line 99, in create_annotation_info
    segmentation = binary_mask_to_polygon(binary_mask, tolerance)
  File "........pycococreator-master\pycococreatortools\pycococreatortools.py", line 48, in binary_mask_to_polygon
    contours = np.subtract(contours, 1)
ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (2,) + inhomogeneous part.

解决方法:

#contours = np.subtract(contours, 1)注释该行,使用下面代替
contours = [np.subtract(c, 1) for c in contours]

详情查看:将CityScapes数据集转换为COCO格式的实例分割数据集_cityscapes数据标签转coco-CSDN博客

三、转为YOLO 格式 

分别将生成的训练集和测试集的json使用yolo v8自带的转换工具(注:尽量不要使用别人写的代码,后面介绍)

from ultralytics.data.converter import convert_coco

convert_coco(labels_dir='path/to/json/', use_segments=True)

别人的代码:

import os
import json
import shutil

def write_yolo_txt_file(txt_file_path,label_seg_x_y_list):
    if not os.path.exists(txt_file_path):
        with open(txt_file_path, "w") as file:
            for element in label_seg_x_y_list:
                file.write(str(element) + " ")
            file.write('\n')
    else:
        with open(txt_file_path, "a") as file:
            for element in label_seg_x_y_list:
                file.write(str(element) + " ")
            file.write('\n')

def read_json(in_json_path,img_dir,target_dir):
    with open(in_json_path, "r", encoding='utf-8') as f:
        # json.load数据到变量json_data
        json_data = json.load(f)

    # print(len(json_data['annotations']))
    # print(len(json_data['images']))
    # print(len(json_data['categories']))

    for annotation in json_data['annotations']: # 遍历标注数据信息
        # print(annotation)
        category_id = annotation['category_id']
        image_id = annotation['image_id']
        for image in json_data['images']: # 遍历图片相关信息
            if image['id'] == image_id:
                width = image['width'] # 图片宽
                height = image['height'] # 图片高
                img_file_name = image['file_name'] # 图片名称
                txt_file_name = image['file_name'].split('.')[0] + '.txt' # 要保存的对应txt文件名
                break
        # print(width,height,img_file_name,txt_file_name)
        segmentation = annotation['segmentation'] # 图像分割点信息[[x1,y1,x2,y2,...,xn,yn]]
        seg_x_y_list = [i/width if num%2==0 else i/height for num,i in enumerate(segmentation[0])] # 归一化图像分割点信息
        label_seg_x_y_list = seg_x_y_list[:]
        label_seg_x_y_list.insert(0,category_id-1) # 图像类别与分割点信息[label,x1,y1,x2,y2,...,xn,yn]    ###coco从1开始的
        # print(label_seg_x_y_list)

        # 写txt文件
        txt_file_path = target_dir + 'labels/' + txt_file_name
        # print(txt_file_path)
        write_yolo_txt_file(txt_file_path,label_seg_x_y_list)

        # 选出txt对应img文件
        img_file_path = img_dir + img_file_name
        # print(img_file_path)
        shutil.copy(img_file_path,target_dir + 'images/')



if __name__=="__main__":
    img_dir = '......../cityscapes/cityscapes_train/val_images/'
    target_dir = '...../cityscapes/cityscapes_train/train/'
    if not os.path.exists(target_dir):
        os.mkdir(target_dir)
    in_json_path = "......./cityscapes/cityscapes_train/val_modified.json"
    read_json(in_json_path,img_dir,target_dir)

四、效果

为什么别人写的代码存在问题呢?(主要还是因为存在一个实例分为多个部分)

yolo自带的转换后的标签:

别人代码转换后的标签:

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值