I am following the Mask R-CNN tutorial and changed the dataset_dict to support segmentation maps in bitmap format using RLE instead of polygons. I confirmed the data is processed properly using detectron2 visualization tool. When trying to train the network, I'm getting an error regarding polygons.
File "/home/ubuntu/detectron2/detectron2/data/detection_utils.py", line 149, in transform_instance_annotations
polygons = [np.asarray(p).reshape(-1, 2) for p in annotation["segmentation"]]
File "/home/ubuntu/detectron2/detectron2/data/detection_utils.py", line 149, in <listcomp>
polygons = [np.asarray(p).reshape(-1, 2) for p in annotation["segmentation"]]
ValueError: cannot reshape array of size 1 into shape (2)
It seems there is no support for RLE format during training although the visualization works. Is there any way to train using bitmasks?
The model does support training with bitmasks, if instances.gt_masks = BitMasks(..). See the BitMasks class at https://detectron2.readthedocs.io/modules/structures.html#detectron2.structures.BitMasks
But the data loader does not recognize RLE, and therefore does not convert RLE to bitmasks.
You can use a different dataloader following https://detectron2.readthedocs.io/tutorials/data_loading.html
Thanks!
I'm with the same problem. To solve it I have edited the following files.
In structures/masks.py BitMasks class add the following method:
@staticmethod
def from_rle(
rles
) -> "BitMasks":
"""
Args:
rles
height, width (int)
"""
masks = [mask_utils.decode(rle).astype(np.bool) for rle in rles]
return BitMasks(torch.stack([torch.from_numpy(x) for x in masks]))
In data/detection_utils.py change:
if len(annos) and "segmentation" in annos[0]:
polygons = [obj["segmentation"] for obj in annos]
if mask_format == "polygon":
masks = PolygonMasks(polygons)
else:
assert mask_format == "bitmask", mask_format
masks = BitMasks.from_polygon_masks(polygons, *image_size)
target.gt_masks = masks
by:
if len(annos) and "segmentation" in annos[0]:
polygons = [obj["segmentation"] for obj in annos]
if mask_format == "polygon":
masks = PolygonMasks(polygons)
elif mask_format == "bitmask":
masks = BitMasks.from_polygon_masks(polygons, *image_size)
elif mask_format == "rle":
masks = BitMasks.from_rle(polygons)
else:
assert mask_format
target.gt_masks = masks
In also dataset_mapper.py change:
# USER: Implement additional transformations if you have other types of data
annos = [
utils.transform_instance_annotations(
obj, transforms, image_shape, keypoint_hflip_indices=self.keypoint_hflip_indices
)
for obj in dataset_dict.pop("annotations")
if obj.get("iscrowd", 0) == 0
]
by:
annos = [
obj
for obj in dataset_dict.pop("annotations")
if obj.get("iscrowd", 0) == 0
]
In your cfg change cfg.INPUT.MASK_FORMAT = 'rle'
I think I have not had to apply more changes.
Now the default dataloader can work with RLE formats inside your dataset.
All you need is:
INPUT.MASK_FORMAT='bitmask'.Hi @ppwwyyxx
I'm trying to train a instance segmentaion model with 1 class X using detectron2's tutorial, but with a binary mask dataset.
With your instructions, I use RLE format (documented at https://detectron2.readthedocs.io/tutorials/datasets.html#standard-dataset-dicts).
In each "annotations", my "segmention" is a dict "represents the per-pixel segmentation mask in COCO’s RLE format. The dict should have keys “size” and “counts”. You can convert a uint8 segmentation mask of 0s and 1s into RLE format by pycocotools.mask.encode(np.asarray(mask, order="F"))." (I verify that bit-mask is successfully converted to RLE format).
So in this case, can you explain some of my questions, please:

WARNING [03/04 10:32:52 d2.evaluation.coco_evaluation]: json_file was not found in MetaDataCatalog for 'hand10_val'. Trying to convert it to COCO format ...
Traceback (most recent call last):
File "/home/n/detectron2/datasets/EgteaGaze+/hand10/test.py", line 132, in <module>
evaluator = COCOEvaluator("hand10_val", cfg, False, output_dir="./output/")
File "/home/n/detectron2/detectron2/evaluation/coco_evaluation.py", line 71, in __init__
convert_to_coco_json(dataset_name, cache_path)
File "/home/n/detectron2/detectron2/data/datasets/coco.py", line 416, in convert_to_coco_json
coco_dict = convert_to_coco_dict(dataset_name)
File "/home/n/detectron2/detectron2/data/datasets/coco.py", line 334, in convert_to_coco_dict
polygons = PolygonMasks([segmentation])
File "/home/n/detectron2/detectron2/structures/masks.py", line 271, in __init__
process_polygons(polygons_per_instance) for polygons_per_instance in polygons
File "/home/n/detectron2/detectron2/structures/masks.py", line 271, in <listcomp>
process_polygons(polygons_per_instance) for polygons_per_instance in polygons
File "/home/n/detectron2/detectron2/structures/masks.py", line 262, in process_polygons
"Got '{}' instead.".format(type(polygons_per_instance))
AssertionError: Cannot create polygons: Expect a list of polygons per instance. Got '<class 'dict'>' instead.I guess that it must have to set INPUT.MASK_FORMAT='bitmask' (this is in the case of training config), so in the case of evaluating, what need to be set?
I also tried to print("cfg.__dict__= ", cfg.__dict__) but only got
type(cfg)= <class 'detectron2.config.config.CfgNode'>
cfg.__dict__= {'__immutable__': False, '__deprecated_keys__': set(), '__renamed_keys__': {}, '__new_allowed__': False}
How can I see all the atribute of the cfg?
Evaluation of a generic (not COCO format) dataset with RLE is not yet supported. There is a TODO in https://github.com/facebookresearch/detectron2/blob/5e2a1ecccd228227c5a605c0a98d58e1b2db3640/detectron2/data/datasets/coco.py#L335-L337 (cc @botcs )
The above issue about evaluation is hopefully fixed in https://github.com/facebookresearch/detectron2/commit/6901cc7e35ffcef6a4515efe26410a457612ac36
The above issue about evaluation is hopefully fixed in 6901cc7
I think I need to do a bit more to get this actually working.
int explicitly, otherwise json dump complains about TypeError: Object of type 'uint32' is not JSON serializablesegmentation["counts"] into an ascii string otherwise json dump complains about not being able to serialize bytes. TypeError: Object of type 'bytes' is not JSON serializableThere are a few different RLE formats cocoapi recognizes and the 'counts' in coco's original json is actually a list of int.
Should figure out how to convert the bytes to that format.
Thanks for the reply! I am not that familiar with different flavors of coco TBH. The only thing I really cared about here is to preserve the RLE annotation (which comes from pycocotools.mask.encode()) through json conversion and back through detectron2's wrappers, since I have a custom dataset, where everything is an image.
So I looked briefly around https://github.com/facebookresearch/detectron2/blob/master/detectron2/data/datasets/coco.py#L160 and looked up where imgToAnns comes from in https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocotools/coco.py
I think my workaround is probably fine for what I care about? As long as json is serializing and deserializing that bytes array the same way I should be fine. I did something like segmentation["counts"] = segmentation["counts"].decode(''ascii") before calling json dump.
Now the default dataloader can work with RLE formats inside your dataset.
All you need is:
- use RLE format (documented at https://detectron2.readthedocs.io/tutorials/datasets.html#standard-dataset-dicts) in your dataset
- set
INPUT.MASK_FORMAT='bitmask'.
Still not working for me. I am not getting any error but the network is not learning anything. It just runs for 500 and doesn't segment anything. The Epoch error is also dropping to 0.
Most helpful comment
Now the default dataloader can work with RLE formats inside your dataset.
All you need is:
INPUT.MASK_FORMAT='bitmask'.