Sfoglia il codice sorgente

added support for relative coordinates in the multi-box annotations

Dimitri Korsch 3 anni fa
parent
commit
72f67a3c63

+ 29 - 2
cvdatasets/dataset/mixins/bounding_box/bbox.py

@@ -40,7 +40,7 @@ class BoundingBox(T.NamedTuple):
 		return BoundingBox(x0, y0, size, size)
 
 	@classmethod
-	def new(cls, **kwargs) -> BoundingBox:
+	def new(cls, *, resize=None, **kwargs) -> BoundingBox:
 		# parameters that should be passed once
 		once = [
 			("x", "x0"),
@@ -62,8 +62,32 @@ class BoundingBox(T.NamedTuple):
 
 		if "y1" in kwargs:
 			h = kwargs["y1"] - y
+		coords = x, y, w, h
+
+		coords = cls.resize(*coords, resize=resize)
+		coords = map(int, coords)
+		return cls(*coords)
+
+	@classmethod
+	def resize(cls, *coords, resize=None):
+		if resize is None or not isinstance(resize, (tuple, int, float)):
+			return coords
+
+		# check if the coordinates are relative
+		_check = lambda value: 0 <= value < 1
+		if not all(map(_check, coords)):
+			return coords
+
+
+		if isinstance(resize, tuple):
+			W, H = resize
+		else: # int
+			W = H = resize
+
+		x, y, w, h = coords
+
+		return x*W, y*H, w*W, h*H
 
-		return cls(x, y, w, h)
 
 	def get(self, *attrs) -> T.Tuple:
 		return tuple(getattr(self, attr) for attr in attrs)
@@ -77,3 +101,6 @@ class BoundingBox(T.NamedTuple):
 if __name__ == '__main__':
 
 	print(BoundingBox.new(x0=1, x1=200, y0=10, y1=90))
+	print(BoundingBox.new(x0=.1, x1=.5, y0=0, y1=.3, resize=1000))
+	print(BoundingBox.new(x0=.25, x1=.5, y0=0, y1=.1, resize=(160, 90)))
+	print(BoundingBox.new(x0=.25, x1=.5, y0=0, y1=.1, resize=(1600, 900)))

+ 5 - 1
cvdatasets/dataset/mixins/bounding_box/multi_box.py

@@ -1,3 +1,4 @@
+from cvdatasets.dataset.image import ImageWrapper
 from cvdatasets.dataset.mixins.base import BaseMixin
 from cvdatasets.dataset.mixins.bounding_box.bbox import BoundingBox
 
@@ -12,9 +13,12 @@ class MultiBoxMixin(BaseMixin):
 		assert keys is None or all([key in self._all_keys for key in keys]), \
 			f"unknown keys found: {keys}. Possible are: {self._all_keys}"
 
-		boxes = [BoundingBox.new(**box)
+
+		im_obj: ImageWrapper = self.image_wrapped(i)
+		boxes = [BoundingBox.new(**box, resize=im_obj._im.size)
 			for box in self._get("multi_box", i)["objects"]
 		]
+		del im_obj
 
 		if keys is None:
 			return boxes

+ 15 - 8
cvdatasets/dataset/mixins/reading.py

@@ -1,11 +1,21 @@
+import abc
 import numpy as np
 
 from os.path import join
 
-from cvdatasets.dataset.mixins.base import BaseMixin
 from cvdatasets.dataset.image import ImageWrapper
+from cvdatasets.dataset.mixins.base import BaseMixin
+
+class BaseReadMixin(BaseMixin):
+
+	def get_example(self, i):
+		return self.image_wrapped(i)
+
+	@abc.abstractmethod
+	def image_wrapped(self, i) -> ImageWrapper:
+		pass
 
-class AnnotationsReadMixin(BaseMixin):
+class AnnotationsReadMixin(BaseReadMixin):
 
 	def __init__(self, *, uuids, annotations, part_rescale_size=None, center_cropped=True, mode="RGB"):
 		super(AnnotationsReadMixin, self).__init__()
@@ -21,10 +31,7 @@ class AnnotationsReadMixin(BaseMixin):
 	def _get(self, method, i):
 		return getattr(self._annot, method)(self.uuids[i])
 
-	def get_example(self, i):
-		# res = super(AnnotationsReadMixin, self).get_example(i)
-		# # if the super class returns something, then the class inheritance is wrong
-		# assert res is None, "AnnotationsReadMixin should be the last class in the hierarchy!"
+	def image_wrapped(self, i):
 
 		methods = ["image", "parts", "label"]
 		im_path, parts, label = [self._get(m, i) for m in methods]
@@ -44,7 +51,7 @@ class AnnotationsReadMixin(BaseMixin):
 		return np.array([self._get("label", i) for i in range(len(self))])
 
 
-class ImageListReadingMixin(BaseMixin):
+class ImageListReadingMixin(BaseReadMixin):
 
 	def __init__(self, *, pairs, root="."):
 		super(ImageListReadingMixin, self).__init__()
@@ -59,7 +66,7 @@ class ImageListReadingMixin(BaseMixin):
 	def __len__(self):
 		return len(self._pairs)
 
-	def get_example(self, i):
+	def image_wrapped(self, i):
 		im_file, label = self._pairs[i]
 		im_path = join(self._root, im_file)