def convert_mask(mask): polygons = mask_tools.mask_to_polygons(mask.image) return [ Polygon(points=p, label=mask.label, z_order=mask.z_order, id=mask.id, attributes=mask.attributes, group=mask.group) for p in polygons ]
def test_mask_can_be_converted_to_polygon(self): mask = np.array([ [0, 1, 1, 1, 0, 1, 1, 1, 1, 0], [0, 0, 1, 1, 0, 1, 0, 1, 0, 0], [0, 0, 0, 1, 0, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ]) expected = [ [1, 0, 3, 0, 3, 2, 1, 0], [5, 0, 8, 0, 5, 3], ] computed = mask_tools.mask_to_polygons(mask) self.assertEqual(len(expected), len(computed))
def find_instance_parts(self, group, img_width, img_height): boxes = [a for a in group if a.type == AnnotationType.bbox] polygons = [a for a in group if a.type == AnnotationType.polygon] masks = [a for a in group if a.type == AnnotationType.mask] anns = boxes + polygons + masks leader = anno_tools.find_group_leader(anns) bbox = anno_tools.max_bbox(anns) mask = None polygons = [p.points for p in polygons] if self._context._segmentation_mode == SegmentationMode.guess: use_masks = True == leader.attributes.get( 'is_crowd', find(masks, lambda x: x.label == leader.label) is not None) elif self._context._segmentation_mode == SegmentationMode.polygons: use_masks = False elif self._context._segmentation_mode == SegmentationMode.mask: use_masks = True else: raise NotImplementedError("Unexpected segmentation mode '%s'" % \ self._context._segmentation_mode) if use_masks: if polygons: mask = mask_tools.rles_to_mask(polygons, img_width, img_height) if masks: masks = (m.image for m in masks) if mask is not None: masks += chain(masks, [mask]) mask = mask_tools.merge_masks(masks) if mask is not None: mask = mask_tools.mask_to_rle(mask) polygons = [] else: if masks: mask = mask_tools.merge_masks(m.image for m in masks) polygons += mask_tools.mask_to_polygons(mask) mask = None return [leader, polygons, mask, bbox]
def parse_xml_annotations(xml_data, annotations, input_zip): from datumaro.util.mask_tools import mask_to_polygons from io import BytesIO from lxml import etree as ET import numpy as np import os.path as osp from PIL import Image def parse_attributes(attributes_string): parsed = [] if not attributes_string: return parsed read = attributes_string.split(',') read = [a.strip() for a in read if a.strip()] for attr in read: if '=' in attr: name, value = attr.split('=', maxsplit=1) parsed.append(annotations.Attribute(name, value)) else: parsed.append(annotations.Attribute(attr, '1')) return parsed root_elem = ET.fromstring(xml_data) frame_number = annotations.match_frame(root_elem.find('filename').text) parsed_annotations = dict() group_assignments = dict() root_annotations = set() for obj_elem in root_elem.iter('object'): obj_id = int(obj_elem.find('id').text) ann_items = [] attributes = [] attributes_elem = obj_elem.find('attributes') if attributes_elem is not None and attributes_elem.text: attributes = parse_attributes(attributes_elem.text) occluded = False occluded_elem = obj_elem.find('occluded') if occluded_elem is not None and occluded_elem.text: occluded = (occluded_elem.text == 'yes') deleted = False deleted_elem = obj_elem.find('deleted') if deleted_elem is not None and deleted_elem.text: deleted = bool(int(deleted_elem.text)) poly_elem = obj_elem.find('polygon') segm_elem = obj_elem.find('segm') type_elem = obj_elem.find('type') # the only value is 'bounding_box' if poly_elem is not None: points = [] for point_elem in poly_elem.iter('pt'): x = float(point_elem.find('x').text) y = float(point_elem.find('y').text) points.append(x) points.append(y) label = obj_elem.find('name').text if label and attributes: label_id = annotations._get_label_id(label) if label_id: attributes = [ a for a in attributes if annotations._get_attribute_id(label_id, a.name) ] else: attributes = [] else: attributes = [] if type_elem is not None and type_elem.text == 'bounding_box': xmin = min(points[::2]) xmax = max(points[::2]) ymin = min(points[1::2]) ymax = max(points[1::2]) ann_items.append( annotations.LabeledShape( type='rectangle', frame=frame_number, label=label, points=[xmin, ymin, xmax, ymax], occluded=occluded, attributes=attributes, )) else: ann_items.append( annotations.LabeledShape( type='polygon', frame=frame_number, label=label, points=points, occluded=occluded, attributes=attributes, )) elif segm_elem is not None: label = obj_elem.find('name').text if label and attributes: label_id = annotations._get_label_id(label) if label_id: attributes = [ a for a in attributes if annotations._get_attribute_id(label_id, a.name) ] else: attributes = [] else: attributes = [] mask_file = segm_elem.find('mask').text mask = input_zip.read(osp.join(_MASKS_DIR, mask_file)) mask = np.asarray(Image.open(BytesIO(mask)).convert('L')) mask = (mask != 0) polygons = mask_to_polygons(mask) for polygon in polygons: ann_items.append( annotations.LabeledShape( type='polygon', frame=frame_number, label=label, points=polygon, occluded=occluded, attributes=attributes, )) if not deleted: parsed_annotations[obj_id] = ann_items parts_elem = obj_elem.find('parts') if parts_elem is not None: children_ids = [] hasparts_elem = parts_elem.find('hasparts') if hasparts_elem is not None and hasparts_elem.text: children_ids = [int(c) for c in hasparts_elem.text.split(',')] parent_ids = [] ispartof_elem = parts_elem.find('ispartof') if ispartof_elem is not None and ispartof_elem.text: parent_ids = [int(c) for c in ispartof_elem.text.split(',')] if children_ids and not parent_ids and hasparts_elem.text: root_annotations.add(obj_id) group_assignments[obj_id] = [None, children_ids] # assign a single group to the whole subtree current_group_id = 0 annotations_to_visit = list(root_annotations) while annotations_to_visit: ann_id = annotations_to_visit.pop() ann_assignment = group_assignments[ann_id] group_id, children_ids = ann_assignment if group_id: continue if ann_id in root_annotations: current_group_id += 1 # start a new group group_id = current_group_id ann_assignment[0] = group_id # continue with children annotations_to_visit.extend(children_ids) assert current_group_id == len(root_annotations) for ann_id, ann_items in parsed_annotations.items(): group_id = 0 if ann_id in group_assignments: ann_assignment = group_assignments[ann_id] group_id = ann_assignment[0] for ann_item in ann_items: if group_id: ann_item = ann_item._replace(group=group_id) if isinstance(ann_item, annotations.LabeledShape): annotations.add_shape(ann_item) else: raise NotImplementedError()