Detectron: Le format RLE ou Polygon de "segmentation" pour étendre à l'ensemble de données coco

Créé le 2 févr. 2018  ·  38Commentaires  ·  Source: facebookresearch/Detectron

Salut Detectron,

Récemment, j'ai essayé d'ajouter mes données coco personnalisées pour exécuter Detectron et j'ai rencontré les problèmes suivants.
(1) "segmentation" dans les données de coco comme ci-dessous ,

{"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 }, "area": ​​6197, "iscrowd": 1, "image_id": 284445, "bbox": [112, 322, 335, 94], "category_id": 1, "id": 9.001002844e + 11},
Le premier format de "segmentation" est le polygone et le second est nécessaire pour encoder / décoder pour le format RLE.

Les formats ci-dessus peuvent fonctionner sur Detectron.

(2) J'ai ajouté une nouvelle catégorie et généré un nouveau format RLE pour le champ "segmentation" via le masque coco api encode () / decode ().
J'ai généré des données comme celles-ci.

"segmentation": [{ "counts ": "MNG = 1fb02O1O1O001N2O001O1O0O2O1O1O001N2O001O1O0O2O1O001O1O1O010000O01000O010000O01000O01000O01000O01N2N2M2O2N2N1O2N2O001O10O B000O10O1O001 ^ OQ ^ O9Pb0EQ ^ O, Wb0OO01O1O1O001O1N2N`jT3?"," taille": [600,1000]}]

J'ai trouvé que les caractères en gras sont différents du format json original de "segmentation" de coco bien qu'il puisse fonctionner sur l'implémentation de MatterPort vers Mask-RCNN.

De plus, j'ai essayé de modifier le code de Detectron pour répondre à mes besoins, mais très difficile pour moi car beaucoup de code doit changer.

Pouvez-vous me donner quelques suggestions pour exécuter mes données personnalisées?

Merci.

community help wanted

Commentaire le plus utile

@topcomma
Vous pouvez peut-être essayer de convertir le masque en polys.

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
        },
    )

Tous les 38 commentaires

J'ai eu un problème similaire: certaines des fonctions de lib / utils / segms.py s'attendent à ce que les segmentations soient au format «poly» et se cassent lorsque celles-ci sont fournies dans RLE.
C'est peu pratique mais semble être conforme aux spécifications des régions non encombrées (iscrowd = 0):

Le format de segmentation dépend du fait que l'instance représente un objet unique (iscrowd = 0 auquel cas des polygones sont utilisés) ou une collection d'objets (iscrowd = 1 auquel cas RLE est utilisé).

[1] http://cocodataset.org/#download , section "4.1. Annotations d'instances d'objets"

La solution de contournement pour moi était de passer au format «poly», qui est essentiellement une liste de sommets (x, y).

-Lesha.

Le 2 février 2018, à 06:41, Hu Xingui [email protected] a écrit:

Salut Detectron,

Récemment, j'ai essayé d'ajouter mes données coco personnalisées pour exécuter Detectron et j'ai rencontré les problèmes suivants.
(1) "segmentation" dans les données de coco comme ci-dessous ,

{"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},
Le premier format de "segmentation" est le polygone et le second est nécessaire pour encoder / décoder pour le format RLE.

Les formats ci-dessus peuvent fonctionner sur Detectron.

(2) J'ai ajouté une nouvelle catégorie et généré un nouveau format RLE pour le champ "segmentation" via le masque coco api encode () / decode ().
J'ai généré des données comme celles-ci.

"Segmentation": [{ "counts": "MNG = 1fb02O1O1O001N2O001O1O0O2O1O1O001N2O001O1O0O2O1O001O1O1O010000O01000O010000O01000O01000O01000O01N2N2M2O2N2N1O2N2O001O10O B000O10O1O001 ^ OQ ^ O9Pb0EQ ^ O, Wb0OO01O1O1O001O1N2N`jT3?", "Taille": [600,1000]}]

J'ai trouvé que les caractères en gras sont différents du format json original de "segmentation" de coco bien qu'il puisse fonctionner sur l'implémentation de MatterPort vers Mask-RCNN.

De plus, j'ai essayé de modifier le code de Detectron pour répondre à mes besoins, mais très difficile pour moi car beaucoup de code doit changer.

Pouvez-vous me donner quelques suggestions pour exécuter mes données personnalisées?

Merci.

-
Vous recevez ceci parce que vous êtes abonné à ce fil de discussion.
Répondez directement à cet e-mail, affichez-le sur GitHub ou désactivez le fil de discussion.

@amokeev , Comment convertir le format "RLE" en "poly" dans votre solution de contournement?

@amokeev , êtes-vous sûr que le nombre dans la segmentation est (x, y) sommets? Par exemple "66916", un grand nombre! Un autre, bien que j'ai défini "iscrowd" comme "1" pour le format RLE, mais ne pouvait pas fonctionner sur Detectron.

J'interprète poly comme une liste de polygones, définie par les sommets, comme [[x1, y1, x2, y2… xN, yN],… [x1, y1, x2, y2… xN, yN]], où les coordonnées sont de la même échelle que l'image.
Les masques, encodés de cette façon, sont affichés correctement par CocoAPI [1]

Mais vous voudrez peut-être obtenir une réponse «officielle».

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

Le 2 février 2018, à 09:18, Hu Xingui [email protected] a écrit:

@amokeev https://github.com/amokeev , êtes-vous sûr que le nombre dans la segmentation est (x, y) vertex? Par exemple "66916", un grand nombre! Un autre, bien que j'ai défini "iscrowd" comme "1" pour le format RLE, mais ne pouvait pas fonctionner sur Detectron.

-
Vous recevez cela parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub https://github.com/facebookresearch/Detectron/issues/100#issuecomment-362516928 , ou désactivez le fil https://github.com/notifications/unsubscribe-auth/AFlh63ObnXg- DcaDKwIi3pB4Ppig464Hks5tQsTkgaJpZM4R2tN3 .

@topcomma
Vous pouvez peut-être essayer de convertir le masque en polys.

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 ,
@Sundrops

Merci pour vos suggestions.
J'essaierai.

@Sundrops , en tant que méthode de conversion, peut obtenir le résultat de la liste "poly". Merci beaucoup! Mais je ne sais toujours pas pourquoi la coordonnée dans le fichier COCO json est un grand / petit nombre tel que "66916" ou "1"?

Les annotations

  1. polygone (instance d'objet) [[499.71, 397.28, ...... 342.71, 172.31]] sommets
  2. RLE non compressé (foule). "segmentation": {"count": [66916, 6, 587, ..... 1, 114303], "size": [594, 640]}, 66916 représente le numéro d'étiquette 0.

Le polygone et le RLE non compressé seront convertis au format RLE compact avec le MaskApi.
Le format compact RLE:
segmentation ": [{" counts ": "MNG = 1fb02O1O1O001N2O001O1O0O2O1O1O001N2O001O1O0O2O1O001O1O1O010000O01000O010000O01000O01000O01000O01N2N2M2O2N2N1O2N2O001O10O B000O10O1O001 ^ OQ ^ O9Pb0EQ ^ O, Wb0OO01O1O1O001O1N2N`jT3"," taille ": [600,1000]}]

@Sundrops ,
Merci pour votre aide.
Mes données personnalisées de type coco peuvent maintenant être entraînées sur Detectron.

@topcomma ,
j'ai le même problème que u.
Comme méthode de Sundrops, je ne trouve pas le fichier pour convertir le masque en polys.
Pouvez-vous me dire quel fichier? Merci beaucoup!

@ lg12170226
Vous pouvez vous référer au code python coco stuff (https://github.com/nightrome/cocostuff) pour l'implémenter vous-même.
Dans la base de code, il n'y a pas de fichier de l'annotation associée.

@topcomma : J'ai une image brute et des images d'étiquettes N . Chaque étiquette est stockée dans un seul fichier, donc j'ai N image pour l'étiquette. Je veux entraîner Mask RCNN dans mon propre ensemble de données, je dois donc d'abord convertir au format COCO. Pourriez-vous partager le code comment le convertir en style COCO? Merci

Vous vous demandez simplement s'il existe un moyen de convertir des RLE compressés en polys / RLE non compressés?

@realwecan après avoir

convertisseur coco-json

@hazirbas : merci pour votre code. Pourquoi ne pas utiliser Davis 2017 qui contient la segmentation des instances? Pourrions-nous utiliser votre code pour convertir Davis 2017 au format coco pour utiliser cette implémentation de maskrcnn?

@ John1231983 vous devez modifier le script en conséquence pour lire les fichiers fractionnés ainsi que le fichier db_info.yml. Pour mes propres recherches, j'en avais besoin pour DAVIS 2016.

Une autre solution pour générer des polygones, mais en utilisant skimage au lieu 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))

Comment convertiriez-vous un masque binaire ou un RLE encodé en RLE non compressé pour une utilisation dans le champ "iscrowd: 1" "count"?

Les segmentations @Sundrops utilisant cv2.
Ces deux résultats sont-ils tous les deux corrects et ces deux résultats peuvent-ils tous deux être utilisés par Detectron? Veuillez me donner quelques conseils, merci. @waspinator @Sundrops

Résultats en utilisant votre code avec skimage:

{ "Segmentation": [[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, 7.0, 252,00196078431372, 8,0, 252,00196078431372, 9,0, 252,00196078431372, 10.0, 252,00196078431372 , 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, 95.078, 251.00196078431372, 95.078 ...

Les résultats obtenus avec le code en utilisant @Sundrops CV2:

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

@Kongsea Je n'ai pas testé l' implémentation de @Sundrops cv2, mais l'idée de base devrait être la même. Ils produiront des résultats différents car il existe une quantité infinie d'ensembles de points que vous pouvez utiliser pour décrire une forme. Mais sinon, ils devraient tous les deux fonctionner. Je n'avais tout simplement pas installé cv2, alors j'ai écrit quelque chose qui n'en a pas besoin.

@Kongsea @waspinator J'ai testé mon code. Ça marche.

Merci @Sundrops @waspinator .
J'essaierai.

@waspinator Existe-t-il un moyen de convertir un sommet poly de segmentation en RLE? Ma cible est faite iscrowd = 1

@Sundrops Pourquoi avez-vous commenté cette partie dans votre code?

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

Nous devons en effet gérer un tel cas, non?

@ Yuliang-Zou Vous devez décommenter cette partie lorsque les contours sont utilisés pour Detectron. Beacase le Detectron le traitera comme un rectangle lorsque len (contour) == 4. J'ai mis à jour mon code précédent.

@Sundrops Merci. Mais nous devons encore gérer len(contour)==2 , non?

@ Yuliang-Zou Oui, mais le code if len(contour) > 4: a le handle len(contour)==2 et len(contour)==4 .

@Sundrops je vois, merci!

J'ai écrit une bibliothèque et un article pour aider à créer des ensembles de données de style COCO.

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

@Sundrops & @topcomma J'ai un problème pour charger les données annotées dans pycocotols car mon annotation est une segmentation incluse sans masque. une idée comment visualiser l'annotation sans masque dans pycocotools?

@Sundrops
ann: {
"segmentation": [
[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.13, 182.48 344.3 , 358,55, 159,36, 377,83, 116,95, 421,53, 167,07, 499,92, 232,61, 560,32, 300,72, 571,89]
],
"zone": 54652,9556,
"iscrowd": 0,
"image_id": 480023,
"bbox": [116,95, 305,86, 285,3, 266,03],
"category_id": 58,
"id": 86
}
Comment puis-je calculer la surface avec mask.py dans coco-api? Merci.
Mon code est comme suit mais erreur:

segmentation = ann ['segmentation']
bimask = np.array (segmentation, dtype = np.uint8, order = 'F')
print ("bimask:", bimask)
rleObjs = mask.encode (bimask)
print ("rleObjs:", rleObjs)
aire = masque.area (rleObjs)
print ("zone:", zone)

@manketon
Peut-être que vous pouvez essayer cv2, mais je ne suis pas sûr que ce soit correct. C'est juste un exemple de Suppression des contours d'une image à l'aide de Python et 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 J'ai une question. Si mon masque d'objet d'origine comporte de gros trous, comment puis-je le reconvertir correctement lorsqu'il est converti en polygones? Les fonctions de décodage et de fusion de l'API coco traiteraient le trou comme des parties de l'objet, de sorte qu'une fois convertis, les trous deviennent des masques. Comment dois-je faire dans ce cas?

@ wangg12 Autant que je sache, COCO n'a pas de méthode native pour encoder les trous.

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

Salut @Sundrops , merci sincèrement pour vos codes. Je suis un débutant sur Detectron. Je ne comprends pas pourquoi la longueur du contour (qui est une liste) devrait être supérieure à 4, en d'autres termes, que se passera-t-il pour le modèle lorsque la longueur est inférieure à 4. L'une de vos réponses a dit que Detectron le traitera comme un rectangle. Dans ma perspective, il peut y avoir des objets avec la forme d'un rectangle, donc je pense que c'est bien. De plus, je me demande si vous ajoutez le contour deux fois en une seule itération. Je pense que le bon code devrait être.

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

Ce sera très apprécié si vous pouvez me donner quelques suggestions. Merci beaucoup!

@BobZhangHT Oui, il devrait ajouter le contour une fois par itération.
Pour votre première question, si len (ann ['segmentation'] [0]) == 4, cocoapi supposera que tous sont rectangulaires.

# 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 Merci pour votre réponse!

J'interprète poly comme une liste de polygones, définie par les sommets, comme [[x1, y1, x2, y2… xN, yN],… [x1, y1, x2, y2… xN, yN]], où les coordonnées sont de la même échelle que l'image. Les masques, encodés de cette façon, sont affichés correctement par CocoAPI [1] Mais vous voudrez peut-être obtenir une réponse «officielle». [1] https://github.com/cocodataset/cocoapi https://github.com/cocodataset/cocoapi

Le 2. févr.2018, à 09:18, Hu Xingui @ . * > a écrit: @amokeev https://github.com/amokeev , Êtes-vous sûr que le nombre dans la segmentation est (x, y) vertex? Par exemple "66916", un grand nombre! Un autre, bien que j'ai défini "iscrowd" comme "1" pour le format RLE, mais ne pouvait pas fonctionner sur Detectron. - Vous recevez cela parce que vous avez été mentionné. Répondez directement à cet e-mail, affichez-le sur GitHub < # 100 (commentaire) > ou désactivez le fil https://github.com/notifications/unsubscribe-auth/AFlh63ObnXg-DcaDKwIi3pB4Ppig464Hks5tQsTkgaJpZM4R2tN3 .

Comment puis-je transformer RLE en polygones lorsque "iscrowd" vaut "1", car le Materialport / MaskRCNN ne fonctionne qu'avec des polygones. @amokeev. Je souhaite utiliser l'implémentation matièreport de maskRCNN avec un ensemble de données coco créé à l'aide de pycococreator.

Cette page vous a été utile?
0 / 5 - 0 notes