deepvisiontools 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. deepvisiontools/__init__.py +16 -0
  2. deepvisiontools/config/__init__.py +3 -0
  3. deepvisiontools/config/config.py +176 -0
  4. deepvisiontools/config/errors.py +12 -0
  5. deepvisiontools/data/__init__.py +24 -0
  6. deepvisiontools/data/additional_augmentations.py +201 -0
  7. deepvisiontools/data/augmentation_class.py +37 -0
  8. deepvisiontools/data/batch_augmentations.py +211 -0
  9. deepvisiontools/data/data_reader/__init__.py +3 -0
  10. deepvisiontools/data/data_reader/readers.py +490 -0
  11. deepvisiontools/data/dataset.py +357 -0
  12. deepvisiontools/data/errors.py +23 -0
  13. deepvisiontools/formats/__init__.py +46 -0
  14. deepvisiontools/formats/base_data.py +802 -0
  15. deepvisiontools/formats/base_formats.py +321 -0
  16. deepvisiontools/formats/errors.py +167 -0
  17. deepvisiontools/formats/formats.py +282 -0
  18. deepvisiontools/formats/utils.py +174 -0
  19. deepvisiontools/inference/__init__.py +4 -0
  20. deepvisiontools/inference/patchifier.py +343 -0
  21. deepvisiontools/inference/predictor.py +208 -0
  22. deepvisiontools/metrics/__init__.py +50 -0
  23. deepvisiontools/metrics/available_metrics.py +215 -0
  24. deepvisiontools/metrics/base_metric.py +436 -0
  25. deepvisiontools/metrics/func.py +34 -0
  26. deepvisiontools/metrics/matcher.py +99 -0
  27. deepvisiontools/metrics/utils.py +39 -0
  28. deepvisiontools/models/__init__.py +14 -0
  29. deepvisiontools/models/basemodel.py +100 -0
  30. deepvisiontools/models/mask2former/__init__.py +3 -0
  31. deepvisiontools/models/mask2former/mask2former.py +285 -0
  32. deepvisiontools/models/smp/__init__.py +0 -0
  33. deepvisiontools/models/smp/errors.py +4 -0
  34. deepvisiontools/models/smp/smp.py +149 -0
  35. deepvisiontools/models/yolov8/__init__.py +15 -0
  36. deepvisiontools/models/yolov8/errors.py +25 -0
  37. deepvisiontools/models/yolov8/utils.py +92 -0
  38. deepvisiontools/models/yolov8/yolov8.py +302 -0
  39. deepvisiontools/models/yolov8seg/__init__.py +4 -0
  40. deepvisiontools/models/yolov8seg/errors.py +14 -0
  41. deepvisiontools/models/yolov8seg/utils.py +135 -0
  42. deepvisiontools/models/yolov8seg/yolov8seg.py +370 -0
  43. deepvisiontools/preprocessing/__init__.py +19 -0
  44. deepvisiontools/preprocessing/image.py +79 -0
  45. deepvisiontools/preprocessing/preprocessing.py +65 -0
  46. deepvisiontools/train/__init__.py +3 -0
  47. deepvisiontools/train/trainer.py +335 -0
  48. deepvisiontools/utils/__init__.py +3 -0
  49. deepvisiontools/utils/errors.py +0 -0
  50. deepvisiontools/utils/visualization.py +318 -0
  51. deepvisiontools-0.0.1.dist-info/LICENSE.txt +661 -0
  52. deepvisiontools-0.0.1.dist-info/METADATA +725 -0
  53. deepvisiontools-0.0.1.dist-info/RECORD +55 -0
  54. deepvisiontools-0.0.1.dist-info/WHEEL +5 -0
  55. deepvisiontools-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,16 @@
1
+ from deepvisiontools.config.config import Configuration
2
+ from deepvisiontools.train.trainer import Trainer
3
+ from deepvisiontools.data.dataset import DeepVisionDataset, DeepVisionLoader
4
+ from deepvisiontools.utils import visualization
5
+ from deepvisiontools.inference.predictor import Predictor
6
+
7
+ __version__ = "0.0.1"
8
+
9
+ __all__ = (
10
+ Configuration,
11
+ Trainer,
12
+ DeepVisionDataset,
13
+ DeepVisionLoader,
14
+ visualization,
15
+ Predictor,
16
+ )
@@ -0,0 +1,3 @@
1
+ from deepvisiontools.config.config import Configuration
2
+
3
+ __all__ = ["Configuration"]
@@ -0,0 +1,176 @@
1
+ from typing import Literal, Union
2
+ import deepvisiontools.config.errors as er
3
+ import numpy as np
4
+ import torch
5
+ import random as rd
6
+
7
+
8
+ class _SingletonConfig(type):
9
+ """Metaclass for Config class Singleton design pattern"""
10
+
11
+ _instance = None
12
+
13
+ def __call__(cls, *args, **kwargs):
14
+ if not isinstance(cls._instance, cls):
15
+ cls._instance = super().__call__(*args, **kwargs)
16
+ return cls._instance
17
+
18
+
19
+ class Configuration(metaclass=_SingletonConfig):
20
+ """Configuration class for deepvisiontools (Singleton -> can be instancied once and then point to same object). Store all configuration information about the library configuration.
21
+ If you wish to changes parameters later on, you can simply modify the corresponding attributes.
22
+
23
+
24
+ Args:
25
+ device (``Literal["cpu", "cuda"]``, **optional**): Device to be used by default when creating objects, running models etc. Defaults to "cpu".
26
+ data_type (``Literal["instance_mask", "bbox", "keypoint", "semantic_mask"]``, **optional**): Default format to use in dataset, models, prediction etc. Defaults to "bbox".
27
+ num_classes (``int``, **optional**): Number of classes in model. Defaults to 1.
28
+ mask_min_size (``int``, **optional**): Minimal size of mask to be considered : below this threshold annotation will be ignored. Defaults to 15.
29
+ semantic_mask_logits_combination (``Literal["avg", "min", "max"]``): How to combine logits in patchification or adding semantic masks. avg takes the mean, min takes the minimum and max takes the maximum.
30
+ splitted_mask_handling (``bool``, **optional**): If set to True redefine masks that are splitted (after cropping for example) so they belong to independant objects. Defaults to False.
31
+ model_nms_threshold (``float``, **optional**): Default nms iou threshold used in models. Defaults to 0.45.
32
+ model_confidence_threshold (``float``, **optional**): Default model confidence threshold to consider it a valid object prediction. Defaults to 0.5.
33
+ model_max_detection (``int``, **optional**): Maximum number of objects outputed by a model (useful for some models such as yolo type models). Defaults to 300.
34
+ metrics_matcher_type (``Literal["bbox", "instance_mask"]``, **optional**): Object matcher data type used in metrics (note that instance_mask is slower because needs transition to cpu to save gpu memory). If data_type is instance mask and matcher type is bbox will convert it to bbox for matching in metrics. Defaults to "bbox".
35
+ metrics_match_iou_threshold (``float``, **optional**): Metrics matcher iou threshold. Defaults to 0.45.
36
+ patchifier_mode (``Literal["bbox", "instance_mask"]``, **optional**): Patchifier data type used for nms and duplicate supresser. If data_type is mask and patchifier to bbox will convert for according operations. Defaults to "bbox".
37
+ seed (``Union[False, int]``, **optional**): use a manual seed to enforce reproducibility (you probably want to also switch deterministic to True in that case). If False it ends reproducibility. Defaults to False.
38
+ deterministic (``bool``, **optional**): Use deterministic algorithms. Helps further reproducibility (see also seeds). Be careful : some models can't be deterministic so sometimes you need to switch it to False even if you are manually seeding. Defaults to False.
39
+
40
+
41
+ Example:
42
+ ----------
43
+
44
+ .. highlight:: python
45
+ .. code-block:: python
46
+
47
+ >>> from deepvisiontools import Configuration()
48
+ >>> config = Configuration(data_type = "instance_mask") # can instantiate with given parameter
49
+ >>> config.device = "cuda" # can modify parameters by modifying attributes / properties
50
+
51
+
52
+ Attributes
53
+ ----------
54
+
55
+ Attributes:
56
+ - data_type (``Literal["instance_mask", "bbox", "keypoint", "semantic_mask"]``, **optional**): Default format to use in dataset, models, prediction etc. Defaults to "bbox".
57
+ - num_classes (``int``): Number of classes in model. Defaults to 1.
58
+ - mask_min_size (``int``): Minimal size of mask to be considered : below this threshold annotation will be ignored. Defaults to 15.
59
+ - semantic_mask_logits_combination (``Literal["avg", "min", "max"]``): How to combine logits in patchification or adding semantic masks. avg takes the mean, min takes the minimum and max takes the maximum.
60
+ - splitted_mask_handling (``bool``): If set to True redefine masks that are splitted (after cropping for example) so they belong to independant objects. Defaults to False.
61
+ - model_nms_threshold (``float``): Default nms iou threshold used in models. Defaults to 0.45.
62
+ - model_confidence_threshold (``float``): Default model confidence threshold to consider it a valid object prediction. Defaults to 0.5.
63
+ - model_max_detection (``int``): Maximum number of objects outputed by a model (useful for some models such as yolo type models). Defaults to 300.
64
+ - metrics_matcher_type (``Literal["bbox", "instance_mask"]``): Object matcher data type used in metrics. If data_type is instance mask and matcher type is bbox will convert it to bbox for matching in metrics. Defaults to "bbox".
65
+ - metrics_match_iou_threshold (``float``): Metrics matcher iou threshold. Defaults to 0.45.
66
+ - patchifier_mode (``Literal["bbox", "instance_mask"]``): Patchifier data type used for nms and duplicate supresser. If data_type is mask and patchifier to bbox will convert for according operations. Defaults to "bbox".
67
+
68
+
69
+ Attributes
70
+ ----------
71
+
72
+ Properties:
73
+ - device (``Literal["cpu", "cuda"]``): Device to be used by default when creating objects, running models etc. Defaults to "cpu".
74
+ - seed (``Union[False, int]``, **optional**): use a manual seed to enforce reproducibility (you probably want to also switch deterministic to True in that case). If False it ends reproducibility. Defaults to False.
75
+ - deterministic (``bool``, **optional**): Use deterministic algorithms. Helps further reproducibility (see also seeds). Be careful : some models can't be deterministic so sometimes you need to switch it to False even if you are manually seeding. Defaults to False.
76
+
77
+
78
+
79
+ Notes:
80
+ 1) If you use instance_mask, bbox will included when needed from the masks.
81
+ 2) you can change model_nms_threshold and model_confidence_threshold for the entire lib by modifying the attributes
82
+ 3) In instance mode, by default the target ``Format`` remove small objects in case their masks contains less than min_mask_threshold (default 5 pixels).
83
+ Change the attribute to modify this behaviour.
84
+ 4) The option splitted_mask_handling is by default False.
85
+ If you set to True, when performing transformation on object mask that split it into discontinuous sub-masks the library creates new objects for every sub-masks.
86
+ Otherwise they will still be describing the same unique object
87
+
88
+ """
89
+
90
+ def __init__(
91
+ self,
92
+ device: Literal["cpu", "cuda"] = "cpu",
93
+ data_type: Literal[
94
+ "instance_mask", "bbox", "keypoint", "semantic_mask"
95
+ ] = "bbox",
96
+ num_classes: int = 1,
97
+ mask_min_size: int = 20,
98
+ semantic_mask_logits_combination: Literal["avg", "min", "max"] = "avg",
99
+ splitted_mask_handling: bool = False,
100
+ model_nms_threshold: float = 0.45,
101
+ model_confidence_threshold: float = 0.5,
102
+ model_max_detection: int = 300,
103
+ metrics_matcher_type: Literal["bbox", "instance_mask"] = "bbox",
104
+ metrics_match_iou_threshold: float = 0.45,
105
+ patchifier_mode: Literal["bbox", "instance_mask"] = "bbox",
106
+ seed: Union[False, int] = False,
107
+ deterministic: bool = False,
108
+ ):
109
+
110
+ # generic
111
+ self.data_type = data_type
112
+ self.device: str = device
113
+ self.num_classes: int = num_classes
114
+ # Format specific parameters
115
+ self.mask_min_size = mask_min_size
116
+ self.splitted_mask_handling = splitted_mask_handling
117
+ self.semantic_mask_logits_combination = semantic_mask_logits_combination
118
+ # Model build_results parameters
119
+ self.model_nms_threshold = model_nms_threshold
120
+ self.model_confidence_threshold = model_confidence_threshold
121
+ self.model_max_detection = model_max_detection
122
+ # metrics params
123
+ self.metrics_matcher_type = metrics_matcher_type
124
+ self.metrics_match_iou_threshold = metrics_match_iou_threshold
125
+ # patchifier setup
126
+ self.patchifier_mode = patchifier_mode
127
+ # reproducibility
128
+ self.seed = seed
129
+ self.deterministic = deterministic
130
+
131
+ @property
132
+ def device(self):
133
+ return self._device
134
+
135
+ @device.setter
136
+ def device(self, val: Literal["cpu", "cuda"]):
137
+ er.check_device_availability(val)
138
+ self._device = val
139
+
140
+ @property
141
+ def seed(self):
142
+ return self._seed
143
+
144
+ @seed.setter
145
+ def seed(self, val: Union[False, int]):
146
+ assert val == False or isinstance(
147
+ val, int
148
+ ), f"seed must be a int or False. Got {val}"
149
+ if val:
150
+ rd.seed(val)
151
+ np.random.seed(val)
152
+ torch.manual_seed(val)
153
+ else:
154
+ rd.seed()
155
+ np.random.seed()
156
+ torch.seed()
157
+ self._seed = val
158
+
159
+ @property
160
+ def deterministic(self):
161
+ return self.deterministic
162
+
163
+ @deterministic.setter
164
+ def deterministic(self, val: bool):
165
+ assert isinstance(val, bool), f"deterministic must be a bool, got {val}"
166
+ if val:
167
+ torch.use_deterministic_algorithms(True)
168
+ # disable convolutions benchmark
169
+ if torch.cuda.is_available():
170
+ torch.backends.cudnn.benchmark = False
171
+ else:
172
+ torch.use_deterministic_algorithms(False)
173
+ # disable convolutions benchmark
174
+ if torch.cuda.is_available():
175
+ torch.backends.cudnn.benchmark = True
176
+ self._deterministic = val
@@ -0,0 +1,12 @@
1
+ import torch
2
+
3
+
4
+ def check_device_availability(device):
5
+ assert (
6
+ device == "cpu" or device == "cuda"
7
+ ), f"{device} is not a valid device, must be: cuda or: cpu"
8
+ if device != "cpu":
9
+ assert (
10
+ torch.cuda.is_available()
11
+ ), "CUDA seems unavailable. Please run torch.cuda.is_available() to verify"
12
+ pass
@@ -0,0 +1,24 @@
1
+ from deepvisiontools.data.dataset import DeepVisionDataset, DeepVisionLoader
2
+ from deepvisiontools.data.augmentation_class import Augmentation
3
+ from deepvisiontools.data.additional_augmentations import (
4
+ RandomCropAndResize,
5
+ RandomCenterCropAndResize,
6
+ RandomChangeBackground,
7
+ RandomPadAndResize,
8
+ )
9
+ from deepvisiontools.data.batch_augmentations import (
10
+ AbstractBatchAugmenter,
11
+ MosaicBatchAugmenter,
12
+ )
13
+
14
+ __all__ = (
15
+ "DeepVisionDataset",
16
+ "DeepVisionLoader",
17
+ "Augmentation",
18
+ "RandomCropAndResize",
19
+ "RandomPadAndResize",
20
+ "RandomChangeBackground",
21
+ "RandomCenterCropAndResize",
22
+ "AbstractBatchAugmenter",
23
+ "MosaicBatchAugmenter",
24
+ )
@@ -0,0 +1,201 @@
1
+ import torch
2
+ import torchvision.transforms.v2 as T
3
+ from torchvision.transforms.v2 import Transform
4
+ from typing import Sequence, Union, Tuple
5
+ import random as rd
6
+ from pathlib import Path
7
+ from deepvisiontools.preprocessing.image import load_image
8
+ from torchvision.tv_tensors import BoundingBoxes, Mask
9
+ from torch import Tensor
10
+ import copy
11
+
12
+
13
+ class RandomCropAndResize(Transform):
14
+ """
15
+ With a given probability, apply RandomCrop and Resize from torchvision.transforms.v2.
16
+ NB : here we resize only and systematically if cropped.
17
+
18
+ Args:
19
+ crop (``Union[int, Sequence[int]]``): Size to crop
20
+ resize (``Union[int, Sequence[int]]``): Size to resize
21
+ p (``float``, **optional**): probability. Defaults to 0.5.
22
+
23
+
24
+ **Methods**:
25
+ """
26
+
27
+ def __init__(
28
+ self,
29
+ crop: Union[int, Sequence[int]],
30
+ resize: Union[int, Sequence[int]],
31
+ p=0.5,
32
+ **kwargs,
33
+ ):
34
+
35
+ super().__init__(**kwargs)
36
+ self.p = p
37
+ self.crop = T.RandomCrop(crop)
38
+ self.resize = T.Resize(resize)
39
+
40
+ def forward(self, *inputs):
41
+ if torch.rand(1) >= self.p:
42
+ pass
43
+ else:
44
+ inputs = self.crop.forward(inputs)
45
+ inputs = self.resize.forward(inputs)
46
+ return inputs
47
+
48
+
49
+ class RandomCenterCropAndResize(Transform):
50
+ """
51
+ With a given probability, apply CenterCrop and Resize from torchvision.transforms.v2.
52
+ NB : here we resize only and systematically if cropped.
53
+
54
+ Args:
55
+ crop (``Union[int, Sequence[int]]``): Size to crop
56
+ resize (``Union[int, Sequence[int]]``): Size to resize
57
+ p (``float``, **optional**): probability. Defaults to 0.5.
58
+ """
59
+
60
+ def __init__(self, crop: Sequence[int], resize: Sequence[int], p=0.5, **kwargs):
61
+ super().__init__(**kwargs)
62
+ self.p = p
63
+ self.crop = T.CenterCrop(crop)
64
+ self.resize = T.Resize(resize)
65
+
66
+ def forward(self, *inputs):
67
+ if torch.rand(1) >= self.p:
68
+ pass
69
+ else:
70
+ inputs = self.crop.forward(inputs)
71
+ inputs = self.resize.forward(inputs)
72
+ return inputs
73
+
74
+
75
+ class RandomPadAndResize(Transform):
76
+ """
77
+ With a given probability, apply Pad and Resize from torchvision.transforms.v2. This looks like a zoom out effect by decreasing spatial resolution.
78
+ NB : here we resize only and systematically if Padded.
79
+
80
+ Args:
81
+ MaxPad (``Union[int, Sequence[int]]``): maximum padding bounds can be int for common padding bound for all borders or sequence of 4 ints for (t, l, b, r)
82
+ resize (``Tuple[int, int]``): Size to resize
83
+ p (``float``, **optional**): probability to apply transformation. Defaults to 0.5.
84
+ """
85
+
86
+ def __init__(
87
+ self,
88
+ maxpad: Sequence[int],
89
+ resize: Tuple[int, int],
90
+ p=0.5,
91
+ **kwargs,
92
+ ):
93
+
94
+ super().__init__(**kwargs)
95
+ self.p = p
96
+ self.max_pad = (maxpad,) * 4 if isinstance(maxpad, int) else maxpad
97
+ self.resize = T.Resize(resize)
98
+
99
+ def forward(self, *inputs):
100
+ if torch.rand(1) >= self.p:
101
+ return inputs
102
+ else:
103
+ t = rd.randrange(0, self.max_pad[0])
104
+ l = rd.randrange(0, self.max_pad[1])
105
+ r = rd.randrange(0, self.max_pad[2])
106
+ b = rd.randrange(0, self.max_pad[3])
107
+ padder = T.Pad([t, l, b, r])
108
+ inputs = padder(inputs)
109
+ inputs = self.resize(inputs)
110
+ return inputs
111
+
112
+
113
+ class RandomChangeBackground(Transform):
114
+ """With a given probability p, swap image background. New background is taken from an image folder for which path is provided.
115
+ Note 1 : it is implemented only for instance_mask, semantic_mask and bbox data type
116
+ Note 2 : new background image type must be one of .jpg, .jpeg, .png, .tif, .tiff, .PNG, .JPG, .JPEG, .TIF, .TIFF
117
+ Args:
118
+ background_dir_path (``Union[str, Path]``): Path to background folder
119
+ p (``float``, **optional**): Probability. Defaults to 0.5.
120
+ """
121
+
122
+ IMPLEMENTED_TVTENSOR = [
123
+ BoundingBoxes,
124
+ Mask,
125
+ ] # list of available hooks, i.e implemented for these type of tv_tensor
126
+
127
+ IMG_TYPE = [
128
+ ".jpg",
129
+ ".jpeg",
130
+ ".png",
131
+ ".tif",
132
+ ".tiff",
133
+ ".PNG",
134
+ ".JPG",
135
+ ".JPEG",
136
+ ".TIF",
137
+ ".TIFF",
138
+ ]
139
+
140
+ def __init__(self, background_dir_path: Union[str, Path], p: float = 0.5, **kwargs):
141
+
142
+ super().__init__(**kwargs)
143
+ path = (
144
+ background_dir_path
145
+ if isinstance(background_dir_path, Path)
146
+ else Path(background_dir_path)
147
+ )
148
+ list_bckg_imgs = []
149
+ for stem in RandomChangeBackground.IMG_TYPE:
150
+ list_bckg_imgs += list(path.glob(f"*{stem}"))
151
+ self.bckg_imgs = list_bckg_imgs
152
+ self.p = p
153
+ self._truth_extracter = _ExtractTruthFromTargetImage()
154
+
155
+ def forward(self, *inputs):
156
+ mu = torch.rand(1)
157
+ if mu > self.p:
158
+ return inputs
159
+ assert (
160
+ len(inputs) == 2
161
+ ), f"RandomChangeBackground is implemented only for exactly image and target input provided. You can't provide only image or additional item like scores. Got {inputs}"
162
+ image, target = inputs
163
+ assert (
164
+ type(target) in RandomChangeBackground.IMPLEMENTED_TVTENSOR
165
+ ), f"RandomChangeBackground is implemented only for {RandomChangeBackground.IMPLEMENTED_TVTENSOR} torchvision tv_tensors. Got {type(target)}"
166
+
167
+ # randomly select background image
168
+ original_dtype = image.dtype
169
+ image = image.float()
170
+ idx = torch.randint(0, len(self.bckg_imgs), (1,)).item()
171
+ bck_img = load_image(self.bckg_imgs[idx]).to(image.device).float()
172
+ bck_img = T.Resize(image.shape[-2:])(bck_img)
173
+ removed_bckg = self._truth_extracter(image, target)
174
+ removed_bckg[removed_bckg == -1.0] = bck_img[removed_bckg == -1.0]
175
+ return removed_bckg.to(original_dtype), target
176
+
177
+
178
+ class _ExtractTruthFromTargetImage:
179
+ """Handle background removing from target. Background is asserted as -1 to avoid errors removing 0 entries from image."""
180
+
181
+ def __call__(self, image: Tensor, targ: Tensor) -> Tensor:
182
+ if isinstance(targ, Mask):
183
+ rm_bckg = self._call_mask(image, targ)
184
+ elif isinstance(targ, BoundingBoxes):
185
+ rm_bckg = self._call_bbox(image, targ)
186
+ return rm_bckg
187
+
188
+ def _call_mask(self, image: Tensor, targ: Mask) -> Tensor:
189
+ removed_bckg = copy.deepcopy(image)
190
+ removed_bckg[:, targ == 0] = -1.0
191
+ return removed_bckg
192
+
193
+ def _call_bbox(self, image: Tensor, targ: BoundingBoxes) -> Tensor:
194
+ mask = Mask(torch.zeros(image.shape[-2:]))
195
+ for box in targ:
196
+ x1, y1, x2, y2 = box.to(torch.uint64).split(1)
197
+ x1, y1, x2, y2 = tuple(
198
+ max(i.item(), 0) for i in (x1, y1, x2, y2)
199
+ ) # ensure that bbox has coordinates positive
200
+ mask[y1:y2, x1:x2] = 1
201
+ return self._call_mask(image, mask)
@@ -0,0 +1,37 @@
1
+ from typing import List
2
+ from deepvisiontools.formats import (
3
+ BaseFormat,
4
+ BboxFormat,
5
+ BboxData,
6
+ InstanceMaskData,
7
+ InstanceMaskFormat,
8
+ )
9
+ import torchvision.transforms.v2 as T
10
+ from torch import Tensor
11
+ from torchvision.tv_tensors import Image
12
+ import torch
13
+ import deepvisiontools.data.errors as er
14
+
15
+ # Tested : Mask : Ok : RandomResize, RandomCrop, RandomZoomOut, ScaleJitter, RandomHorizontalFlip / Vertical, RandomRotation, RandomAffine, RandomPerspective
16
+ # Errors : RandomCropIou if you have masks only -> needs boxes
17
+ # boxes : Ok : same as mask but careful with crop / rotation : can lead to slightly off new boxes as per rotation / crops don't preserve structural information of boxes by nature
18
+
19
+ # TODO check augmentation rotation with boxes : got an error of different input shape / canvas size between image and boxes
20
+
21
+
22
+ class Augmentation:
23
+ """Class that handles augmentation in dataset. Call on different Formats (data_type) specific methods
24
+ Args:
25
+ augmentations (List[T.Transform]): List of torchvision.transforms.v2 Transform classes (or from deepvisiontools.data.additional_augmentations)
26
+ """
27
+
28
+ def __init__(self, augmentations: List[T.Transform]) -> None:
29
+ self.transform = T.Compose(augmentations)
30
+
31
+ def __call__(self, image: Tensor, target: BaseFormat):
32
+ """Augment depending on format type"""
33
+ image = Image(image)
34
+ transformed_target, _, transformed_img = target.apply_augmentation(
35
+ image, self.transform
36
+ )
37
+ return transformed_img, transformed_target