فهرست منبع

added implementation for Uniform parts

Dimitri Korsch 6 سال پیش
والد
کامیت
e7f86cc67d
6فایلهای تغییر یافته به همراه54 افزوده شده و 28 حذف شده
  1. 1 1
      nabirds/__init__.py
  2. 2 1
      nabirds/annotations/base.py
  3. 5 1
      nabirds/dataset/__init__.py
  4. 2 3
      nabirds/dataset/image.py
  5. 37 13
      nabirds/dataset/part.py
  6. 7 9
      scripts/display_from_info.py

+ 1 - 1
nabirds/__init__.py

@@ -1,4 +1,4 @@
-from .dataset import Dataset
+from .dataset import Dataset, ImageWrapperDataset
 from .annotations import NAB_Annotations, CUB_Annotations
 
 __version__ = "0.2.1"

+ 2 - 1
nabirds/annotations/base.py

@@ -78,7 +78,8 @@ class BaseAnnotations(abc.ABC):
 		dataset_info = self.dataset_info
 		# TODO: pass all scales
 		new_opts = {
-			"ratio": dataset_info.scales[0]
+			"ratio": dataset_info.scales[0],
+			"uniform_parts": dataset_info.is_uniform
 		}
 
 		if self.part_type is not None:

+ 5 - 1
nabirds/dataset/__init__.py

@@ -2,7 +2,11 @@ from .mixins.reading import AnnotationsReadMixin, ImageListReadingMixin
 from .mixins.parts import PartMixin, RevealedPartMixin, CroppedPartMixin
 from .mixins.features import PreExtractedFeaturesMixin
 
-class Dataset(PartMixin, PreExtractedFeaturesMixin, AnnotationsReadMixin):
+
+class ImageWrapperDataset(PartMixin, PreExtractedFeaturesMixin, AnnotationsReadMixin):
+	pass
+
+class Dataset(ImageWrapperDataset):
 
 	def get_example(self, i):
 		im_obj = super(Dataset, self).get_example(i)

+ 2 - 3
nabirds/dataset/image.py

@@ -6,7 +6,7 @@ import copy
 import numpy as np
 
 from . import utils
-from .part import Parts
+from .part import Parts, UniformParts
 
 def should_have_parts(func):
 	def inner(self, *args, **kwargs):
@@ -113,8 +113,7 @@ class ImageWrapper(object):
 
 	def uniform_parts(self, ratio):
 		result = self.copy()
-		raise NotImplementedError("FIX ME!")
-		result.parts = utils.uniform_parts(self.im, ratio=ratio)
+		result.parts = UniformParts(self.im, ratio=ratio)
 		return result
 
 	@should_have_parts

+ 37 - 13
nabirds/dataset/part.py

@@ -7,12 +7,7 @@ from abc import ABC, abstractmethod, abstractproperty
 
 from . import utils
 
-class Parts(object):
-
-	def __init__(self, image, part_annotations, rescale_size):
-		super(Parts, self).__init__()
-
-		self._parts = [BasePart.new(image, a, rescale_size) for a in part_annotations]
+class BaseParts(ABC):
 
 	def __getitem__(self, i):
 		return self._parts[i]
@@ -65,6 +60,36 @@ class Parts(object):
 
 		return res
 
+class Parts(BaseParts):
+
+	def __init__(self, image, part_annotations, rescale_size):
+		super(Parts, self).__init__()
+		self._parts = [BasePart.new(image, a, rescale_size) for a in part_annotations]
+
+
+class UniformParts(BaseParts):
+
+	def __init__(self, image, ratio):
+		super(UniformParts, self).__init__()
+		self._parts = list(self.generate_parts(image, ratio))
+
+	def generate_parts(self, im, ratio, round_op=np.floor):
+		h, w, c = utils.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
+
+		# fit best possible part_w and part_h
+		part_w = int(w / n)
+		part_h = int(h / m)
+
+		for i in range(n*m):
+			row, col = np.unravel_index(i, (n, m))
+			x, y = col * part_w, row * part_h
+
+			yield BBoxPart(im, [i, x, y, part_w, part_h])
 
 class BasePart(ABC):
 
@@ -100,6 +125,9 @@ class BasePart(ABC):
 		return np.array([self.x, self.y])
 
 	def crop(self, im, w, h, padding_mode="edge", is_location=True):
+		if not self.is_visible:
+			_, _, 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
@@ -119,7 +147,7 @@ class BasePart(ABC):
 class LocationPart(BasePart):
 	DEFAULT_RATIO = np.sqrt(49 / 400) # 0.35
 
-	def __init__(self, image, annotation, rescale_size):
+	def __init__(self, image, annotation, rescale_size=None):
 		super(LocationPart, self).__init__()
 
 		annotation = self.rescale(image, annotation, rescale_size)
@@ -131,11 +159,7 @@ class LocationPart(BasePart):
 		ratio = ratio or self._ratio
 		_h, _w, c = utils.dimensions(image)
 		w, h = int(_w * ratio), int(_h * ratio)
-
-		if not self.is_visible:
-			return np.zeros((h, w, c), dtype=np.uint8)
-		else:
-			return super(LocationPart, self).crop(image, w, h,
+		return super(LocationPart, self).crop(image, w, h,
 				padding_mode, is_location=True)
 
 	def reveal(self, im, ratio=None, *args, **kwargs):
@@ -159,7 +183,7 @@ class LocationPart(BasePart):
 
 class BBoxPart(BasePart):
 
-	def __init__(self, image, annotation, rescale_size):
+	def __init__(self, image, annotation, rescale_size=None):
 		super(BBoxPart, self).__init__()
 
 		annotation = self.rescale(image, annotation, rescale_size)

+ 7 - 9
scripts/display_from_info.py

@@ -16,7 +16,7 @@ from matplotlib.patches import Rectangle
 
 from argparse import ArgumentParser
 
-from nabirds import CUB_Annotations, Dataset
+from nabirds import CUB_Annotations
 
 def init_logger(args):
 	fmt = "%(levelname)s - [%(asctime)s] %(filename)s:%(lineno)d [%(funcName)s]: %(message)s"
@@ -59,8 +59,6 @@ def main(args):
 	data = annot.new_dataset(
 		args.subset,
 
-		uniform_parts=args.uniform_parts,
-
 		crop_to_bb=args.crop_to_bb,
 		crop_uniform=args.crop_uniform,
 
@@ -90,7 +88,11 @@ def main(args):
 		axs[1].axis("off")
 		axs[1].set_title("{}selected parts".format("randomly " if args.rnd else ""))
 		axs[1].imshow(parts.reveal(im, ratio=data.ratio))
-		crop_names = list(data._annot.part_names.values())
+
+		if data.uniform_parts:
+			crop_names = None
+		else:
+			crop_names = list(data._annot.part_names.values())
 
 		part_crops = parts.visible_crops(im, ratio=data.ratio)
 		if args.rnd:
@@ -111,7 +113,7 @@ parser = ArgumentParser()
 parser.add_argument("info")
 
 parser.add_argument("--parts", "-p",
-	choices=["GT", "GT2", "NAC", "L1_pred", "L1_full"]
+	choices=["GT", "GT2", "NAC", "UNI", "L1_pred", "L1_full"]
 )
 
 parser.add_argument("--feature_model", "-fm",
@@ -138,10 +140,6 @@ parser.add_argument("--rnd",
 	help="select random subset of present parts",
 	action="store_true")
 
-parser.add_argument("--uniform_parts", "-u",
-	help="Do not use GT parts, but sample parts uniformly from the image",
-	action="store_true")
-
 parser.add_argument("--crop_to_bb",
 	help="Crop image to the bounding box",
 	action="store_true")