Selaa lähdekoodia

added some more tests and refactored tests structure a bit

Dimitri Korsch 5 vuotta sitten
vanhempi
commit
c7ca2591d7

+ 1 - 1
Makefile

@@ -15,4 +15,4 @@ get_version:
 	@python setup.py --version
 
 run_tests:
-	@cd scripts && bash tests.sh
+	bash scripts/tests.sh

+ 2 - 1
cvdatasets/dataset/part/annotation.py

@@ -9,13 +9,14 @@ from .base import BasePart
 class LocationPart(BasePart):
 	DEFAULT_RATIO = np.sqrt(49 / 400) # 0.35
 
-	def __init__(self, image, annotation, rescale_size=None):
+	def __init__(self, image, annotation, rescale_size=None, surrogate_type=None):
 		super(LocationPart, self).__init__()
 
 		annotation = self.rescale(image, annotation, rescale_size)
 		# here x,y are the center of the part
 		self._id, self.x, self.y, self.is_visible = annotation
 		self._ratio = LocationPart.DEFAULT_RATIO
+		self._surrogate_type = surrogate_type
 
 	@property
 	def as_annotation(self):

+ 11 - 10
cvdatasets/dataset/part/base.py

@@ -1,4 +1,5 @@
 import numpy as np
+import warnings
 
 from abc import ABC
 from abc import abstractproperty
@@ -75,15 +76,16 @@ class BasePartCollection(ABC):
 
 
 class BasePart(ABC):
+	_surrogate_type = None
 
 	def __repr__(self):
 		return repr(self.as_annotation)
 
 	@staticmethod
-	def new(image, annotation, rescale_size=-1, center_cropped=True):
+	def new(image, annotation, rescale_size=-1, center_cropped=True, surrogate_type=None):
 		from .annotation import BBoxPart, LocationPart
 		if len(annotation) == 4:
-			return LocationPart(image, annotation, rescale_size)
+			return LocationPart(image, annotation, rescale_size, surrogate_type=surrogate_type)
 		elif len(annotation) == 5:
 			return BBoxPart(image, annotation, rescale_size, center_cropped)
 		else:
@@ -110,14 +112,13 @@ class BasePart(ABC):
 
 	def crop(self, im, w, h, padding_mode="edge", is_location=True):
 		if not self.is_visible:
-			_part_surrogate = resize(utils.asarray(im), (h, w),
-				mode="constant",
-				anti_aliasing=True,
-				preserve_range=True)
-			return _part_surrogate.astype(np.uint8)
-			# old code using black images as surrogates
-			_, _, c = utils.dimensions(im)
-			return np.zeros((h, w, c), dtype=np.uint8)
+			surrogate = self._surrogate_type
+			if surrogate is not None and callable(surrogate):
+				return surrogate(im, w, h, im.dtype)
+			else:
+				warnings.warn("Part surrogate was not set, but is needed! Returning blank patch as fallback.")
+				_, _, c = utils.dimensions(im)
+				return np.zeros((h, w, c), dtype=np.uint8)
 
 		x, y = self.xy
 		pad_h, pad_w = h // 2, w // 2

+ 43 - 0
cvdatasets/dataset/part/surrogate.py

@@ -0,0 +1,43 @@
+import enum
+import numpy as np
+
+from cvdatasets import utils
+from skimage.transform import resize
+
+class SurrogateType(enum.Enum):
+
+	BLANK = enum.auto()
+	MIDDLE = enum.auto()
+	IMAGE = enum.auto()
+
+	def __call__(self, im, w, h, dtype=np.uint8):
+		if self is SurrogateType.BLANK:
+			return self._blank(im, w, h, dtype=dtype)
+		elif self is SurrogateType.IMAGE:
+			return self._image(im, w, h, dtype=dtype)
+		elif self is SurrogateType.MIDDLE:
+			return self._middle(im, w, h, dtype=dtype)
+		else:
+			raise ValueError("Unknown surrogate method: {}".format(self))
+
+	def _blank(self, im, w, h, dtype):
+		_, _, c = utils.dimensions(im)
+		return np.zeros((h, w, c), dtype=dtype)
+
+	def _image(self, im, w, h, dtype):
+		_part_surrogate = resize(utils.asarray(im), (h, w),
+			mode="constant",
+			anti_aliasing=True,
+			preserve_range=True)
+		return _part_surrogate.astype(dtype)
+
+	def _middle(self, im, w, h, dtype):
+		im_h, im_w, c = utils.dimensions(im)
+
+		middle_x, middle_y = im_w // 2, im_h // 2
+
+		x0 = middle_x - w // 2
+		y0 = middle_y - h // 2
+
+		return im[y0: y0+h, x0: x0+w]
+

+ 4 - 3
scripts/tests.sh

@@ -1,6 +1,7 @@
 #!/usr/bin/env bash
-source config.sh
+_root=$(dirname $(dirname $(realpath $0)))
+source ${_root}/scripts/config.sh
 
-export BASE_DIR="."
+export BASE_DIR="${_root}/tests"
 
-$PYTHON -m unittest discover -s ${1:-".."}
+$PYTHON ${BASE_DIR}/main.py

+ 2 - 1
tests/__init__.py

@@ -1,7 +1,8 @@
 from .test_annotations import *
-from .test_parts import *
+from .part_tests import *
 
 __all__ = [
 	"AnnotationTest",
 	"PartCropTest",
+	"SurrogateTest",
 ]

+ 2 - 0
tests/configs.py

@@ -7,3 +7,5 @@ class config(abc.ABC):
 	BASE_DIR = Path(os.environ.get("BASE_DIR", Path(__file__).parent))
 
 	INFO_FILE = str(BASE_DIR / "test_info.yml")
+
+print(config.BASE_DIR)

+ 2 - 0
tests/part_tests/__init__.py

@@ -0,0 +1,2 @@
+from .crop_tests import PartCropTest
+from .surrogate_tests import SurrogateTest

+ 97 - 0
tests/part_tests/crop_tests.py

@@ -0,0 +1,97 @@
+import unittest
+import numpy as np
+
+from skimage.transform import resize
+
+from cvdatasets.dataset.part.surrogate import SurrogateType
+from cvdatasets.dataset.part.base import BasePart
+
+class PartCropTest(unittest.TestCase):
+
+
+	def setUp(self):
+		self.im = np.random.randn(300, 300, 3).astype(np.uint8)
+
+	def _check_crop(self, cropped_im, _should):
+
+		self.assertIsNotNone(cropped_im,
+			"method crop should return something!")
+
+		self.assertIsInstance(cropped_im, type(self.im),
+			"result should have the same type as the input image")
+
+		crop_h, crop_w, _ = cropped_im.shape
+		h, w, _ = _should.shape
+		self.assertEqual(crop_h, h, "incorrect crop height")
+		self.assertEqual(crop_w, w, "incorrect crop width")
+
+		self.assertTrue((cropped_im == _should).all(),
+			"crop was incorret")
+
+
+	def test_bbox_part_crop(self):
+		_id, x, y, w, h = annotation = (0, 20, 20, 100, 100)
+
+		part = BasePart.new(self.im, annotation)
+
+		cropped_im = part.crop(self.im)
+
+		_should = self.im[y:y+h, x:x+w]
+		self._check_crop(cropped_im, _should)
+
+	def test_location_part_crop(self):
+		_id, center_x, center_y, _vis = annotation = (0, 50, 50, 1)
+
+		part = BasePart.new(self.im, annotation)
+
+		h, w, c = self.im.shape
+		for ratio in np.linspace(0.1, 0.3, num=9):
+			_h, _w = int(h * ratio), int(w * ratio)
+
+			cropped_im = part.crop(self.im, ratio=ratio)
+
+			x, y = center_x - _h // 2, center_y - _w // 2
+			_should = self.im[y : y + _h, x : x + _w]
+
+			self._check_crop(cropped_im, _should)
+
+	def test_non_visible_location_crop(self):
+		_id, center_x, center_y, _vis = annotation = (0, 50, 50, 0)
+
+		def _blank(im, w, h):
+			return np.zeros((h, w, 3), dtype=im.dtype)
+
+		def _middle(im, w, h):
+			im_h, im_w, c = im.shape
+			middle_x, middle_y = im_w // 2, im_h // 2
+
+			x0 = middle_x - w // 2
+			y0 = middle_y - h // 2
+
+			return im[y0: y0+h, x0: x0+w]
+
+		def _image(im, w, h):
+			return resize(im, (h, w),
+				mode="constant",
+				anti_aliasing=True,
+				preserve_range=True).astype(np.uint8)
+
+		shoulds = [
+			(SurrogateType.BLANK, _blank),
+			(SurrogateType.MIDDLE, _middle),
+			(SurrogateType.IMAGE, _image),
+		]
+
+		for surr_type, should in shoulds:
+
+			bbox = BasePart.new(self.im, annotation, surrogate_type=surr_type)
+
+			h, w, c = self.im.shape
+			for ratio in np.linspace(0.1, 0.3, num=9):
+				_h, _w = int(h * ratio), int(w * ratio)
+
+				cropped_im = bbox.crop(self.im, ratio=ratio)
+
+				_should = should(self.im, _w, _h)
+
+				self._check_crop(cropped_im, _should)

+ 45 - 0
tests/part_tests/surrogate_tests.py

@@ -0,0 +1,45 @@
+import unittest
+import numpy as np
+
+from skimage.transform import resize
+
+from cvdatasets.dataset.part.surrogate import SurrogateType
+
+
+class SurrogateTest(unittest.TestCase):
+
+	def setUp(self):
+		self.im = np.random.randn(300, 300, 3).astype(np.uint8)
+
+	def test_middle_surrogate(self):
+
+		w = h = 100
+		should = self.im[100:200, 100:200]
+		computed = SurrogateType.MIDDLE(self.im, w, h)
+
+		self.assertEqual(should.shape, computed.shape)
+		self.assertTrue(np.all(should == computed))
+
+
+	def test_blank_surrogate(self):
+
+		w = h = 100
+		should = np.zeros((h,w,3), dtype=np.uint8)
+		computed = SurrogateType.BLANK(self.im, w, h)
+
+		self.assertEqual(should.shape, computed.shape)
+		self.assertTrue(np.all(should == computed))
+
+	def test_image_surrogate(self):
+
+		w = h = 100
+		should = resize(self.im, (h, w),
+			mode="constant",
+			anti_aliasing=True,
+			preserve_range=True).astype(np.uint8)
+		computed = SurrogateType.IMAGE(self.im, w, h)
+
+		self.assertEqual(should.shape, computed.shape)
+		self.assertTrue(np.all(should == computed))
+
+

+ 0 - 55
tests/test_parts.py

@@ -1,55 +0,0 @@
-import unittest
-import numpy as np
-
-from cvdatasets.dataset.part.base import BasePart
-
-class PartCropTest(unittest.TestCase):
-
-
-	def setUp(self):
-		self.im = np.random.randn(300, 300, 3)
-
-	def tearDown(self):
-		pass
-
-	def _check_crop(self, cropped_im, _should):
-
-		self.assertIsNotNone(cropped_im,
-			"method crop should return something!")
-
-		self.assertIsInstance(cropped_im, type(self.im),
-			"result should have the same type as the input image")
-
-		crop_h, crop_w, _ = cropped_im.shape
-		h, w, _ = _should.shape
-		self.assertEqual(crop_h, h, "incorrect crop height")
-		self.assertEqual(crop_w, w, "incorrect crop width")
-
-		self.assertTrue((cropped_im == _should).all(),
-			"crop was incorret")
-
-
-
-	def test_bbox_part_crop(self):
-		_id, x, y, w, h = annotation = (0, 20, 20, 100, 100)
-
-		bbox = BasePart.new(self.im, annotation)
-
-		cropped_im = bbox.crop(self.im)
-
-		_should = self.im[y:y+h, x:x+w]
-		self._check_crop(cropped_im, _should)
-
-	def test_location_part_crop(self):
-		_id, center_x, center_y, _vis = annotation = (0, 50, 50, 1)
-
-		bbox = BasePart.new(self.im, annotation)
-
-		h, w, c = self.im.shape
-		for ratio in np.linspace(0.1, 0.3, num=9):
-			_h, _w = int(h * ratio), int(w * ratio)
-			cropped_im = bbox.crop(self.im, ratio=ratio)
-			x, y = center_x - _h // 2, center_y - _w // 2
-			_should = self.im[y : y + _h, x : x + _w]
-
-			self._check_crop(cropped_im, _should)