-
Notifications
You must be signed in to change notification settings - Fork 9.5k
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
Rename BitMap to Bitmap, perfect unit test. #2391
Merged
Merged
Changes from 4 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
7d0084a
rename BitMap to Bitmap, add input check for polygon
yhcao6 ba2da6b
fix test mask
yhcao6 80417f1
fix test config
yhcao6 9b019c1
complete test
yhcao6 8333388
add mask contest test for bitmap resize
yhcao6 887b2a6
update with np.diag
yhcao6 ef0afe2
perfect test polygon resize
yhcao6 d3f3aa4
perfect test polygon crop
yhcao6 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
from .mask_target import mask_target | ||
from .structures import BitMapMasks, PolygonMasks | ||
from .structures import BitmapMasks, PolygonMasks | ||
from .utils import split_combined_polys | ||
|
||
__all__ = [ | ||
'split_combined_polys', 'mask_target', 'BitMapMasks', 'PolygonMasks' | ||
'split_combined_polys', 'mask_target', 'BitmapMasks', 'PolygonMasks' | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,6 +40,10 @@ def crop_and_resize(self, | |
def expand(self, expanded_h, expanded_w, top, left): | ||
pass | ||
|
||
@abstractmethod | ||
def area(self): | ||
pass | ||
|
||
@abstractmethod | ||
def to_ndarray(self): | ||
pass | ||
|
@@ -49,7 +53,7 @@ def to_tensor(self, dtype, device): | |
pass | ||
|
||
|
||
class BitMapMasks(BaseInstanceMasks): | ||
class BitmapMasks(BaseInstanceMasks): | ||
"""This class represents masks in the form of bitmaps. | ||
|
||
Args: | ||
|
@@ -78,7 +82,7 @@ def __init__(self, masks, height, width): | |
|
||
def __getitem__(self, index): | ||
masks = self.masks[index].reshape(-1, self.height, self.width) | ||
return BitMapMasks(masks, self.height, self.width) | ||
return BitmapMasks(masks, self.height, self.width) | ||
|
||
def __iter__(self): | ||
return iter(self.masks) | ||
|
@@ -95,7 +99,7 @@ def rescale(self, scale, interpolation='nearest'): | |
interpolation (str): same as :func:`mmcv.imrescale` | ||
|
||
Returns: | ||
BitMapMasks: the rescaled masks | ||
BitmapMasks: the rescaled masks | ||
""" | ||
if len(self.masks) == 0: | ||
new_w, new_h = mmcv.rescale_size((self.width, self.height), scale) | ||
|
@@ -106,7 +110,7 @@ def rescale(self, scale, interpolation='nearest'): | |
for mask in self.masks | ||
]) | ||
height, width = rescaled_masks.shape[1:] | ||
return BitMapMasks(rescaled_masks, height, width) | ||
return BitmapMasks(rescaled_masks, height, width) | ||
|
||
def resize(self, out_shape, interpolation='nearest'): | ||
"""Resize masks to the given out_shape. | ||
|
@@ -116,7 +120,7 @@ def resize(self, out_shape, interpolation='nearest'): | |
interpolation (str): see `mmcv.imresize` | ||
|
||
Returns: | ||
BitMapMasks: the resized masks | ||
BitmapMasks: the resized masks | ||
""" | ||
if len(self.masks) == 0: | ||
resized_masks = np.empty((0, *out_shape), dtype=np.uint8) | ||
|
@@ -125,7 +129,7 @@ def resize(self, out_shape, interpolation='nearest'): | |
mmcv.imresize(mask, out_shape, interpolation=interpolation) | ||
for mask in self.masks | ||
]) | ||
return BitMapMasks(resized_masks, *out_shape) | ||
return BitmapMasks(resized_masks, *out_shape) | ||
|
||
def flip(self, flip_direction='horizontal'): | ||
"""flip masks alone the given direction. | ||
|
@@ -134,7 +138,7 @@ def flip(self, flip_direction='horizontal'): | |
flip_direction (str): either 'horizontal' or 'vertical' | ||
|
||
Returns: | ||
BitMapMasks: the flipped masks | ||
BitmapMasks: the flipped masks | ||
""" | ||
assert flip_direction in ('horizontal', 'vertical') | ||
|
||
|
@@ -145,7 +149,7 @@ def flip(self, flip_direction='horizontal'): | |
mmcv.imflip(mask, direction=flip_direction) | ||
for mask in self.masks | ||
]) | ||
return BitMapMasks(flipped_masks, self.height, self.width) | ||
return BitmapMasks(flipped_masks, self.height, self.width) | ||
|
||
def pad(self, out_shape, pad_val=0): | ||
"""Pad masks to the given size of (h, w). | ||
|
@@ -155,7 +159,7 @@ def pad(self, out_shape, pad_val=0): | |
pad_val (int): the padded value | ||
|
||
Returns: | ||
BitMapMasks: the padded masks | ||
BitmapMasks: the padded masks | ||
""" | ||
if len(self.masks) == 0: | ||
padded_masks = np.empty((0, *out_shape), dtype=np.uint8) | ||
|
@@ -164,7 +168,7 @@ def pad(self, out_shape, pad_val=0): | |
mmcv.impad(mask, out_shape, pad_val=pad_val) | ||
for mask in self.masks | ||
]) | ||
return BitMapMasks(padded_masks, *out_shape) | ||
return BitmapMasks(padded_masks, *out_shape) | ||
|
||
def crop(self, bbox): | ||
"""Crop each mask by the given bbox. | ||
|
@@ -173,7 +177,7 @@ def crop(self, bbox): | |
bbox (ndarray): bbox in format [x1, y1, x2, y2], shape (4, ) | ||
|
||
Return: | ||
BitMapMasks: the cropped masks. | ||
BitmapMasks: the cropped masks. | ||
""" | ||
assert isinstance(bbox, np.ndarray) | ||
assert bbox.ndim == 1 | ||
|
@@ -190,7 +194,7 @@ def crop(self, bbox): | |
cropped_masks = np.empty((0, h, w), dtype=np.uint8) | ||
else: | ||
cropped_masks = self.masks[:, y1:y1 + h, x1:x1 + w] | ||
return BitMapMasks(cropped_masks, h, w) | ||
return BitmapMasks(cropped_masks, h, w) | ||
|
||
def crop_and_resize(self, | ||
bboxes, | ||
|
@@ -214,7 +218,7 @@ def crop_and_resize(self, | |
""" | ||
if len(self.masks) == 0: | ||
empty_masks = np.empty((0, *out_shape), dtype=np.uint8) | ||
return BitMapMasks(empty_masks, *out_shape) | ||
return BitmapMasks(empty_masks, *out_shape) | ||
|
||
resized_masks = [] | ||
for i in range(len(bboxes)): | ||
|
@@ -228,7 +232,7 @@ def crop_and_resize(self, | |
mask[y1:y1 + h, x1:x1 + w], | ||
out_shape, | ||
interpolation=interpolation)) | ||
return BitMapMasks(np.stack(resized_masks), *out_shape) | ||
return BitmapMasks(np.stack(resized_masks), *out_shape) | ||
|
||
def expand(self, expanded_h, expanded_w, top, left): | ||
"""see `transforms.Expand`.""" | ||
|
@@ -240,7 +244,15 @@ def expand(self, expanded_h, expanded_w, top, left): | |
dtype=np.uint8) | ||
expanded_mask[:, top:top + self.height, | ||
left:left + self.width] = self.masks | ||
return BitMapMasks(expanded_mask, expanded_h, expanded_w) | ||
return BitmapMasks(expanded_mask, expanded_h, expanded_w) | ||
|
||
def area(self): | ||
"""Compute area of each instance | ||
|
||
Return: | ||
ndarray: areas of each instance | ||
""" | ||
return self.masks.sum((1, 2)) | ||
|
||
def to_ndarray(self): | ||
return self.masks | ||
|
@@ -297,7 +309,7 @@ def __len__(self): | |
return len(self.masks) | ||
|
||
def rescale(self, scale, interpolation=None): | ||
"""see BitMapMasks.rescale""" | ||
"""see BitmapMasks.rescale""" | ||
new_w, new_h = mmcv.rescale_size((self.width, self.height), scale) | ||
if len(self.masks) == 0: | ||
rescaled_masks = PolygonMasks([], new_h, new_w) | ||
|
@@ -306,7 +318,7 @@ def rescale(self, scale, interpolation=None): | |
return rescaled_masks | ||
|
||
def resize(self, out_shape, interpolation=None): | ||
"""see BitMapMasks.resize""" | ||
"""see BitmapMasks.resize""" | ||
if len(self.masks) == 0: | ||
resized_masks = PolygonMasks([], *out_shape) | ||
else: | ||
|
@@ -325,7 +337,7 @@ def resize(self, out_shape, interpolation=None): | |
return resized_masks | ||
|
||
def flip(self, flip_direction='horizontal'): | ||
"""see BitMapMasks.flip""" | ||
"""see BitmapMasks.flip""" | ||
assert flip_direction in ('horizontal', 'vertical') | ||
if len(self.masks) == 0: | ||
flipped_masks = PolygonMasks([], self.height, self.width) | ||
|
@@ -349,7 +361,7 @@ def flip(self, flip_direction='horizontal'): | |
return flipped_masks | ||
|
||
def crop(self, bbox): | ||
"""see BitMapMasks.crop""" | ||
"""see BitmapMasks.crop""" | ||
assert isinstance(bbox, np.ndarray) | ||
assert bbox.ndim == 1 | ||
|
||
|
@@ -368,6 +380,7 @@ def crop(self, bbox): | |
for poly_per_obj in self.masks: | ||
cropped_poly_per_obj = [] | ||
for p in poly_per_obj: | ||
# pycocotools will clip the boundary | ||
p = p.copy() | ||
p[0::2] -= bbox[0] | ||
p[1::2] -= bbox[1] | ||
|
@@ -388,7 +401,7 @@ def crop_and_resize(self, | |
out_shape, | ||
inds, | ||
interpolation='bilinear'): | ||
"""see BitMapMasks.crop_and_resize""" | ||
"""see BitmapMasks.crop_and_resize""" | ||
out_h, out_w = out_shape | ||
if len(self.masks) == 0: | ||
return PolygonMasks([], out_h, out_w) | ||
|
@@ -407,6 +420,7 @@ def crop_and_resize(self, | |
for p in mask: | ||
p = p.copy() | ||
# crop | ||
# pycocotools will clip the boundary | ||
p[0::2] -= bbox[0] | ||
p[1::2] -= bbox[1] | ||
|
||
|
@@ -420,7 +434,24 @@ def crop_and_resize(self, | |
def to_bitmap(self): | ||
"""convert polygon masks to bitmap masks""" | ||
bitmap_masks = self.to_ndarray() | ||
return BitMapMasks(bitmap_masks, self.height, self.width) | ||
return BitmapMasks(bitmap_masks, self.height, self.width) | ||
|
||
def area(self): | ||
""" Compute area of masks using the shoelace formula | ||
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. Add a blank line between the summary and description. |
||
https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates | ||
This func is modified from | ||
https://github.com/facebookresearch/detectron2/blob/ffff8acc35ea88ad1cb1806ab0f00b4c1c5dbfd9/detectron2/structures/masks.py#L387 | ||
|
||
Return: | ||
ndarray: areas of each instance | ||
""" # noqa: W501 | ||
area = [] | ||
for polygons_per_obj in self.masks: | ||
area_per_obj = 0 | ||
for p in polygons_per_obj: | ||
area_per_obj += polygon_area(p[0::2], p[1::2]) | ||
area.append(area_per_obj) | ||
return np.asarray(area) | ||
|
||
def to_ndarray(self): | ||
if len(self.masks) == 0: | ||
|
@@ -455,3 +486,10 @@ def polygon_to_bitmap(polygons, height, width): | |
rle = maskUtils.merge(rles) | ||
bitmap_mask = maskUtils.decode(rle).astype(np.bool) | ||
return bitmap_mask | ||
|
||
|
||
def polygon_area(x, y): | ||
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. Make it a private method of PolygonMasks. |
||
"""Using the shoelace formula | ||
https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates | ||
""" # noqa: 501 | ||
return 0.5 * np.abs(np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
@abstractproperty