Open collinmccarthy opened 5 months ago
I stumbled upon the root of the problem here. I still stand by my solution above but the issue is stemming from Visualizer.get_image()
@master_only
def get_image(self) -> np.ndarray:
"""Get the drawn image. The format is RGB.
Returns:
np.ndarray: the drawn image which channel is RGB.
"""
assert self._image is not None, 'Please set image using `set_image`'
return img_from_canvas(self.fig_save_canvas) # type: ignore
It looks like the img_from_canvas()
method is not pixel-wise accurate. It is producing small off-by-one errors sometimes, likely due to the underlying rendering method. I'm not sure how the mechanics of the Visualizer
class work, but I think the point is we need to make sure we only call this method when necessary. Since it's called from draw_binary_masks()
that means calling draw_binary_masks()
one time is much much better than calling it many times (from a pixel-wise accuracy point of view).
Describe the bug Semantic segmentations are not being accurately visualized with
DetLocalVisualizer
, leading to the same artifacts as are shown in mmengine issue 741 and below. I don't think the root issue here is withDetLocalVisualizer
, but the issue can be fixed by changing the implementation of_draw_sem_seg()
. This "fixed" implementation mirrors the_draw_panoptic_seg()
method and is also significantly faster.The current implementation calls
Visualizer.draw_binary_masks()
andVisualizer.draw_texts()
once per label ID in the semantic segmentation. This is causing artifacts around the borders of the image. I tried modifying the interpolation and the implementation ofdraw_binary_masks
to only modify the masked region, but it still causes artifacts outside of a masked region. The solution seems to simply be callingdraw_binary_masks()
/draw_texts()
methods once, drawing all masks and labels at the same time. For the images below I also addeddraw_polygons()
calls to draw outlines as in instance segmentation. This more easily shows the issue is with the borders of the masked regions (and the text boxes).Reproduction
This was discovered as part of a larger project. I created a minimum working example with two files,
show_draw_sem_seg_issue.py
, which imports the fixed visualizer fromfix_local_visualizer.py
. These are in show_draw_sem_seg_issue.zip. These assume COCO-Stuff is setup withtools/dataset_converters/coco_stuff164k.py
as shown in the docs (and shown below for clarity).To reproduce you may do the following (also in the docstring of
show_draw_sem_seg_issue.py
). The images above are output with these calls.stuffthingmaps_semseg
from here: https://mmdetection.readthedocs.io/en/latest/user_guides/dataset_prepare.html#coco-semantic-dataset-preparationExample:
After, the data directory should look like: ~/mmdetection ├── data # "Data root" used below with --data-root │ ├── coco │ │ ├── annotations │ │ ├── train2017 │ │ ├── val2017 │ │ ├── test2017 │ │ ├── stuffthingmaps │ │ ├── stuffthingmaps_semseg
Output a subset of val2017 annotations using this script
Example:
Did you make any modifications on the code or config? Did you understand what you have modified? All code is above and is my own.
What dataset did you use? COCO-Stuff as described above.
Environment
python mmdet/utils/collect_env.py
to collect necessary environment information and paste it here.$PATH
,$LD_LIBRARY_PATH
,$PYTHONPATH
, etc.)I setup my environment with a conda/pip/mim. If you need the scripts/instructions I can share them.
Error traceback N/A
Bug fix If you have already identified the reason, you can provide the information here. If you are willing to create a PR to fix it, please also leave a comment here and that would be much appreciated!
I can submit my fix with a PR, or someone on your team can if that's easier. The fix is in
fix_local_visualizer.py
in the zip above, but here is the core of it. This version has a flag to implement the single-draw fix (sem_seg_single_draw_call
) and also has a flag to output the polygon outlines (sem_seg_draw_polygons
).If submitting my own PR I have a couple of other suggestions for an updated
DetLocalVisualizer
which I have implemented in my own codebase:add_datasample()
if multiple GT annotations exist, e.g.gt_instances
andgt_sem_seg
, rather than always merge them into one, have a flag to separate them and concatenate the images together. Same thing for the predictions, because if both of these exist the output is very difficult to parse. Default behavior should obviously be to leave it the way it is, which makes sense if the instance/semantic segmentations (GT or predicted) are non-overlapping.Thank you for reviewing this.