diff --git a/page_xml/output_pageXML.py b/page_xml/output_pageXML.py index d5b48f9..27af3d0 100644 --- a/page_xml/output_pageXML.py +++ b/page_xml/output_pageXML.py @@ -15,12 +15,11 @@ from detectron2.config import CfgNode from tqdm import tqdm -from core.setup import get_git_hash - sys.path.append(str(Path(__file__).resolve().parent.joinpath(".."))) +from core.setup import get_git_hash from datasets.dataset import classes_to_colors +from page_xml.pageXML_creator import PageXMLCreator from page_xml.xml_regions import XMLRegions -from page_xml.xmlPAGE import PageData from utils.copy_utils import copy_mode from utils.image_utils import save_image_array_to_path from utils.input_utils import get_file_paths, supported_image_formats @@ -166,10 +165,10 @@ def generate_image_from_sem_seg(self, sem_seg: torch.Tensor, old_height: int, ol return image - def add_baselines_to_page(self, page: PageData, sem_seg: torch.Tensor, image_path: Path, old_height, old_width): + def add_baselines_to_page(self, page: PageXMLCreator, sem_seg: torch.Tensor, image_path: Path, old_height, old_width): pass - def add_regions_to_page(self, page: PageData, sem_seg: torch.Tensor, old_height, old_width) -> PageData: + def add_regions_to_page(self, page: PageXMLCreator, sem_seg: torch.Tensor, old_height, old_width) -> PageXMLCreator: if self.output_dir is None: raise TypeError("Output dir is None") if self.page_dir is None: @@ -226,11 +225,11 @@ def add_regions_to_page(self, page: PageData, sem_seg: torch.Tensor, old_height, region_coords = region_coords.strip() _uuid = uuid.uuid4() - text_reg = page.add_element(region_type, f"region_{_uuid}_{region_id}", region, region_coords) + text_reg = page.add_region(region_type, f"region_{_uuid}_{region_id}", region, region_coords) return page - def process_tensor(self, page: PageData, sem_seg: torch.Tensor, image_path: Path, old_height, old_width): + def process_tensor(self, page: PageXMLCreator, sem_seg: torch.Tensor, image_path: Path, old_height, old_width): if self.output_dir is None: raise TypeError("Output dir is None") if self.page_dir is None: @@ -280,7 +279,7 @@ def generate_single_page( scaling = np.asarray([old_width, old_height] / np.asarray([width, height])) - page = PageData(xml_output_path) + page = PageXMLCreator(xml_output_path) page.new_page(image_path.name, str(old_height), str(old_width)) if self.cfg is not None: @@ -330,7 +329,7 @@ def generate_single_page( region_coords = region_coords.strip() _uuid = uuid.uuid4() - text_reg = page.add_element(region_type, f"region_{_uuid}_{region_id}", region, region_coords) + text_reg = page.add_region(region_type, f"region_{_uuid}_{region_id}", region, region_coords) elif self.xml_regions.mode in ["baseline", "start", "end", "separator"]: # Push the calculation to outside of the python code <- mask is used by minion sem_seg_output_path = self.page_dir.joinpath(image_path.stem + ".png") diff --git a/page_xml/pageXML_creator.py b/page_xml/pageXML_creator.py new file mode 100644 index 0000000..5693016 --- /dev/null +++ b/page_xml/pageXML_creator.py @@ -0,0 +1,348 @@ +# Modified from P2PaLA + +import datetime +import logging +import os +import re +import sys +import xml.etree.ElementTree as ET +from pathlib import Path +from types import NoneType +from typing import Iterable, Optional, TypedDict + +import numpy as np +from detectron2.config import CfgNode + +sys.path.append(str(Path(__file__).resolve().parent.joinpath(".."))) +from utils.logging_utils import get_logger_name +from utils.tempdir import AtomicFileName + +_VALID_TYPES = {tuple, list, str, int, float, bool, NoneType} + + +def convert_to_dict(cfg_node, key_list: list = []): + """Convert a config node to dictionary""" + if not isinstance(cfg_node, CfgNode): + if type(cfg_node) not in _VALID_TYPES: + print( + "Key {} with value {} is not a valid type; valid types: {}".format( + ".".join(key_list), type(cfg_node), _VALID_TYPES + ), + ) + return cfg_node + else: + cfg_dict = dict(cfg_node) + for k, v in cfg_dict.items(): + cfg_dict[k] = convert_to_dict(v, key_list + [k]) + return cfg_dict + + +class Coords(ET.Element): + def __init__(self, points: np.ndarray, **kwargs): + super().__init__(**kwargs) + self.tag = "Coords" + self.points = points + + @property + def points(self) -> np.ndarray: + str_points = self.attrib["points"] + points = np.array([i.split(",") for i in str_points]).astype(np.int32) + return points + + @points.setter + def points(self, value: np.ndarray): + assert value.shape[1] == 2, f"Expected 2D array, got {value.shape}" + str_coords = "" + for coords in value: + str_coords += f" {round(coords[0])},{round(coords[1])}" + self.attrib["points"] = str_coords.strip() + + +class Baseline(Coords): + def __init__(self, points: np.ndarray, **kwargs): + super().__init__(points, **kwargs) + self.tag = "Baseline" + + +class _Polygon(ET.Element): + def __init__(self, points: np.ndarray, id: Optional[str] = None, custom: Optional[str] = None, **kwargs): + super().__init__(**kwargs) + self.tag = "_Polygon" + self.append(Coords(points)) + if id is not None: + self.attrib["id"] = id + if custom is not None: + self.attrib["custom"] = custom + + +class TextLine(_Polygon): + def __init__(self, points: np.ndarray, reading_order: Optional[int]=None, **kwargs): + super().__init__(points, **kwargs) + self.tag = "TextLine" + self.reading_order = reading_order + + self.logger = logging.getLogger(get_logger_name()) + + @property + def reading_order(self) -> Optional[int]: + try: + re_match = re.match(r".*readingOrder {index:(\d+);.*}", self.attrib["custom"]) + except KeyError: + self.logger.warning(f"No reading order defined for {self.attrib["id"]}") + return None + if re_match is None: + self.logger.warning(f"No reading order defined for {self.attrib["id"]}") + return None + reading_order_index = re_match.group(1) + + return int(reading_order_index) + + @reading_order.setter + def reading_order(self, value: Optional[int]): + if value is not None: + self.attrib["custom"] = f"readingOrder {{index:{value};}}" + + +class TextEquiv(ET.Element): + def __init__(self, value: str, **kwargs): + super().__init__(**kwargs) + self.tag = "TextEquiv" + unicode = ET.SubElement(self, "Unicode") + unicode.text = value + + +class Region(_Polygon): + def __init__(self, points: np.ndarray, region_type: str, **kwargs): + super().__init__(points, **kwargs) + self.tag = "Region" + self.attrib["custom"] = f"structure {{type:{region_type};}}" + + self.logger = logging.getLogger(get_logger_name()) + + @property + def region_type(self) -> Optional[str]: + try: + re_match = re.match(r".*structure {.*type:(.*);.*}", self.attrib["custom"]) + except KeyError: + self.logger.warning(f"No region type defined for {self.attrib["id"]}") + return None + if re_match is None: + self.logger.warning(f"No region type defined for {self.attrib["id"]}") + return None + e_type = re_match.group(1) + + return e_type + + @region_type.setter + def region_type(self, value: str): + if value is not None: + self.attrib["custom"] = f"structure {{type:{value};}}" + + +class PcGts(ET.Element): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.tag = "PcGts" + self.attrib = { + "xmlns": "http://schema.primaresearch.org/PAGE/gts/pagecontent/2013-07-15", + "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", + "xsi:schemaLocation": "http://schema.primaresearch.org/PAGE/gts/pagecontent/2013-07-15 http://schema.primaresearch.org/PAGE/gts/pagecontent/2013-07-15/pagecontent.xsd", + } + + +class Metadata(ET.Element): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.tag = "Metadata" + creator = ET.SubElement(self, "Creator") + creator.text = "Laypa" + created = ET.SubElement(self, "Created") + created.text = datetime.datetime.today().strftime("%Y-%m-%dT%X") + last_change = ET.SubElement(self, "LastChange") + last_change.text = datetime.datetime.today().strftime("%Y-%m-%dT%X") + +class Page(ET.Element): + def __init__(self, imageFilename: str, imageWidth: int, imageHeight: int, **kwargs): + super().__init__(**kwargs) + self.tag = "Page" + self.attrib = { + "imageFilename": imageFilename, + "imageWidth": str(imageWidth), + "imageHeight": str(imageHeight), + } + + +class PageXML(ET.ElementTree): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self._root = PcGts() + + def save_xml(self, filepath: Path): + """write out XML file of current PAGE data""" + self._indent(self._root) + tree = ET.ElementTree(self._root) + with AtomicFileName(filepath) as path: + tree.write(path, encoding="UTF-8", xml_declaration=True) + + def _indent(self, elem, level=0): + """ + Function borrowed from: + http://effbot.org/zone/element-lib.htm + """ + i = "\n" + level * " " + if len(elem): + if not elem.text or not elem.text.strip(): + elem.text = i + " " + if not elem.tail or not elem.tail.strip(): + elem.tail = i + for elem in elem: + self._indent(elem, level + 1) + if not elem.tail or not elem.tail.strip(): + elem.tail = i + else: + if level and (not elem.tail or not elem.tail.strip()): + elem.tail = i + + +class PageXMLCreator: + """Class to process PAGE xml files""" + + def __init__(self, filepath: Path, creator=None): + """ + Args: + filepath (string): Path to PAGE-xml file. + """ + self.logger = logging.getLogger(get_logger_name()) + self.filepath = filepath + self.name = self.filepath.stem + self.creator = "Laypa" if creator == None else creator + + # REVIEW should this be replaced with the newer pageXML standard? + self.XMLNS = { + "xmlns": "http://schema.primaresearch.org/PAGE/gts/pagecontent/2013-07-15", + "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", + "xsi:schemaLocation": " ".join( + [ + "http://schema.primaresearch.org/PAGE/gts/pagecontent/2013-07-15", + " http://schema.primaresearch.org/PAGE/gts/pagecontent/2013-07-15/pagecontent.xsd", + ] + ), + } + self.size = None + + def set_size(self, size: tuple[int, int]): + self.size = size + + def new_page(self, name, rows, cols): + """create a new PAGE xml""" + self.xml = ET.Element("PcGts") + self.xml.attrib = self.XMLNS + self.metadata = ET.SubElement(self.xml, "Metadata") + ET.SubElement(self.metadata, "Creator").text = self.creator + ET.SubElement(self.metadata, "Created").text = datetime.datetime.today().strftime("%Y-%m-%dT%X") + ET.SubElement(self.metadata, "LastChange").text = datetime.datetime.today().strftime("%Y-%m-%dT%X") + self.page = ET.SubElement(self.xml, "Page") + self.page.attrib = { + "imageFilename": name, + "imageWidth": cols, + "imageHeight": rows, + } + + def add_processing_step(self, git_hash: str, uuid: str, cfg: CfgNode, whitelist: Iterable[str]): + if git_hash is None: + raise TypeError(f"git_hash is None") + if uuid is None: + raise TypeError(f"uuid is None") + if cfg is None: + raise TypeError(f"cfg is None") + if whitelist is None: + raise TypeError(f"whitelist is None") + if self.metadata is None: + raise TypeError(f"self.metadata is None") + + processing_step = ET.SubElement(self.metadata, "MetadataItem") + processing_step.attrib = { + "type": "processingStep", + "name": "layout-analysis", + "value": "laypa", + } + labels = ET.SubElement(processing_step, "Labels") + git_hash_element = ET.SubElement(labels, "Label") + git_hash_element.attrib = { + "type": "githash", + "value": git_hash, + } + + uuid_element = ET.SubElement(labels, "Label") + uuid_element.attrib = { + "type": "uuid", + "value": uuid, + } + + for key in whitelist: + sub_node = cfg + for sub_key in key.split("."): + try: + sub_node = sub_node[sub_key] + except KeyError as error: + self.logger.error(f"No key {key} in config, missing sub key {sub_key}") + raise error + whilelisted_element = ET.SubElement(labels, "Label") + whilelisted_element.attrib = { + "type": key, + "value": str(convert_to_dict(sub_node)), + } + + def add_region(self, region_class, region_id, region_type, region_coords, parent=None): + """add element to parent node""" + parent = self.page if parent == None else parent + t_reg = ET.SubElement(parent, region_class) + t_reg.attrib = { + "id": str(region_id), + "custom": f"structure {{type:{region_type};}}", + } + ET.SubElement(t_reg, "Coords").attrib = {"points": region_coords} + return t_reg + + def remove_element(self, element, parent=None): + """remove element from parent node""" + parent = self.page if parent == None else parent + parent.remove(element) + + def add_textline(self, t_coords, t_id, reading_order, parent): + """add textline element to parent region node""" + ET.SubElement(parent, "TextLine").attrib = { + "id": t_id, + "custom": f"readingOrder {{index:{reading_order};}}", + } + ET.SubElement(parent, "Coords").attrib = {"points": t_coords} + + def add_baseline(self, b_coords, parent): + """add baseline element ot parent line node""" + ET.SubElement(parent, "Baseline").attrib = {"points": b_coords} + + def _indent(self, elem, level=0): + """ + Function borrowed from: + http://effbot.org/zone/element-lib.htm#prettyprint + """ + i = "\n" + level * " " + if len(elem): + if not elem.text or not elem.text.strip(): + elem.text = i + " " + if not elem.tail or not elem.tail.strip(): + elem.tail = i + for elem in elem: + self._indent(elem, level + 1) + if not elem.tail or not elem.tail.strip(): + elem.tail = i + else: + if level and (not elem.tail or not elem.tail.strip()): + elem.tail = i + + def save_xml(self): + """write out XML file of current PAGE data""" + self._indent(self.xml) + tree = ET.ElementTree(self.xml) + with AtomicFileName(self.filepath) as path: + tree.write(path, encoding="UTF-8", xml_declaration=True) diff --git a/page_xml/xmlPAGE.py b/page_xml/pageXML_parser.py similarity index 53% rename from page_xml/xmlPAGE.py rename to page_xml/pageXML_parser.py index 179d560..4c6e9aa 100644 --- a/page_xml/xmlPAGE.py +++ b/page_xml/pageXML_parser.py @@ -8,7 +8,7 @@ import xml.etree.ElementTree as ET from pathlib import Path from types import NoneType -from typing import Iterable, TypedDict +from typing import Iterable, Optional, TypedDict import numpy as np from detectron2.config import CfgNode @@ -17,27 +17,8 @@ from utils.logging_utils import get_logger_name from utils.tempdir import AtomicFileName -_VALID_TYPES = {tuple, list, str, int, float, bool, NoneType} - -def convert_to_dict(cfg_node, key_list: list = []): - """Convert a config node to dictionary""" - if not isinstance(cfg_node, CfgNode): - if type(cfg_node) not in _VALID_TYPES: - print( - "Key {} with value {} is not a valid type; valid types: {}".format( - ".".join(key_list), type(cfg_node), _VALID_TYPES - ), - ) - return cfg_node - else: - cfg_dict = dict(cfg_node) - for k, v in cfg_dict.items(): - cfg_dict[k] = convert_to_dict(v, key_list + [k]) - return cfg_dict - - -class PageData: +class PageXMLParser: """Class to process PAGE xml files""" def __init__(self, filepath: Path, creator=None): @@ -206,130 +187,3 @@ def get_text(self, element): return "" else: return text_data.encode("utf-8").strip() - - def get_transcription(self): - """Extracts text from each line on the XML file""" - data = {} - for element in self.root.findall("".join([".//", self.base, "TextRegion"])): - r_id = self.get_id(element) - for line in element.findall("".join([".//", self.base, "TextLine"])): - l_id = self.get_id(line) - data["_".join([r_id, l_id])] = self.get_text(line) - - return data - - def write_transcriptions(self, out_dir): - """write out one txt file per text line""" - # for line, text in self.get_transcription().iteritems(): - for line, text in list(self.get_transcription().items()): - fh = open(os.path.join(out_dir, "".join([self.name, "_", line, ".txt"])), "w") - fh.write(text + "\n") - fh.close() - - ## NEW PAGEXML - - def new_page(self, name, rows, cols): - """create a new PAGE xml""" - self.xml = ET.Element("PcGts") - self.xml.attrib = self.XMLNS - self.metadata = ET.SubElement(self.xml, "Metadata") - ET.SubElement(self.metadata, "Creator").text = self.creator - ET.SubElement(self.metadata, "Created").text = datetime.datetime.today().strftime("%Y-%m-%dT%X") - ET.SubElement(self.metadata, "LastChange").text = datetime.datetime.today().strftime("%Y-%m-%dT%X") - self.page = ET.SubElement(self.xml, "Page") - self.page.attrib = { - "imageFilename": name, - "imageWidth": cols, - "imageHeight": rows, - } - - def add_processing_step(self, git_hash: str, uuid: str, cfg: CfgNode, whitelist: Iterable[str]): - if git_hash is None: - raise TypeError(f"git_hash is None") - if uuid is None: - raise TypeError(f"uuid is None") - if cfg is None: - raise TypeError(f"cfg is None") - if whitelist is None: - raise TypeError(f"whitelist is None") - if self.metadata is None: - raise TypeError(f"self.metadata is None") - - processing_step = ET.SubElement(self.metadata, "MetadataItem") - processing_step.attrib = { - "type": "processingStep", - "name": "layout-analysis", - "value": "laypa", - } - labels = ET.SubElement(processing_step, "Labels") - git_hash_element = ET.SubElement(labels, "Label") - git_hash_element.attrib = { - "type": "githash", - "value": git_hash, - } - - uuid_element = ET.SubElement(labels, "Label") - uuid_element.attrib = { - "type": "uuid", - "value": uuid, - } - - for key in whitelist: - sub_node = cfg - for sub_key in key.split("."): - try: - sub_node = sub_node[sub_key] - except KeyError as error: - self.logger.error(f"No key {key} in config, missing sub key {sub_key}") - raise error - whilelisted_element = ET.SubElement(labels, "Label") - whilelisted_element.attrib = { - "type": key, - "value": str(convert_to_dict(sub_node)), - } - - def add_element(self, region_class, region_id, region_type, region_coords, parent=None): - """add element to parent node""" - parent = self.page if parent == None else parent - t_reg = ET.SubElement(parent, region_class) - t_reg.attrib = { - "id": str(region_id), - "custom": f"structure {{type:{region_type};}}", - } - ET.SubElement(t_reg, "Coords").attrib = {"points": region_coords} - return t_reg - - def remove_element(self, element, parent=None): - """remove element from parent node""" - parent = self.page if parent == None else parent - parent.remove(element) - - def add_baseline(self, b_coords, parent): - """add baseline element ot parent line node""" - ET.SubElement(parent, "Baseline").attrib = {"points": b_coords} - - def save_xml(self): - """write out XML file of current PAGE data""" - self._indent(self.xml) - tree = ET.ElementTree(self.xml) - with AtomicFileName(self.filepath) as path: - tree.write(path, encoding="UTF-8", xml_declaration=True) - - def _indent(self, elem, level=0): - """ - Function borrowed from: - http://effbot.org/zone/element-lib.htm#prettyprint - """ - i = "\n" + level * " " - if len(elem): - if not elem.text or not elem.text.strip(): - elem.text = i + " " - if not elem.tail or not elem.tail.strip(): - elem.tail = i - for elem in elem: - self._indent(elem, level + 1) - if not elem.tail or not elem.tail.strip(): - elem.tail = i - else: - if level and (not elem.tail or not elem.tail.strip()): - elem.tail = i diff --git a/page_xml/xml_converter.py b/page_xml/xml_converter.py index c40656a..14eb074 100644 --- a/page_xml/xml_converter.py +++ b/page_xml/xml_converter.py @@ -9,8 +9,8 @@ from detectron2 import structures sys.path.append(str(Path(__file__).resolve().parent.joinpath(".."))) +from page_xml.pageXML_parser import PageXMLParser from page_xml.xml_regions import XMLRegions -from page_xml.xmlPAGE import PageData from utils.logging_utils import get_logger_name from utils.vector_utils import ( point_at_start_or_end_assignment, @@ -146,7 +146,7 @@ def draw_line( ## REGIONS - def build_region_instances(self, page: PageData, out_size: tuple[int, int], elements, class_dict) -> list[Instance]: + def build_region_instances(self, page: PageXMLParser, out_size: tuple[int, int], elements, class_dict) -> list[Instance]: size = page.get_size() instances = [] for element in elements: @@ -168,7 +168,7 @@ def build_region_instances(self, page: PageData, out_size: tuple[int, int], elem self.logger.warning(f"File {page.filepath} does not contains region instances") return instances - def build_region_pano(self, page: PageData, out_size: tuple[int, int], elements, class_dict): + def build_region_pano(self, page: PageXMLParser, out_size: tuple[int, int], elements, class_dict): """ Create the pano version of the regions """ @@ -195,7 +195,7 @@ def build_region_pano(self, page: PageData, out_size: tuple[int, int], elements, self.logger.warning(f"File {page.filepath} does not contains region pano") return pano_mask, segments_info - def build_region_sem_seg(self, page: PageData, out_size: tuple[int, int], elements, class_dict): + def build_region_sem_seg(self, page: PageXMLParser, out_size: tuple[int, int], elements, class_dict): """ Builds a "image" mask of desired elements """ @@ -212,7 +212,7 @@ def build_region_sem_seg(self, page: PageData, out_size: tuple[int, int], elemen ## TEXT LINE - def build_text_line_instances(self, page: PageData, out_size: tuple[int, int]) -> list[Instance]: + def build_text_line_instances(self, page: PageXMLParser, out_size: tuple[int, int]) -> list[Instance]: """ Create the instance version of the text line """ @@ -238,7 +238,7 @@ def build_text_line_instances(self, page: PageData, out_size: tuple[int, int]) - self.logger.warning(f"File {page.filepath} does not contains text line instances") return instances - def build_text_line_pano(self, page: PageData, out_size: tuple[int, int]): + def build_text_line_pano(self, page: PageXMLParser, out_size: tuple[int, int]): """ Create the pano version of the text line """ @@ -265,7 +265,7 @@ def build_text_line_pano(self, page: PageData, out_size: tuple[int, int]): self.logger.warning(f"File {page.filepath} does not contains text line pano") return pano_mask, segments_info - def build_text_line_sem_seg(self, page: PageData, out_size: tuple[int, int]): + def build_text_line_sem_seg(self, page: PageXMLParser, out_size: tuple[int, int]): """ Builds a "image" mask of the text line """ @@ -282,7 +282,7 @@ def build_text_line_sem_seg(self, page: PageData, out_size: tuple[int, int]): ## BASELINE - def build_baseline_instances(self, page: PageData, out_size: tuple[int, int], line_width: int): + def build_baseline_instances(self, page: PageXMLParser, out_size: tuple[int, int], line_width: int): """ Create the instance version of the baselines """ @@ -321,7 +321,7 @@ def build_baseline_instances(self, page: PageData, out_size: tuple[int, int], li self.logger.warning(f"File {page.filepath} does not contains baseline instances") return instances - def build_baseline_pano(self, page: PageData, out_size: tuple[int, int], line_width: int): + def build_baseline_pano(self, page: PageXMLParser, out_size: tuple[int, int], line_width: int): """ Create the pano version of the baselines """ @@ -334,7 +334,7 @@ def build_baseline_pano(self, page: PageData, out_size: tuple[int, int], line_wi for baseline_coords in page.iter_baseline_coords(): coords = self._scale_coords(baseline_coords, out_size, size) rgb_color = self.id2rgb(_id) - pano_mask, overlap = self.draw_line(pano_mask, coords, rgb_color, thickness=line_width) + pano_mask, overlap = self.draw_line(pano_mask, coords, rgb_color, thickness=line_width) # type: ignore total_overlap = total_overlap or overlap segment: SegmentsInfo = { "id": _id, @@ -350,7 +350,7 @@ def build_baseline_pano(self, page: PageData, out_size: tuple[int, int], line_wi self.logger.warning(f"File {page.filepath} does not contains baseline pano") return pano_mask, segments_info - def build_baseline_sem_seg(self, page: PageData, out_size: tuple[int, int], line_width: int): + def build_baseline_sem_seg(self, page: PageXMLParser, out_size: tuple[int, int], line_width: int): """ Create the sem_seg version of the baselines """ @@ -371,7 +371,7 @@ def build_baseline_sem_seg(self, page: PageData, out_size: tuple[int, int], line # TOP BOTTOM - def build_top_bottom_sem_seg(self, page: PageData, out_size: tuple[int, int], line_width: int): + def build_top_bottom_sem_seg(self, page: PageXMLParser, out_size: tuple[int, int], line_width: int): """ Create the sem_seg version of the top bottom """ @@ -402,7 +402,7 @@ def build_top_bottom_sem_seg(self, page: PageData, out_size: tuple[int, int], li ## START - def build_start_sem_seg(self, page: PageData, out_size: tuple[int, int], line_width: int): + def build_start_sem_seg(self, page: PageXMLParser, out_size: tuple[int, int], line_width: int): """ Create the sem_seg version of the start """ @@ -419,7 +419,7 @@ def build_start_sem_seg(self, page: PageData, out_size: tuple[int, int], line_wi ## END - def build_end_sem_seg(self, page: PageData, out_size: tuple[int, int], line_width: int): + def build_end_sem_seg(self, page: PageXMLParser, out_size: tuple[int, int], line_width: int): """ Create the sem_seg version of the end """ @@ -436,7 +436,7 @@ def build_end_sem_seg(self, page: PageData, out_size: tuple[int, int], line_widt ## SEPARATOR - def build_separator_sem_seg(self, page: PageData, out_size: tuple[int, int], line_width: int): + def build_separator_sem_seg(self, page: PageXMLParser, out_size: tuple[int, int], line_width: int): """ Create the sem_seg version of the separator """ @@ -456,7 +456,7 @@ def build_separator_sem_seg(self, page: PageData, out_size: tuple[int, int], lin ## BASELINE + SEPARATOR - def build_baseline_separator_sem_seg(self, page: PageData, out_size: tuple[int, int], line_width: int): + def build_baseline_separator_sem_seg(self, page: PageXMLParser, out_size: tuple[int, int], line_width: int): """ Create the sem_seg version of the baseline separator """ @@ -503,7 +503,7 @@ def to_sem_seg( Returns: Optional[np.ndarray]: mask of labels """ - gt_data = PageData(xml_path) + gt_data = PageXMLParser(xml_path) gt_data.parse() if original_image_shape is not None: @@ -591,7 +591,7 @@ def to_instances( Returns: Optional[dict]: scaled coordinates about the location of the objects in the image """ - gt_data = PageData(xml_path) + gt_data = PageXMLParser(xml_path) gt_data.parse() if original_image_shape is not None: @@ -644,7 +644,7 @@ def to_pano( Returns: Optional[tuple[np.ndarray, list]]: pano mask and the segments information """ - gt_data = PageData(xml_path) + gt_data = PageXMLParser(xml_path) gt_data.parse() if original_image_shape is not None: diff --git a/utils/regions_from_dataset.py b/utils/regions_from_dataset.py index 7e2c208..7f83532 100644 --- a/utils/regions_from_dataset.py +++ b/utils/regions_from_dataset.py @@ -10,7 +10,7 @@ from tqdm import tqdm sys.path.append(str(Path(__file__).resolve().parent.joinpath(".."))) -from page_xml.xmlPAGE import PageData +from page_xml.pageXML_parser import PageXMLParser from utils.input_utils import get_file_paths, supported_image_formats from utils.path_utils import image_path_to_xml_path from xml_comparison import pretty_print @@ -35,7 +35,7 @@ def count_regions_single_page(xml_path: Path) -> Counter: Returns: Counter: Count of all unique regions """ - page_data = PageData(xml_path) + page_data = PageXMLParser(xml_path) page_data.parse() region_names = ["TextRegion"] # Assuming this is all there is