Detectron: Формат "сегментации" RLE или Polygon для расширения до набора данных coco.

Созданный на 2 февр. 2018  ·  38Комментарии  ·  Источник: facebookresearch/Detectron

Привет, Детектрон,

Недавно я попытался добавить свои собственные данные кокоса для запуска Detectron и столкнулся со следующими проблемами.
(1) «сегментация» в данных о кокосе, как показано ниже ,

{"сегментация": [[ 499.71, 397.28, ...... 342.71, 172.31 ]] , "область": 43466.12825, "iscrowd": 0, "image_id": 182155, "bbox": [338.89, 51.69, 205.82, 367.61], "category_id": 1, "id": 1248258},

{"segmentation": {"counts": [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},
Первый формат «сегментации» - многоугольник, а второй нужен для кодирования / декодирования для формата RLE.

Вышеуказанные форматы могут работать на Detectron.

(2) Я добавил новую категорию и сгенерировал новый формат RLE для поля «сегментация» с помощью маски кодирования () / декодирования () coco api.
Я сгенерировал такие данные.

"сегментация": [{ "рассчитывает ": "MNG = 1fb02O1O1O001N2O001O1O0O2O1O1O001N2O001O1O0O2O1O001O1O1O010000O01000O010000O01000O01000O01000O01N2N2M2O2N2N1O2N2O001O10O B000O10O1O001 ^ OQ ^ O9Pb0EQ ^ О; Wb0OO01O1O1O001O1N2N`jT3?"," размер": [600,1000]}]

Я обнаружил, что выделенные жирным шрифтом символы отличаются от исходного json-формата "сегментации" coco, хотя он может работать в реализации MatterPort для Mask-RCNN.

Кроме того, я попытался изменить некоторый код Detectron в соответствии с моими требованиями, но для меня это было очень сложно, потому что нужно изменить много кода.

Не могли бы вы дать мне несколько советов по использованию моих пользовательских данных?

Спасибо.

community help wanted

Самый полезный комментарий

@topcomma
Может быть, вы можете попробовать преобразовать маску в полигоны.

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

Все 38 Комментарий

У меня была аналогичная проблема: некоторые функции в lib / utils / segms.py ожидают, что сегментирование будет в формате «поли», и прерываются, когда они предоставляются в RLE.
Это неудобно, но, похоже, соответствует спецификации для малонаселенных регионов (iscrowd = 0):

Формат сегментации зависит от того, представляет ли экземпляр отдельный объект (iscrowd = 0, в этом случае используются многоугольники) или коллекцию объектов (iscrowd = 1, в этом случае используется RLE).

[1] http://cocodataset.org/#download , раздел «4.1. Аннотации экземпляров объекта»

Для меня обходным путем было преобразование в формат «поли», который по сути представляет собой список вершин (x, y).

-Леша.

2 февраля 2018 г. в 06:41 Ху Сингуи [email protected] написал:

Привет, Детектрон,

Недавно я попытался добавить свои собственные данные кокоса для запуска Detectron и столкнулся со следующими проблемами.
(1) «сегментация» в данных о кокосе, как показано ниже ,

{"сегментация": [[499.71, 397.28, ...... 342.71, 172.31]], "область": 43466.12825, "iscrowd": 0, "image_id": 182155, "bbox": [338.89, 51.69, 205.82, 367.61], "category_id": 1, "id": 1248258},

{"segmentation": {"counts": [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},
Первый формат «сегментации» - многоугольник, а второй нужен для кодирования / декодирования для формата RLE.

Вышеуказанные форматы могут работать на Detectron.

(2) Я добавил новую категорию и сгенерировал новый формат RLE для поля «сегментация» с помощью маски кодирования () / декодирования () coco api.
Я сгенерировал такие данные.

"Сегментация": [{ "рассчитывает": "MNG = 1fb02O1O1O001N2O001O1O0O2O1O1O001N2O001O1O0O2O1O001O1O1O010000O01000O010000O01000O01000O01000O01N2N2M2O2N2N1O2N2O001O10O B000O10O1O001 ^ OQ ^ O9Pb0EQ ^ О; Wb0OO01O1O1O001O1N2N`jT3?", "Размер": [600,1000]}]

Я обнаружил, что выделенные жирным шрифтом символы отличаются от исходного json-формата "сегментации" coco, хотя он может работать в реализации MatterPort для Mask-RCNN.

Кроме того, я попытался изменить некоторый код Detectron в соответствии с моими требованиями, но для меня это было очень сложно, потому что нужно изменить много кода.

Не могли бы вы дать мне несколько советов по использованию моих пользовательских данных?

Спасибо.

-
Вы получаете это, потому что подписаны на эту ветку.
Ответьте на это письмо напрямую, просмотрите его на GitHub или отключите чат.

@amokeev , как конвертировать "RLE" в "poly" формат по вашему обходному пути?

@amokeev , Вы уверены, что количество в сегментации (x, y) вершин? Например «66916», большое количество! Другой, хотя я установил "iscrowd" как "1" для формата RLE, все же не смог работать на Detectron.

Я интерпретирую поли как список многоугольников, определенных вершинами, например [[x1, y1, x2, y2… xN, yN],… [x1, y1, x2, y2… xN, yN]], где координаты тот же масштаб, что и изображение.
Маски, закодированные таким образом, правильно отображаются в CocoAPI [1]

Но вы можете получить «официальный» ответ.

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

2 февраля 2018 г. в 09:18 Ху Сингуи [email protected] написал:

@amokeev https://github.com/amokeev , вы уверены, что число в сегментации составляет (x, y) вершин? Например «66916», большое количество! Другой, хотя я установил "iscrowd" как "1" для формата RLE, все же не смог работать на Detectron.

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub https://github.com/facebookresearch/Detectron/issues/100#issuecomment-362516928 или отключите поток https://github.com/notifications/unsubscribe-auth/AFlh63ObnXg- DcaDKwIi3pB4Ppig464Hks5tQsTkgaJpZM4R2tN3 .

@topcomma
Может быть, вы можете попробовать преобразовать маску в полигоны.

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

Спасибо за ваши предложения.
Попытаюсь.

@Sundrops , как ваш способ конвертировать, может получить результат "поли" списка. Большое спасибо! Но я все еще не знаю, почему координата в файле COCO json имеет большое / маленькое число, например «66916» или «1»?

Аннотации @topcomma COCO имеют два типа аннотаций сегментации

  1. полигон (экземпляр объекта) [[499.71, 397.28, ...... 342.71, 172.31]] вершин
  2. несжатый RLE (толпа). "segmentation": {"counts": [66916, 6, 587, ..... 1, 114303], "size": [594, 640]}, 66916 представляет собой номер метки 0.

Многоугольник и несжатый RLE будут преобразованы в компактный формат RLE с помощью MaskApi.
Компактный формат RLE:
Сегментация ": [{" рассчитывает ": "MNG = 1fb02O1O1O001N2O001O1O0O2O1O1O001N2O001O1O0O2O1O001O1O1O010000O01000O010000O01000O01000O01000O01N2N2M2O2N2N1O2N2O001O10O B000O10O1O001 ^ OQ ^ O9Pb0EQ ^ О; Wb0OO01O1O1O001O1N2N`jT3"," размер ": [600,1000]}]

@Sundrops ,
Спасибо за вашу огромную помощь.
Мои пользовательские кокосовые данные теперь можно обучить на Detectron.

@topcomma ,
У меня такая же проблема, как и у тебя.
Как метод Sundrops, я не могу найти файл для преобразования маски в полигоны.
Не могли бы вы сказать мне, какой файл? Большое спасибо!

@ lg12170226
Вы можете сослаться на код python coco stuff (https://github.com/nightrome/cocostuff), чтобы реализовать его самостоятельно.
В кодовой базе нет файла соответствующей аннотации.

@topcomma : у меня есть необработанное изображение и изображения N . Каждая метка хранится в одном файле, поэтому у меня есть N image для метки. Я хочу обучить Mask RCNN в моем собственном наборе данных, поэтому сначала мне нужно преобразовать в формат COCO. Не могли бы вы поделиться кодом, как преобразовать его в стиль COCO? Спасибо

Просто интересно, есть ли способ конвертировать сжатые RLE в polys / несжатые RLE?

@realwecan после декодирования RLE с помощью pycocotools.mask.decode, вы можете проверить мою реализацию для генерации полигонов с помощью opencv:

коко-json-конвертер

@hazirbas : спасибо за ваш код. Почему бы не использовать Davis 2017, который содержит сегментирование экземпляров? Можем ли мы использовать ваш код для преобразования Davis 2017 в формат coco, чтобы использовать эту реализацию maskrcnn?

@ John1231983 вам необходимо соответствующим образом изменить скрипт для чтения разделенных файлов, а также файла db_info.yml. Для моих собственных исследований он мне понадобился для DAVIS 2016.

Другое решение для создания многоугольников, но с использованием skimage вместо 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))

как бы вы преобразовали двоичную маску или закодированный RLE в несжатый RLE для использования в поле «iscrowd: 1» «counts»?

@waspinator Сегментация вашего кода с использованием skimage отличается от кода @Sundrops, использующего cv2.
Правильны ли оба этих результата и могут ли оба эти результата использоваться Detectron? Пожалуйста, дайте мне совет, спасибо. @waspinator @Sundrops

Результаты с использованием вашего кода с skimage:

{"сегментация": [[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.0019607843132.0043, 252.00196078431372, 6.0, 252.001960784313260.00, 252.0013232880.0043, 252.00196078431372.0043.0, 252.00196078431372.004.0, 252.001960784313260.0043, 7.0192.00196078431372.00 , 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, 9560,0 ...

Результаты с @Sundrops код с использованием CV2:

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

@Kongsea Я не тестировал реализацию @Sundrops cv2, но основная идея должна быть такой же. Они будут давать разные результаты, поскольку существует бесконечное количество наборов точек, которые вы можете использовать для описания формы. Но в остальном они оба должны работать. У меня просто не было установленного cv2, поэтому я написал кое-что, что этого не требует.

@Kongsea @waspinator Я проверил свой код. Оно работает.

Спасибо @Sundrops @waspinator .
Я попробую.

@waspinator Есть ли способ преобразовать

@Sundrops Почему вы прокомментировали эту часть кода?

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

Нам действительно нужно разобраться с таким делом, верно?

@ Yuliang-Zou Вы должны раскомментировать эту часть, когда контуры используются для Detectron. Beacase детектор будет рассматривать его как прямоугольник, когда len (contour) == 4. Я обновил свой предыдущий код.

@Sundrops Спасибо. Но нам все еще нужно обрабатывать len(contour)==2 , верно?

@ Yuliang-Zou Да, но код if len(contour) > 4: имеет дескриптор len(contour)==2 и len(contour)==4 .

@Sundrops Понятно , спасибо!

Я написал библиотеку и статью, чтобы помочь с созданием наборов данных в стиле COCO.

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

@Sundrops & @topcomma У меня проблема с загрузкой аннотированных данных в pycocotols, поскольку моя аннотация включает сегментацию без маски. есть идеи, как визуализировать аннотацию без маски в pycocotools?

@Sundrops
Аня: {
"сегментация": [
[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,13, 321,29, 132, 347,41,3, 347,13 , 358,55, 159,36, 377,83, 116,95, 421,53, 167,07, 499,92, 232,61, 560,32, 300,72, 571,89]
],
«площадь»: 54652.9556, г.
"iscrowd": 0,
"image_id": 480023,
"bbox": [116.95, 305.86, 285.3, 266.03],
"category_id": 58,
"id": 86
}
Как я могу рассчитать площадь с помощью mask.py в coco-api? Спасибо.
Мой код выглядит следующим образом, но с ошибкой:

segmentation = ann ['сегментация']
bimask = np.array (сегментация, dtype = np.uint8, порядок = 'F')
print ("бимаска:", бимаска)
rleObjs = mask.encode (бимаска)
print ("rleObjs:", rleObjs)
area = mask.area (rleObjs)
print ("область:", область)

@manketon
Возможно, вы можете попробовать cv2, но я не уверен, что это правильно. Это просто пример из раздела Удаление контуров с изображения с помощью Python и 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 У меня вопрос. Если моя исходная маска объекта имеет большие дыры, когда она преобразуется в полигоны, как мне правильно преобразовать ее обратно? Функции декодирования и слияния в coco API будут обрабатывать дыры как части объекта, поэтому при обратном преобразовании дыры становятся масками. Как мне поступить в этом случае?

@ wangg12 Насколько я знаю, в COCO нет собственного способа кодирования дыр.

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

Привет, @Sundrops , искренне спасибо за коды. Я новичок в Detectron. Я не понимаю, почему длина контура (который представляет собой список) должна быть больше 4, другими словами, что произойдет с моделью, когда длина меньше 4. В одном из ваших ответов говорилось, что Detectron будет рассматривать его как прямоугольник. На мой взгляд, там могут быть объекты прямоугольной формы, так что я думаю, что это нормально. Кроме того, мне интересно, добавляете ли вы контур дважды за одну итерацию. Думаю, правильный код должен быть.

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

Буду очень признателен, если вы дадите мне несколько предложений. Большое спасибо!

@BobZhangHT Да, он должен добавлять контур один раз за одну итерацию.
Что касается вашего первого вопроса, если len (ann ['segmentation'] [0]) == 4, cocoapi будет считать, что все прямоугольные.

# 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 Спасибо за ответ!

Я интерпретирую поли как список многоугольников, определенных вершинами, например [[x1, y1, x2, y2… xN, yN],… [x1, y1, x2, y2… xN, yN]], где координаты тот же масштаб, что и изображение. Маски, закодированные таким образом, правильно отображаются в CocoAPI [1]. Но вы можете захотеть получить «официальный» ответ. [1] https://github.com/cocodataset/cocoapi https://github.com/cocodataset/cocoapi

2 февраля 2018 г. в 09:18 Ху Сингуи @ . * > писал: @amokeev https://github.com/amokeev , вы уверены, что число в сегментации равно (x, y) вершин? Например «66916», большое количество! Другой, хотя я установил "iscrowd" как "1" для формата RLE, все же не смог работать на Detectron. - Вы получили это, потому что вас упомянули. Ответьте на это письмо напрямую, просмотрите его на GitHub < # 100 (comment) > или отключите поток https://github.com/notifications/unsubscribe-auth/AFlh63ObnXg-DcaDKwIi3pB4Ppig464Hks5tQsTkgaJpZM4R2tN3 .

Как я могу преобразовать RLE в полигоны, когда iscrowd равно «1», потому что материальный порт / MaskRCNN работает только с полигонами. @amokeev. Я хочу использовать материальную реализацию maskRCNN с набором данных coco, созданным с помощью pycococreator.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги