Coretex
classes_format.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 __future__ import annotations
19 
20 from typing import Optional, List, Dict, Set
21 from uuid import UUID
22 
23 import uuid
24 import random
25 
26 from ....codable import Codable, KeyDescriptor
27 
28 
30 
31  """
32  Image Dataset class metadata
33 
34  Properties
35  ----------
36  classIds : List[UUID]
37  list of all uuids connected to this class
38  label : str
39  name of the class
40  color : str
41  color of the class
42  """
43 
44  classIds: List[UUID]
45  label: str
46  color: str
47 
48  def __init__(self, label: Optional[str] = None, color: Optional[str] = None):
49  if label is None:
50  label = ""
51 
52  if color is None:
53  color = ""
54 
55  self.classIdsclassIds = [uuid.uuid4()]
56  self.labellabel = label
57  self.colorcolor = color
58 
59  @classmethod
60  def _keyDescriptors(cls) -> Dict[str, KeyDescriptor]:
61  descriptors = super()._keyDescriptors()
62 
63  descriptors["classIds"] = KeyDescriptor("ids", UUID, list)
64  descriptors["label"] = KeyDescriptor("name")
65 
66  return descriptors
67 
68  @classmethod
69  def generate(cls, labels: Set[str]) -> ImageDatasetClasses:
70  """
71  Generates list of Coretex classes based on provided
72  labels (class names)
73 
74  Parameters
75  ----------
76  labels : Set[str]
77  list of labels (class names)
78 
79  Returns
80  -------
81  ImageDatasetClasses -> list of ImageDatasetClass (Coretex class metadata) objects
82 
83  Example
84  -------
85  >>> from coretex import ImageDatasetClass
86  \b
87  >>> labels = {"car", "bicycle"}
88  >>> imgDatasetClasses = ImageDatasetClass.generate(labels)
89  >>> print(classes)
90  [
91  ImageDatasetClass(
92  classIds = [UUID("81add001-1c9c-4949-8b73-3599f1d0de9d")],
93  name = "car",
94  color = "#bcb86b"
95  ),
96  ImageDatasetClass(
97  classIds = [UUID("d710019b-f28f-40ab-aa65-e13df949beff")],
98  name = "bicycle",
99  color = "#cbc66b"
100  )
101  ]
102  """
103 
104  colors: Set[str] = set()
105 
106  while len(colors) != len(labels):
107  color = f'#{"%06x" % random.randint(0, 0xFFFFFF)}'
108  colors.add(color)
109 
110  return ImageDatasetClasses(
111  [cls(label, color) for label, color in zip(labels, colors)]
112  )
113 
114 
115 class ImageDatasetClasses(List[ImageDatasetClass]):
116 
117  """
118  List of Image Dataset class metadata
119 
120  Properties
121  ----------
122  labels : List[str]
123  list of the classes names
124  """
125 
126  @property
127  def labels(self) -> List[str]:
128  labels = [element.label for element in self]
129  labels.sort()
130 
131  return labels
132 
133  def classById(self, classId: UUID) -> Optional[ImageDatasetClass]:
134  """
135  Retrieves a Image dataset class based on provided ID
136 
137  Parameters
138  ----------
139  classID : UUID
140  id of class
141 
142  Returns
143  -------
144  Optional[ImageDatasetClasses] -> fetched class if provided ID
145  is found in list of class IDs, None otherwise
146 
147  Examples
148  --------
149  >>> from coretex import ImageDataset
150  \b
151  >>> dataset = ImageDataset.fetchById(1023)
152  >>> classObj = dataset.classes.classById(UUID("d710019b-f28f-40ab-aa65-e13df949beff"))
153  \b
154  >>> if classObj is not None:
155  print(classObj.classIds)
156  print(classObj.label)
157  print(classObj.color)
158  UUID("d710019b-f28f-40ab-aa65-e13df949beff")
159  "bicycle"
160  "#d06df5"
161  """
162 
163  for element in self:
164  for other in element.classIds:
165  if str(classId) == str(other):
166  return element
167 
168  return None
169 
170  def classByLabel(self, label: str) -> Optional[ImageDatasetClass]:
171  """
172  Retrieves a Image dataset class based on provided label
173 
174  Parameters
175  ----------
176  label : str
177  name of class
178 
179  Returns
180  -------
181  Optional[ImageDatasetClasses] -> fetched class if provided label
182  is found in list of class labels, None otherwise
183  """
184 
185  for element in self:
186  if element.label == label:
187  return element
188 
189  return None
190 
191  def labelIdForClassId(self, classId: UUID) -> Optional[int]:
192  """
193  Retrieves a label ID based on provided class ID
194 
195  Parameters
196  ----------
197  classId : UUID
198  id of class
199 
200  Returns
201  -------
202  Optional[int] -> label ID if provided class ID
203  is found in list of class IDs, None otherwise
204 
205  Example
206  -------
207  >>> from coretex import ImageDataset
208  \b
209  >>> dataset = ImageDataset.fetchById(1023)
210  >>> labelId = dataset.classes.labelIdForClassId(UUID("d710019b-f28f-40ab-aa65-e13df949beff"))
211  >>> print(labelId)
212  1
213 
214  """
215 
216  clazz = self.classByIdclassById(classId)
217  if clazz is None:
218  return None
219 
220  try:
221  return self.labelslabels.index(clazz.label)
222  except ValueError:
223  return None
224 
225  def labelIdForClass(self, clazz: ImageDatasetClass) -> Optional[int]:
226  """
227  Retrieves a label ID based on provided ImageDatasetClass object
228 
229  Parameters
230  ----------
231  clazz : ImageDatasetClass
232  Image Dataset class metadata object
233 
234  Returns
235  -------
236  Optional[int] -> label ID if provided class exists
237  in a list of ImageDataset classes otherwise None
238 
239  Example
240  -------
241  >>> from coretex import ImageDatasetClass
242  \b
243  >>> dataset = ImageDataset.fetchById(1023)
244  >>> labelId = dataset.classes.labelIdForClass(dataset.classes[0])
245  >>> print(labelId)
246  0
247  """
248 
249  return self.labelIdForClassIdlabelIdForClassId(clazz.classIds[0])
250 
251  def exclude(self, excludedClasses: List[str]) -> None:
252  """
253  Excludes classes that are provided in excludedClasses list
254 
255  Parameters
256  ----------
257  excludedClasses : List[str]
258  list of classes that will be excluded
259  """
260 
261  classes = [
262  element for element in self
263  if element.label not in excludedClasses
264  ]
265 
266  self.clear()
267  self.extend(classes)
Optional[int] labelIdForClass(self, ImageDatasetClass clazz)
Optional[ImageDatasetClass] classByLabel(self, str label)
Optional[ImageDatasetClass] classById(self, UUID classId)