Skip to content

Commit 2064f0d

Browse files
feat(opendataset): add mask for BDD100K_MOTS2020 dataset
PR Closed: #995
1 parent 11a32f7 commit 2064f0d

File tree

2 files changed

+97
-53
lines changed

2 files changed

+97
-53
lines changed

tensorbay/opendataset/BDD100K/catalog_mots.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,14 @@
2727
"type": "boolean"
2828
}
2929
]
30+
},
31+
"INSTANCE_MASK": {
32+
"categories": [{ "name": "background", "categoryId": 0 }],
33+
"attributes": [
34+
{ "name": "crowd", "type": "boolean" },
35+
{ "name": "ignore", "type": "boolean" },
36+
{ "name": "occluded", "type": "boolean" },
37+
{ "name": "truncated", "type": "boolean" }
38+
]
3039
}
3140
}

tensorbay/opendataset/BDD100K/loader.py

Lines changed: 88 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,10 @@
4949
"pan": ("pan_seg", "bitmasks"),
5050
}
5151
_TRACKING_DATASET_INFO = {
52-
"mots": ("bdd100k_seg_track_20", "seg_track_20", os.path.join("seg_track_20", "polygons")),
53-
"mot": (
54-
"bdd100k_box_track_20",
55-
"",
56-
"",
57-
),
52+
"mots": ("bdd100k_seg_track_20", "seg_track_20"),
53+
"mot": ("bdd100k_box_track_20", ""),
5854
}
59-
_DATA_GETTER = Callable[[str, Dict[str, Any]], Data]
60-
_DATA_GENERATOR = Callable[[str, str, _DATA_GETTER], Iterable[Data]]
55+
_DATA_GENERATOR = Callable[[str, str, str, str, str], Iterable[Data]]
6156

6257

6358
def BDD100K(path: str) -> Dataset:
@@ -250,13 +245,13 @@ def _get_data_10k(
250245
_add_poly2d_label_10k(label_info, polygon)
251246
label = data.label
252247
label.polygon = polygon
253-
filename = os.path.splitext(os.path.basename(image_path))[0]
254-
label.semantic_mask = SemanticMask(os.path.join(original_mask_paths["sem"], f"{filename}.png"))
248+
stem = os.path.splitext(os.path.basename(image_path))[0]
249+
label.semantic_mask = SemanticMask(os.path.join(original_mask_paths["sem"], f"{stem}.png"))
255250
label.instance_mask = _get_instance_mask(
256-
filename, original_mask_paths["ins"], single_channel_mask_paths["ins"]
251+
stem, original_mask_paths["ins"], single_channel_mask_paths["ins"]
257252
)
258253
label.panoptic_mask = _get_panoptic_mask(
259-
filename, original_mask_paths["pan"], single_channel_mask_paths["pan"]
254+
stem, original_mask_paths["pan"], single_channel_mask_paths["pan"]
260255
)
261256
return data
262257

@@ -369,13 +364,13 @@ def _merge_label(source_label_contents: List[List[Dict[str, Any]]]) -> Dict[str,
369364

370365

371366
def _get_instance_mask(
372-
filename: str, original_mask_directory: str, mask_directory: str
367+
stem: str, original_mask_directory: str, mask_directory: str
373368
) -> InstanceMask:
374-
mask_path = os.path.join(mask_directory, f"{filename}.png")
369+
mask_path = os.path.join(mask_directory, f"{stem}.png")
375370
mask_info = _save_and_get_mask_info(
376-
os.path.join(original_mask_directory, f"{filename}.png"),
371+
os.path.join(original_mask_directory, f"{stem}.png"),
377372
mask_path,
378-
os.path.join(mask_directory, f"{filename}.json"),
373+
os.path.join(mask_directory, f"{stem}.json"),
379374
"ins",
380375
)
381376

@@ -385,13 +380,13 @@ def _get_instance_mask(
385380

386381

387382
def _get_panoptic_mask(
388-
filename: str, original_mask_directory: str, mask_directory: str
383+
stem: str, original_mask_directory: str, mask_directory: str
389384
) -> PanopticMask:
390-
mask_path = os.path.join(mask_directory, f"{filename}.png")
385+
mask_path = os.path.join(mask_directory, f"{stem}.png")
391386
mask_info = _save_and_get_mask_info(
392-
os.path.join(original_mask_directory, f"{filename}.png"),
387+
os.path.join(original_mask_directory, f"{stem}.png"),
393388
mask_path,
394-
os.path.join(mask_directory, f"{filename}.json"),
389+
os.path.join(mask_directory, f"{stem}.json"),
395390
"pan",
396391
)
397392

@@ -405,29 +400,31 @@ def _save_and_get_mask_info(
405400
original_mask_path: str, mask_path: str, mask_info_path: str, seg_type: str
406401
) -> Dict[str, Any]:
407402
if not os.path.exists(mask_path):
408-
mask = np.array(Image.open(original_mask_path))
403+
mask = np.array(Image.open(original_mask_path), dtype=np.uint16)
409404
all_attributes = {}
410405
if seg_type == "pan":
411406
all_category_ids = {}
412-
for instance_info in set(map(tuple, np.reshape(mask, (-1, 4)))):
413-
instance_id = int(instance_info[-1]) # type:ignore[call-overload]
414-
attributes = instance_info[1]
407+
for category_id, attributes, instance_id_high, instance_id_low in np.unique(
408+
np.reshape(mask, (-1, 4)), axis=0
409+
):
410+
# the instance_id is represented by 2 channels, instance_id = high*256+low
411+
instance_id = int(instance_id_low + (instance_id_high << 8))
415412
all_attributes[instance_id] = {
416-
"truncated": bool(attributes & 8), # type:ignore[operator]
417-
"occluded": bool(attributes & 4), # type:ignore[operator]
418-
"crowd": bool(attributes & 2), # type:ignore[operator]
419-
"ignore": bool(attributes & 1), # type:ignore[operator]
413+
"truncated": bool(attributes & 8),
414+
"occluded": bool(attributes & 4),
415+
"crowd": bool(attributes & 2),
416+
"ignore": bool(attributes & 1),
420417
}
421418
if seg_type == "pan":
422-
all_category_ids[instance_id] = int(instance_info[0]) # type:ignore[call-overload]
419+
all_category_ids[instance_id] = int(category_id)
423420
mask_info = (
424421
{"all_attributes": all_attributes, "all_category_ids": all_category_ids}
425422
if seg_type == "pan"
426423
else {"all_attributes": all_attributes}
427424
)
428425
with open(mask_info_path, "w") as fp:
429426
json.dump(mask_info, fp)
430-
Image.fromarray(mask[:, :, -1]).save(mask_path)
427+
Image.fromarray(mask[:, :, -1] + (mask[:, :, -2] << 8)).save(mask_path)
431428
else:
432429
with open(mask_info_path, "r") as fp:
433430
mask_info = json.load(
@@ -467,6 +464,17 @@ def _BDD100K_MOTS2020(path: str) -> Dataset:
467464
...
468465
labels/
469466
seg_track_20/
467+
bitmasks/
468+
train/
469+
000d4f89-3bcbe37a/
470+
000d4f89-3bcbe37a-0000001.png
471+
...
472+
...
473+
val/
474+
b1c9c847-3bda4659/
475+
b1c9c847-3bda4659-0000001.png
476+
...
477+
...
470478
polygons/
471479
train/
472480
000d4f89-3bcbe37a.json
@@ -529,19 +537,14 @@ def _BDD100K_MOT2020(path: str) -> Dataset:
529537

530538

531539
def _tracking_loader(path: str, tracking_type: str) -> Dataset:
532-
if tracking_type == "mot":
533-
get_data = _get_mot_data
534-
else:
535-
get_data = _get_mots_data
536-
root_path = os.path.join(
537-
os.path.abspath(os.path.expanduser(path)), _TRACKING_DATASET_INFO[tracking_type][0]
538-
)
540+
tracking_dataset_info = _TRACKING_DATASET_INFO[tracking_type]
541+
root_path = os.path.join(os.path.abspath(os.path.expanduser(path)), tracking_dataset_info[0])
539542
dataset = Dataset(DATASET_NAMES[tracking_type])
540543
dataset.notes.is_continuous = True
541544
dataset.load_catalog(os.path.join(os.path.dirname(__file__), f"catalog_{tracking_type}.json"))
542-
images_directory = os.path.join(root_path, "images", _TRACKING_DATASET_INFO[tracking_type][1])
543-
labels_directory = os.path.join(root_path, "labels", _TRACKING_DATASET_INFO[tracking_type][2])
544-
_load_tracking_segment(dataset, images_directory, labels_directory, get_data)
545+
images_directory = os.path.join(root_path, "images", tracking_dataset_info[1])
546+
labels_directory = os.path.join(root_path, "labels", tracking_dataset_info[1])
547+
_load_tracking_segment(dataset, images_directory, labels_directory, tracking_type)
545548

546549
return dataset
547550

@@ -550,39 +553,64 @@ def _load_tracking_segment(
550553
dataset: Dataset,
551554
images_directory: str,
552555
labels_directory: str,
553-
load_label: _DATA_GETTER,
556+
tracking_type: str,
554557
) -> None:
555558
for segment_prefix in _SEGMENT_NAMES:
556559
image_directory = glob(os.path.join(images_directory, segment_prefix, "*"))
557-
labels_directory_segment = os.path.join(labels_directory, segment_prefix)
560+
segment_labels_directory = os.path.join(labels_directory, "polygons", segment_prefix)
561+
original_mask_directory = os.path.join(labels_directory, "bitmasks", segment_prefix)
562+
mask_directory = os.path.join(labels_directory, "single_channel_masks", segment_prefix)
563+
os.makedirs(mask_directory, exist_ok=True)
564+
558565
if segment_prefix == "test":
559566
generate_data: _DATA_GENERATOR = _generate_test_data
560567
else:
561568
generate_data = _generate_data
562569
for image_subdir in image_directory:
563570
segment = dataset.create_segment(f"{segment_prefix}_{os.path.basename(image_subdir)}")
564-
segment.extend(generate_data(image_subdir, labels_directory_segment, load_label))
571+
segment.extend(
572+
generate_data(
573+
image_subdir,
574+
segment_labels_directory,
575+
original_mask_directory,
576+
mask_directory,
577+
tracking_type,
578+
)
579+
)
565580

566581

567-
def _generate_test_data(image_subdir: str, _: str, __: _DATA_GETTER) -> Iterable[Data]:
582+
def _generate_test_data(image_subdir: str, _: str, __: str, ___: str, ____: str) -> Iterable[Data]:
568583
yield from map(Data, glob(os.path.join(image_subdir, "*.jpg")))
569584

570585

571586
def _generate_data(
572587
image_subdir: str,
573-
labels_directory_segment: str,
574-
get_data: _DATA_GETTER,
588+
segment_labels_directory: str,
589+
original_mask_directory: str,
590+
mask_directory: str,
591+
tracking_type: str,
575592
) -> Iterable[Data]:
576-
label_filename = f"{os.path.basename(image_subdir)}.json"
577-
with open(os.path.join(labels_directory_segment, label_filename), "r") as fp:
593+
subdir_name = os.path.basename(image_subdir)
594+
if tracking_type == "mots":
595+
original_mask_subdir = os.path.join(original_mask_directory, subdir_name)
596+
mask_subdir = os.path.join(mask_directory, subdir_name)
597+
os.makedirs(mask_subdir, exist_ok=True)
598+
with open(os.path.join(segment_labels_directory, f"{subdir_name}.json"), "r") as fp:
578599
label_contents = json.load(fp)
579600
for label_content in label_contents:
580601
label_content_name = label_content["name"]
581602
if "/" in label_content_name:
582603
label_content_name = label_content_name[len(label_content["videoName"]) + 1 :]
583604
image_path = os.path.join(image_subdir, label_content_name)
584-
585-
yield get_data(image_path, label_content)
605+
yield _get_mot_data(
606+
image_path, label_content
607+
) if tracking_type == "mot" else _get_mots_data(
608+
image_path,
609+
original_mask_subdir,
610+
mask_subdir,
611+
os.path.splitext(label_content_name)[0],
612+
label_content,
613+
)
586614

587615

588616
def _get_mot_data(image_path: str, label_content: Dict[str, Any]) -> Data:
@@ -607,7 +635,13 @@ def _get_mot_data(image_path: str, label_content: Dict[str, Any]) -> Data:
607635
return data
608636

609637

610-
def _get_mots_data(image_path: str, label_content: Dict[str, Any]) -> Data:
638+
def _get_mots_data(
639+
image_path: str,
640+
original_mask_subdir: str,
641+
mask_subdir: str,
642+
stem: str,
643+
label_content: Dict[str, Any],
644+
) -> Data:
611645
data = Data(image_path)
612646
labeled_multipolygons = []
613647
for label_info in label_content.get("labels", ()):
@@ -620,6 +654,7 @@ def _get_mots_data(image_path: str, label_content: Dict[str, Any]) -> Data:
620654
instance=str(label_info["id"]),
621655
)
622656
labeled_multipolygons.append(labeled_multipolygon)
623-
data.label.multi_polygon = labeled_multipolygons
624-
657+
label = data.label
658+
label.multi_polygon = labeled_multipolygons
659+
label.instance_mask = _get_instance_mask(stem, original_mask_subdir, mask_subdir)
625660
return data

0 commit comments

Comments
 (0)