def get_bbox(self) -> Tuple[int, int, int, int]: """ Computes the bounding box of the mask. Returns: [x, y, w, h] """ from datumaro.util.mask_tools import find_mask_bbox return find_mask_bbox(self.image)
def _save_item(self, item, subset_dir, index): from lxml import etree as ET log.debug("Converting item '%s'", item.id) image_filename = self._make_image_filename(item) if self._save_images: if item.has_image and item.image.has_data: self._save_image(item, osp.join(subset_dir, image_filename)) else: log.debug("Item '%s' has no image", item.id) root_elem = ET.Element('annotation') ET.SubElement(root_elem, 'filename').text = osp.basename(image_filename) ET.SubElement(root_elem, 'folder').text = osp.dirname(image_filename) source_elem = ET.SubElement(root_elem, 'source') ET.SubElement(source_elem, 'sourceImage').text = '' ET.SubElement(source_elem, 'sourceAnnotation').text = 'Datumaro' if item.has_image: image_elem = ET.SubElement(root_elem, 'imagesize') image_size = item.image.size ET.SubElement(image_elem, 'nrows').text = str(image_size[0]) ET.SubElement(image_elem, 'ncols').text = str(image_size[1]) groups = defaultdict(list) obj_id = 0 for ann in item.annotations: if not ann.type in { AnnotationType.polygon, AnnotationType.bbox, AnnotationType.mask }: continue obj_elem = ET.SubElement(root_elem, 'object') ET.SubElement(obj_elem, 'name').text = self._get_label(ann.label) ET.SubElement(obj_elem, 'deleted').text = '0' ET.SubElement(obj_elem, 'verified').text = '0' ET.SubElement(obj_elem, 'occluded').text = \ 'yes' if ann.attributes.pop('occluded', '') == True else 'no' ET.SubElement(obj_elem, 'date').text = '' ET.SubElement(obj_elem, 'id').text = str(obj_id) parts_elem = ET.SubElement(obj_elem, 'parts') if ann.group: groups[ann.group].append((obj_id, parts_elem)) else: ET.SubElement(parts_elem, 'hasparts').text = '' ET.SubElement(parts_elem, 'ispartof').text = '' if ann.type == AnnotationType.bbox: ET.SubElement(obj_elem, 'type').text = 'bounding_box' poly_elem = ET.SubElement(obj_elem, 'polygon') x0, y0, x1, y1 = ann.points points = [ (x0, y0), (x1, y0), (x1, y1), (x0, y1) ] for x, y in points: point_elem = ET.SubElement(poly_elem, 'pt') ET.SubElement(point_elem, 'x').text = '%.2f' % x ET.SubElement(point_elem, 'y').text = '%.2f' % y ET.SubElement(poly_elem, 'username').text = \ str(ann.attributes.pop('username', '')) elif ann.type == AnnotationType.polygon: poly_elem = ET.SubElement(obj_elem, 'polygon') for x, y in zip(ann.points[::2], ann.points[1::2]): point_elem = ET.SubElement(poly_elem, 'pt') ET.SubElement(point_elem, 'x').text = '%.2f' % x ET.SubElement(point_elem, 'y').text = '%.2f' % y ET.SubElement(poly_elem, 'username').text = \ str(ann.attributes.pop('username', '')) elif ann.type == AnnotationType.mask: mask_filename = '%s_mask_%s.png' % \ (item.id.replace('/', '_'), obj_id) save_image(osp.join(subset_dir, LabelMePath.MASKS_DIR, mask_filename), self._paint_mask(ann.image)) segm_elem = ET.SubElement(obj_elem, 'segm') ET.SubElement(segm_elem, 'mask').text = mask_filename bbox = find_mask_bbox(ann.image) box_elem = ET.SubElement(segm_elem, 'box') ET.SubElement(box_elem, 'xmin').text = '%.2f' % bbox[0] ET.SubElement(box_elem, 'ymin').text = '%.2f' % bbox[1] ET.SubElement(box_elem, 'xmax').text = \ '%.2f' % (bbox[0] + bbox[2]) ET.SubElement(box_elem, 'ymax').text = \ '%.2f' % (bbox[1] + bbox[3]) ET.SubElement(segm_elem, 'username').text = \ str(ann.attributes.pop('username', '')) else: raise NotImplementedError("Unknown shape type '%s'" % ann.type) attrs = [] for k, v in ann.attributes.items(): attrs.append('%s=%s' % (k, v)) ET.SubElement(obj_elem, 'attributes').text = ', '.join(attrs) obj_id += 1 for _, group in groups.items(): leader_id, leader_parts_elem = group[0] leader_parts = [str(o_id) for o_id, _ in group[1:]] ET.SubElement(leader_parts_elem, 'hasparts').text = \ ','.join(leader_parts) ET.SubElement(leader_parts_elem, 'ispartof').text = '' for obj_id, parts_elem in group[1:]: ET.SubElement(parts_elem, 'hasparts').text = '' ET.SubElement(parts_elem, 'ispartof').text = str(leader_id) xml_path = osp.join(subset_dir, 'item_%09d.xml' % index) with open(xml_path, 'w', encoding='utf-8') as f: xml_data = ET.tostring(root_elem, encoding='unicode', pretty_print=True) f.write(xml_data)
def get_bbox(self): from datumaro.util.mask_tools import find_mask_bbox return find_mask_bbox(self.image)
def _save_item(self, item, subset_dir): # Disable B410: import_lxml - the library is used for writing here from lxml import etree as ET # nosec log.debug("Converting item '%s'", item.id) image_filename = self._make_image_filename(item) if self._save_images: if item.has_image and item.image.has_data: self._save_image(item, osp.join(subset_dir, image_filename)) else: log.debug("Item '%s' has no image", item.id) root_elem = ET.Element('annotation') ET.SubElement(root_elem, 'filename').text = osp.basename(image_filename) ET.SubElement(root_elem, 'folder').text = osp.dirname(image_filename) source_elem = ET.SubElement(root_elem, 'source') ET.SubElement(source_elem, 'sourceImage').text = '' ET.SubElement(source_elem, 'sourceAnnotation').text = 'Datumaro' if item.has_image: image_elem = ET.SubElement(root_elem, 'imagesize') image_size = item.image.size ET.SubElement(image_elem, 'nrows').text = str(image_size[0]) ET.SubElement(image_elem, 'ncols').text = str(image_size[1]) groups = defaultdict(list) obj_id = 0 for ann in item.annotations: if not ann.type in { AnnotationType.polygon, AnnotationType.bbox, AnnotationType.mask }: continue obj_elem = ET.SubElement(root_elem, 'object') ET.SubElement(obj_elem, 'name').text = self._get_label(ann.label) ET.SubElement(obj_elem, 'deleted').text = '0' ET.SubElement(obj_elem, 'verified').text = '0' ET.SubElement(obj_elem, 'occluded').text = \ 'yes' if ann.attributes.get('occluded') is True else 'no' ET.SubElement(obj_elem, 'date').text = '' ET.SubElement(obj_elem, 'id').text = str(obj_id) parts_elem = ET.SubElement(obj_elem, 'parts') if ann.group: groups[ann.group].append((obj_id, parts_elem)) else: ET.SubElement(parts_elem, 'hasparts').text = '' ET.SubElement(parts_elem, 'ispartof').text = '' if ann.type == AnnotationType.bbox: ET.SubElement(obj_elem, 'type').text = 'bounding_box' poly_elem = ET.SubElement(obj_elem, 'polygon') x0, y0, x1, y1 = ann.points points = [ (x0, y0), (x1, y0), (x1, y1), (x0, y1) ] for x, y in points: point_elem = ET.SubElement(poly_elem, 'pt') ET.SubElement(point_elem, 'x').text = '%.2f' % x ET.SubElement(point_elem, 'y').text = '%.2f' % y ET.SubElement(poly_elem, 'username').text = \ str(ann.attributes.get('username', '')) elif ann.type == AnnotationType.polygon: poly_elem = ET.SubElement(obj_elem, 'polygon') for x, y in zip(ann.points[::2], ann.points[1::2]): point_elem = ET.SubElement(poly_elem, 'pt') ET.SubElement(point_elem, 'x').text = '%.2f' % x ET.SubElement(point_elem, 'y').text = '%.2f' % y ET.SubElement(poly_elem, 'username').text = \ str(ann.attributes.get('username', '')) elif ann.type == AnnotationType.mask: mask_filename = '%s_mask_%s.png' % (item.id, obj_id) save_image(osp.join(subset_dir, LabelMePath.MASKS_DIR, mask_filename), self._paint_mask(ann.image), create_dir=True) segm_elem = ET.SubElement(obj_elem, 'segm') ET.SubElement(segm_elem, 'mask').text = mask_filename bbox = find_mask_bbox(ann.image) box_elem = ET.SubElement(segm_elem, 'box') ET.SubElement(box_elem, 'xmin').text = '%.2f' % bbox[0] ET.SubElement(box_elem, 'ymin').text = '%.2f' % bbox[1] ET.SubElement(box_elem, 'xmax').text = \ '%.2f' % (bbox[0] + bbox[2]) ET.SubElement(box_elem, 'ymax').text = \ '%.2f' % (bbox[1] + bbox[3]) ET.SubElement(segm_elem, 'username').text = \ str(ann.attributes.get('username', '')) else: raise NotImplementedError("Unknown shape type '%s'" % ann.type) attrs = [] for k, v in ann.attributes.items(): if k in { 'username' , 'occluded' }: continue if isinstance(v, str): if cast(v, float) is not None and str(float(v)) == v or \ cast(v, int) is not None and str(int(v)) == v: v = f'"{v}"' # add escaping for string values else: v = self._escape(v) # pylint: disable=redundant-keyword-arg due FP https://github.com/PyCQA/pylint/issues/2271 attrs.append('%s=%s' % (self._escape(k), v)) # pylint: disable=redundant-keyword-arg due FP https://github.com/PyCQA/pylint/issues/2271 ET.SubElement(obj_elem, 'attributes').text = ', '.join(attrs) obj_id += 1 for _, group in groups.items(): leader_id, leader_parts_elem = group[0] leader_parts = [str(o_id) for o_id, _ in group[1:]] ET.SubElement(leader_parts_elem, 'hasparts').text = \ ','.join(leader_parts) ET.SubElement(leader_parts_elem, 'ispartof').text = '' for obj_id, parts_elem in group[1:]: ET.SubElement(parts_elem, 'hasparts').text = '' ET.SubElement(parts_elem, 'ispartof').text = str(leader_id) os.makedirs(osp.join(subset_dir, osp.dirname(image_filename)), exist_ok=True) xml_path = osp.join(subset_dir, osp.splitext(image_filename)[0] + '.xml') if osp.exists(xml_path): xml_path = osp.join(subset_dir, image_filename + '.xml') with open(xml_path, 'w', encoding='utf-8') as f: xml_data = ET.tostring(root_elem, encoding='unicode', pretty_print=True) f.write(xml_data)