-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Adding dump for VOC instance mask. #859
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
Changes from 2 commits
a9f01ec
e9be235
86e8452
636fa56
0add0e1
a6fcf07
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Copyright (C) 2019 Intel Corporation | ||
# | ||
# SPDX-License-Identifier: MIT | ||
|
||
format_spec = { | ||
"name": "MASK INSTANCE", | ||
"dumpers": [ | ||
{ | ||
"display_name": "{name} {format} {version}", | ||
"format": "ZIP", | ||
"version": "1.0", | ||
"handler": "dump" | ||
}, | ||
], | ||
"loaders": [ | ||
], | ||
} | ||
|
||
def dump(file_object, annotations): | ||
from zipfile import ZipFile | ||
import numpy as np | ||
import os | ||
from pycocotools import mask as maskUtils | ||
import matplotlib.image | ||
import io | ||
from collections import OrderedDict | ||
|
||
# RGB format, (0, 0, 0) used for background | ||
def genearte_pascal_colormap(size=256): | ||
zhiltsov-max marked this conversation as resolved.
Show resolved
Hide resolved
|
||
colormap = np.zeros((size, 3), dtype=int) | ||
ind = np.arange(size, dtype=int) | ||
|
||
for shift in reversed(range(8)): | ||
for channel in range(3): | ||
colormap[:, channel] |= ((ind >> channel) & 1) << shift | ||
ind >>= 3 | ||
|
||
return colormap | ||
|
||
def convert_box_to_polygon(points): | ||
xtl = shape.points[0] | ||
ytl = shape.points[1] | ||
xbr = shape.points[2] | ||
ybr = shape.points[3] | ||
|
||
return [xtl, ytl, xbr, ytl, xbr, ybr, xtl, ybr] | ||
|
||
colormap = genearte_pascal_colormap() | ||
instance_colors = OrderedDict((idx, colormap[idx]) for idx in range(len(colormap))) | ||
|
||
with ZipFile(file_object, "w") as output_zip: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding some compression may be not extraneous, check There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @zhiltsov-max by default, the ZipFile use ZIP_STORED so it won't use any compression. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, so I suggest adding it, or, at least, checking if it worth, as masks are There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added the ZIP_STORED in the new commit There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please check if |
||
for frame_annotation in annotations.group_by_frame(): | ||
image_name = frame_annotation.name | ||
annotation_name = "{}.png".format(os.path.splitext(os.path.basename(image_name))[0]) | ||
width = frame_annotation.width | ||
height = frame_annotation.height | ||
|
||
shapes = frame_annotation.labeled_shapes | ||
# convert to mask only rectangles and polygons | ||
shapes = [shape for shape in shapes if shape.type == 'rectangle' or shape.type == 'polygon'] | ||
if not shapes: | ||
continue | ||
shapes = sorted(shapes, key=lambda x: int(x.z_order)) | ||
img = np.zeros((height, width, 3)) | ||
buf = io.BytesIO() | ||
for cnt, shape in enumerate(shapes): | ||
zhiltsov-max marked this conversation as resolved.
Show resolved
Hide resolved
|
||
points = shape.points if shape.type != 'rectangle' else convert_box_to_polygon(shape.points) | ||
rles = maskUtils.frPyObjects([points], height, width) | ||
rle = maskUtils.merge(rles) | ||
mask = maskUtils.decode(rle) | ||
# 0 is used background color. instance mask color started from 1 | ||
color = instance_colors[cnt+1] / 255 | ||
idx = (mask > 0) | ||
img[idx] = color | ||
|
||
matplotlib.image.imsave(buf, img, format='png') | ||
output_zip.writestr(annotation_name, buf.getvalue()) | ||
labels = '\n'.join('{}:{}'.format(label, ','.join(str(i) for i in color)) for label, color in instance_colors.items()) | ||
output_zip.writestr('colormap.txt', labels) |
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 would suggest adding this functionality to
pascal_voc.py
nearby as one extra dumper in the corresponding list.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.
@zhiltsov-max , @gachiemchiep , It is a great idea to join several parsers. I believe MASK and MASK INSTANCE are very similar. Thus it is better to extend "MASK" annotation format instead of creating a new one. Thus it will not be necessary to duplicate code.
Uh oh!
There was an error while loading. Please reload this page.
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.
@zhiltsov-max you're right. mask and mask instance are used in pascal voc so those parser should be merged into pascal_voc.py. Maybe it is a good idea to dump "bounding box" + "mask" + "mask instance" at the same time.
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.
@zhiltsov-max I merged the mask_instance and mask into mask.py.