加载COCO实例分割标注出现错误:TypeError: Argument ‘bb‘ has incorrect type (expected numpy.ndarray, got list)的解决方案

使用labelImage对自己的数据集标注之后,使用label2coco脚本转换得到coco_instancestrain.json格式的标注文件,然后使用mmdetection框架加载上述自己做的实例分割任务数据集和自己做的对应的coco实例分割格式标注文件时出现错误:

TypeError: Argument 'bb' has incorrect type (expected numpy.ndarray, got list)

解决办法如下:

  1. 首先,检查转换后的coco_instancestrain.json和coco_instancesval.json标注文件格式是否错误,提供了如下python脚本:
from pycocotools.coco import COCO
import json

def check_coco_format(json_file_path):
    # 加载JSON文件
    with open(json_file_path, 'r') as f:
        coco_data = json.load(f)

    # 创建COCO实例
    coco = COCO()
    coco.dataset = coco_data
    coco.createIndex()

    # 验证格式
    ann_ids = coco.getAnnIds()
    img_ids = coco.getImgIds()
    cat_ids = coco.getCatIds()

    # 检查是否存在图像、注释和类别
    if not img_ids:
        print("错误:缺少图像数据。")
        return False
    if not ann_ids:
        print("错误:缺少注释数据。")
        return False
    if not cat_ids:
        print("错误:缺少类别数据。")
        return False

    # 验证注释中的图像ID和类别ID是否有效
    for ann_id in ann_ids:
        ann = coco.loadAnns(ann_id)[0]
        if ann['image_id'] not in img_ids:
            print(f"错误:注释 {ann_id} 中的图像ID无效。")
            return False
        if ann['category_id'] not in cat_ids:
            print(f"错误:注释 {ann_id} 中的类别ID无效。")
            return False

    print("COCO格式验证通过。")
    return True

# 在此处替换为你的coco_instances.json文件路径
json_file_path = 'path/to/your/coco_instancesxxx.json'

# 检查coco_instances.json文件的格式
check_coco_format(json_file_path)

如果检查成功,那么会返回”COCO格式验证通过。“结果。如果coco标注没有问题,那么进行下面的检查。

  1. 由于mmdetection对coco数据集标注文件的加载使用pycocotools/mask.py中的frPyObjects()函数[https://github.com/cocodataset/cocoapi/blob/8c9bcc3cf640524c4c20a9c40e89cb6a2f2fa0e9/PythonAPI/pycocotools/_mask.pyx#L288],且该函数完整代码如下:
def frPyObjects(pyobj, h, w):
    # encode rle from a list of python objects
    if type(pyobj) == np.ndarray:
        objs = frBbox(pyobj, h, w)
    elif type(pyobj) == list and len(pyobj[0]) == 4:
        objs = frBbox(pyobj, h, w)
    elif type(pyobj) == list and len(pyobj[0]) > 4:
        objs = frPoly(pyobj, h, w)
    elif type(pyobj) == list and type(pyobj[0]) == dict \
        and 'counts' in pyobj[0] and 'size' in pyobj[0]:
        objs = frUncompressedRLE(pyobj, h, w)
    # encode rle from single python object
    elif type(pyobj) == list and len(pyobj) == 4:
        objs = frBbox([pyobj], h, w)[0]
    elif type(pyobj) == list and len(pyobj) > 4:
        objs = frPoly([pyobj], h, w)[0]
    elif type(pyobj) == dict and 'counts' in pyobj and 'size' in pyobj:
        objs = frUncompressedRLE([pyobj], h, w)[0]
    else:
        raise Exception('input type is not supported.')
    return objs

其中,可以看到该函数传入的第一个参数为“pyobj”,该参数对应coco_instancestrain.json/coco_instancesval.json标注文件中的每个segmentation对象,一个典型的segmentation对象格式如下:

{
            "id": 414,
            "image_id": 36,
            "category_id": 2,
            # 一个典型的segmentation对象
            "segmentation": [
                [
                    241.2121212121212,
                    173.93939393939394,
                    242.2121212121212,
                    173.93939393939394,
                    243.2121212121212,
                    173.93939393939394
                ]
            ],
            "area": 97.0,
            "bbox": [
                236.0,
                168.0,
                11.0,
                11.0
            ],
            "iscrowd": 0
        },

那么,如果报错“raise Exception(‘input type is not supported.’)”,说明frPyObjects()函数的所有if条件不满足,肯定存在个别segmentation对象的len(segmentation[0])的长度不满足大于4(那就是小于等于4,都需要进行判断),这里提供一个修改脚本,将不符合条件的segmentation列表修改为符合条件即可:

import json
import numpy as np

# 首先将frPyObjects()完整函数copy过来,用于之后的判断,对于每个if条件语句,打印对应的标注
def frPyObjects(i, pyobj):
    # encode rle from a list of python objects
    if type(pyobj) == np.ndarray:
        print("{}, {}, {}".format(i, type(pyobj), len(pyobj[0])))
    elif type(pyobj) == list and len(pyobj[0]) == 4:
        print("{}, {}, {}".format(i, type(pyobj), len(pyobj[0])))
    elif type(pyobj) == list and len(pyobj[0]) > 4:
        print("{}, {}, {}".format(i, type(pyobj), len(pyobj[0])))
    elif type(pyobj) == list and type(pyobj) == dict and 'counts' in pyobj[0] and 'size' in pyobj[0]:
        print("{}, {}, {}".format(i, type(pyobj), len(pyobj[0])))
    # encode rle from single python object
    elif type(pyobj) == list and len(pyobj[0]) == 4:
        print("{}, {}, {}".format(i, type(pyobj), len(pyobj[0])))
    elif type(pyobj) == list and len(pyobj[0]) > 4:
        print("{}, {}, {}".format(i, type(pyobj), len(pyobj[0])))
    elif type(pyobj) == dict and 'counts' in pyobj and 'size' in pyobj:
        print("{}, {}, {}".format(i, type(pyobj), len(pyobj[0])))
    else:
        print("{}, {}, {}".format(i, type(pyobj), len(pyobj[0])))
        raise Exception('input type is not supported.')

# 然后传入你自己的coco格式标注文件绝对路径
JSON_LOC="path/to/your/coco.json"

#打开json文件
val_json = open(JSON_LOC, "r")
json_object = json.load(val_json)
val_json.close()

# 遍历coco.json文件中的所有segmentation对象,对于每个对象送入frPyObjects()函数进行检查,来找到不符合条件的segmentation对象
for i, instance in enumerate(json_object["annotations"]):
    frPyObjects(i, instance["segmentation"])

# 之后,可以根据上述print()打印出来的不符合条件对象的id,来修改对应的segmentation列表(手动修改即可,不符合条件的数量一般很少)
json_object["annotations"][1510]["segmentation"] = [[230.83333333333331, 773.8888888888889, 231.83333333333331, 773.8888888888889, 237.22222222222223, 770.5555555555555]]

# 将修改后的json文件重新写回到coco_instancestrain.json/coco_instancesval.json中即可
val_json = open(JSON_LOC, "w")
json.dump(json_object, val_json)
val_json.close()

一般来说,经过上述步骤就可以实现对coco格式的实例分割标注文件进行一个全面检查,重新运行程序,应该就不会报错了。

你可能感兴趣的:(研1沉淀,mmdetection,labelImage,coco_instance,实例分割任务报错解决)