Detectron: El formato RLE o polígono de "segmentación" para extender al conjunto de datos de coco

Creado en 2 feb. 2018  ·  38Comentarios  ·  Fuente: facebookresearch/Detectron

Hola Detectron,

Recientemente intenté agregar mis datos de coco personalizados para ejecutar Detectron y encontré los siguientes problemas.
(1) "segmentación" en datos de coco como se muestra a continuación ,

{"segmentation": [[ 499.71, 397.28, ...... 342.71, 172.31 ]] , "area": ​​43466.12825, "iscrowd": 0, "image_id": 182155, "bbox": [338.89, 51.69, 205.82, 367.61], "category_id": 1, "id": 1248258},

{"segmentation": {"count": [66916, 6, 587, ..... 1, 114303], "size": [594, 640] }, "area": ​​6197, "iscrowd": 1, "image_id": 284445, "bbox": [112, 322, 335, 94], "category_id": 1, "id": 9.001002844e + 11},
El primer formato de "segmentación" es polígono y el segundo es necesario para codificar / decodificar para formato RLE.

Los formatos anteriores se pueden ejecutar en Detectron.

(2) Agregué una nueva categoría y generé un nuevo formato RLE para el campo de "segmentación" a través de la máscara coco api encode () / decode ().
Genere datos como este.

"segmentación": [{ "cuenta ": "Gestión = 1fb02O1O1O001N2O001O1O0O2O1O1O001N2O001O1O0O2O1O001O1O1O010000O01000O010000O01000O01000O01000O01N2N2M2O2N2N1O2N2O001O10O B000O10O1O001 ^ OQ ^ O9Pb0EQ ^ O; Wb0OO01O1O1O001O1N2N`jT3?"," tamaño": [600,1000]}]

Encontré que los caracteres en negrita son diferentes del formato json de "segmentación" de coco original, aunque puede ejecutarse en la implementación de MatterPort para Mask-RCNN.

Además, traté de modificar algunos códigos de Detectron para cumplir con mis requisitos, pero fue muy difícil para mí porque es necesario cambiar muchos códigos.

¿Podría darme algunas sugerencias para ejecutar mis datos personalizados?

Gracias.

community help wanted

Comentario más útil

@topcomma
Tal vez puedas intentar convertir la máscara en polis.

labels_info = []
for mask in mask_list:
    # opencv 3.2
    mask_new, contours, hierarchy = cv2.findContours((mask).astype(np.uint8), cv2.RETR_TREE,
                                                        cv2.CHAIN_APPROX_SIMPLE)
    # before opencv 3.2
    # contours, hierarchy = cv2.findContours((mask).astype(np.uint8), cv2.RETR_TREE,
    #                                                    cv2.CHAIN_APPROX_SIMPLE)
    segmentation = []

    for contour in contours:
        contour = contour.flatten().tolist()
        # segmentation.append(contour)
        if len(contour) > 4:
            segmentation.append(contour)
    if len(segmentation) == 0:
        continue
    # get area, bbox, category_id and so on
    labels_info.append(
        {
            "segmentation": segmentation,  # poly
            "area": area,  # segmentation area
            "iscrowd": 0,
            "image_id": index,
            "bbox": [x1, y1, bbox_w, bbox_h],
            "category_id": category_id,
            "id": label_id
        },
    )

Todos 38 comentarios

Tuve un problema similar: algunas de las funciones en lib / utils / segms.py esperan que las segmentaciones estén en formato "poli" y se rompan cuando se proporcionan en RLE.
Es un inconveniente, pero parece estar en línea con la especificación para regiones no concurridas (iscrowd = 0):

El formato de segmentación depende de si la instancia representa un solo objeto (iscrowd = 0 en cuyo caso se usan polígonos) o una colección de objetos (iscrowd = 1 en cuyo caso se usa RLE).

[1] http://cocodataset.org/#download , sección "4.1. Anotaciones de instancia de objeto"

La solución para mí fue transformarme al formato "poli", que es esencialmente una lista de vértices (x, y).

-Lesha.

El 2 de febrero de 2018, a las 06:41, Hu Xingui [email protected] escribió:

Hola Detectron,

Recientemente intenté agregar mis datos de coco personalizados para ejecutar Detectron y encontré los siguientes problemas.
(1) "segmentación" en datos de coco como se muestra a continuación ,

{"segmentation": [[499.71, 397.28, ...... 342.71, 172.31]], "area": ​​43466.12825, "iscrowd": 0, "image_id": 182155, "bbox": [338.89, 51.69, 205.82, 367.61], "category_id": 1, "id": 1248258},

{"segmentation": {"count": [66916, 6, 587, ..... 1, 114303], "size": [594, 640]}, "area": ​​6197, "iscrowd": 1, "image_id": 284445, "bbox": [112, 322, 335, 94], "category_id": 1, "id": 9.001002844e + 11},
El primer formato de "segmentación" es polígono y el segundo es necesario para codificar / decodificar para formato RLE.

Los formatos anteriores se pueden ejecutar en Detectron.

(2) Agregué una nueva categoría y generé un nuevo formato RLE para el campo de "segmentación" a través de la máscara coco api encode () / decode ().
Genere datos como este.

"Segmentación": [{ "cuenta": "Gestión = 1fb02O1O1O001N2O001O1O0O2O1O1O001N2O001O1O0O2O1O001O1O1O010000O01000O010000O01000O01000O01000O01N2N2M2O2N2N1O2N2O001O10O B000O10O1O001 ^ OQ ^ O9Pb0EQ ^ O; Wb0OO01O1O1O001O1N2N`jT3?", "Tamaño": [600,1000]}]

Encontré que los caracteres en negrita son diferentes del formato json de "segmentación" de coco original, aunque puede ejecutarse en la implementación de MatterPort para Mask-RCNN.

Además, traté de modificar algunos códigos de Detectron para cumplir con mis requisitos, pero fue muy difícil para mí porque es necesario cambiar muchos códigos.

¿Podría darme algunas sugerencias para ejecutar mis datos personalizados?

Gracias.

-
Estás recibiendo esto porque estás suscrito a este hilo.
Responda a este correo electrónico directamente, véalo en GitHub o silencie el hilo.

@amokeev , ¿Cómo convertir el formato "RLE" a "poli" a su solución?

@amokeev , ¿estás seguro de que el número en la segmentación es (x, y) vértices? Por ejemplo, "66916", ¡un gran número! Otro, aunque configuré "iscrowd" como "1" para el formato RLE, no se pudo ejecutar en Detectron.

Interpreto poli como una lista de polígonos, definida por los vértices, como [[x1, y1, x2, y2… xN, yN],… [x1, y1, x2, y2… xN, yN]], donde las coordenadas son de la misma escala que la imagen.
Las máscaras, codificadas de esta manera, se muestran correctamente en CocoAPI [1].

Pero es posible que desee obtener una respuesta "oficial".

[1] https://github.com/cocodataset/cocoapi https://github.com/cocodataset/cocoapi

El 2 de febrero de 2018, a las 09:18, Hu Xingui [email protected] escribió:

@amokeev https://github.com/amokeev , ¿está seguro de que el número en la segmentación es (x, y) vértices? Por ejemplo, "66916", ¡un gran número! Otro, aunque configuré "iscrowd" como "1" para el formato RLE, no se pudo ejecutar en Detectron.

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub https://github.com/facebookresearch/Detectron/issues/100#issuecomment-362516928 , o silencie el hilo https://github.com/notifications/unsubscribe-auth/AFlh63ObnXg- DcaDKwIi3pB4Ppig464Hks5tQsTkgaJpZM4R2tN3 .

@topcomma
Tal vez puedas intentar convertir la máscara en polis.

labels_info = []
for mask in mask_list:
    # opencv 3.2
    mask_new, contours, hierarchy = cv2.findContours((mask).astype(np.uint8), cv2.RETR_TREE,
                                                        cv2.CHAIN_APPROX_SIMPLE)
    # before opencv 3.2
    # contours, hierarchy = cv2.findContours((mask).astype(np.uint8), cv2.RETR_TREE,
    #                                                    cv2.CHAIN_APPROX_SIMPLE)
    segmentation = []

    for contour in contours:
        contour = contour.flatten().tolist()
        # segmentation.append(contour)
        if len(contour) > 4:
            segmentation.append(contour)
    if len(segmentation) == 0:
        continue
    # get area, bbox, category_id and so on
    labels_info.append(
        {
            "segmentation": segmentation,  # poly
            "area": area,  # segmentation area
            "iscrowd": 0,
            "image_id": index,
            "bbox": [x1, y1, bbox_w, bbox_h],
            "category_id": category_id,
            "id": label_id
        },
    )

@amokeev ,
@Gotas de sol

Gracias por tus sugerencias.
Intentará.

@Sundrops , como su método para convertir, puede obtener el resultado de la lista "poli". Muchas gracias! ¿Pero todavía no sé por qué la coordenada en el archivo json de COCO es un número grande / pequeño como "66916" o "1"?

@topcomma Las anotaciones COCO tienen dos tipos de anotaciones de segmentación

  1. polígono (instancia de objeto) [[499.71, 397.28, ...... 342.71, 172.31]] vértices
  2. RLE sin comprimir (multitud). "segmentation": {"count": [66916, 6, 587, ..... 1, 114303], "size": [594, 640]}, 66916 representa el número de etiqueta 0.

El polígono y el RLE sin comprimir se convertirán al formato RLE compacto con MaskApi.
El formato compacto RLE:
segmentación ": [{" cuenta ": "Gestión = 1fb02O1O1O001N2O001O1O0O2O1O1O001N2O001O1O0O2O1O001O1O1O010000O01000O010000O01000O01000O01000O01N2N2M2O2N2N1O2N2O001O10O B000O10O1O001 ^ OQ ^ O9Pb0EQ ^ O; Wb0OO01O1O1O001O1N2N`jT3"," tamaño ":? [600,1000]}]

@Gotas de sol ,
Gracias por tu gran ayuda.
Mis datos personalizados tipo coco se pueden entrenar en Detectron ahora.

@topcomma ,
tengo el mismo problema que tú.
Como método de Sundrops, no puedo encontrar el archivo para convertir la máscara a polys.
¿Podrías decirme qué archivo? ¡Muchas gracias!

@ lg12170226
Puede consultar el código python de coco stuff (https://github.com/nightrome/cocostuff) para implementarlo usted mismo.
En la base del código no hay ningún archivo de la anotación relacionada.

@topcomma : Tengo una imagen sin procesar e imágenes de etiqueta N . Cada etiqueta se almacena en un solo archivo, por lo que tengo N imagen para la etiqueta. Quiero entrenar Mask RCNN en mi propio conjunto de datos, por lo que primero necesito convertir al formato COCO. ¿Podrías compartir el código de cómo convertirlo al estilo COCO? Gracias

¿Me pregunto si hay una manera de convertir RLE comprimidos en polys / RLE sin comprimir?

@realwecan después de decodificar RLE con pycocotools.mask.decode, puede verificar mi implementación para generar polígonos con opencv:

coco-json-convertidor

@hazirbas : gracias por tu código. ¿Por qué no utilizar Davis 2017 que contiene segmentación de instancias? ¿Podríamos usar su código para convertir Davis 2017 a formato coco para usar esta implementación de maskrcnn?

@ John1231983 , debe modificar el script en consecuencia para leer archivos divididos, así como el archivo db_info.yml. Para mi propia investigación, lo necesitaba para DAVIS 2016.

Otra solución para generar polígonos, pero usando skimage lugar de opencv .

import json
import numpy as np
from pycocotools import mask
from skimage import measure

ground_truth_binary_mask = np.array([[  0,   0,   0,   0,   0,   0,   0,   0,   0,   0],
                                     [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0],
                                     [  0,   0,   0,   0,   0,   1,   1,   1,   0,   0],
                                     [  0,   0,   0,   0,   0,   1,   1,   1,   0,   0],
                                     [  0,   0,   0,   0,   0,   1,   1,   1,   0,   0],
                                     [  0,   0,   0,   0,   0,   1,   1,   1,   0,   0],
                                     [  1,   0,   0,   0,   0,   0,   0,   0,   0,   0],
                                     [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0],
                                     [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0]], dtype=np.uint8)

fortran_ground_truth_binary_mask = np.asfortranarray(ground_truth_binary_mask)
encoded_ground_truth = mask.encode(fortran_ground_truth_binary_mask)
ground_truth_area = mask.area(encoded_ground_truth)
ground_truth_bounding_box = mask.toBbox(encoded_ground_truth)
contours = measure.find_contours(ground_truth_binary_mask, 0.5)

annotation = {
        "segmentation": [],
        "area": ground_truth_area.tolist(),
        "iscrowd": 0,
        "image_id": 123,
        "bbox": ground_truth_bounding_box.tolist(),
        "category_id": 1,
        "id": 1
    }

for contour in contours:
    contour = np.flip(contour, axis=1)
    segmentation = contour.ravel().tolist()
    annotation["segmentation"].append(segmentation)

print(json.dumps(annotation, indent=4))

¿Cómo convertiría una máscara binaria o RLE codificado en RLE sin comprimir para usar en el campo "iscrowd: 1" "cuenta"?

@waspinator Las segmentaciones con su código usando skimage son diferentes del código de @Sundrops usando cv2.
¿Son estos dos resultados correctos y puede Detectron utilizar ambos resultados? Por favor, dame un consejo, gracias. @waspinator @Sundrops

Resultados usando su código con skimage:

{"segmentación": [[0.0, 252.00196078431372, 1.0, 252.00196078431372, 2.0, 252.00196078431372, 3.0, 252.00196078431372, 4.0, 252.00196078431372, 5.0, 252.00196078431372, 6.0, 252.00196078431372, 6.0, 252.00196078431360, 10.02.00196078431360, 7.02132.003 , 11,0, 252,00196078431372, 12,0, 252,00196078431372, 13,0, 252,00196078431372, 14,0, 252,00196078431372, 15,0, 252,00196078431372, 16,0, 252,00196078431372, 17,0, 252,00196078431372, 18,0, 252,00196078431372, 19,0, 252,00196078431372, 20,0, 252,00196078431372, 21,0, 252,00196078431372, 22,0, 252,00196078431372, 23,0 , 252,00196078431372, 24,0, 252,00196078431372, 25,0, 252,00196078431372, 26,0, 252,00196078431372, 27,0, 252,00196078431372, 28,0, 252,00196078431372, 29,0, 252,00196078431372, 30,0, 252,00196078431372, 31,0, 252,00196078431372, 32,0, 252,00196078431372, 33,0, 252,00196078431372, 34,0, 252,00196078431372, 35,0, 252,00196078431372 , 36,0, 252,00196078431372, 37,0, 252,00196078431372, 38. 0, 252,00196078431372, 39,0, 252,00196078431372, 40,0, 252,00196078431372, 41,0, 252,00196078431372, 42,0, 252,00196078431372, 43,0, 252,00196078431372, 44,0, 252,00196078431372, 45,0, 252,00196078431372, 46,0, 252,00196078431372, 47,0, 252,00196078431372, 48,0, 252,00196078431372, 49,0, 252,00196078431372, 50,0, 252,00196078431372, 51,0, 252,00196078431372, 52,0, 252,00196078431372, 53,0, 252,00196078431372, 54,0, 252,00196078431372, 55,0, 252,00196078431372, 56,0, 252,00196078431372, 57,0, 252,00196078431372, 58,0, 252,00196078431372, 59,0, 252,00196078431372, 60,0, 252,00196078431372, 61,0, 252,00196078431372, 62,0, 252,00196078431372, 63.0, 252,00196078431372, 64,0, 252,00196078431372, 65,0, 252,00196078431372, 66,0, 252,00196078431372, 67,0, 252,00196078431372, 68,0, 252,00196078431372, 69,0, 252,00196078431372, 70,0, 252,00196078431372, 71,0, 252,00196078431372, 72,0, 252,00196078431372, 73,0, 252,00196078431372, 74,0, 252,00196078431372, 75,0, 252.00196078431372, 76.0, 252.00196 078431372, 77,0, 252,00196078431372, 78,0, 252,00196078431372, 79,0, 252,00196078431372, 80,0, 252,00196078431372, 81,0, 252,00196078431372, 82,0, 252,00196078431372, 83,0, 252,00196078431372, 84,0, 252,00196078431372, 85,0, 252,00196078431372, 86,0, 252,00196078431372, 87,0, 252,00196078431372, 88,0, 252,00196078431372, 89.0, 252.00196078431372, 90.0, 252.00196078431372, 91.0, 252.00196078431372, 92.0, 252.00196078431372, 93.0, 252.00196078431372, 93.00196078431372, 252.0, 94.0, 251.00196078431372, 951960.0 ...

Los resultados con el uso de código de @Sundrops cv2:

[94, 252, 93, 253, 0, 253, 0, 286, 188, 286, 188, 269, 187, 268, 187, 252]

@Kongsea No he probado la implementación de @Sundrops cv2, pero la idea básica debería ser la misma. Producirán resultados diferentes ya que hay una cantidad infinita de conjuntos de puntos que puede usar para describir una forma. Pero de lo contrario, ambos deberían funcionar. Simplemente no tenía cv2 instalado, así que escribí algo que no lo requiere.

@Kongsea @waspinator He probado mi código. Funciona.

Gracias @Sundrops @waspinator .
Lo intentaré.

@waspinator ¿Hay alguna forma de convertir el vértice polivinílico de segmentación en RLE? Mi objetivo es iscrowd = 1

@Sundrops ¿Por qué

# if len(contour) > 4:
    #     segmentation.append(contour)
# if len(segmentation) == 0:
#     continue

De hecho, necesitamos manejar un caso así, ¿verdad?

@ Yuliang-Zou Debería descomentar esta parte cuando se utilicen contornos para Detectron. Beacase, el Detectron lo tratará como un rectángulo cuando len (contorno) == 4. He actualizado mi código anterior.

@Sundrops Gracias. Pero todavía tenemos que manejar len(contour)==2 , ¿verdad?

@ Yuliang-Zou Sí, pero el código if len(contour) > 4: maneja len(contour)==2 y len(contour)==4 .

@Sundrops ya veo, ¡gracias!

Escribí una biblioteca y un artículo para ayudar a crear conjuntos de datos de estilo COCO.

https://patrickwasp.com/create-your-own-coco-style-dataset/

@Sundrops & @topcomma Tengo un problema para cargar los datos anotados en pycocotols ya que mi anotación está incluida en la segmentación sin máscara. ¿Alguna idea de cómo visualizar la anotación sin máscara en pycocotools?

@Gotas de sol
Ana: {
"segmentación": [
[312.29, 562.89, 402.25, 511.49, 400.96, 425.38, 398.39, 372.69, 388.11, 332.85, 318.71, 325.14, 295.58, 305.86, 269.88, 314.86, 258.31, 337.99, 217.19, 321.29, 182.38 , 358.55, 159.36, 377.83, 116.95, 421.53, 167.07, 499.92, 232.61, 560.32, 300.72, 571.89]
],
"área": ​​54652.9556,
"iscrowd": 0,
"image_id": 480023,
"bbox": [116,95, 305,86, 285,3, 266,03],
"category_id": 58,
"id": 86
}
¿Cómo puedo calcular el área con mask.py en coco-api? Gracias.
Mi código es el siguiente pero error:

segmentación = ann ['segmentación']
bimask = np.array (segmentación, dtype = np.uint8, order = 'F')
imprimir ("bimask:", bimask)
rleObjs = mask.encode (bimask)
print ("rleObjs:", rleObjs)
area = mascara.area (rleObjs)
print ("área:", área)

@manketon
Quizás puedas probar cv2, pero no estoy seguro de que sea correcto. Es solo un ejemplo de Eliminar contornos de una imagen usando Python y OpenCV .

def is_contour_bad(c):
    # approximate the contour
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    # return True if it is not a rectangle
    return not len(approx) == 4
image = cv2.imread('xx.jpg')
contours = ann['segmentation']
mask = np.ones(image.shape[:2], dtype="uint8") * 255
# loop over the contours
for c in contours:
    # if the contour is not a rectangle, draw it on the mask
    if is_contour_bad(c):
        cv2.drawContours(mask, [c], -1, 0, -1)
area = (mask==0).sum()

@Sundrops @waspinator Tengo una pregunta. Si mi máscara de objeto original tiene grandes agujeros, cuando se convierte en polígonos, ¿cómo debo volver a convertirla correctamente? Las funciones de decodificación y fusión en coco API tratarían el agujero como partes del objeto, por lo que cuando se convierte de nuevo, los agujeros se convierten en máscaras. ¿Cómo debo hacer en este caso?

@ wangg12 Hasta donde yo sé, COCO no tiene una forma nativa de codificar agujeros.

for contour in contours:
        contour = contour.flatten().tolist()
        segmentation.append(contour)
        if len(contour) > 4:
            segmentation.append(contour)

Hola @Sundrops , sinceramente gracias por tus códigos. Soy un principiante en Detectron. Me siento confundido por qué la longitud del contorno (que es una lista) debería ser mayor que 4, en otras palabras, qué sucederá con el modelo cuando la longitud sea menor que 4. Una de sus respuestas dijo que Detectron lo tratará como un rectángulo. En mi perspectiva, puede haber algunos objetos con forma de rectángulo, así que creo que está bien. Además, me pregunto si agrega el contorno dos veces en una iteración. Creo que debería ser el código correcto.

for contour in contours:
        contour = contour.flatten().tolist()
        if len(contour) > 4:
            segmentation.append(contour)

Le agradeceríamos mucho que me pudiera dar algunas sugerencias. ¡Muchas gracias!

@BobZhangHT Sí, debería agregar el contorno por una vez en una iteración.
Para su primera pregunta, si len (ann ['segmentación'] [0]) == 4, cocoapi asumirá que todos son rectángulos.

# cocoapi/PythonAPI/pycocotools/coco.py
def annToRLE(self, ann):
    t = self.imgs[ann['image_id']]
    h, w = t['height'], t['width']
    segm = ann['segmentation']
    if type(segm) == list:
        rles = maskUtils.frPyObjects(segm, h, w) 
        rle = maskUtils.merge(rles)
   ......
# cocoapi/PythonAPI/pycocotools/_mask.pyx
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)
   ......

@Sundrops ¡ Gracias por tu respuesta!

Interpreto poli como una lista de polígonos, definida por los vértices, como [[x1, y1, x2, y2… xN, yN],… [x1, y1, x2, y2… xN, yN]], donde las coordenadas son de la misma escala que la imagen. CocoAPI [1] muestra correctamente las máscaras, codificadas de esta manera, pero es posible que desee obtener una respuesta “oficial”. [1] https://github.com/cocodataset/cocoapi https://github.com/cocodataset/cocoapi
...
El 2 de febrero de 2018, a las 09:18, Hu Xingui @ . * > escribió: @amokeev https://github.com/amokeev , ¿Está seguro de que el número en la segmentación es (x, y) vértices? Por ejemplo, "66916", ¡un gran número! Otro, aunque configuré "iscrowd" como "1" para el formato RLE, no se pudo ejecutar en Detectron. - Recibes esto porque te mencionaron. Responda a este correo electrónico directamente, véalo en GitHub < # 100 (comentario) > o silencia el hilo https://github.com/notifications/unsubscribe-auth/AFlh63ObnXg-DcaDKwIi3pB4Ppig464Hks5tQsTkgaJpZM4R2tN3 .

¿Cómo puedo transformar RLE en polígonos cuando "iscrowd" es "1" porque el puerto de materia / MaskRCNN solo funciona con polígonos? @amokeev. Quiero usar la implementación de Matterport de maskRCNN con un conjunto de datos de coco creado usando pycococreator.

¿Fue útil esta página
0 / 5 - 0 calificaciones