Module deepsport_utilities.transforms
Classes
class DataExtractorTransform (*factories)-
Expand source code
class DataExtractorTransform(Transform): def __init__(self, *factories): self.factories = list(factories) def __call__(self, key, item): if not item: return None data = {} for factory in self.factories: if factory is None: continue try: data.update(**factory(key, item)) except BaseException as e: print(factory, "failed", e) raise return dataAncestors
class DeclutterItems (drop)-
Expand source code
class DeclutterItems(Transform): """ Drops attributes from dataset items. Attributes to drop are given by the 'drop' argument. """ def __init__(self, drop): self.drop = drop def __call__(self, key, item): for name in self.drop: delattr(item, name) return itemDrops attributes from dataset items. Attributes to drop are given by the 'drop' argument.
Ancestors
class DoNothing-
Expand source code
class DoNothing(Transform): def __call__(self, key, item): return itemAncestors
class IncompatibleCropException (*args, **kwargs)-
Expand source code
class IncompatibleCropException(ValueError): passInappropriate argument value (of correct type).
Ancestors
- builtins.ValueError
- builtins.Exception
- builtins.BaseException
class JPEGCompressionTransform (key_names, q_range=(30, 60))-
Expand source code
class JPEGCompressionTransform(Transform): def __init__(self, key_names, q_range=(30,60)): self.key_names = key_names self.q_range = q_range assert len(q_range) == 2 and q_range[0] < q_range[1] and q_range[0] > 0 and q_range[1] <= 100 def __call__(self, key, data): if data is None: return None q = random.randint(*self.q_range) for k in data: if k in self.key_names: data[k] = jpegBlur(data[k], q) return dataAncestors
class RandomCropperTransform (output_shape,
size_min,
size_max,
max_angle=0,
do_flip=False,
padding=0,
margin=0,
debug=False,
regenerate=False)-
Expand source code
class RandomCropperTransform(Transform, metaclass=abc.ABCMeta): linewidth = 4 random_size = np.random.uniform def __init__(self, output_shape, size_min, size_max, max_angle=0, do_flip=False, padding=0, margin=0, debug=False, regenerate=False): """ Randomly scale, crop and rotate dataset items. The scale factor is randomly selected to keep the given keypoints of interest between `size_min` and `size_max` (At each call, the current keypoint size is returned by `_get_current_parameters`). Arguments: output_shape: Tuple(int, int) final shape of image-like data. size_min: (int) lower bound of keypoints random size. If `0` `size_min` and `size_max` are ignored and no random scaling is applied. size_max: (int) upper bound of keypoints random size. If `0` `size_min` and `size_max` are ignored and no random scaling is applied. max_angle: (int) positive and negative bounds for random rotation (in degrees) do_flip: (bool) tells if random flip should be applied padding: (int) amount of padding (in pixels) in input image margin: (int) minimum margin (in pixels) between keypoints and output image border debug: (bool) if `True`, doesn't actually crop but display debug information on image instead. regenerate: (bool) if `True`, items are (deep)-copied before calling `_apply_transformation`. Else, transformation can occur in-place. """ self.output_shape = output_shape self.size_min = size_min self.size_max = size_max self.max_angle = max_angle self.do_flip = do_flip assert not self.do_flip, "There seem to be a bug in the flip" self.padding = padding self.margin = margin self.debug = debug self.regenerate = regenerate def compute(self, input_shape, keypoints, actual_size, size_min=None, size_max=None): if size_min is not None and self.size_min*self.size_max == 0: # updated size range after failing to create a crop at given scale raise IncompatibleCropException("Impossible to crop image without changing the scale") size_min = size_min or self.size_min size_max = size_max or self.size_max if size_min > size_max: raise IncompatibleCropException("Impossible to crop image with object in the given size range") target_size = self.random_size(size_min, size_max) if size_min and size_max else actual_size ratio = target_size/actual_size tmp_width, tmp_height = [int(x/ratio) for x in self.output_shape] if tmp_width == 0 or tmp_height == 0: raise IncompatibleCropException("Impossible to crop image with object in the given size range") input_width, input_height = input_shape # If target size makes the output image bigger than input image, try with a lower size if tmp_width >= input_width + 2*self.padding or tmp_height >= input_height + 2*self.padding: if not size_min or not size_max: raise IncompatibleCropException("Impossible to crop image with object in the given size range") return self.compute(input_shape, keypoints, actual_size, size_min=target_size*1.1, size_max=size_max) margin = self.margin / ratio # margin expressed in pixels in the output image if keypoints is not None: # Restrict keypoints in input image limits max_keypoints_x = min(int(np.max(keypoints.x))+margin, input_width) min_keypoints_x = max(0, int(np.min(keypoints.x))-margin) max_keypoints_y = min(int(np.max(keypoints.y))+margin, input_height) min_keypoints_y = max(0, int(np.min(keypoints.y))-margin) # Compute offsets to fit input image x_offset_min = max(-self.padding, max_keypoints_x - tmp_width) x_offset_max = min(min_keypoints_x, input_width + self.padding) y_offset_min = max(-self.padding, max_keypoints_y - tmp_height) y_offset_max = min(min_keypoints_y, input_height + self.padding) else: x_offset_min = -self.padding x_offset_max = input_width - tmp_width + self.padding y_offset_min = -self.padding y_offset_max = input_height - tmp_height + self.padding x_offset_max = int(np.ceil(x_offset_max)) x_offset_min = int(np.floor(x_offset_min)) y_offset_max = int(np.ceil(y_offset_max)) y_offset_min = int(np.floor(y_offset_min)) # If target size makes it incompatible with input image shape and keypoints positions, try with a higher size if x_offset_max < x_offset_min or y_offset_max < y_offset_min: return self.compute(input_shape, keypoints, actual_size, size_min=size_min, size_max=target_size*0.9) x_offset = np.random.randint(x_offset_min, x_offset_max) if x_offset_min != x_offset_max else x_offset_max y_offset = np.random.randint(y_offset_min, y_offset_max) if y_offset_min != y_offset_max else y_offset_max x_slice = slice(x_offset, x_offset+tmp_width, None) y_slice = slice(y_offset, y_offset+tmp_height, None) angle = self.max_angle*(2*np.random.beta(2, 2)-1) return angle, x_slice, y_slice @abc.abstractmethod def _get_current_parameters(self, key, item): raise NotImplementedError( "This method should return (keypoints, actual_size, shape) corresponding to the " \ "current keypoints and size of object of interest in the image, as well as the " \ "current image shape (width, height)") @abc.abstractmethod def _apply_transformation(self, item, A): raise NotImplementedError( "This method should return the final transformed item, based on the original" \ "item and the affine transformation matrix") def __call__(self, key, item): if item is None: return None parameters = self._get_current_parameters(key, item) if parameters is None: return None keypoints, actual_size, input_shape = parameters try: angle, x_slice, y_slice = self.compute(input_shape, keypoints, actual_size) flip = self.do_flip and bool(np.random.randint(0,2)) except IncompatibleCropException: return None A = parameters_to_affine_transform(angle, x_slice, y_slice, self.output_shape, flip) if self.regenerate: item = copy.deepcopy(item) return self._apply_transformation(item, A)Randomly scale, crop and rotate dataset items. The scale factor is randomly selected to keep the given keypoints of interest between
size_minandsize_max(At each call, the current keypoint size is returned by_get_current_parameters).Arguments
output_shape: Tuple(int, int) final shape of image-like data. size_min: (int) lower bound of keypoints random size. If
0size_minandsize_maxare ignored and no random scaling is applied. size_max: (int) upper bound of keypoints random size. If0size_minandsize_maxare ignored and no random scaling is applied. max_angle: (int) positive and negative bounds for random rotation (in degrees) do_flip: (bool) tells if random flip should be applied padding: (int) amount of padding (in pixels) in input image margin: (int) minimum margin (in pixels) between keypoints and output image border debug: (bool) ifTrue, doesn't actually crop but display debug information on image instead. regenerate: (bool) ifTrue, items are (deep)-copied before calling_apply_transformation. Else, transformation can occur in-place.Ancestors
Subclasses
Class variables
var linewidth
Static methods
def random_size(low=0.0, high=1.0, size=None)-
uniform(low=0.0, high=1.0, size=None)
Draw samples from a uniform distribution.
Samples are uniformly distributed over the half-open interval
[low, high)(includes low, but excludes high). In other words, any value within the given interval is equally likely to be drawn byuniform.Note
New code should use the
~numpy.random.Generator.uniformmethod of a~numpy.random.Generatorinstance instead; please see the :ref:random-quick-start.Parameters
low:floatorarray_likeoffloats, optional- Lower boundary of the output interval. All values generated will be greater than or equal to low. The default value is 0.
high:floatorarray_likeoffloats- Upper boundary of the output interval.
All values generated will be
less than or equal to high.
The high limit may be included in the
returned array of floats due to floating-point rounding in the
equation
low + (high-low) * random_sample(). The default value is 1.0. size:intortupleofints, optional- Output shape.
If the given shape is, e.g.,
(m, n, k), thenm * n * ksamples are drawn. If size isNone(default), a single value is returned iflowandhighare both scalars. Otherwise,np.broadcast(low, high).sizesamples are drawn.
Returns
out:ndarrayorscalar- Drawn samples from the parameterized uniform distribution.
See Also
randint- Discrete uniform distribution, yielding integers.
random_integers- Discrete uniform distribution over the closed interval
[low, high]. random_sample- Floats uniformly distributed over
[0, 1). random- Alias for
random_sample. rand- Convenience function that accepts dimensions as input, e.g.,
rand(2,2)would generate a 2-by-2 array of floats, uniformly distributed over[0, 1). random.Generator.uniform- which should be used for new code.
Notes
The probability density function of the uniform distribution is
[ ]
anywhere within the interval
[a, b), and zero elsewhere.When
high==low, values oflowwill be returned. Ifhigh<low, the results are officially undefined and may eventually raise an error, i.e. do not rely on this function to behave when passed arguments satisfying that inequality condition. Thehighlimit may be included in the returned array of floats due to floating-point rounding in the equationlow + (high-low) * random_sample(). For example:>>> x = np.float32(5*0.99999999) >>> x np.float32(5.0)Examples
Draw samples from the distribution:
>>> s = np.random.uniform(-1,0,1000)All values are within the given interval:
>>> np.all(s >= -1) True >>> np.all(s < 0) TrueDisplay the histogram of the samples, along with the probability density function:
>>> import matplotlib.pyplot as plt >>> count, bins, ignored = plt.hist(s, 15, density=True) >>> plt.plot(bins, np.ones_like(bins), linewidth=2, color='r') >>> plt.show()
Methods
def compute(self, input_shape, keypoints, actual_size, size_min=None, size_max=None)-
Expand source code
def compute(self, input_shape, keypoints, actual_size, size_min=None, size_max=None): if size_min is not None and self.size_min*self.size_max == 0: # updated size range after failing to create a crop at given scale raise IncompatibleCropException("Impossible to crop image without changing the scale") size_min = size_min or self.size_min size_max = size_max or self.size_max if size_min > size_max: raise IncompatibleCropException("Impossible to crop image with object in the given size range") target_size = self.random_size(size_min, size_max) if size_min and size_max else actual_size ratio = target_size/actual_size tmp_width, tmp_height = [int(x/ratio) for x in self.output_shape] if tmp_width == 0 or tmp_height == 0: raise IncompatibleCropException("Impossible to crop image with object in the given size range") input_width, input_height = input_shape # If target size makes the output image bigger than input image, try with a lower size if tmp_width >= input_width + 2*self.padding or tmp_height >= input_height + 2*self.padding: if not size_min or not size_max: raise IncompatibleCropException("Impossible to crop image with object in the given size range") return self.compute(input_shape, keypoints, actual_size, size_min=target_size*1.1, size_max=size_max) margin = self.margin / ratio # margin expressed in pixels in the output image if keypoints is not None: # Restrict keypoints in input image limits max_keypoints_x = min(int(np.max(keypoints.x))+margin, input_width) min_keypoints_x = max(0, int(np.min(keypoints.x))-margin) max_keypoints_y = min(int(np.max(keypoints.y))+margin, input_height) min_keypoints_y = max(0, int(np.min(keypoints.y))-margin) # Compute offsets to fit input image x_offset_min = max(-self.padding, max_keypoints_x - tmp_width) x_offset_max = min(min_keypoints_x, input_width + self.padding) y_offset_min = max(-self.padding, max_keypoints_y - tmp_height) y_offset_max = min(min_keypoints_y, input_height + self.padding) else: x_offset_min = -self.padding x_offset_max = input_width - tmp_width + self.padding y_offset_min = -self.padding y_offset_max = input_height - tmp_height + self.padding x_offset_max = int(np.ceil(x_offset_max)) x_offset_min = int(np.floor(x_offset_min)) y_offset_max = int(np.ceil(y_offset_max)) y_offset_min = int(np.floor(y_offset_min)) # If target size makes it incompatible with input image shape and keypoints positions, try with a higher size if x_offset_max < x_offset_min or y_offset_max < y_offset_min: return self.compute(input_shape, keypoints, actual_size, size_min=size_min, size_max=target_size*0.9) x_offset = np.random.randint(x_offset_min, x_offset_max) if x_offset_min != x_offset_max else x_offset_max y_offset = np.random.randint(y_offset_min, y_offset_max) if y_offset_min != y_offset_max else y_offset_max x_slice = slice(x_offset, x_offset+tmp_width, None) y_slice = slice(y_offset, y_offset+tmp_height, None) angle = self.max_angle*(2*np.random.beta(2, 2)-1) return angle, x_slice, y_slice
class Transform-
Expand source code
class Transform(metaclass=abc.ABCMeta): def __lt__(self, other): return self.__repr__() < other.__repr__() def __gt__(self, other): return self.__repr__() > other.__repr__() @abc.abstractmethod def __call__(self, key, item): pass def __repr__(self): config = getattr(self, "config", {k:v for k, v in self.__dict__.items() if not k.startswith("_")}) attributes = ",".join("{}={}".format(k, v) for k,v in config.items()) return "{}({})".format(self.__class__.__name__, attributes)Subclasses
- CropBlockDividable
- EnhanceColorTransform
- GammaCorrectionTransform
- ProjectBall
- RemoveAnnotationMetadata
- RemoveGroundTruth
- AddBallAnnotation
- AddBallFactory
- AddBallHeightFactory
- AddBallPositionFactory
- AddBallPresenceFactory
- AddBallSegmentationTargetViewFactory
- AddBallSizeFactory
- AddBallStateFactory
- AddBallVisibilityFactory
- AddCalibFactory
- AddCourtFactory
- AddDiffFactory
- AddHumansSegmentationTargetViewFactory
- AddImageFactory
- AddNextImageFactory
- BayeringTransform
- ComputeDiff
- GameGammaColorTransform
- GameRGBColorTransform
- UndistortTransform
- DataExtractorTransform
- DeclutterItems
- DoNothing
- JPEGCompressionTransform
- RandomCropperTransform