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
Add VIAMaskParser
for parsing polygons as mask annotations.
#593
Conversation
Move some code from `VIABaseParser` to `VIABBoxParser` and add the assumption that bounding boxes are to be parsed from the `rect` attribute only
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An option that we have is to keep the bbox parser able to handle both "polygon" and "rect" and overwrite the function bboxes
to only parse rect
on the mask parser. (I'm just throwing this out there, I'm not sure this would be the best strategy)
How common it's to have bboxes as polygon? I think this is a specific case because @jerbly originally had rotated bboxes on his dataset.
@jerbly what do you think?
icevision/parsers/via_parser.py
Outdated
|
||
# create empty image and fill it with the polygon | ||
# mask_img = PIL.Image.new("L", get_image_size(self.filepath(o)), 0) | ||
PIL.ImageDraw.Draw(mask_img).polygon(xy_coords, outline=1, fill=1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of returning a image mask, can we directly return a Polygon
class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current Polygon
class requires points
to be vertices, like the COCO format. We'll need to convert x,y
coordinate pairs to vertices to do that. I'm not sure how to do this, but I can look around for solutions
I think it would be good to have that option. We can have the following scenarios:
|
@jerbly I'm unable to load the test |
As a user you're already selecting |
|
`polygon` annotations. The choice is left to the user and defaults are set to maintain backward compatibility. Masks from `rect` annotations, tests yet to be implemented
Made some heavy-ish changes based on the feedback. The parser is now quite flexible, I've also separated the logic to create Curious to hear what you guys think :) EDIT: I need to write unit tests to cover the added functionality -- that's a WIP |
Codecov Report
@@ Coverage Diff @@
## master #593 +/- ##
==========================================
- Coverage 88.15% 87.41% -0.75%
==========================================
Files 113 113
Lines 2694 2749 +55
==========================================
+ Hits 2375 2403 +28
- Misses 319 346 +27
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
I'm considering adding keypoint parsing for VIA too so this gets pretty messy. There comes a point where the factory function is more cumbersome than just instantiating the concrete class yourself. So I think either remove the factory function or do something like this... Instead of all the boolean flags in the factory function we should use two enums. One for Something like this: from enum import Enum
VIAShape = Enum('VIAShape', [('POLYGON', 'polygon'), ('RECT', 'rect'), ('POINT', 'point'),
('POLYLINE', 'polyline'), ('ELLIPSE', 'ellipse'), ('CIRCLE', 'circle')])
ParserType = Enum('ParserType', 'BBOX MASK KEYPOINT')
def via(
annotations_file: Union[str, Path],
img_dir: Union[str, Path],
class_map: ClassMap,
label_field: str = "label",
parser_type: ParserType = ParserType.BBOX,
exclude_shapes: set = None
) -> Parser:
if parser_type is ParserType.BBOX:
parser_cls = VIABBoxParser
elif parser_type is ParserType.MASK:
parser_cls = VIAMaskParser
else:
raise NotImplementedError()
return parser_cls(annotations_file, img_dir, class_map, label_field, exclude_shapes) As a user, if I wanted a mask parser that ignored p = via('file', 'dir', class_map, parser_type = ParserType.MASK, exclude_shapes = {VIAShape.RECT}) Then in the parser classes you can get the union set of not-supported-shapes and excluded-shapes to determine which shapes to parse. Oh, and by using the string for the enum value in shape = VIAShape(shape_attr["name"])
if shape not in exclude_shapes:
... |
I'm up for removing the factory function and just instantiating the class, let's go with that? |
Yes. I think that's much cleaner. Also it means we don't need |
Specially when it's untested code, then I just see the coverage percentages going up, really nice! hahaaah Let's do that then. @rsomani95 what do you think? |
Concur, I think the |
Hi hi, I hope you both had a great new year! I'm returning back to this, @rsomani95 should I go and make the changes or you would like to do it?
Just to be clear, I think if we're instantiating directly from the class we don't need Enums anymore |
Hi @lgvaz, thanks. hope you had a good one too! |
@lgvaz - I think there's potentially still value in the VIAShape enum to tidy up the parsing and to allow the user to optionally specify shapes to exclude. But, perhaps that's an extension from initial mask support for another PR some day? |
@jerbly I'm a bit confused about ...parser_type = ParserType.MASK, exclude_shapes = {VIAShape.RECT}) If I understood correctly this would not parse bboxes, but to train the segmentation models we need them. Maybe what you have in mind is that if rect gets remove we calculate the bboxes from the masks? |
@lgvaz - no, that's not what I intended. The VIA spec allows you to mark up multiple shapes like rectangles, circles, ellipses etc. The exclude_shapes set was intended to allow you to take a dataset but only parse a subset of the shapes. This is independent of the parsing type be that bboxes, mask or keypoints. Think of shapes as the input and bbox/mask/keypoint as the output. I can have a go at a PR for this if that makes more sense? I'm just a little short on time this week. |
@jerbly - Aaah okay, gotcha!! Let's do that as a subsequent PR as you suggested, I'll work and merge this one this week and then you can open a new PR next week, what do you think? |
@lgvaz - sure, I can if you think there's value in it? |
@jerbly - I don't have a definitive answer right now, let me explore VIA a little bit more this weekend while I work on this PR, then I can provide you with a better answer without BSing 😅 |
I'm falling behind on this, but just want to let you know that I didn't forget, I'll get back to this after mmdetection support has been tackled |
In order to do this, I had to remove
VIABBoxParser
's ability to parse bounding boxes from bothrect
andpolygon
shape attributes and assume thatrect
annotations are for bounding boxes andpolygon
annotations for masks. If not, then the polygon annotations were added as an additional bbox and this didn't allow it to be parsed due to length mismatch betwen number of boxes and masks.I've left some of the older code commented out rather than delete it, will be happy to clean that up after some feedback.