From 1b0b456a5eca4ddc7a774baff2f3f044d9d4f20e Mon Sep 17 00:00:00 2001 From: Dmitry Sidnev Date: Wed, 13 Feb 2019 16:30:26 +0300 Subject: [PATCH 1/2] Add filtering of small segments --- utils/coco/converter.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/utils/coco/converter.py b/utils/coco/converter.py index 15d58aca92c..1f502f64196 100644 --- a/utils/coco/converter.py +++ b/utils/coco/converter.py @@ -52,11 +52,12 @@ def parse_args(): return parser.parse_args() -def mask_to_polygon(mask, tolerance=1.0): +def mask_to_polygon(mask, tolerance=1.0, area_threshold=5): """Convert object's mask to polygon [[x1,y1, x2,y2 ...], [...]] Args: mask: object's mask presented as 2D array of 0 and 1 tolerance: maximum distance from original points of polygon to approximated + area_threshold: if area of a polygon is less than this value, remove this small object """ polygons = [] # pad mask with 0 around borders @@ -77,7 +78,11 @@ def mask_to_polygon(mask, tolerance=1.0): for i in range(0, len(reshaped_contour)): if reshaped_contour[i] < 0: reshaped_contour[i] = 0 - polygons.append(reshaped_contour) + # Check if area of a polygon is enough + rle = mask_util.frPyObjects([reshaped_contour], mask.shape[0], mask.shape[1]) + area = mask_util.area(rle) + if sum(area) > area_threshold: + polygons.append(reshaped_contour) return polygons def draw_polygons(polygons, img_name, input_dir, output_dir, draw_labels): From 5062a32b86d545ff7a6b6ef92e9054dfb6323fc8 Mon Sep 17 00:00:00 2001 From: Dmitry Sidnev Date: Mon, 18 Feb 2019 17:36:06 +0300 Subject: [PATCH 2/2] Add polygon-area-threshold command line argument --- utils/coco/converter.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/utils/coco/converter.py b/utils/coco/converter.py index 1f502f64196..8780d9f0b07 100644 --- a/utils/coco/converter.py +++ b/utils/coco/converter.py @@ -49,10 +49,14 @@ def parse_args(): '--use_background_label', action='store_true', help='insert in output annotation objects with label \'background\'. By default is false' ) + parser.add_argument( + '--polygon-area-threshold', type=int, default=1, + help='polygons with area less than this value will be ignored. By default set to 1' + ) return parser.parse_args() -def mask_to_polygon(mask, tolerance=1.0, area_threshold=5): +def mask_to_polygon(mask, tolerance=1.0, area_threshold=1): """Convert object's mask to polygon [[x1,y1, x2,y2 ...], [...]] Args: mask: object's mask presented as 2D array of 0 and 1 @@ -120,7 +124,7 @@ def draw_polygons(polygons, img_name, input_dir, output_dir, draw_labels): cv2.imwrite(output_file, img) def fix_segments_intersections(polygons, height, width, img_name, use_background_label, - threshold=0.0, ratio_tolerance=0.001): + threshold=0.0, ratio_tolerance=0.001, area_threshold=1): """Find all intersected regions and crop contour for back object by objects which are in front of the first one. It is related to a specialty of segmentation in CVAT annotation. Intersection is calculated via function 'iou' from cocoapi @@ -180,7 +184,7 @@ def fix_segments_intersections(polygons, height, width, img_name, use_background bottom_mask = np.sum(bottom_mask, axis=2) bottom_mask = np.array(bottom_mask > 0, dtype=np.uint8) - converted_polygons[i]['points'] = mask_to_polygon(bottom_mask) + converted_polygons[i]['points'] = mask_to_polygon(bottom_mask, area_threshold=area_threshold) # If some segment is empty, do small fix to avoid error in cocoapi function if len(converted_polygons[i]['points']) == 0: converted_polygons[i]['points'] = [empty_polygon] @@ -407,7 +411,8 @@ def main(): height = result_annotation['images'][-1]['height'] width = result_annotation['images'][-1]['width'] image['polygon'] = fix_segments_intersections(image['polygon'], height, width, - image['name'], args.use_background_label) + image['name'], args.use_background_label, + area_threshold=args.polygon_area_threshold) # Create new annotation for this image for poly in image['polygon']: