-
Notifications
You must be signed in to change notification settings - Fork 7.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
handle annotations with inner holes #4196
Comments
Hi, I have been facing the same issue as yours, have you tested this solution at all? I am puzzled on why would they not account for this case, you would think it should be a typical scenario that’s accounted for. I realized today after hours of debugging that regardless what you pass as an input (I,.e., polygons, RLEs, or binary masks, it will all be converted to RLE first, which is the root of the issue since the conversion does not account for complex structures with multiple holes and polygons properly).. documentation on this particular case is very limited to the best of knowledge, relevant issues don’t provide much info either. I found this comment in response to one of the issues below: “You can represent masks with holes by union of multiple polygons, or you can use BitMasks as inputs to the model directly.“ and I have been trying to achieve that effect with no luck!! Only to realize that all inputs will get converted to RLE representation which is the root cause of the issue so regardless how you handle the input if the conversion is input->RLE->binary then it will be affected by the same semantic issue since the conversion doesn’t account for holes properly. Related issues: |
I have visualized the effect of the suggested modification and it seems to work fine, but am not sure where to apply the changes to make sure this behavior is consistent across training/testing and visualization. Detectron2's visualizer uses pycocotools backend (e.g., mask_util) for mask conversions I guess and this should also be considered when adapting the new approach to ensure consistency of visualized masks and training/testing masks. |
@ppwwyyxx any thoughts on this, please? |
Here's my implementation. # Encode all polygons with holes to RLEs
rles = mask_util.frPyObjects(polygons_with_holes, height, width)
# Decode the RLEs to boolean masks
masks = mask_util.decode(rles).astype(bool)
# XOR sum over all mask and holes (This will make mask filter out all holes)
# Note that all holes should be located inside the mask, and should not overlap each other
mask = (masks.sum(axis=2) % 2).astype(bool)
# Encode the mask to a RLE
rle = mask_util.encode(mask) |
@donghyeon thank you for sharing!! what file/s did you update for this behavior to take effect? I struggled with locating parts to change and keep behavior consistent across training/validation/testing.. Many thanks for your input :) |
Using the script general_json2yolo.py, you can convert the RLE mask with holes to the YOLO segmentation format. The RLE mask is converted to a parent polygon and a child polygon using
The RLE mask. The converted YOLO segmentation format. To run the script, put the COCO JSON file coco_train.json into Edit use_segments and use_keypoints in the script.
To convert the COCO bbox format to YOLO bbox format.
To convert the COCO segmentation format to YOLO segmentation format.
To convert the COCO keypoints format to YOLO keypoints format.
This script originates from Ultralytics JSON2YOLO repository. |
🚀 Feature
I think you need to modify the way polygons are converted into bitmasks, I suppose the function responsible of this conversion is
polygons_to_bitmask
indetectron2/structures/masks.py
because it doesn't take into account inner holes of an object
Motivation & Examples
for example this is the original mask
after turning this object into polygons and feeding it through that function,
this is the reconstructed mask
the solution I have found (up to you to decide if it's good) is to delete the
and replace it with
my idea is we check if there is multiple masks, add the masks into one mask, overlays between masks will be expressed as value greater than 2, so we set these values to zero
The text was updated successfully, but these errors were encountered: