Source code for pytwovision.utils.annotations_parser

from __future__ import annotations
from abc import ABC, abstractmethod

import glob
import os
import xml.etree.ElementTree as ET


[docs]class Parser(ABC): """ The Parser interface declares an `parse` method that should take the base AnnotationsFormat interface as an argument. """ @abstractmethod def parse(self, anno: AnnotationsFormat): pass
[docs]class XmlParser(Parser): """ Each Concrete Parser must implement the `parse` method in such a way that it calls the annotationsFormat's method corresponding to the Parser's class. """
[docs] def parse(self, anno: AnnotationsFormat, xml_path, annotations_output_name, classes_output_name, image_path, work_dir=None, print_output=False): """ This method convert annotations from COCO or PASCAL VOC dataset in xml format to be compatible with an especific network model. Exporting a text file for annotations and a text file for classes names Args: xml_path: a string with the full path of xml annotations. annotations_output_name: a string with the name of annotations file that will be generated. classes_output_name: a string with the name of classes file that will be generated. image_path: a full path where the images are saved. work_dir: a path where the annotations and classes files will be saved, if is None these will be saved in current directory. print_output: a boolean to print in console each annotation line """ anno.visit_xml_parser(self, xml_path, annotations_output_name, classes_output_name, image_path, work_dir, print_output)
[docs]class AnnotationsFormat(ABC): """ The AnnotationsFormat Interface declares a set of visiting methods that correspond to Parser classes. The signature of a visiting method allows the visitor to identify the exact class of the Parser that it's dealing with. """ @abstractmethod def visit_xml_parser(self, element: XmlParser, xml_path, annotations_output_name, classes_output_name, image_path, work_dir=None, print_output=False): pass
[docs]class YoloV3AnnotationsFormat(AnnotationsFormat): """Get a group of xml annotations to transform in a .txt file compatible with YoloV3 dataset""" def visit_xml_parser(self, element ,xml_path, annotations_output_name, classes_output_name, image_path, work_dir=None, print_output=False): xmls = glob.glob(xml_path+'/*.xml') xmls = sorted(xmls) if len(xmls) == 0: raise FileNotFoundError("There isn't annotations in {}".format(xml_path)) if work_dir is None: anno_file = os.getcwd() anno_file = os.path.join(anno_file, annotations_output_name) classes_file = os.getcwd() classes_file = os.path.join(classes_file, classes_output_name) else: anno_file = os.path.join(work_dir, annotations_output_name) classes_file = os.path.join(work_dir, classes_output_name) classes_names = [] with open('{}.txt'.format(anno_file), 'w') as file: for xml_file in xmls: tree = ET.parse(open(xml_file)) root = tree.getroot() image_name = root.find('filename').text img_path = image_path + '/' + image_name for i, obj in enumerate(root.iter('object')): cls = obj.find('name').text if cls not in classes_names: classes_names.append(cls) cls_id = classes_names.index(cls) xmlbox = obj.find('bndbox') object_params = (str(int(float(xmlbox.find('xmin').text)))+',' +str(int(float(xmlbox.find('ymin').text)))+',' +str(int(float(xmlbox.find('xmax').text)))+',' +str(int(float(xmlbox.find('ymax').text)))+',' +str(cls_id)) img_path += ' '+object_params if print_output: print(img_path) file.write(img_path+'\n') with open('{}.txt'.format(classes_file), 'w') as file: for name in classes_names: file.write(str(name)+'\n')