Browse Source

moved nabirds.dataset.utils module to nabirds.utils; fixed parts_in_bb computation

Dimitri Korsch 6 years ago
parent
commit
9af56c3ed8
5 changed files with 70 additions and 168 deletions
  1. 2 5
      nabirds/dataset/image.py
  2. 26 3
      nabirds/dataset/part.py
  3. 0 160
      nabirds/dataset/utils.py
  4. 18 0
      nabirds/utils/__init__.py
  5. 24 0
      nabirds/utils/image.py

+ 2 - 5
nabirds/dataset/image.py

@@ -5,7 +5,7 @@ from os.path import isfile
 import copy
 import numpy as np
 
-from . import utils
+from nabirds import utils
 from .part import Parts, UniformParts
 
 def should_have_parts(func):
@@ -104,11 +104,8 @@ class ImageWrapper(object):
 
 	@should_have_parts
 	def hide_parts_outside_bb(self, x, y, w, h):
-		idxs, (xs,ys) = self.visible_part_locs()
-		f = np.logical_and
-		mask = f(f(x <= xs, xs <= x+w), f(y <= ys, ys <= y+h))
 		result = self.copy()
-		result.parts.select(idxs[mask])
+		result.parts.hide_outside_bb(x, y, w, h)
 		return result
 
 	def uniform_parts(self, ratio):

+ 26 - 3
nabirds/dataset/part.py

@@ -3,9 +3,9 @@ from matplotlib import pyplot as plt
 
 from contextlib import contextmanager
 from matplotlib.patches import Rectangle
-from abc import ABC, abstractmethod, abstractproperty
+from abc import ABC, abstractproperty
 
-from . import utils
+from nabirds import utils
 
 class BaseParts(ABC):
 
@@ -28,6 +28,9 @@ class BaseParts(ABC):
 		for p in self._parts:
 			p.is_visible = p._id in idxs
 
+	def hide_outside_bb(self, *bounding_box):
+		for p in self._parts:
+			p.hide_if_outside(*bounding_box)
 
 	def invert_selection(self):
 		self.select(np.logical_not(self.selected))
@@ -140,10 +143,17 @@ class BasePart(ABC):
 
 		return padded_im[y0:y0+h, x0:x0+w]
 
+	@abstractproperty
+	def middle(self):
+		raise NotImplementedError
 
 	def plot(self, **kwargs):
 		return
 
+	def hide_if_outside(self, x, y, w, h):
+		mid_x, mid_y = self.middle
+		self.is_visible = ((x <= mid_x <= x+w) and (y <= mid_y <= y+h))
+
 class LocationPart(BasePart):
 	DEFAULT_RATIO = np.sqrt(49 / 400) # 0.35
 
@@ -169,7 +179,6 @@ class LocationPart(BasePart):
 		x, y = max(x - w // 2, 0), max(y - h // 2, 0)
 		return x, y, im[y:y+h, x:x+w]
 
-
 	def plot(self, im, ax, ratio, fill=False, linestyle="--", **kwargs):
 		if not self.is_visible: return
 		x, y = self.xy
@@ -181,6 +190,14 @@ class LocationPart(BasePart):
 			**kwargs
 		))
 
+		ax.scatter(*self.middle, marker="x", color="white", alpha=0.8)
+
+
+	@property
+	def middle(self):
+		return np.array([self.x, self.y])
+
+
 class BBoxPart(BasePart):
 
 	def __init__(self, image, annotation, rescale_size=None):
@@ -202,6 +219,9 @@ class BBoxPart(BasePart):
 
 		return annotation
 
+	@property
+	def middle(self):
+		return np.array([self.x + self.w // 2, self.y + self.h // 2])
 
 	def crop(self, image, padding_mode="edge", *args, **kwargs):
 		return super(BBoxPart, self).crop(image, self.w, self.h,
@@ -220,3 +240,6 @@ class BBoxPart(BasePart):
 			fill=fill, linestyle=linestyle,
 			**kwargs
 		))
+
+		ax.scatter(*self.middle, marker="x", color="white", alpha=0.8)
+

+ 0 - 160
nabirds/dataset/utils.py

@@ -1,160 +0,0 @@
-import numpy as np
-from PIL.Image import Image as PIL_Image
-
-DEFAULT_RATIO = np.sqrt(49 / 400)
-
-def dimensions(im):
-	if isinstance(im, np.ndarray):
-		if im.ndim != 3:
-			import pdb; pdb.set_trace()
-		assert im.ndim == 3, "Only RGB images are currently supported!"
-		return im.shape
-	elif isinstance(im, PIL_Image):
-		w, h = im.size
-		c = len(im.getbands())
-		# assert c == 3, "Only RGB images are currently supported!"
-		return h, w, c
-	else:
-		raise ValueError("Unknown image instance ({})!".format(type(im)))
-
-def asarray(im, dtype=np.uint8):
-	if isinstance(im, np.ndarray):
-		return im.astype(dtype)
-	elif isinstance(im, PIL_Image):
-		return np.asarray(im, dtype=dtype)
-	else:
-		raise ValueError("Unknown image instance ({})!".format(type(im)))
-
-def random_idxs(idxs, rnd=None, n_parts=None):
-
-	if rnd is None or isinstance(rnd, int):
-		rnd = np.random.RandomState(rnd)
-	else:
-		assert isinstance(rnd, np.random.RandomState), \
-			"'rnd' should be either a random seed or a RandomState instance!"
-
-	n_parts = n_parts or rnd.randint(1, len(idxs))
-	res = rnd.choice(idxs, n_parts, replace=False)
-	res.sort()
-	return res
-
-
-
-##### DEPRECATED #####
-
-# def __expand_parts(p):
-# 	return p[:, 0], p[:, 1:3], p[:, 3].astype(bool)
-
-def selection_mask(idxs, n):
-	raise DeprecationWarning("Do not use me!")
-	# return np.bincount(idxs, minlength=n).astype(bool)
-
-def select_crops(crops, mask):
-	raise DeprecationWarning("Do not use me!")
-	# selected = np.zeros_like(crops)
-	# selected[mask] = crops[mask]
-	# return selected
-
-def random_select(idxs, xy, part_crops, *args, **kw):
-	raise DeprecationWarning("Do not use me!")
-	# rnd_idxs = random_idxs(np.arange(len(idxs)), *args, **kw)
-	# idxs = idxs[rnd_idxs]
-	# xy = xy[:, rnd_idxs]
-
-	# mask = selection_mask(idxs, len(part_crops))
-	# selected_crops = select_crops(part_crops, mask)
-
-	# return idxs, xy, selected_crops
-
-
-def uniform_parts(im, ratio=DEFAULT_RATIO, round_op=np.floor):
-	raise DeprecationWarning("Do not use me!")
-	# h, w, c = dimensions(im)
-
-	# part_w = round_op(w * ratio).astype(np.int32)
-	# part_h = round_op(h * ratio).astype(np.int32)
-
-	# n, m = w // part_w, h // part_h
-
-	# parts = np.ones((n*m, 4), dtype=int)
-	# parts[:, 0] = np.arange(n*m)
-
-	# for x in range(n):
-	# 	for y in range(m):
-	# 		i = y * n + x
-	# 		x0, y0 = x * part_w, y * part_h
-	# 		parts[i, 1:3] = [x0 + part_w // 2, y0 + part_h // 2]
-
-	# return parts
-
-def rescale_parts(im, parts, part_rescale_size):
-	raise DeprecationWarning("Do not use me!")
-	# if part_rescale_size is None or part_rescale_size < 0:
-	# 	return parts
-	# h, w, c = dimensions(im)
-	# scale = np.array([w, h]) / part_rescale_size
-
-	# xy = parts[:, 1:3]
-	# xy = xy * scale
-	# parts[:, 1:3] = xy
-
-	# if parts.shape[1] == 5:
-	# 	wh = parts[:, 3:5]
-	# 	wh = wh * scale
-	# 	parts[:, 3:5] = wh
-
-	# return parts
-
-def visible_part_locs(p):
-	raise DeprecationWarning("Do not use me!")
-	# res = p.visible_locs()
-	# return res
-
-	# idxs, locs, vis = __expand_parts(p)
-	# return idxs[vis], locs[vis].T
-
-
-def crop(im, xy, w, h, padding_mode="edge", is_location=True):
-	raise DeprecationWarning("Do not use me!")
-
-	# x, y = xy
-	# pad_h, pad_w = h // 2, w // 2
-
-	# padded_im = np.pad(im, [(pad_h, pad_h), (pad_w, pad_w), [0,0]], mode=padding_mode)
-	# x0, y0 = x + pad_w, y + pad_h
-
-	# if is_location:
-	# 	x0, y0 = x0 - w // 2, y0 - h // 2
-
-	# return padded_im[y0:y0+h, x0:x0+w]
-
-def crops(im, xys, ratio=DEFAULT_RATIO, padding_mode="edge"):
-	raise DeprecationWarning("Do not use me!")
-
-	# h, w, c = dimensions(im)
-	# crop_h, crop_w = int(h * ratio), int(w * ratio)
-	# return np.stack([crop(im, xy, crop_w, crop_h, padding_mode)
-	# 	for xy in xys.T])
-
-def visible_crops(im, p, *args, **kw):
-	raise DeprecationWarning("Do not use me!")
-	# res = p.visible_crops(*args, **kw)
-	# return res
-
-	# idxs, locs, vis = __expand_parts(p)
-	# parts = crops(asarray(im), locs[vis].T, *args, **kw)
-	# res = np.zeros((len(idxs),) + parts.shape[1:], dtype=parts.dtype)
-	# res[vis] = parts
-	# return res
-
-def reveal_parts(im, xy, ratio=DEFAULT_RATIO):
-	raise DeprecationWarning("Do not use me!")
-	# h, w, c = dimensions(im)
-	# crop_h, crop_w = int(h * ratio), int(w * ratio)
-	# im = asarray(im)
-	# res = np.zeros_like(im)
-	# for x, y in xy.T:
-	# 	x0, y0 = max(x - crop_w // 2, 0), max(y - crop_h // 2, 0)
-	# 	res[y0:y0+crop_h, x0:x0+crop_w] = im[y0:y0+crop_h, x0:x0+crop_w]
-
-	# return res

+ 18 - 0
nabirds/utils.py → nabirds/utils/__init__.py

@@ -1,3 +1,18 @@
+import numpy as np
+
+def random_idxs(idxs, rnd=None, n_parts=None):
+
+	if rnd is None or isinstance(rnd, int):
+		rnd = np.random.RandomState(rnd)
+	else:
+		assert isinstance(rnd, np.random.RandomState), \
+			"'rnd' should be either a random seed or a RandomState instance!"
+
+	n_parts = n_parts or rnd.randint(1, len(idxs))
+	res = rnd.choice(idxs, n_parts, replace=False)
+	res.sort()
+	return res
+
 class attr_dict(dict):
 	def __getattr__(self, name):
 		if name in self:
@@ -17,3 +32,6 @@ class _MetaInfo(object):
 		for name, value in kwargs.items():
 			setattr(self, name, value)
 		self.structure = []
+
+
+from .image import asarray, dimensions

+ 24 - 0
nabirds/utils/image.py

@@ -0,0 +1,24 @@
+import numpy as np
+from PIL.Image import Image as PIL_Image
+
+def dimensions(im):
+	if isinstance(im, np.ndarray):
+		if im.ndim != 3:
+			import pdb; pdb.set_trace()
+		assert im.ndim == 3, "Only RGB images are currently supported!"
+		return im.shape
+	elif isinstance(im, PIL_Image):
+		w, h = im.size
+		c = len(im.getbands())
+		# assert c == 3, "Only RGB images are currently supported!"
+		return h, w, c
+	else:
+		raise ValueError("Unknown image instance ({})!".format(type(im)))
+
+def asarray(im, dtype=np.uint8):
+	if isinstance(im, np.ndarray):
+		return im.astype(dtype)
+	elif isinstance(im, PIL_Image):
+		return np.asarray(im, dtype=dtype)
+	else:
+		raise ValueError("Unknown image instance ({})!".format(type(im)))