Module deepsport_utilities.ds.instants_dataset
Expand source code
from .instants_dataset import InstantsDataset, Instant, InstantKey, DownloadFlags, Player, Ball, BallState
from .instants_transforms import GammaCorrectionTransform
from .views_dataset import ViewsDataset, ViewKey, View, BuildBallViews, BuildCameraViews, \
BuildHeadsViews, BuildCourtViews, BuildPlayersViews, BuildThumbnailViews
from .views_transforms import AddBallAnnotation, UndistortTransform, \
ComputeDiff, GameGammaColorTransform, GameRGBColorTransform, \
BayeringTransform, ViewRandomCropperTransform, AddCalibFactory, AddCourtFactory, AddDiffFactory, \
AddNextImageFactory, BallCropperTransform
from .dataset_splitters import DeepSportDatasetSplitter, KFoldsArenaLabelsTestingDatasetSplitter, \
TestingArenaLabelsDatasetSplitter
try:
from .views_transforms import AddBallDistance
except ImportError:
pass
# all but "InstantsDataset"
__all__ = ["Instant", "InstantKey", "DownloadFlags", "Player", "BallState",
"Ball", "GammaCorrectionTransform", "ViewsDataset", "ViewKey", "View",
"BuildBallViews", "BuildCameraViews", "AddBallAnnotation", "UndistortTransform",
"DeepSportDatasetSplitter", "KFoldsArenaLabelsTestingDatasetSplitter",
"TestingArenaLabelsDatasetSplitter", "BuildHeadsViews", "BuildCourtViews",
"BuildPlayersViews", "BuildThumbnailViews", "ComputeDiff",
"GameGammaColorTransform", "GameRGBColorTransform", "BayeringTransform",
"ViewRandomCropperTransform", "AddCalibFactory", "AddCourtFactory",
"AddDiffFactory", "AddNextImageFactory", "BallCropperTransform"]
Sub-modules
deepsport_utilities.ds.instants_dataset.dataset_splitters
deepsport_utilities.ds.instants_dataset.instants_dataset
deepsport_utilities.ds.instants_dataset.instants_transforms
deepsport_utilities.ds.instants_dataset.views_dataset
deepsport_utilities.ds.instants_dataset.views_transforms
Classes
class AddBallAnnotation
-
Expand source code
class AddBallAnnotation(Transform): def __call__(self, key, view): balls = [a for a in view.annotations if a.type == 'ball'] assert len(balls) == 1, f"Expected one ball. received {len(balls)}." view.ball = balls[0] return view
Ancestors
class AddCalibFactory (as_dict=False)
-
Expand source code
class AddCalibFactory(Transform): def __init__(self, as_dict=False): self.as_dict = as_dict @staticmethod def to_basic_dict(calib): return { "K": calib.K, "r": cv2.Rodrigues(calib.R)[0].flatten(), "T": calib.T, "width": np.array([calib.width]), "height": np.array([calib.height]), "kc": np.array(calib.kc), } def __call__(self, view_key, view): if self.as_dict: return self.to_basic_dict(view.calib) return {"calib": view.calib}
Ancestors
Static methods
def to_basic_dict(calib)
-
Expand source code
@staticmethod def to_basic_dict(calib): return { "K": calib.K, "r": cv2.Rodrigues(calib.R)[0].flatten(), "T": calib.T, "width": np.array([calib.width]), "height": np.array([calib.height]), "kc": np.array(calib.kc), }
class AddCourtFactory
-
Expand source code
class AddCourtFactory(Transform): def __call__(self, view_key, view): if not getattr(view, "court", None): view.court = Court() return { "court_width": np.array([view.court.w]), "court_height": np.array([view.court.h]) }
Ancestors
class AddDiffFactory
-
Expand source code
class AddDiffFactory(Transform): def __call__(self, view_key, view): raise NotImplementedError() # code needs to be re-implemented: current implementation only adds next image return {"input_image2": view.all_images[1]}
Ancestors
class AddNextImageFactory
-
Expand source code
class AddNextImageFactory(Transform): def __call__(self, view_key, view): return {"input_image2": view.all_images[1]}
Ancestors
class Ball (data)
-
Expand source code
class Ball(): state = BallState.NONE # default visible = None # default value = None # default def __init__(self, data): self.type = "ball" self.center = Point3D(*data['center']) self.origin = data.get('origin', "annotation") self.camera = data['image'] self.visible = data.get('visible', None) self.state = data.get('state', BallState.NONE) self.value = data.get('value', None) def to_dict(self): return { "type": self.type, "origin": self.origin, "center": self.center.to_list(), "image": self.camera, "visible": self.visible, "state": self.state, "value": self.value } def __repr__(self): return "Ball(" + ",".join([ f"origin='{self.origin}', " \ f"center=({self.center.x:.01f}, {self.center.y:.01f}, {self.center.z:.01f})" \ ]) + ")"
Subclasses
Class variables
var state
var value
var visible
Methods
def to_dict(self)
-
Expand source code
def to_dict(self): return { "type": self.type, "origin": self.origin, "center": self.center.to_list(), "image": self.camera, "visible": self.visible, "state": self.state, "value": self.value }
class BallCropperTransform (*args, def_min=None, def_max=None, size_min=None, size_max=None, scale_min=None, scale_max=None, **kwargs)
-
Create a random scaled thumbnail around view's ball. - If [min_size, max_size] range is given, scale factor is chosen s.t. ball size is in the [min_size, max_size] range. - If [def_min, def_max] range is given, scale factor is chosen s.t. image definition [px/m] is in the [def_min, def_max] range at ball location. - If [scale_min, scale_max] range is given, scale factor is chosen in that range. An error is raised if multiple options are given.
Randomly scale, crop and rotate dataset items. The scale factor is randomly selected to keep the given keypoints of interest between
size_min
andsize_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
andsize_max
are ignored and no random scaling is applied. size_max: (int) upper bound of keypoints random size. If0
size_min
andsize_max
are ignored and no random scaling is applied. max_angle: (degrees) positive and negative bounds for random rotation do_flip: (bool) tells if random flip should be applied padding: (px) amount of padding margin: (px) minimum margin 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.Expand source code
class BallCropperTransform(ViewRandomCropperTransform): """ Create a random scaled thumbnail around view's ball. - If [min_size, max_size] range is given, scale factor is chosen s.t. ball size is in the [min_size, max_size] range. - If [def_min, def_max] range is given, scale factor is chosen s.t. image definition [px/m] is in the [def_min, def_max] range at ball location. - If [scale_min, scale_max] range is given, scale factor is chosen in that range. An error is raised if multiple options are given. """ def __init__(self, *args, def_min=None, def_max=None, size_min=None, size_max=None, scale_min=None, scale_max=None, **kwargs): msg = "Only one of ('size_min' and 'size_max') or ('def_min' and 'def_max') or ('scale_min' and 'scale_max') should be defined" if size_min is not None and size_max is not None: assert all([x is None for x in [def_min, def_max, scale_min, scale_max]]), msg super().__init__(*args, size_min=size_min, size_max=size_max, **kwargs) self.true_size = BALL_DIAMETER elif def_min is not None and def_max is not None: assert all([x is None for x in [size_min, size_max, scale_min, scale_max]]), msg super().__init__(*args, size_min=def_min, size_max=def_max, **kwargs) self.true_size = 100 elif scale_min is not None and scale_max is not None: assert all([x is None for x in [size_min, size_max, def_min, def_max]]), msg super().__init__(*args, size_min=scale_min, size_max=scale_max, **kwargs) self.true_size = None else: raise ValueError(msg) def _get_current_parameters(self, view_key, view): keypoints = view.calib.project_3D_to_2D(view.ball.center) if self.true_size is None: size = 1 else: size = float(view.calib.compute_length2D(view.ball.center, self.true_size)) input_shape = view.calib.width, view.calib.height return keypoints, size, input_shape
Ancestors
Inherited members
class BallState (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code
class BallState(IntEnum): NONE = 0 FLYING = 1 CONSTRAINT = 2 DRIBBLING = 3
Ancestors
- enum.IntEnum
- builtins.int
- enum.Enum
Class variables
var CONSTRAINT
var DRIBBLING
var FLYING
var NONE
class BayeringTransform
-
Expand source code
class BayeringTransform(Transform): def __init__(self): self.R_filter = np.array([[1,0],[0,0]]) self.G_filter = np.array([[0,1],[1,0]]) self.B_filter = np.array([[0,0],[0,1]]) def __call__(self, view_key, view): height, width, _ = view.image.shape R_mask = np.tile(self.R_filter, [height//2, width//2]) G_mask = np.tile(self.G_filter, [height//2, width//2]) B_mask = np.tile(self.B_filter, [height//2, width//2]) mask = np.stack((R_mask, G_mask, B_mask), axis=2) mask = mask[np.newaxis] for i, image in enumerate(view.all_images): view.all_images[i] = np.sum(image*mask, axis=3) view.image = view.all_images[0]
Ancestors
class BuildBallViews (*args, origins=['annotation'], **kwargs)
-
Margin given in world coordinates by default, except if
margin_in_pixels
is True.Expand source code
class BuildBallViews(ViewBuilder): def __init__(self, *args, origins=["annotation"], **kwargs): super().__init__(*args, **kwargs) self.origins = origins def __call__(self, instant_key: InstantKey, instant: Instant): balls = instant.annotations + getattr(instant, "detections", []) predicate = lambda a: a.type == 'ball' and a.origin in self.origins for idx, ball in enumerate(filter(predicate, balls)): keypoints = [ball.center] c = int(ball.camera) timestamp = getattr(instant, "timestamps", [instant.timestamp]*instant.num_cameras)[c] # timestamps may be different for each camera yield ViewDescription(c, idx, self.compute_box(keypoints, instant.calibs[c]), ball=ball, timestamp=timestamp)
Ancestors
Class variables
var margin : float
var margin_in_pixels : bool
var padding : int
class BuildCameraViews (margin: float = 0, padding: int = None, margin_in_pixels: bool = False)
-
Builds a view for each camera (margin parameter is useless)
Expand source code
class BuildCameraViews(ViewBuilder): """ Builds a view for each camera (margin parameter is useless) """ def __call__(self, instant_key: InstantKey, instant:Instant): for c in range(instant.num_cameras): yield ViewDescription(c, 0, BoundingBox(0, 0, instant.calibs[c].width, instant.calibs[c].height), court_dim=instant.court_dim)
Ancestors
Class variables
var margin : float
var margin_in_pixels : bool
var padding : int
class BuildCourtViews (margin: float = 0, padding: int = None, margin_in_pixels: bool = False, height: float = 300)
-
Builds a view including all the court keypoints visible on each camera Note: keypoints are duplicated at 2m from the floor
Expand source code
class BuildCourtViews(ViewBuilder): """ Builds a view including all the court keypoints visible on each camera Note: keypoints are duplicated at 2m from the floor """ height: float = 300 def __call__(self, instant_key: InstantKey, instant:Instant): for c in range(instant.num_cameras): calib = instant.calibs[c] visible_edges = Court(instant.rule_type).visible_edges(calib) court_keypoints = [] for p1, p2 in visible_edges: court_keypoints = court_keypoints + [p1, p1+Point3D(0,0,-self.height), p2, p2+Point3D(0,0,-self.height)] yield ViewDescription(c, 0, self.compute_box(court_keypoints, calib))
Ancestors
Class variables
var height : float
class BuildHeadsViews (margin: float = 0, padding: int = None, margin_in_pixels: bool = False)
-
Margin given in world coordinates by default, except if
margin_in_pixels
is True.Expand source code
class BuildHeadsViews(ViewBuilder): def __call__(self, instant_key: InstantKey, instant: Instant): for idx, player in enumerate([a for a in instant.annotations if a.type == "player"]): c = int(player.camera) keypoints = [player.head] yield ViewDescription(c, idx, self.compute_box(keypoints, instant.calibs[c]), annotation=player)
Ancestors
Class variables
var margin : float
var margin_in_pixels : bool
var padding : int
class BuildPlayersViews (margin: float = 0, padding: int = None, margin_in_pixels: bool = False, min_annotations: int = 1)
-
Builds a view around the players visible on each camera min_annotations: minimum required number of person to use that camera
Expand source code
class BuildPlayersViews(ViewBuilder): """ Builds a view around the players visible on each camera min_annotations: minimum required number of person to use that camera """ min_annotations: int = 1 def __call__(self, instant_key: InstantKey, instant: Instant): for c in range(instant.num_cameras): annotations = [a for a in instant.annotations if a.camera == c and a.type == "player" and a.team > 0] if len(annotations) < self.min_annotations: continue keypoints = [] for a in annotations: keypoints += [a.head, a.hips, a.foot1, a.foot2] yield ViewDescription(c, 0, self.compute_box(keypoints, instant.calibs[c]))
Ancestors
Class variables
var min_annotations : int
class BuildThumbnailViews (margin: float = 0, padding: int = None, margin_in_pixels: bool = False, with_annotations: bool = True, with_detections: bool = False, with_random: Tuple[int, bool] = 0, with_occlusions: bool = False)
-
Builds a view around each person (players, referee)
Expand source code
class BuildThumbnailViews(ViewBuilder): """ Builds a view around each person (players, referee) """ with_annotations: bool = True with_detections: bool = False with_random: Tuple[int, bool] = 0 with_occlusions: bool = False BODY_HEIGHT = 180 threshold = 0.25 def __post_init__(self): self.with_random = 10 if isinstance(self.with_random, bool) and self.with_random else self.with_random def check_density_map(self, density_map, box, threshold): if 0 in density_map[box.y_slice, box.x_slice].shape: return False if np.mean(density_map[box.y_slice, box.x_slice]) <= threshold: return True return False def sample_density_map(self, density_map): # avoid going too close to other detections dilation = cv2.dilate(density_map, np.ones((3,3)), iterations=10) indices_y, indices_x = np.where(dilation == 0) # random choic a position in the image i = np.random.randint(0, len(indices_x)) return np.array([[indices_x[i], indices_y[i]]]) @staticmethod def fill_density_map(density_map, box): density_map[box.y_slice, box.x_slice] += 1 def __call__(self, instant_key: InstantKey, instant:Instant): # Set random seed with timestamp random_state = np.random.get_state() np.random.seed(instant_key.timestamp & 0xFFFFFFFF) instant.density_maps = [np.zeros(img.shape[0:2], dtype=np.uint8) for img in instant.images] for c in range(instant.num_cameras): calib = instant.calibs[c] density_map = instant.density_maps[c] index = 0 # From annotation for a in [a for a in instant.annotations if a.type == "player" and calib.projects_in(a.hips) and self.with_annotations]: keypoints = [a.head, a.hips, a.foot1, a.foot2] box = self.compute_box(keypoints, calib) #if self.check_density_map(instant.density_maps, box, c, 1+self.threshold) or self.with_occlusions: yield ViewDescription(c, index, box, origin='annotation', annotation=a, density_map=density_map) self.fill_density_map(density_map, box) index = index + 1 if self.with_detections: # From keemotion foregrounddetector detections # FIXME: for detection in []:#[d for d in instant.fg_detections if d.camera == c and calib.projects_in(d.feet) and self.with_detections]: keypoints = [ detection.feet, detection.feet + Point3D(0, 0, -self.BODY_HEIGHT) ] box = self.compute_box(keypoints, calib) if self.check_density_map(density_map, box, self.threshold): yield ViewDescription(c, index, box, origin='detection', detection=detection, density_map=density_map) self.fill_density_map(density_map, box) index = index + 1 # From random if self.with_random: raise NotImplementedError # TODO: use Calib.visible_edge() to replace the function "find_court_intersection_with_camera_border" court_keypoints_3D = []# find_court_intersection_with_camera_border(calib, instant.rule_type) court_keypoints_2D = np.array([calib.project_3D_to_2D(p).to_list() for p in court_keypoints_3D]) convex_hull = ConvexHull(court_keypoints_2D) points = np.array([court_keypoints_2D[i,:] for i in convex_hull.vertices]).astype(np.int32) court = np.ones(instant.images[c].shape[0:2], dtype=np.uint8) density_map[cv2.fillPoly(court, [points], 0)==1] += 1 for _ in range(self.with_random): feet = calib.project_2D_to_3D(Point2D(self.sample_density_map(density_map)), Z=0) keypoints = [feet, feet + Point3D(0, 0, -self.BODY_HEIGHT)] box = self.compute_box(keypoints, calib) if self.check_density_map(density_map, box, self.threshold): yield ViewDescription(c, index, box, origin='random', density_map=density_map) self.fill_density_map(density_map, box) index = index + 1 # Restore random seed np.random.set_state(random_state)
Ancestors
Class variables
var BODY_HEIGHT
var threshold
var with_annotations : bool
var with_detections : bool
var with_occlusions : bool
var with_random : Tuple[int, bool]
Static methods
def fill_density_map(density_map, box)
-
Expand source code
@staticmethod def fill_density_map(density_map, box): density_map[box.y_slice, box.x_slice] += 1
Methods
def check_density_map(self, density_map, box, threshold)
-
Expand source code
def check_density_map(self, density_map, box, threshold): if 0 in density_map[box.y_slice, box.x_slice].shape: return False if np.mean(density_map[box.y_slice, box.x_slice]) <= threshold: return True return False
def sample_density_map(self, density_map)
-
Expand source code
def sample_density_map(self, density_map): # avoid going too close to other detections dilation = cv2.dilate(density_map, np.ones((3,3)), iterations=10) indices_y, indices_x = np.where(dilation == 0) # random choic a position in the image i = np.random.randint(0, len(indices_x)) return np.array([[indices_x[i], indices_y[i]]])
class ComputeDiff (squash=False, inplace=False)
-
Expand source code
class ComputeDiff(Transform): def __init__(self, squash=False, inplace=False): self.squash = squash self.inplace = inplace def __call__(self, view_key: ViewKey, view: View): diff = np.abs(view.image.astype(np.int32) - view.all_images[1].astype(np.int32)).astype(np.uint8) if self.squash: diff = np.mean(diff, axis=2).astype(np.uint8) if self.inplace: view.image = np.dstack((view.image, diff)) else: view.diff = diff return view
Ancestors
class DeepSportDatasetSplitter (validation_pc: int = 15, additional_keys_usage: str = 'skip', folds: str = 'ABCDE')
-
DeepSportDatasetSplitter(validation_pc: int = 15, additional_keys_usage: str = 'skip', folds: str = 'ABCDE')
Expand source code
class DeepSportDatasetSplitter: # pylint: disable=too-few-public-methods validation_pc: int = 15 additional_keys_usage: str = "skip" folds: str = "ABCDE" split = { "A": ['KS-FR-CAEN', 'KS-FR-LIMOGES', 'KS-FR-ROANNE'], "B": ['KS-FR-NANTES', 'KS-FR-BLOIS', 'KS-FR-FOS'], "C": ['KS-FR-LEMANS', 'KS-FR-MONACO', 'KS-FR-STRASBOURG'], "D": ['KS-FR-GRAVELINES', 'KS-FR-STCHAMOND', 'KS-FR-POITIERS'], "E": ['KS-FR-NANCY', 'KS-FR-BOURGEB', 'KS-FR-VICHY'], } def split_keys(self, keys, fold=0): assert 0 <= fold <= len(self.folds)-1, "Invalid fold index" testing_fold = self.folds[fold] testing_keys = [k for k in keys if k.arena_label in self.split[testing_fold]] remaining_arena_labels = [label for f in self.folds.replace(testing_fold, "") for label in self.split[f]] remaining_keys = [k for k in keys if k.arena_label in remaining_arena_labels] # Backup random seed random_state = random.getstate() random.seed(fold) validation_keys = random.sample(remaining_keys, len(remaining_keys)*self.validation_pc//100) training_keys = [k for k in remaining_keys if k not in validation_keys] additional_keys = [k for k in keys if k not in training_keys+validation_keys+testing_keys] if additional_keys: if self.additional_keys_usage == "testing": testing_keys += additional_keys elif self.additional_keys_usage == "training": training_keys += additional_keys elif self.additional_keys_usage == "validation": validation_keys += additional_keys elif self.additional_keys_usage in ["none", "skip"]: pass else: raise ValueError("They are additional arena labels that I don't know what to do with. Please tell me the 'additional_keys_usage' argument") # Restore random seed random.setstate(random_state) return training_keys, validation_keys, testing_keys def __call__(self, dataset, fold=0): keys = list(dataset.keys.all()) training_keys, validation_keys, testing_keys = self.split_keys(keys, fold) return [ Subset(name="training", subset_type=SubsetType.TRAIN, keys=training_keys, dataset=dataset), Subset(name="validation", subset_type=SubsetType.EVAL, keys=validation_keys, dataset=dataset, repetitions=1), Subset(name="testing", subset_type=SubsetType.EVAL, keys=testing_keys, dataset=dataset, repetitions=1), ]
Subclasses
- ArenaLabelFoldsDatasetSplitter
- KFoldsArenaLabelsTestingDatasetSplitter
- OfficialFoldsDatasetSplitter
- SingleArenaDatasetSplitter
Class variables
var additional_keys_usage : str
var folds : str
var split
var validation_pc : int
Methods
def split_keys(self, keys, fold=0)
-
Expand source code
def split_keys(self, keys, fold=0): assert 0 <= fold <= len(self.folds)-1, "Invalid fold index" testing_fold = self.folds[fold] testing_keys = [k for k in keys if k.arena_label in self.split[testing_fold]] remaining_arena_labels = [label for f in self.folds.replace(testing_fold, "") for label in self.split[f]] remaining_keys = [k for k in keys if k.arena_label in remaining_arena_labels] # Backup random seed random_state = random.getstate() random.seed(fold) validation_keys = random.sample(remaining_keys, len(remaining_keys)*self.validation_pc//100) training_keys = [k for k in remaining_keys if k not in validation_keys] additional_keys = [k for k in keys if k not in training_keys+validation_keys+testing_keys] if additional_keys: if self.additional_keys_usage == "testing": testing_keys += additional_keys elif self.additional_keys_usage == "training": training_keys += additional_keys elif self.additional_keys_usage == "validation": validation_keys += additional_keys elif self.additional_keys_usage in ["none", "skip"]: pass else: raise ValueError("They are additional arena labels that I don't know what to do with. Please tell me the 'additional_keys_usage' argument") # Restore random seed random.setstate(random_state) return training_keys, validation_keys, testing_keys
class DownloadFlags (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code
class DownloadFlags(IntFlag): NONE = 0 WITH_IMAGE = 1 WITH_CALIB_FILE = 2 #WITH_FOREGROUND_MASK_FILE = 4 # obsolete WITH_HUMAN_SEGMENTATION_MASKS = 8 WITH_FOLLOWING_IMAGE = 16 WITH_ALL_IMAGES = 32 ALL = -1
Ancestors
- enum.IntFlag
- builtins.int
- enum.Flag
- enum.Enum
Class variables
var ALL
var NONE
var WITH_ALL_IMAGES
var WITH_CALIB_FILE
var WITH_FOLLOWING_IMAGE
var WITH_HUMAN_SEGMENTATION_MASKS
var WITH_IMAGE
class GameGammaColorTransform (transform_dict)
-
Expand source code
class GameGammaColorTransform(Transform): def __init__(self, transform_dict): assert all([isinstance(k, int) for k in transform_dict.keys()]) #29582 : [1.04, 1.02, 0.93], #24651 : [1.05, 1.02, 0.92], #30046 : [1.01, 1.01, 1.01] self.transform_dict = transform_dict def __call__(self, view_key, view): if view_key.instant_key.game_id in self.transform_dict.keys(): gammas = np.array(self.transform_dict[view_key.instant_key.game_id]) view.image = gamma_correction(view.image, gammas) return view
Ancestors
class GameRGBColorTransform (transform_dict)
-
Expand source code
class GameRGBColorTransform(Transform): def __init__(self, transform_dict): assert all([isinstance(k, int) for k in transform_dict.keys()]) self.transform_dict = transform_dict def __call__(self, view_key: ViewKey, view: View): if view_key.instant_key.game_id in self.transform_dict.keys(): adaptation_vector = np.array(self.transform_dict[view_key.instant_key.game_id]) view.image = np.clip(view.image.astype(np.float32)*adaptation_vector, 0, 255).astype(np.uint8) return view
Ancestors
class GammaCorrectionTransform (transform_dict=None)
-
Expand source code
class GammaCorrectionTransform(Transform): def __init__(self, transform_dict=None): self.transform_dict = { 29582 : [1.04, 1.02, 0.93], # Gravelines game 24651 : [1.05, 1.02, 0.92], # Gravelines game 69244 : [1.035, 1.025, 0.990], # Gravelines game 59201 : [1.040, 1.030, 0.990], # Gravelines game 30046 : [0.98, 0.98, 0.98], # Strasbourg game # TODO: LAPUA # TODO: ESPOO **(transform_dict if transform_dict is not None else {}) } # transform_dict is a dict of game_id, gamma correction triplets assert all([isinstance(k, int) for k in self.transform_dict.keys()]) def __call__(self, instant_key: InstantKey, instant: Instant): if instant_key.game_id in self.transform_dict.keys(): gammas = np.array(self.transform_dict[instant_key.game_id]) for k, image in instant.all_images.items(): instant.all_images[k] = gamma_correction(image, gammas) return instant
Ancestors
class Instant (db_item, dataset_folder, download_flags)
-
Python object describing dataset item.
Important
Attributes that require files to be downloaded (like images) should be decorated with
functools.cached_property
to prevent being read before they get downloaded.Expand source code
class Instant(GenericItem): def __init__(self, db_item, dataset_folder, download_flags): self.dataset_folder = dataset_folder self.download_flags = download_flags self.arena_label = db_item["arena_label"] self.num_cameras = db_item["num_cameras"] self.game_id = db_item["game_id"] self.league_id = db_item["league_id"] self.rule_type = db_item["rule_type"] self.sport = db_item["sport"] self.timestamp = db_item["timestamp"] self.offsets = db_item["offsets"] self.annotation_state = db_item.get("annotation_state", None) self.annotator_id = db_item.get("annotator_id", None) self.annotation_ts = db_item.get("annotation_ts", None) self.annotation_duration = db_item.get("annotation_duration", None) self.annotation_game_state = db_item.get("annotation_game_state", "standard_game") self.annotated_human_masks = db_item.get("annotated_human_masks", False) self.format = db_item["format"] annotation_map = { "player": Player, "ball": Ball } self.annotations = [annotation_map[a['type']](a)for a in (db_item.get('annotations', []) or [])] self.image_source = db_item.get("image_source", "raw") self.court_dim = COURT_DIM[self.rule_type] def __str__(self): return "({}[{:5d}]@{})".format(self.arena_label, self.game_id, self.timestamp) def get_filekey(self, prefix, suffix): return os.path.join(self.arena_label, str(self.game_id), "{}{}{}".format(prefix, self.timestamp, suffix)) @cached_property def calibs(self): return [self.__load_calib(c) for c in range(self.num_cameras)] @cached_property def all_images(self): all_images = {} for c in range(self.num_cameras): for idx, offset in enumerate(self.offsets): if (idx == 0) \ or (idx == 1 and self.download_flags & DownloadFlags.WITH_FOLLOWING_IMAGE) \ or (self.download_flags & DownloadFlags.WITH_ALL_IMAGES): try: all_images[(c,offset)] = self.__load_image(c, offset) except BaseException as e: raise ValueError((self.offsets, self.key)) from e return all_images @property def images(self): return [img for (c, offset), img in self.all_images.items() if offset == 0] @cached_property def human_masks(self): assert self.download_flags & DownloadFlags.WITH_HUMAN_SEGMENTATION_MASKS, \ "Provided flag doesn't contain 'human_masks'. Recreate your dataset with appropriate DownloadFlags" try: filenames = [os.path.join(self.dataset_folder, self.get_filekey("camcourt{}_".format(cam_idx+1), "_humans.png")) for cam_idx in range(self.num_cameras)] return [imageio.imread(filename) for filename in filenames] # imageio handles 16bits images while cv2 doesn't except FileNotFoundError: # If one human_masks file is missing for one camera, no human_masks will be available. # If file is missing because no human appears on that camera, you should upload an empty image to the bucket. return [] def __load_image(self, cam_idx, offset=0): filename = os.path.join(self.dataset_folder, self.get_filekey("camcourt{}_".format(cam_idx+1), "_{}.png".format(offset))) image = cv2.imread(filename) if image is None: raise FileNotFoundError(filename) return cv2.cvtColor(image, cv2.COLOR_BGR2RGB) def __load_calib(self, cam_idx): assert self.download_flags & DownloadFlags.WITH_CALIB_FILE, \ "Provided flag doesn't contain calib files. Recreate your dataset with appropriate DownloadFlags" filename = os.path.join(self.dataset_folder, self.get_filekey("camcourt{}_".format(cam_idx+1), ".json")) return parse_DeepSport_calib(json.load(open(filename, 'r'))['calibration']) def draw(self, i=None, draw_players=True, draw_ball=True, draw_lines=False): if i is None: w, h = self.court_dim image = np.ones((int(h), int(w), 3), np.uint8)*255 R = np.identity(3) C = Point3D(w/2, h/2, -3000) m = w/0.01 # pixel_size (pixels/meters) on 1 centimeter sensor f = 0.009 # focal (meters) R = np.identity(3) calib = Calib(width=w, height=h, T=-R@C[:3], R=R, K=np.array([[f*m, 0, w/2], [0, f*m, h/2], [0, 0, 1]])) else: image = self.images[i].copy() calib = self.calibs[i] if draw_lines: Court(self.rule_type).draw_lines(image, calib) # if fg_detections is not None: # calib = self.calibs[i] if i is not None else None # detections = self.fg_detections[i][fg_detections] if i is not None else \ # itertools.chain(*self.fg_detections) # for det in detections: # v = calib.project_3D_to_2D(det.feet).to_int_tuple() # cv2.circle(image, v[0:2].flatten(), 7, [255, 0, 255], -1) for annotation in self.annotations: if annotation.type == "player" and draw_players: head = calib.project_3D_to_2D(annotation.head).to_int_tuple() hips = calib.project_3D_to_2D(annotation.hips).to_int_tuple() foot1 = calib.project_3D_to_2D(annotation.foot1).to_int_tuple() foot2 = calib.project_3D_to_2D(annotation.foot2).to_int_tuple() if any([kp[0] < 0 or kp[1] > image.shape[1] or kp[1] < 0 or kp[1] > image.shape[0] for kp in [head, hips]]): continue # head tip length = 70 # cm headT3D = length * Point3D(np.cos(annotation.headAngle), np.sin(annotation.headAngle), 0) headT = calib.project_3D_to_2D(annotation.head+headT3D).to_int_tuple() color = [0, 0, 0] color[annotation.team-1] = 255 if i is not None: cv2.line(image, hips, foot1, color, 3) cv2.line(image, hips, foot2, color, 3) cv2.line(image, head, hips, color, 3) else: cv2.circle(image, head, 5, color, -1) cv2.line(image, head, headT, color, 3) elif annotation.type == "ball" and draw_ball: center = tuple(int(x) for x in calib.project_3D_to_2D(annotation.center).to_list()) color = [255, 255, 0] cv2.circle(image, center, 5, color, -1) return image @property def files(self): for i in range(0, int(self.num_cameras)): if self.download_flags & DownloadFlags.WITH_IMAGE: for idx, offset in enumerate(self.offsets): if (self.download_flags & DownloadFlags.WITH_ALL_IMAGES) \ or (self.download_flags & DownloadFlags.WITH_FOLLOWING_IMAGE and idx == 1) \ or (idx == 0): yield self.get_filekey("camcourt{}_".format(i+1), "_{}.png".format(offset)) if self.download_flags & DownloadFlags.WITH_CALIB_FILE: yield self.get_filekey("camcourt{}_".format(i+1), ".json") if self.download_flags & DownloadFlags.WITH_HUMAN_SEGMENTATION_MASKS: yield self.get_filekey("camcourt{}_".format(i+1), "_humans.png") @property def key(self): return InstantKey(self.arena_label, self.game_id, self.timestamp) @property def db_item(self): db_item = { "format": self.format, "image_source": self.image_source, # arena relative infos "arena_label": self.arena_label, "num_cameras": self.num_cameras, # game relative infos "sport": self.sport, "game_id": self.game_id, "league_id": self.league_id, "rule_type": self.rule_type, # instant relative infos "timestamp": self.timestamp, "offsets": self.offsets, "annotation_state": self.annotation_state, "annotations": [a.to_dict() for a in self.annotations], "annotated_human_masks": self.annotated_human_masks } for attr in ["annotation_ts", "annotator_id", "annotation_duration", "annotation_game_state"]: if value := getattr(self, attr, None): db_item[attr] = value return db_item def to_dict(self): return {"db_item": self.db_item, "download_flags": self.download_flags, "dataset_folder": self.dataset_folder}
Ancestors
Instance variables
var all_images
-
Declares a property to be lazy (evaluated only if absent from the object) Also provides a first basic mechanism for a lazy property. Enhanced by Lazy
Expand source code
def __get__(self, instance, ownerclass=None): name = self.name value = instance.__dict__.get(name, _NOVALUE) if value is _NOVALUE: try: value = self.initializer(instance) except AttributeError as e: raise LazyPropertyError(name) from e instance.__dict__[name] = value return value
var calibs
-
Declares a property to be lazy (evaluated only if absent from the object) Also provides a first basic mechanism for a lazy property. Enhanced by Lazy
Expand source code
def __get__(self, instance, ownerclass=None): name = self.name value = instance.__dict__.get(name, _NOVALUE) if value is _NOVALUE: try: value = self.initializer(instance) except AttributeError as e: raise LazyPropertyError(name) from e instance.__dict__[name] = value return value
var human_masks
-
Declares a property to be lazy (evaluated only if absent from the object) Also provides a first basic mechanism for a lazy property. Enhanced by Lazy
Expand source code
def __get__(self, instance, ownerclass=None): name = self.name value = instance.__dict__.get(name, _NOVALUE) if value is _NOVALUE: try: value = self.initializer(instance) except AttributeError as e: raise LazyPropertyError(name) from e instance.__dict__[name] = value return value
var images
-
Expand source code
@property def images(self): return [img for (c, offset), img in self.all_images.items() if offset == 0]
Methods
def draw(self, i=None, draw_players=True, draw_ball=True, draw_lines=False)
-
Expand source code
def draw(self, i=None, draw_players=True, draw_ball=True, draw_lines=False): if i is None: w, h = self.court_dim image = np.ones((int(h), int(w), 3), np.uint8)*255 R = np.identity(3) C = Point3D(w/2, h/2, -3000) m = w/0.01 # pixel_size (pixels/meters) on 1 centimeter sensor f = 0.009 # focal (meters) R = np.identity(3) calib = Calib(width=w, height=h, T=-R@C[:3], R=R, K=np.array([[f*m, 0, w/2], [0, f*m, h/2], [0, 0, 1]])) else: image = self.images[i].copy() calib = self.calibs[i] if draw_lines: Court(self.rule_type).draw_lines(image, calib) # if fg_detections is not None: # calib = self.calibs[i] if i is not None else None # detections = self.fg_detections[i][fg_detections] if i is not None else \ # itertools.chain(*self.fg_detections) # for det in detections: # v = calib.project_3D_to_2D(det.feet).to_int_tuple() # cv2.circle(image, v[0:2].flatten(), 7, [255, 0, 255], -1) for annotation in self.annotations: if annotation.type == "player" and draw_players: head = calib.project_3D_to_2D(annotation.head).to_int_tuple() hips = calib.project_3D_to_2D(annotation.hips).to_int_tuple() foot1 = calib.project_3D_to_2D(annotation.foot1).to_int_tuple() foot2 = calib.project_3D_to_2D(annotation.foot2).to_int_tuple() if any([kp[0] < 0 or kp[1] > image.shape[1] or kp[1] < 0 or kp[1] > image.shape[0] for kp in [head, hips]]): continue # head tip length = 70 # cm headT3D = length * Point3D(np.cos(annotation.headAngle), np.sin(annotation.headAngle), 0) headT = calib.project_3D_to_2D(annotation.head+headT3D).to_int_tuple() color = [0, 0, 0] color[annotation.team-1] = 255 if i is not None: cv2.line(image, hips, foot1, color, 3) cv2.line(image, hips, foot2, color, 3) cv2.line(image, head, hips, color, 3) else: cv2.circle(image, head, 5, color, -1) cv2.line(image, head, headT, color, 3) elif annotation.type == "ball" and draw_ball: center = tuple(int(x) for x in calib.project_3D_to_2D(annotation.center).to_list()) color = [255, 255, 0] cv2.circle(image, center, 5, color, -1) return image
def get_filekey(self, prefix, suffix)
-
Expand source code
def get_filekey(self, prefix, suffix): return os.path.join(self.arena_label, str(self.game_id), "{}{}{}".format(prefix, self.timestamp, suffix))
def to_dict(self)
-
Expand source code
def to_dict(self): return {"db_item": self.db_item, "download_flags": self.download_flags, "dataset_folder": self.dataset_folder}
Inherited members
class InstantKey (arena_label: str, game_id: int, timestamp: int)
-
InstantKey(arena_label, game_id, timestamp)
Expand source code
class InstantKey(NamedTuple): arena_label: str game_id: int timestamp: int
Ancestors
- builtins.tuple
Instance variables
var arena_label : str
-
Alias for field number 0
var game_id : int
-
Alias for field number 1
var timestamp : int
-
Alias for field number 2
class KFoldsArenaLabelsTestingDatasetSplitter (fold_count=8, validation_pc=15)
-
DeepSportDatasetSplitter(validation_pc: int = 15, additional_keys_usage: str = 'skip', folds: str = 'ABCDE')
Expand source code
class KFoldsArenaLabelsTestingDatasetSplitter(DeepSportDatasetSplitter): def __init__(self, fold_count=8, validation_pc=15): self.fold_count = fold_count self.validation_pc = validation_pc def __call__(self, dataset, fold=0): keys = list(dataset.keys.all()) assert fold >= 0 and fold < self.fold_count keys_dict = count_keys_per_arena_label(keys) keys_lists = split_equally(keys_dict, self.fold_count) testing_keys = [k for k in keys if k.arena_label in keys_lists[fold]] remaining_keys = [k for k in keys if k not in testing_keys] # Backup random seed random_state = random.getstate() random.seed(fold) validation_keys = random.sample(remaining_keys, len(keys)*self.validation_pc//100) # Restore random seed random.setstate(random_state) training_keys = [k for k in remaining_keys if k not in validation_keys] return [ Subset(name="training", subset_type=SubsetType.TRAIN, keys=training_keys, dataset=dataset), Subset(name="validation", subset_type=SubsetType.EVAL, keys=validation_keys, dataset=dataset, repetitions=5), Subset(name="testing", subset_type=SubsetType.EVAL, keys=testing_keys, dataset=dataset, repetitions=5), ]
Ancestors
Class variables
var additional_keys_usage : str
var folds : str
var validation_pc : int
class Player (data)
-
Expand source code
class Player(): def __init__(self, data): self.type = "player" self.origin = data.get('origin', "annotation") self.team = data['team'] self.head = Point3D(*data['head']) self.hips = Point3D(*data['hips']) self.foot1 = Point3D(*data['foot1']) self.foot2 = Point3D(*data['foot2']) self.foot1_at_the_ground = str(data["foot1_at_the_ground"]).lower() == "true" self.foot2_at_the_ground = str(data["foot2_at_the_ground"]).lower() == "true" self.headAngle = data['headOrientation'] self.camera = data['image'] self.hipsAngle = data.get('hipsOrientation', self.headAngle) self.feet = (self.foot1 + self.foot2) / 2 def to_dict(self): return { "type": self.type, "origin": self.origin, "team": self.team, "head": self.head.to_list(), "headOrientation": self.headAngle, "hips": self.hips.to_list(), "foot1": self.foot1.to_list(), "foot2": self.foot2.to_list(), "foot1_at_the_ground": self.foot1_at_the_ground, "foot2_at_the_ground": self.foot2_at_the_ground, "image": self.camera }
Methods
def to_dict(self)
-
Expand source code
def to_dict(self): return { "type": self.type, "origin": self.origin, "team": self.team, "head": self.head.to_list(), "headOrientation": self.headAngle, "hips": self.hips.to_list(), "foot1": self.foot1.to_list(), "foot2": self.foot2.to_list(), "foot1_at_the_ground": self.foot1_at_the_ground, "foot2_at_the_ground": self.foot2_at_the_ground, "image": self.camera }
class TestingArenaLabelsDatasetSplitter (testing_arena_labels, validation_pc=15)
-
Expand source code
class TestingArenaLabelsDatasetSplitter(): def __init__(self, testing_arena_labels, validation_pc=15): self.testing_arena_labels = testing_arena_labels self.validation_pc = validation_pc assert isinstance(self.testing_arena_labels, list) def __call__(self, dataset, fold=0): keys = list(dataset.keys.all()) testing_keys = [k for k in keys if k.arena_label in self.testing_arena_labels] remaining_keys = [k for k in keys if k not in testing_keys] # Backup random seed random_state = random.getstate() random.seed(fold) validation_keys = random.sample(remaining_keys, len(keys)*self.validation_pc//100) if self.validation_pc else [] # Restore random seed random.setstate(random_state) training_keys = [k for k in remaining_keys if k not in validation_keys] subsets = [ Subset(name="training", subset_type=SubsetType.TRAIN, keys=training_keys, dataset=dataset), Subset(name="validation", subset_type=SubsetType.EVAL, keys=validation_keys, dataset=dataset, repetitions=2), Subset(name="testing", subset_type=SubsetType.EVAL, keys=testing_keys, dataset=dataset, repetitions=2), ] return [s for s in subsets if len(s.keys) > 0]
class UndistortTransform
-
Expand source code
class UndistortTransform(Transform): def __call__(self, key, view): all_images = [] for image in view.all_images: all_images.append(cv2.undistort(image, view.calib.K, view.calib.kc)) view.calib = view.calib.update(kc=np.array([0,0,0,0,0])) return view
Ancestors
class View (all_images, calib, annotations=None, **kwargs)
-
Expand source code
class View(): def __init__(self, all_images, calib, annotations=None, **kwargs): self.image = all_images[0] self.all_images = all_images self.calib = calib self.annotations = annotations for k, v in kwargs.items(): setattr(self, k, v) def draw(self): image = self.image.copy() coord_2D_int = lambda x: self.calib.project_3D_to_2D(x).to_int_tuple() for annotation in self.annotations: if annotation.type == "player": head = annotation.head hips = annotation.hips foot1 = annotation.foot1 foot2 = annotation.foot2 color = [0, 0, 0] color[annotation.team-1] = 255 cv2.line(image, coord_2D_int(head), coord_2D_int(hips), color, 3) cv2.line(image, coord_2D_int(hips), coord_2D_int(foot1), color, 3) cv2.line(image, coord_2D_int(hips), coord_2D_int(foot2), color, 3) elif annotation.type == "ball": ball = annotation.center color = [255, 255, 0] cv2.circle(image, coord_2D_int(ball), 5, color, -1) return image
Methods
def draw(self)
-
Expand source code
def draw(self): image = self.image.copy() coord_2D_int = lambda x: self.calib.project_3D_to_2D(x).to_int_tuple() for annotation in self.annotations: if annotation.type == "player": head = annotation.head hips = annotation.hips foot1 = annotation.foot1 foot2 = annotation.foot2 color = [0, 0, 0] color[annotation.team-1] = 255 cv2.line(image, coord_2D_int(head), coord_2D_int(hips), color, 3) cv2.line(image, coord_2D_int(hips), coord_2D_int(foot1), color, 3) cv2.line(image, coord_2D_int(hips), coord_2D_int(foot2), color, 3) elif annotation.type == "ball": ball = annotation.center color = [255, 255, 0] cv2.circle(image, coord_2D_int(ball), 5, color, -1) return image
class ViewKey (instant_key: InstantKey, camera: int, index: int)
-
ViewKey(instant_key, camera, index)
Expand source code
class ViewKey(NamedTuple): instant_key: InstantKey camera: int index: int @property def arena_label(self): return self.instant_key.arena_label @property def timestamp(self): return self.instant_key.timestamp @property def game_id(self): return self.instant_key.game_id
Ancestors
- builtins.tuple
Instance variables
var arena_label
-
Expand source code
@property def arena_label(self): return self.instant_key.arena_label
var camera : int
-
Alias for field number 1
var game_id
-
Expand source code
@property def game_id(self): return self.instant_key.game_id
var index : int
-
Alias for field number 2
var instant_key : InstantKey
-
Alias for field number 0
var timestamp
-
Expand source code
@property def timestamp(self): return self.instant_key.timestamp
class ViewRandomCropperTransform (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
andsize_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
andsize_max
are ignored and no random scaling is applied. size_max: (int) upper bound of keypoints random size. If0
size_min
andsize_max
are ignored and no random scaling is applied. max_angle: (degrees) positive and negative bounds for random rotation do_flip: (bool) tells if random flip should be applied padding: (px) amount of padding margin: (px) minimum margin 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.Expand source code
class ViewRandomCropperTransform(RandomCropperTransform): def _apply_transformation(self, view, A): if self.debug: w, h = self.output_shape points = Point2D(np.linalg.inv(A)@Point2D([0,0,w,w],[0,h,h,0]).H) cv2.polylines(view.image, [points.T.astype(np.int32)], True, (255,0,0), self.linewidth) else: view.image = cv2.warpAffine(view.image, A[0:2,:], self.output_shape, flags=cv2.INTER_LINEAR) view.calib = view.calib.update(K=A@view.calib.K, width=self.output_shape[0], height=self.output_shape[1]) if hasattr(view, "all_images"): for i in range(1, len(view.all_images)): # skip first image as it was already done view.all_images[i] = cv2.warpAffine(view.all_images[i], A[0:2,:], self.output_shape, flags=cv2.INTER_LINEAR) if hasattr(view, "human_masks") and view.human_masks is not None: view.human_masks = cv2.warpAffine(view.human_masks, A[0:2,:], self.output_shape, flags=cv2.INTER_NEAREST) return view
Ancestors
Subclasses
- BallCropperTransform
- CleverViewRandomCropperTransform
- NaiveViewRandomCropperTransform
- PlayerViewRandomCropperTransform
Inherited members
class ViewsDataset (instants_dataset: InstantsDataset, view_builder: ViewBuilder, output_shape=None, rescale=True, crop=True)
-
Dataset of views built according the given ViewBuilder, extracted from the given InstantDataset.
Arguments
instants_dataset - the InstantDataset from which views are built view_builder - the ViewBuilder dictating what type of view is to be created output_shape - view aspect ratio (or exact dimension if 'rescale' is given) rescale - tells whether the view should be rescaled to output_shape size crop - tells whether the original image should be cropped or a rectangle should be drawn instead (for debug purposes)
Expand source code
class ViewsDataset(AugmentedDataset): """ Dataset of views built according the given ViewBuilder, extracted from the given InstantDataset. Arguments: instants_dataset - the InstantDataset from which views are built view_builder - the ViewBuilder dictating what type of view is to be created output_shape - view aspect ratio (or exact dimension if 'rescale' is given) rescale - tells whether the view should be rescaled to output_shape size crop - tells whether the original image should be cropped or a rectangle should be drawn instead (for debug purposes) """ def __init__(self, instants_dataset: InstantsDataset, view_builder: ViewBuilder, output_shape=None, rescale=True, crop=True): super().__init__(instants_dataset) self.view_builder = view_builder self.output_shape = output_shape self.rescale = rescale self.crop = crop def _crop_view(self, view_description: ViewDescription, instant: Instant, **kwargs): padding = self.view_builder.padding c = view_description.camera input_height, input_width, _ = instant.images[c].shape aspect_ratio = self.output_shape[0]/self.output_shape[1] if self.output_shape else None x_slice, y_slice = view_description.box.increase_box( max_width=input_width, max_height=input_height, aspect_ratio=aspect_ratio, padding=self.view_builder.padding ) all_images = [] if self.crop: for offset in instant.offsets: index = (c,offset) if index not in instant.all_images: continue # that offset was not downloaded with the download flag of instants dataset image = crop_padded(instant.all_images[index], x_slice, y_slice, padding) if self.rescale and self.output_shape: image = cv2.resize(image, self.output_shape) all_images.append(image) calib = instant.calibs[c].crop(x_slice, y_slice) # handles negative `slice.start` positions if self.rescale and self.output_shape: calib = calib.scale(*self.output_shape) if instant.download_flags & DownloadFlags.WITH_HUMAN_SEGMENTATION_MASKS and instant.human_masks: human_masks = crop_padded(instant.human_masks[c], x_slice, y_slice, padding) if self.rescale and self.output_shape: human_masks = cv2.resize(human_masks, self.output_shape) else: human_masks = None else: for offset in instant.offsets: # the coordinates of the rectangle below are probably wrong see documentation of cv2.rectangle raise NotImplementedError("TODO: check rectangle coordinates") image = cv2.rectangle(instant.all_images[(c, offset)], (x_slice.start, x_slice.stop), (y_slice.start, y_slice.stop), (255,0,0), 10) all_images.append(image) calib = instant.calibs[c] human_masks = instant.human_masks[c] return View(all_images, calib, instant.annotations, rule_type=instant.rule_type, human_masks=human_masks, **kwargs) def augment(self, instant_key: InstantKey, instant: Instant): random_state = np.random.get_state() np.random.seed(instant_key.timestamp & 0xFFFFFFFF) for view_description in self.view_builder(instant_key, instant): view_key = ViewKey(instant_key, view_description.camera, view_description.index) yield view_key, self._crop_view(view_description, instant, **view_description.data) # required to keep the random seed random np.random.set_state(random_state)
Ancestors
- mlworkflow.datasets.AugmentedDataset
- mlworkflow.datasets.Dataset
Methods
def augment(self, instant_key: InstantKey, instant: Instant)
-
Expand source code
def augment(self, instant_key: InstantKey, instant: Instant): random_state = np.random.get_state() np.random.seed(instant_key.timestamp & 0xFFFFFFFF) for view_description in self.view_builder(instant_key, instant): view_key = ViewKey(instant_key, view_description.camera, view_description.index) yield view_key, self._crop_view(view_description, instant, **view_description.data) # required to keep the random seed random np.random.set_state(random_state)