Coretex
city_scape_converter.py
1 # Copyright (C) 2023 Coretex LLC
2 
3 # This file is part of Coretex.ai
4 
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
9 
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Affero General Public License for more details.
14 
15 # You should have received a copy of the GNU Affero General Public License
16 # along with this program. If not, see <https://www.gnu.org/licenses/>.
17 
18 from typing import Any, Optional, List, Set, Dict
19 from pathlib import Path
20 
21 import glob
22 import os
23 import json
24 import logging
25 
26 import numpy as np
27 
28 from ..base_converter import BaseConverter
29 from ...annotation import CoretexImageAnnotation, CoretexSegmentationInstance, BBox
30 
31 
32 class CityScapeConverter(BaseConverter):
33 
34  def __init__(self, datasetName: str, projectId: int, datasetPath: str) -> None:
35  super().__init__(datasetName, projectId, datasetPath)
36 
37  self.__baseImagePath = os.path.join(datasetPath, "leftImg8bit_trainvaltest", "leftImg8bit")
38  self.__baseAnnotationsPaths = [
39  os.path.join(datasetPath, "gtFine_trainvaltest", "gtFine", "train"),
40  os.path.join(datasetPath, "gtFine_trainvaltest", "gtFine", "val")
41  ]
42 
43  self.__imagePaths: List[str] = []
44  self.__imagePaths.extend(glob.glob(f"{self.__baseImagePath}/train/*/*.png"))
45  self.__imagePaths.extend(glob.glob(f"{self.__baseImagePath}/val/*/*.png"))
46 
47  def __annotationPathFor(self, imagePath: str) -> str:
48  # Extract last 2 components of imagePath
49  annotationName = os.path.sep.join(Path(imagePath).parts[-2:])
50 
51  # Replace image specific name with annotation name
52  annotationName = annotationName.replace("leftImg8bit.png", "gtFine_polygons.json")
53 
54  for annotationsPath in self.__baseAnnotationsPaths:
55  annotationPath = os.path.join(annotationsPath, annotationName)
56 
57  if os.path.exists(annotationPath):
58  return annotationPath
59 
60  raise RuntimeError
61 
62  def _dataSource(self) -> List[str]:
63  return self.__imagePaths
64 
65  def _extractLabels(self) -> Set[str]:
66  labels: Set[str] = set()
67 
68  for imagePath in self.__imagePaths:
69  annotationPath = self.__annotationPathFor(imagePath)
70 
71  with open(annotationPath, mode="r") as annotationFile:
72  annotationData: Dict[str, Any] = json.load(annotationFile)
73 
74  for obj in annotationData["objects"]:
75  labels.add(obj["label"])
76 
77  return labels
78 
79  def __extractInstance(self, obj: Dict[str, Any]) -> Optional[CoretexSegmentationInstance]:
80  label = obj["label"]
81 
82  coretexClass = self._dataset.classByName(label)
83  if coretexClass is None:
84  logging.getLogger("coretexpylib").info(f">> [Coretex] Class: ({label}) is not a part of dataset")
85  return None
86 
87  polygon = np.array(obj["polygon"]).flatten().tolist()
88 
89  return CoretexSegmentationInstance.create(
90  coretexClass.classIds[0],
91  BBox.fromPoly(polygon),
92  [polygon]
93  )
94 
95  def __extractImageAnnotation(self, imagePath: str, annotationData: Dict[str, Any]) -> None:
96  imageName = Path(imagePath).stem
97  width = annotationData["imgWidth"]
98  height = annotationData["imgHeight"]
99 
100  coretexAnnotation = CoretexImageAnnotation.create(imageName, width, height, [])
101 
102  for obj in annotationData["objects"]:
103  instance = self.__extractInstance(obj)
104  if instance is None:
105  continue
106 
107  coretexAnnotation.instances.append(instance)
108 
109  self._saveImageAnnotationPair(imagePath, coretexAnnotation)
110 
111  def _extractSingleAnnotation(self, imagePath: str) -> None:
112  annotationPath = self.__annotationPathFor(imagePath)
113 
114  with open(annotationPath, mode="r") as annotationFile:
115  annotationData: Dict[str, Any] = json.load(annotationFile)
116  self.__extractImageAnnotation(imagePath, annotationData)