Сериализация/десериализация маски изображения в приложении FiftyOne

Я хотел бы использовать приложение FiftyOne для оценки прогнозов сегментации экземпляров. Для начала я использовал загружаемый набор данных для быстрого старта и создал свой собственный файл samples.json для наземных данных и прогнозных данных, который можно загрузить с помощью Dataset.from_dir. Файл json в руководстве содержит только ограничивающие рамки, но не маски. В документации я нашел только маски, которые установлены на None, но они мне понадобятся.

{
  "samples": [
    {
      "filepath": "some_image.png",
      "tags": [
        "validation"
      ],
      "metadata": null,
      "uniqueness": 0.998,
      "ground_truth": {
        "_cls": "Detections",
        "detections": [
          {
            "_id": {
              "$oid": "efd81c917c9a49dc9f8aca3f"
            },
            "_cls": "Detection",
            "label": "1",
            "bounding_box": [
              0.62609375,
              0.27044921875,
              0.030078124999999956,
              0.009550781250000001
            ],
            "mask": ???,
          }
        ]
      },
      "predictions": {
        "_cls": "Detections",
        "detections": [
          {
            "_id": {
              "$oid": "6db44c71c1414b8989c92255"
            },
            "_cls": "Detection",
            "label": "1",
            "bounding_box": [
              0.3303889036178589,
              0.4432219862937927,
              0.07914596796035767,
              0.02226179838180542
            ],
            "mask": ???,
            "confidence": 0.999962329864502
          },
        ]
      }
    }
  ]
}

У меня проблема в том, как мне создать свойство mask для маски сегментации? Это пустой массив, который по умолчанию не сериализуется. Dataset.from_dir использует функцию core.utils.deserialize_numpy_array для загрузки набора данных, поэтому я безуспешно пытался использовать serialize_numpy_array для сохранения набора данных.

Итак, как лучше всего записать маску в файл json, который можно десериализовать? Спасибо!

Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
0
0
31
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Синтаксис Dataset.from_dir() обычно используется для четко определенных типов наборов данных, таких как набор данных, хранящийся на диске в формате COCODetectionDataset.

В вашем случае при загрузке пользовательского набора данных, который напрямую не соответствует одному из связанных типов набора данных, рекомендуется написать простой цикл Python и создание набора данных по одной выборке за раз.

В этом случае вам просто нужно загрузите свою маску в виде массива numpy и сохраните ее в атрибуте mask вашего объекта обнаружения.

import glob
import fiftyone as fo

images_patt = "/path/to/images/*"

# Ex: your custom label format
annotations = {
    "/path/to/images/000001.jpg": [
        {"bbox": ..., "label": ..., "mask": ...},
        ...
    ],
    ...
}

# Create samples for your data
samples = []
for filepath in glob.glob(images_patt):
    sample = fo.Sample(filepath=filepath)

    # Convert detections to FiftyOne format
    detections = []
    for objects in annotations[filepath]:
        label = obj["label"]

        # Bounding box coordinates should be relative values
        # in [0, 1] in the following format:
        # [top-left-x, top-left-y, width, height]
        bounding_box = obj["bbox"]

        # Boolean or 0/1 Numpy array 
        mask = obj["mask"]
        
        detection = fo.Detection(
            label=label,
            bounding_box=bounding_box,
            mask=mask,
        )

        detections.append(detection)

    # Store detections in a field name of your choice
    sample["ground_truth"] = fo.Detections(detections=detections)

    samples.append(sample)

# Create dataset
dataset = fo.Dataset("my-detection-dataset")
dataset.add_samples(samples)

Прогнозы могут быть загружены одновременно с реальными данными, или вы всегда можете перебирать свой набор данных в будущем и добавить прогнозы позже:

import fiftyone as fo

# Ex: your custom predictions format
predictions = {
    "/path/to/images/000001.jpg": [
        {"bbox": ..., "label": ..., "mask": ..., "score": ...},
        ...
    ],
    ...
}

# Add predictions to your samples
for sample in dataset:
    filepath = sample.filepath

    # Convert predictions to FiftyOne format
    detections = []
    for obj in predictions[filepath]:
        label = obj["label"]
        confidence = obj["score"]

        # Bounding box coordinates should be relative values
        # in [0, 1] in the following format:
        # [top-left-x, top-left-y, width, height]
        bounding_box = obj["bbox"]
        
        # Boolean or 0/1 Numpy array 
        mask = obj["mask"]

        detection = fo.Detection(
            label=label,
            bounding_box=bounding_box,
            confidence=confidence,
        )

        detection["mask"] = mask

        detections.append(detection)

    # Store detections in a field name of your choice
    sample["predictions"] = fo.Detections(detections=detections)

    sample.save()

Обратите внимание, что точная структура анализа вашего пользовательского формата метки будет зависеть от того, как вы храните данные. Это всего лишь один пример, в котором метки хранятся в словаре с указанием путей к файлам мультимедиа. Сначала вам может потребоваться проанализировать и преобразовать ваши метки, например, в ожидаемый формат ограничивающей рамки.

Спасибо за предложение! Таким образом, я действительно могу создать набор данных, который можно передать в приложение 51, такое как session = fo.launch_app(dataset). Но, например, я не могу сделать следующее dataset.sort_by("eval_fp", reverse=True).filter_labels("predictions", F("eval") == "fp"), потому что не существует поля «eval_fp». Создание «samples.json» (аналогично набору данных быстрого запуска) и загрузка его с помощью Dataset.from_dir каким-то образом создает набор данных, который дополнен некоторыми дополнительными полезными полями.

Terrordrone 22.03.2022 17:20

Эти дополнительные поля должны быть созданы явно для вашего набора данных и не должны копироваться из одного набора данных в другой. Например, поле «eval_fp» заполняется путем запуска оценки обнаружения в вашем наборе данных: voxel51.com/docs/fiftyone/user_guide/evaluation.html#detecti‌​ons, а поле «уникальность» создается с помощью этого рабочего процесса: voxel51.com/docs/fiftyone/user_guide/….

Eric Hofesmann 22.03.2022 17:40

О, круто. Немного не интуитивно понятно, что evaluate_detections изменяет сам набор данных, но в любом случае это хорошая новость.

Terrordrone 22.03.2022 18:17

Основная причина использования оценки в FiftyOne заключается в том, что она добавляет поля в сам набор данных. В других инструментах оценки вы просто получаете статистику по всему набору данных, но FiftyOne будет хранить отдельные ложные/истинные положительные/отрицательные результаты непосредственно на ваших ярлыках, чтобы вы могли запросить их и изучить, чтобы увидеть, как ваша модель работает на конкретных примерах.

Eric Hofesmann 22.03.2022 19:24

Раньше я использовал одну или две оценки, но только коснулся поверхности и попробовал некоторые базовые вещи. Есть что исследовать.

Terrordrone 22.03.2022 21:36

Еще один вопрос, если не возражаете. Я создал образцы и добавил их в набор данных, который теперь содержит маски Ground_truth и предсказаний (логические массивы numpy), но маски не отображаются в приложении, когда я его запускаю, только ограничивающие прямоугольники. Означает ли это, что я сделал что-то не так при создании набора данных, или нужно как-то настроить отображение? (Когда я загружаю набор данных кокоса с диска, предоставляя необходимые типы меток, все в порядке.)

Terrordrone 23.03.2022 12:26

Правильно, похоже, что маски были загружены неправильно. Приложение автоматически отобразит маски, если они имеют правильный формат. Не могли бы вы перейти на Slack-канал FiftyOne Users и предоставить больше контекста, будет легче отлаживать: join.slack.com/t/fiftyone-users/shared_invite/…

Eric Hofesmann 23.03.2022 14:19

Другие вопросы по теме