-
Notifications
You must be signed in to change notification settings - Fork 6
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
Segmentation mask convertor #117
Conversation
- added some more documentation and TODOs - changes "contours" to "segmentation" to fit within COCO terminology
Codecov Report
@@ Coverage Diff @@
## master #117 +/- ##
==========================================
- Coverage 51.15% 45.86% -5.29%
==========================================
Files 8 9 +1
Lines 477 532 +55
==========================================
Hits 244 244
- Misses 233 288 +55
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
@jnothman this has been built based on working with the ginger images/masks. These are binary (black = nothing, white = plant), and there are usually one or two main objects with a bunch of super tiny ones, created as a result of the masking/annotation process. How should we deal with these? Subtract the tiny polygons, or potentially subsume them with the main ones? |
Do you mean ginger?
I had imagined a config file FFFFFF: "weed: UNSPECIFIED" or FF0000: "weed: lolium perenne"
00FF00: "weed: rapistrum rugosum"
0000FF: "weed: sonchus oleraceus"
I don't think so. We should be authentic to the input. On this, it's not our job to be opinionated. COCO assumes that there are multiple (or, more precisely, one or more) polygons. #90 codifies this in the schema: https://github.com/Sydney-Informatics-Hub/Weed-ID-Interchange/blob/6ef3a168215627c039b74224a73f2782a98a4b63/weedcoco/schema/Annotation.yaml#L33-L42. Note that an alternative representation is as a mask (a 2d binary array) encoded with RLE and special encoding that only seems to be handled by COCO API (https://github.com/cocodataset/cocoapi/blob/8c9bcc3cf640524c4c20a9c40e89cb6a2f2fa0e9/common/maskApi.c#L204-L231). Turning the image into a mask, based on known annotation colours, and then using pycocotools, may provide more straightforward solutions than thresholding and opencv, which is designed more for photography than discrete masking. |
I have no idea why I wrote carrots; yes I meant ginger!!! |
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.
I don't think coco_from_mask.json should be included in the repo. Rather:
- there should be at least one pytest test case checking that the converter works;
- we might add a script
search/scripts/index_rds_images.sh
which is given the path to the RDS root, and converts and loads data from there.
|
||
|
||
def generate_masks_contours(mask_path): | ||
|
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.
This blank line violates PEP257. I'm surprised black lets it through
weedcoco/importers/mask.py
Outdated
|
||
image_id = 0 | ||
for filename in os.listdir(image_dir): | ||
if filename.endswith(".png") or filename.endswith(".jpg"): |
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.
there should be an else clause that warns or raises an error if the file type is unexpected
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.
jpeg
and tif
might also be possible extensions
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.
A neat shorthand
if filename.endswith(".png") or filename.endswith(".jpg"): | |
if filename.endswith((".png", ".jpg", ".jpeg", ".tif", ".tiff")): |
### crop_type ### | ||
# description: 'Crop type. | ||
|
||
# One of several strings describing the crop grown in the image.' |
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.
these comments aren't needed in a test file. You can do sed -E 's/^$|^#/d'
on the file to get only the content lines
Similar in concept to the origina convertor. Bootstrapped from a blog post with changes. Still not completely functional, but parts of it will run and seem to behave how we want.
Major changes are afoot. Using this blog post as a template, to redesign this convertor to work with colour category mapping. In some ways this is reinventing aspects of the opencv contour generator, but it may be a better direction for our use case. |
don't look
I'm not yet happy with the sufficiency of the tests, but this is otherwise ready for review. |
Maybe I should open a new PR so that Henry can review. @hlydecker would you like to and are you available to do so? |
Happy to review this sometime this afternoon! |
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.
This looks good and the existing tests are sensible enough. Most of my comments are just some suggestions for making warnings and errors more clear to potential users.
I do wonder what sort of other tests could be included. test_basic is indeed basic but it does test the basic functionality!
"image_id": len(images), | ||
"category_id": cat_idx, | ||
"segmentation": rle, | ||
# "is_crowd": 0, # TODO: how should we define this? |
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.
When using RLE, we should probably set is_crowd: 1. From my understanding, RLE is really made for situations where we have a a field of several objects of the same category but we aren't annotating each individual one. So in terms of our data, we aren't annotating individual plants; instead we are imply annotating any visible stuff that falls within that category, which could potentially be multiple plants.
Ah of course now I realise the awkwardness here; it makes sense that I cannot be a reviewer for my own pull request even if the actual content is not my progeny. |
Co-authored-by: Henry Lydecker <henry.lydecker@gmail.com>
Co-authored-by: Henry Lydecker <henry.lydecker@gmail.com>
Want to check out the changes since last review, @hlydecker and gimme a tick if possible? |
Will take a look this afternoon! |
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.
LGTM; not much was changed. Documentation changes have improved clarity.
The testing plan sounds good to me as well.
@@ -30,7 +30,7 @@ def generate_segmentations(mask_path, color_map, colors_not_found): | |||
Yields | |||
------ | |||
segmentation : str | |||
COCO segmentation string | |||
COCO segmentation string in compressed RLE format |
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.
Good addition to the documentation
# * check segmentation RLE string can be read back in and reproduces the mask | ||
# * check handling of missing correspondence between mask and image files | ||
# * check handling of different image file formats | ||
# * check handling of agcontext |
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.
This would be good. The agcontext ingestion + testing would probably make sense as something that is shared as a utility called by each individual converter.
@@ -163,7 +163,7 @@ def _image_name_to_mask(name): | |||
warnings.warn( | |||
f"{len(categories)} categories defined, but only " | |||
f"{len(categories_found)} of these are present in masks. " | |||
f"Missing are {missing_category_colors}" | |||
f"These categories were not found: {missing_category_colors}" |
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.
Both this change and the one at 118 are great improvements in the clarity of the messages to users.
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.
Both this change and the one at 118 are great improvements in the clarity of the messages to users.
They were both your explicit contributions! :D
Okay to merge as is, despite TODOs? |
I'd say so :) |
Thanks for the review @hlydecker |
WIP. Some questions need answering.
Currently only works with hard coded categories, for single category images. Will need to adapt it to link categories to masks by colour codes.
Currently is missing license and info objects.