Browse Source

adapted part rescaling for center cropped images (typical case in preprocessing of images)

Dimitri Korsch 6 years ago
parent
commit
fb94710893

+ 1 - 1
cvdatasets/_version.py

@@ -1 +1 @@
-__version__ = "0.4.1"
+__version__ = "0.4.2"

+ 13 - 8
cvdatasets/dataset/part/annotation.py

@@ -64,10 +64,10 @@ class LocationPart(BasePart):
 
 class BBoxPart(BasePart):
 
-	def __init__(self, image, annotation, rescale_size=None):
+	def __init__(self, image, annotation, rescale_size=None, center_cropped=True):
 		super(BBoxPart, self).__init__()
 
-		annotation = self.rescale(image, annotation, rescale_size)
+		annotation = self.rescale(image, annotation, rescale_size, center_cropped)
 		# here x,y are top left corner of the part
 		self._id, self.x, self.y, self.w, self.h = annotation
 		self.is_visible = True
@@ -76,14 +76,19 @@ class BBoxPart(BasePart):
 	def as_annotation(self):
 		return np.array([self._id, self.x, self.y, self.w, self.h])
 
-	def rescale(self, image, annotation, rescale_size):
+	def rescale(self, image, annotation, rescale_size, center_cropped=True):
+
 		if rescale_size is not None and rescale_size > 0:
-			annotation = super(BBoxPart, self).rescale(image, annotation, rescale_size)
-			h, w, c = utils.dimensions(image)
-			scale = np.array([w, h]) / rescale_size
+			from chainer_addons.utils.imgproc import _center_crop
+
+			annotation = super(BBoxPart, self).rescale(image, annotation, rescale_size, center_cropped)
+
+			# base class rescales only x and y.
+			# now we need to rescale the width and height.
+
 			wh = annotation[3:5]
-			wh = wh * scale
-			annotation[3:5] = wh
+			new_wh = utils.rescale(image, wh, rescale_size, center_cropped, no_offset=True)
+			annotation[3:5] = new_wh
 
 		return annotation
 

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

@@ -10,6 +10,9 @@ class BasePartCollection(ABC):
 	def __getitem__(self, i):
 		return self._parts[i]
 
+	def __len__(self, i):
+		return len(self._parts)
+
 	def __repr__(self):
 		return repr(np.stack([p.as_annotation for p in self._parts]))
 
@@ -47,7 +50,9 @@ class BasePartCollection(ABC):
 		return np.array(idxs), np.array(xy).T
 
 	def visible_crops(self, *args, **kwargs):
-		return np.array([p.crop(*args, **kwargs) for p in self._parts])
+		crops = [p.crop(*args, **kwargs) for p in self._parts]
+		return crops
+		# return np.array(crops)
 
 	def plot(self, cmap=plt.cm.jet, **kwargs):
 		for i, p in enumerate(self._parts):
@@ -73,7 +78,7 @@ class BasePart(ABC):
 		return repr(self.as_annotation)
 
 	@staticmethod
-	def new(image, annotation, rescale_size=-1):
+	def new(image, annotation, rescale_size=-1, center_cropped=True):
 		from .annotation import BBoxPart, LocationPart
 		if len(annotation) == 4:
 			return LocationPart(image, annotation, rescale_size)
@@ -82,14 +87,11 @@ class BasePart(ABC):
 		else:
 			raise ValueError("Unknown part annotation format: {}".format(annotation))
 
-	def rescale(self, image, annotation, rescale_size):
+	def rescale(self, image, annotation, rescale_size, center_cropped=True):
 		if rescale_size is not None and rescale_size > 0:
-			h, w, c = utils.dimensions(image)
-			scale = np.array([w, h]) / rescale_size
 			xy = annotation[1:3]
-			xy = xy * scale
-			annotation[1:3] = xy
-
+			new_xy = utils.rescale(image, xy, rescale_size, center_cropped)
+			annotation[1:3] = new_xy
 		return annotation
 
 	@property

+ 1 - 1
cvdatasets/utils/__init__.py

@@ -59,5 +59,5 @@ class _MetaInfo(object):
 		self.structure = []
 
 
-from .image import asarray, dimensions
+from .image import asarray, dimensions, rescale
 from .dataset import new_iterator

+ 15 - 0
cvdatasets/utils/image.py

@@ -1,6 +1,21 @@
 import numpy as np
 from PIL.Image import Image as PIL_Image
 
+def rescale(im, coords, rescale_size, center_cropped=True, no_offset=False):
+	h, w, c = dimensions(im)
+
+	offset = 0
+	if center_cropped:
+		_min_val = min(w, h)
+		wh = np.array([_min_val, _min_val])
+		if not no_offset:
+			offset = (np.array([w, h]) - wh) / 2
+	else:
+		wh = np.array([w, h])
+
+	scale = wh / rescale_size
+	return coords * scale + offset
+
 def dimensions(im):
 	if isinstance(im, np.ndarray):
 		if im.ndim != 3:

+ 1 - 1
scripts/utils/__init__.py

@@ -4,7 +4,7 @@ import matplotlib.pyplot as plt
 
 def plot_crops(crops, title, scatter_mid=False, names=None):
 
-	n_crops = crops.shape[0]
+	n_crops = len(crops)
 	if n_crops == 0: return
 	rows = int(np.ceil(np.sqrt(n_crops)))
 	cols = int(np.ceil(n_crops / rows))