batchgeneratorsv2 0.3.3__tar.gz → 0.3.5__tar.gz
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.
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/PKG-INFO +1 -1
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/intensity/brightness.py +1 -1
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/intensity/contrast.py +1 -2
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/intensity/gamma.py +1 -2
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/intensity/gaussian_noise.py +4 -3
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/intensity/inversion.py +5 -4
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/intensity/random_clip.py +6 -6
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/local/brightness_gradient.py +5 -1
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/local/local_contrast.py +7 -5
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/local/local_gamma.py +9 -9
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/local/local_smoothing.py +4 -4
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/local/local_transform.py +27 -1
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/nnunet/seg_to_onehot.py +10 -3
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/noise/gaussian_blur.py +13 -6
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/noise/rician.py +9 -6
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/noise/sharpen.py +4 -3
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/spatial/channel_misalignment.py +63 -13
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/spatial/spatial.py +35 -17
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/deep_supervision_downsampling.py +5 -2
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2.egg-info/PKG-INFO +1 -1
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/pyproject.toml +1 -1
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/LICENSE +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/benchmarks/__init__.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/benchmarks/bg_comparison/__init__.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/benchmarks/bg_comparison/nnUNet_pipeline_bg.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/benchmarks/bg_comparison/nnUNet_pipeline_here.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/benchmarks/unique_values.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/dataloading/__init__.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/helpers/__init__.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/helpers/fft_conv.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/helpers/scalar_type.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/__init__.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/base/__init__.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/base/basic_transform.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/intensity/__init__.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/local/__init__.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/nnunet/__init__.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/nnunet/random_binary_operator.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/nnunet/remove_connected_components.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/noise/__init__.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/noise/blank_rectangle.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/noise/median_filter.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/spatial/__init__.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/spatial/low_resolution.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/spatial/mirroring.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/spatial/rot90.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/spatial/transpose.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/__init__.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/compose.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/cropping.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/move_channels.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/nnunet_masking.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/pseudo2d.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/random.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/remove_label.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/seg_to_regions.py +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2.egg-info/SOURCES.txt +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2.egg-info/dependency_links.txt +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2.egg-info/requires.txt +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2.egg-info/top_level.txt +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/readme.md +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/setup.cfg +0 -0
- {batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/setup.py +0 -0
|
@@ -30,7 +30,7 @@ class MultiplicativeBrightnessTransform(ImageOnlyTransform):
|
|
|
30
30
|
# even though this is array notation it's a lot slower. Shame shame
|
|
31
31
|
# img[params['apply_to_channel']] *= params['multipliers'].view(-1, *[1]*(img.ndim - 1))
|
|
32
32
|
for c, m in zip(params['apply_to_channel'], params['multipliers']):
|
|
33
|
-
img[c] *= m
|
|
33
|
+
img[c].mul_(m) # in-place on the channel view; avoids the __setitem__ write-back copy of `img[c] *= m`
|
|
34
34
|
return img
|
|
35
35
|
|
|
36
36
|
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/intensity/gamma.py
RENAMED
|
@@ -79,8 +79,7 @@ class GammaTransform(ImageOnlyTransform):
|
|
|
79
79
|
mean = x.mean()
|
|
80
80
|
std = x.std()
|
|
81
81
|
|
|
82
|
-
minm = x
|
|
83
|
-
maxm = x.max()
|
|
82
|
+
minm, maxm = torch.aminmax(x) # single reduction pass instead of separate min()/max()
|
|
84
83
|
rnge = maxm - minm
|
|
85
84
|
denom = torch.clamp(rnge, min=eps)
|
|
86
85
|
|
|
@@ -66,9 +66,10 @@ class GaussianNoiseTransform(ImageOnlyTransform):
|
|
|
66
66
|
sigma = sigmas
|
|
67
67
|
noise = torch.empty((n, *spatial), device=device, dtype=dtype).normal_(mean=0.0, std=float(sigma))
|
|
68
68
|
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
img[idx] += noise
|
|
69
|
+
# index_add_ adds noise[i] into channel img[idx[i]] fully in place. idx is unique (from nonzero),
|
|
70
|
+
# so there is no accumulation ambiguity. This avoids the full (n, *spatial) gather copy + scatter that
|
|
71
|
+
# advanced-indexed `img[idx] += noise` would allocate.
|
|
72
|
+
img.index_add_(0, idx, noise)
|
|
72
73
|
return img
|
|
73
74
|
|
|
74
75
|
|
|
@@ -31,10 +31,11 @@ class InvertImageTransform(ImageOnlyTransform):
|
|
|
31
31
|
return img
|
|
32
32
|
else:
|
|
33
33
|
for ch in params['apply_to_channel']:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
x = img[ch] # channel view; operate in place to drop the per-op __setitem__ write-backs
|
|
35
|
+
mn = x.mean()
|
|
36
|
+
x.sub_(mn)
|
|
37
|
+
x.mul_(-1)
|
|
38
|
+
x.add_(mn)
|
|
38
39
|
return img
|
|
39
40
|
|
|
40
41
|
|
|
@@ -67,18 +67,18 @@ class CutOffOutliersTransform(ImageOnlyTransform):
|
|
|
67
67
|
if retain_std[c]:
|
|
68
68
|
orig_std = img_c.std()
|
|
69
69
|
|
|
70
|
-
# Percentiles in torch to avoid numpy roundtrip
|
|
70
|
+
# Percentiles in torch to avoid numpy roundtrip; must run on the pre-clamp values
|
|
71
71
|
q = torch.tensor([perc[0] / 100.0, perc[1] / 100.0], device=img_c.device, dtype=torch.float32)
|
|
72
72
|
lower_val, upper_val = torch.quantile(img_c.float(), q)
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
# clamp in place on the channel view
|
|
75
|
+
img_c.clamp_(min=lower_val.item(), max=upper_val.item())
|
|
75
76
|
|
|
76
77
|
if retain_std[c]:
|
|
77
|
-
clipped_std =
|
|
78
|
+
clipped_std = img_c.std()
|
|
78
79
|
if clipped_std > 1e-8:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
img[c] = img_c_clipped
|
|
80
|
+
m = img_c.mean() # reused for both centering steps
|
|
81
|
+
img[c] = (img_c - m) / clipped_std * orig_std + m
|
|
82
82
|
|
|
83
83
|
return img
|
|
84
84
|
|
|
@@ -140,6 +140,10 @@ class BrightnessGradientAdditiveTransform(ImageOnlyTransform, LocalTransform):
|
|
|
140
140
|
return {'kernels': kernels}
|
|
141
141
|
|
|
142
142
|
def _apply_to_image(self, img: torch.Tensor, **params) -> torch.Tensor:
|
|
143
|
+
if self.clip_intensities:
|
|
144
|
+
original_min = img.min()
|
|
145
|
+
original_max = img.max()
|
|
146
|
+
|
|
143
147
|
for c, kernel in enumerate(params['kernels']):
|
|
144
148
|
if kernel is None:
|
|
145
149
|
continue
|
|
@@ -147,7 +151,7 @@ class BrightnessGradientAdditiveTransform(ImageOnlyTransform, LocalTransform):
|
|
|
147
151
|
img[c].add_(kernel_tensor)
|
|
148
152
|
|
|
149
153
|
if self.clip_intensities:
|
|
150
|
-
img.clamp_(min=
|
|
154
|
+
img.clamp_(min=original_min, max=original_max)
|
|
151
155
|
|
|
152
156
|
return img
|
|
153
157
|
|
|
@@ -40,7 +40,7 @@ class LocalContrastTransform(ImageOnlyTransform, LocalTransform):
|
|
|
40
40
|
return {'kernels': [None] * C, 'contrasts': [None] * C}
|
|
41
41
|
|
|
42
42
|
if self.same_for_all_channels:
|
|
43
|
-
kernel = self._generate_kernel(spatial)
|
|
43
|
+
kernel = self._generate_kernel(spatial)
|
|
44
44
|
contrast = sample_scalar(self.new_contrast)
|
|
45
45
|
|
|
46
46
|
kernels = [kernel if apply else None for apply in apply_channel]
|
|
@@ -52,7 +52,7 @@ class LocalContrastTransform(ImageOnlyTransform, LocalTransform):
|
|
|
52
52
|
kernels.append(None)
|
|
53
53
|
contrasts.append(None)
|
|
54
54
|
continue
|
|
55
|
-
kernel = self._generate_kernel(spatial)
|
|
55
|
+
kernel = self._generate_kernel(spatial)
|
|
56
56
|
contrast = sample_scalar(self.new_contrast)
|
|
57
57
|
kernels.append(kernel)
|
|
58
58
|
contrasts.append(contrast)
|
|
@@ -67,9 +67,11 @@ class LocalContrastTransform(ImageOnlyTransform, LocalTransform):
|
|
|
67
67
|
continue
|
|
68
68
|
|
|
69
69
|
channel = img_np[c]
|
|
70
|
-
mean = (channel * kernel).sum() / (kernel.sum() + 1e-8)
|
|
71
|
-
modified =
|
|
72
|
-
|
|
70
|
+
mean = (channel * kernel).sum() / (kernel.sum() + 1e-8) # keep exact summation order
|
|
71
|
+
modified = channel - mean # fresh owned array
|
|
72
|
+
modified *= contrast
|
|
73
|
+
modified += mean # (channel - mean) * contrast + mean
|
|
74
|
+
img_np[c] = self.run_interpolation_inplace(channel, modified, kernel)
|
|
73
75
|
|
|
74
76
|
return torch.from_numpy(img_np).to(img.device, dtype=img.dtype)
|
|
75
77
|
|
|
@@ -42,7 +42,7 @@ class LocalGammaTransform(ImageOnlyTransform, LocalTransform):
|
|
|
42
42
|
return {'kernels': [None] * C, 'gammas': [None] * C}
|
|
43
43
|
|
|
44
44
|
if self.same_for_all_channels:
|
|
45
|
-
kernel = self._generate_kernel(spatial)
|
|
45
|
+
kernel = self._generate_kernel(spatial)
|
|
46
46
|
gamma = sample_scalar(self.gamma)
|
|
47
47
|
|
|
48
48
|
kernels = [kernel if apply else None for apply in apply_channel]
|
|
@@ -54,7 +54,7 @@ class LocalGammaTransform(ImageOnlyTransform, LocalTransform):
|
|
|
54
54
|
kernels.append(None)
|
|
55
55
|
gammas.append(None)
|
|
56
56
|
continue
|
|
57
|
-
kernel = self._generate_kernel(spatial)
|
|
57
|
+
kernel = self._generate_kernel(spatial)
|
|
58
58
|
gamma = sample_scalar(self.gamma)
|
|
59
59
|
kernels.append(kernel)
|
|
60
60
|
gammas.append(gamma)
|
|
@@ -72,15 +72,15 @@ class LocalGammaTransform(ImageOnlyTransform, LocalTransform):
|
|
|
72
72
|
min_val, max_val = channel.min(), channel.max()
|
|
73
73
|
denom = max(max_val - min_val, 1e-8)
|
|
74
74
|
|
|
75
|
-
# Normalize to [0, 1]
|
|
76
|
-
norm =
|
|
75
|
+
# Normalize to [0, 1] (norm is a fresh owned array; channel/kernel are never mutated)
|
|
76
|
+
norm = channel - min_val
|
|
77
|
+
norm /= denom
|
|
77
78
|
gamma_corrected = np.power(norm, gamma)
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
blended
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
img_np[c] = blended * denom + min_val
|
|
80
|
+
blended = self.run_interpolation_inplace(norm, gamma_corrected, kernel)
|
|
81
|
+
blended *= denom # rescale to original range
|
|
82
|
+
blended += min_val
|
|
83
|
+
img_np[c] = blended
|
|
84
84
|
|
|
85
85
|
return torch.from_numpy(img_np).to(img.device, dtype=img.dtype)
|
|
86
86
|
|
|
@@ -47,7 +47,7 @@ class LocalSmoothingTransform(ImageOnlyTransform, LocalTransform):
|
|
|
47
47
|
sigma = sample_scalar(self.kernel_size)
|
|
48
48
|
|
|
49
49
|
if self.same_for_all_channels:
|
|
50
|
-
kernel = self._generate_kernel(spatial)
|
|
50
|
+
kernel = self._generate_kernel(spatial)
|
|
51
51
|
strength = sample_scalar(self.smoothing_strength)
|
|
52
52
|
|
|
53
53
|
kernels = [kernel if apply else None for apply in apply_channel]
|
|
@@ -59,7 +59,7 @@ class LocalSmoothingTransform(ImageOnlyTransform, LocalTransform):
|
|
|
59
59
|
kernels.append(None)
|
|
60
60
|
strengths.append(None)
|
|
61
61
|
continue
|
|
62
|
-
kernel = self._generate_kernel(spatial)
|
|
62
|
+
kernel = self._generate_kernel(spatial)
|
|
63
63
|
strength = sample_scalar(self.smoothing_strength)
|
|
64
64
|
kernels.append(kernel)
|
|
65
65
|
strengths.append(strength)
|
|
@@ -74,9 +74,9 @@ class LocalSmoothingTransform(ImageOnlyTransform, LocalTransform):
|
|
|
74
74
|
if kernel is None:
|
|
75
75
|
continue
|
|
76
76
|
|
|
77
|
-
kernel = kernel * strength #
|
|
77
|
+
kernel = kernel * strength # fresh owned array (shared param kernel is never mutated)
|
|
78
78
|
smoothed = gaussian_filter(img_np[c], sigma=sigma)
|
|
79
|
-
img_np[c] = self.
|
|
79
|
+
img_np[c] = self.run_interpolation_inplace(img_np[c], smoothed, kernel)
|
|
80
80
|
|
|
81
81
|
return torch.from_numpy(img_np).to(img.device, dtype=img.dtype)
|
|
82
82
|
|
|
@@ -11,6 +11,9 @@ class LocalTransform(ABC):
|
|
|
11
11
|
self.scale = scale
|
|
12
12
|
|
|
13
13
|
def _generate_kernel(self, img_shp: Tuple[int, ...]) -> np.ndarray:
|
|
14
|
+
"""
|
|
15
|
+
Always returns a float32 array in [0, 1]; callers rely on this and do not re-cast.
|
|
16
|
+
"""
|
|
14
17
|
ndim = len(img_shp)
|
|
15
18
|
x_grids = [np.arange(-0.5, s + 0.5, dtype=np.float32) for s in img_shp]
|
|
16
19
|
kernels = []
|
|
@@ -75,6 +78,8 @@ class LocalTransform(ABC):
|
|
|
75
78
|
"""
|
|
76
79
|
Blends original and modified images using the given kernel as a per-pixel weight map.
|
|
77
80
|
|
|
81
|
+
Reference implementation; prefer run_interpolation_inplace in per-sample code paths.
|
|
82
|
+
|
|
78
83
|
Parameters:
|
|
79
84
|
original_image (np.ndarray): Unmodified input image
|
|
80
85
|
modified_image (np.ndarray): Modified version (e.g., gamma-corrected)
|
|
@@ -83,4 +88,25 @@ class LocalTransform(ABC):
|
|
|
83
88
|
Returns:
|
|
84
89
|
np.ndarray: Blended result
|
|
85
90
|
"""
|
|
86
|
-
return original_image * (1.0 - kernel_image) + modified_image * kernel_image
|
|
91
|
+
return original_image * (1.0 - kernel_image) + modified_image * kernel_image
|
|
92
|
+
|
|
93
|
+
@staticmethod
|
|
94
|
+
def run_interpolation_inplace(original_image: np.ndarray,
|
|
95
|
+
modified_image: np.ndarray,
|
|
96
|
+
kernel_image: np.ndarray) -> np.ndarray:
|
|
97
|
+
"""
|
|
98
|
+
Same blend as run_interpolation, computed into modified_image's buffer with a single extra
|
|
99
|
+
temporary. Uses the identical individual * and + ops with only IEEE-commutative operand swaps
|
|
100
|
+
(no reassociation), so the result is bit-identical to run_interpolation.
|
|
101
|
+
|
|
102
|
+
Contract: modified_image must be a fresh buffer owned by the caller (it is overwritten);
|
|
103
|
+
original_image and kernel_image are only read. original_image may alias the eventual output
|
|
104
|
+
slot as long as that slot is written only after this call returns.
|
|
105
|
+
|
|
106
|
+
Returns modified_image (now holding the blended result).
|
|
107
|
+
"""
|
|
108
|
+
tmp = 1.0 - kernel_image
|
|
109
|
+
tmp *= original_image # original * (1 - kernel)
|
|
110
|
+
modified_image *= kernel_image
|
|
111
|
+
modified_image += tmp
|
|
112
|
+
return modified_image
|
|
@@ -22,10 +22,17 @@ class MoveSegAsOneHotToDataTransform(BasicTransform):
|
|
|
22
22
|
|
|
23
23
|
def apply(self, data_dict, **params):
|
|
24
24
|
seg = data_dict['segmentation'][self.source_channel_idx]
|
|
25
|
-
|
|
25
|
+
img = data_dict['image']
|
|
26
|
+
C = img.shape[0]
|
|
27
|
+
# Allocate the concatenated result once and write the one-hot channels straight into their final slots,
|
|
28
|
+
# instead of building a separate seg_onehot tensor and then torch.cat-copying everything again. Only the
|
|
29
|
+
# one-hot tail needs zeroing; the image channels are fully overwritten anyway.
|
|
30
|
+
out = torch.empty((C + len(self.all_labels), *seg.shape), dtype=img.dtype)
|
|
31
|
+
out[:C] = img
|
|
32
|
+
out[C:].zero_()
|
|
26
33
|
for i, l in enumerate(self.all_labels):
|
|
27
|
-
|
|
28
|
-
data_dict['image'] =
|
|
34
|
+
out[C + i][seg == l] = 1
|
|
35
|
+
data_dict['image'] = out
|
|
29
36
|
if self.remove_channel_from_source:
|
|
30
37
|
remaining_channels = [i for i in range(data_dict['segmentation'].shape[0]) if i != self.source_channel_idx]
|
|
31
38
|
data_dict['segmentation'] = data_dict['segmentation'][remaining_channels]
|
|
@@ -20,7 +20,8 @@ def blur_dimension(img: torch.Tensor, sigma: float, dim_to_blur: int, force_use_
|
|
|
20
20
|
where C is the channel dimension and X, Y, Z are spatial dimensions.
|
|
21
21
|
:param sigma: The standard deviation of the Gaussian kernel.
|
|
22
22
|
:param dim_to_blur: The dimension along which to apply the Gaussian blur (0 for X, 1 for Y, 2 for Z).
|
|
23
|
-
:return: The blurred image tensor.
|
|
23
|
+
:return: The blurred image tensor. `img` is never modified; a new tensor is returned (callers such as
|
|
24
|
+
GaussianBlurTransform chain these calls and rely on this non-mutation contract).
|
|
24
25
|
"""
|
|
25
26
|
assert img.ndim - 1 > dim_to_blur, "dim_to_blur must be a valid spatial dimension of the input image."
|
|
26
27
|
# Adjustments for kernel based on image dimensions
|
|
@@ -122,22 +123,28 @@ class GaussianBlurTransform(ImageOnlyTransform):
|
|
|
122
123
|
# print(params['sigmas'])
|
|
123
124
|
if self.synchronize_channels:
|
|
124
125
|
# we can compute that in one go as the conv implementation supports arbitrary input channels (with expanded kernel)
|
|
126
|
+
# Gather the selected channels once (advanced indexing copies), chain the per-dim blurs, scatter back once.
|
|
127
|
+
# blur_dimension never mutates its input, so this is the same composition as writing back each dim.
|
|
128
|
+
mask = params['apply_to_channel']
|
|
129
|
+
sub = img[mask]
|
|
125
130
|
for d in range(dim):
|
|
126
|
-
# print(d, params['sigmas'][d])
|
|
127
131
|
if not self.benchmark:
|
|
128
|
-
|
|
132
|
+
sub = blur_dimension(sub, params['sigmas'][d], d)
|
|
129
133
|
else:
|
|
130
|
-
|
|
134
|
+
sub = self._benchmark_wrapper(sub, params['sigmas'][d], d)
|
|
135
|
+
img[mask] = sub
|
|
131
136
|
else:
|
|
132
137
|
# we have to go through all the channels, build the kernel for each channel etc
|
|
133
138
|
idx = np.where(params['apply_to_channel'])[0]
|
|
134
139
|
for j, i in enumerate(idx):
|
|
140
|
+
sub = img[i:i+1] # view for the first read; blur_dimension returns fresh tensors thereafter
|
|
135
141
|
for d in range(dim):
|
|
136
142
|
# print(i, d, params['sigmas'][i][d])
|
|
137
143
|
if not self.benchmark:
|
|
138
|
-
|
|
144
|
+
sub = blur_dimension(sub, params['sigmas'][j][d], d)
|
|
139
145
|
else:
|
|
140
|
-
|
|
146
|
+
sub = self._benchmark_wrapper(sub, params['sigmas'][j][d], d)
|
|
147
|
+
img[i:i+1] = sub
|
|
141
148
|
return img
|
|
142
149
|
|
|
143
150
|
def _benchmark_wrapper(self, img: torch.Tensor, sigma: float, dim_to_blur: int):
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/noise/rician.py
RENAMED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import numpy as np
|
|
1
2
|
import torch
|
|
2
3
|
from typing import Tuple
|
|
3
4
|
from batchgeneratorsv2.transforms.base.basic_transform import ImageOnlyTransform
|
|
@@ -25,19 +26,21 @@ class RicianNoiseTransform(ImageOnlyTransform):
|
|
|
25
26
|
noise_imag = torch.empty_like(img).normal_(mean=0.0, std=var)
|
|
26
27
|
|
|
27
28
|
min_val = img.min()
|
|
28
|
-
shifted = img - min_val
|
|
29
|
+
shifted = img - min_val # fresh owned buffer (img itself is never mutated below)
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
# Run the whole Rician pipeline in `shifted`'s buffer. Same elementwise ops in the same order as
|
|
32
|
+
# sqrt((shifted+noise_real)^2 + noise_imag^2) + min_val, just in place -> bit-identical.
|
|
33
|
+
rician = shifted.add_(noise_real).pow_(2).add_(noise_imag.pow_(2)).sqrt_()
|
|
34
|
+
rician.add_(min_val)
|
|
32
35
|
|
|
33
|
-
# Normalize to match original mean and std
|
|
36
|
+
# Normalize to match original mean and std (scalars captured before the in-place normalization)
|
|
34
37
|
input_mean, input_std = img.mean(), img.std()
|
|
35
38
|
rician_mean, rician_std = rician.mean(), rician.std()
|
|
36
39
|
|
|
37
40
|
if rician_std > 0:
|
|
38
|
-
rician
|
|
41
|
+
rician.sub_(rician_mean).div_(rician_std).mul_(input_std).add_(input_mean)
|
|
39
42
|
else:
|
|
40
|
-
rician
|
|
43
|
+
rician.mul_(0).add_(input_mean) # keep mul_(0) (not fill_) so inf/nan propagate as before
|
|
41
44
|
|
|
42
45
|
return rician
|
|
43
46
|
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/noise/sharpen.py
RENAMED
|
@@ -81,7 +81,7 @@ class SharpeningTransform(ImageOnlyTransform):
|
|
|
81
81
|
continue
|
|
82
82
|
|
|
83
83
|
if clamp:
|
|
84
|
-
mn, mx = torch.
|
|
84
|
+
mn, mx = torch.aminmax(img[c]) # single reduction pass instead of separate min()/max()
|
|
85
85
|
|
|
86
86
|
x = img[c].unsqueeze(0).unsqueeze(0) # (1, 1, H, W) or (1, 1, D, H, W)
|
|
87
87
|
padded = F.pad(x, pad, mode='replicate')
|
|
@@ -91,8 +91,9 @@ class SharpeningTransform(ImageOnlyTransform):
|
|
|
91
91
|
else:
|
|
92
92
|
laplace = F.conv3d(padded, kernel)
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
out[c]
|
|
94
|
+
# laplace is a fresh conv output (owned, not reused). Combine in place: strength*laplace + x == x +
|
|
95
|
+
# strength*laplace (IEEE add commutes). x is read here before out[c] (== img[c]) is written -> no hazard.
|
|
96
|
+
out[c] = laplace.mul_(strength).add_(x).squeeze()
|
|
96
97
|
|
|
97
98
|
if clamp:
|
|
98
99
|
out[c].clamp_(mn, mx)
|
|
@@ -201,24 +201,74 @@ class ChannelMisalignmentTransform(ImageOnlyTransform):
|
|
|
201
201
|
if params['elastic_offsets'] is not None:
|
|
202
202
|
grid += params['elastic_offsets']
|
|
203
203
|
if params['affine'] is not None:
|
|
204
|
-
grid
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
204
|
+
# grid stores spatial vectors as row vectors (shape [..., dim]), whereas affine is built to act on
|
|
205
|
+
# column vectors (x' = affine @ x). We therefore multiply by affine.T so that each grid point is
|
|
206
|
+
# transformed by affine rather than its transpose (see issue #24).
|
|
207
|
+
grid = torch.matmul(grid, torch.from_numpy(params['affine'].T).float())
|
|
208
|
+
|
|
209
|
+
# re-center the mean of the grid (not the center position). new_center is all-zeros here (translation is
|
|
210
|
+
# handled via the shifted crop center below, not via the grid), so in the non-deform case mn is also 0 and
|
|
211
|
+
# `grid += (0 - 0)` would be a wasted full-grid pass -> skipped. This skip is only valid while new_center
|
|
212
|
+
# stays all-zeros; if a nonzero new_center is ever reintroduced, the shift must apply in both paths again.
|
|
208
213
|
if params['elastic_offsets'] is not None:
|
|
209
214
|
mn = grid.mean(dim=list(range(img.ndim - 1)))
|
|
210
|
-
|
|
211
|
-
|
|
215
|
+
# new_center = torch.Tensor([c - s / 2 for c, s in zip(params['center_location_in_pixels'], img.shape[1:])])
|
|
216
|
+
new_center = torch.zeros(len(im_shape))
|
|
217
|
+
grid += (new_center - mn)
|
|
212
218
|
|
|
213
|
-
#
|
|
214
|
-
|
|
215
|
-
grid += (new_center - mn)
|
|
219
|
+
# compute the grid_sample grid once instead of once per channel
|
|
220
|
+
grid_sample_grid = _convert_my_grid_to_grid_sample_grid(grid, img.shape[1:])[None]
|
|
216
221
|
|
|
217
222
|
for ch in self.im_channels_2_misalign:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
223
|
+
# crop the grid_sample result directly instead of writing it into img[ch] and reading it back
|
|
224
|
+
resampled = grid_sample(img[ch, ...].unsqueeze(0).unsqueeze(0),
|
|
225
|
+
grid_sample_grid,
|
|
226
|
+
mode='bilinear', padding_mode="zeros", align_corners=False)[0]
|
|
227
|
+
img[ch, ...] = crop_tensor(resampled,
|
|
222
228
|
[math.floor(i) for i in params['center_location_in_pixels']], im_shape,
|
|
223
229
|
pad_mode='constant', pad_kwargs={'value': 0})
|
|
224
230
|
return img
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
# from copy import deepcopy
|
|
234
|
+
# import SimpleITK as sitk
|
|
235
|
+
# from pathlib import Path
|
|
236
|
+
|
|
237
|
+
# if __name__ == '__main__':
|
|
238
|
+
|
|
239
|
+
# source_folder = Path('./test_images/')
|
|
240
|
+
|
|
241
|
+
# img0 = sitk.GetArrayFromImage(sitk.ReadImage(source_folder / 'case001_0000.nii.gz'))
|
|
242
|
+
# img1 = sitk.GetArrayFromImage(sitk.ReadImage(source_folder / 'case001_0001.nii.gz'))
|
|
243
|
+
# img2 = sitk.GetArrayFromImage(sitk.ReadImage(source_folder / 'case001_0002.nii.gz'))
|
|
244
|
+
# seg = sitk.GetArrayFromImage(sitk.ReadImage(source_folder / 'case001.nii.gz'))
|
|
245
|
+
|
|
246
|
+
# sp = ChannelMisalignmentTransform(
|
|
247
|
+
# im_channels_2_misalign=(0,),
|
|
248
|
+
|
|
249
|
+
# squeezing_zyx=(0.0, 0.1, 0.0),
|
|
250
|
+
# p_squeeze=1.0,
|
|
251
|
+
|
|
252
|
+
# rotation_ax_cor_sag=(30, 0, 0),
|
|
253
|
+
# rad_or_deg="deg",
|
|
254
|
+
# p_rotation=1.0,
|
|
255
|
+
|
|
256
|
+
# shift_zyx=(5, 100, 20),
|
|
257
|
+
# p_shift = 1.0,
|
|
258
|
+
|
|
259
|
+
# )
|
|
260
|
+
|
|
261
|
+
# data_dict = {'image': torch.cat([torch.from_numpy(deepcopy(img0[None])).float(),
|
|
262
|
+
# torch.from_numpy(deepcopy(img1[None])).float(),
|
|
263
|
+
# torch.from_numpy(deepcopy(img2[None])).float()], dim=0)}
|
|
264
|
+
# if seg is not None:
|
|
265
|
+
# data_dict['segmentation'] = torch.from_numpy(deepcopy(seg[None]))
|
|
266
|
+
|
|
267
|
+
# out = sp(**data_dict)
|
|
268
|
+
|
|
269
|
+
# sitk.WriteImage(sitk.GetImageFromArray(img0), source_folder / 'original_ch0.nii.gz')
|
|
270
|
+
# sitk.WriteImage(sitk.GetImageFromArray(img1), source_folder / 'original_ch1.nii.gz')
|
|
271
|
+
# sitk.WriteImage(sitk.GetImageFromArray(img2), source_folder / 'original_ch2.nii.gz')
|
|
272
|
+
# sitk.WriteImage(sitk.GetImageFromArray(out['image'][0].numpy()), source_folder / 'transformed_ch0.nii.gz')
|
|
273
|
+
# sitk.WriteImage(sitk.GetImageFromArray(out['image'][1].numpy()), source_folder / 'transformed_ch1.nii.gz')
|
|
274
|
+
# sitk.WriteImage(sitk.GetImageFromArray(out['image'][2].numpy()), source_folder / 'transformed_ch2.nii.gz')
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/spatial/spatial.py
RENAMED
|
@@ -219,7 +219,10 @@ class SpatialTransform(BasicTransform):
|
|
|
219
219
|
if offsets is not None:
|
|
220
220
|
grid += offsets
|
|
221
221
|
if affine is not None:
|
|
222
|
-
grid
|
|
222
|
+
# grid stores spatial vectors as row vectors (shape [..., dim]), whereas affine is built to act on
|
|
223
|
+
# column vectors (x' = affine @ x). We therefore multiply by affine.T so that each grid point is
|
|
224
|
+
# transformed by affine rather than its transpose (see issue #24).
|
|
225
|
+
grid = torch.matmul(grid, torch.from_numpy(affine.T).float())
|
|
223
226
|
|
|
224
227
|
# we center the grid around the center_location_in_pixels. We should center the mean of the grid, not the center position
|
|
225
228
|
# only do this if we elastic deform
|
|
@@ -300,6 +303,11 @@ class SpatialTransform(BasicTransform):
|
|
|
300
303
|
if self.bg_style_seg_sampling:
|
|
301
304
|
for c in range(segmentation.shape[0]):
|
|
302
305
|
labels = torch.from_numpy(np.sort(pd.unique(segmentation[c].numpy().ravel())))
|
|
306
|
+
# result_seg is zero-initialized, so when the lowest label is the 0 background we never have to
|
|
307
|
+
# write it: any voxel it would claim is already 0, and being the lowest label it can only be
|
|
308
|
+
# overwritten by (never overwrite) the foreground labels processed after it. Skipping it saves a
|
|
309
|
+
# full grid_sample per channel. Output is bit-identical.
|
|
310
|
+
bg_is_zero = bool(labels[0] == 0)
|
|
303
311
|
# if we only have 2 labels then we can save compute time
|
|
304
312
|
if len(labels) == 2:
|
|
305
313
|
out = grid_sample(
|
|
@@ -310,9 +318,10 @@ class SpatialTransform(BasicTransform):
|
|
|
310
318
|
align_corners=self.align_corners
|
|
311
319
|
)[0][0] >= 0.5
|
|
312
320
|
result_seg[c][out] = labels[1]
|
|
313
|
-
|
|
321
|
+
if not bg_is_zero:
|
|
322
|
+
result_seg[c][~out] = labels[0]
|
|
314
323
|
else:
|
|
315
|
-
for
|
|
324
|
+
for u in (labels[1:] if bg_is_zero else labels):
|
|
316
325
|
result_seg[c][
|
|
317
326
|
grid_sample(
|
|
318
327
|
((segmentation[c] == u).float())[None, None],
|
|
@@ -322,26 +331,35 @@ class SpatialTransform(BasicTransform):
|
|
|
322
331
|
align_corners=self.align_corners
|
|
323
332
|
)[0][0] >= 0.5] = u
|
|
324
333
|
else:
|
|
334
|
+
# Per-voxel argmax over the interpolated one-hot label channels, computed incrementally so the
|
|
335
|
+
# (num_labels, *patch_size) stack is never materialized: only a running best value and the winning
|
|
336
|
+
# label (written straight into result_seg) are kept. This equals threshold-then-argmax sampling
|
|
337
|
+
# because the interpolated channels form a convex combination (they sum to <= scale_factor per
|
|
338
|
+
# voxel, so at most one label can exceed 0.7 * scale_factor). Load-bearing for bit-identical
|
|
339
|
+
# results: the running comparison is done in float16, and the strict > keeps the lowest label
|
|
340
|
+
# index on ties, exactly like torch.argmax(0) over a float16 stack.
|
|
341
|
+
scale_factor = 1000
|
|
325
342
|
for c in range(segmentation.shape[0]):
|
|
326
343
|
labels = torch.from_numpy(np.sort(pd.unique(segmentation[c].numpy().ravel())))
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
((segmentation[c] == u).float() * scale_factor)[None, None],
|
|
344
|
+
best_val = None
|
|
345
|
+
for u in labels:
|
|
346
|
+
onehot = (segmentation[c] == u).float()
|
|
347
|
+
onehot *= scale_factor
|
|
348
|
+
cur = grid_sample(
|
|
349
|
+
onehot[None, None],
|
|
334
350
|
grid[None],
|
|
335
351
|
mode=self.mode_seg,
|
|
336
352
|
padding_mode=grid_sample_padding_mode,
|
|
337
353
|
align_corners=self.align_corners
|
|
338
|
-
)[0][0]
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
354
|
+
)[0][0].to(torch.float16)
|
|
355
|
+
if best_val is None:
|
|
356
|
+
best_val = cur
|
|
357
|
+
if u != 0: # result_seg is zero-initialized, so filling with 0 would be a no-op
|
|
358
|
+
result_seg[c] = u
|
|
359
|
+
else:
|
|
360
|
+
better = cur > best_val
|
|
361
|
+
torch.maximum(best_val, cur, out=best_val)
|
|
362
|
+
result_seg[c][better] = u
|
|
345
363
|
|
|
346
364
|
if self._requires_constant_padding_fixup(self.border_mode_seg, self.padding_value_seg):
|
|
347
365
|
out_of_bounds_mask = self._compute_out_of_bounds_mask(grid, segmentation.shape[1:])
|
|
@@ -12,6 +12,8 @@ class DownsampleSegForDSTransform(SegOnlyTransform):
|
|
|
12
12
|
|
|
13
13
|
def _apply_to_segmentation(self, segmentation: torch.Tensor, **params) -> List[torch.Tensor]:
|
|
14
14
|
results = []
|
|
15
|
+
dtype = segmentation.dtype
|
|
16
|
+
seg_float = None # full-res float copy, built once and shared across scales (interpolate only reads it)
|
|
15
17
|
for s in self.ds_scales:
|
|
16
18
|
if not isinstance(s, (tuple, list)):
|
|
17
19
|
s = [s] * (segmentation.ndim - 1)
|
|
@@ -22,9 +24,10 @@ class DownsampleSegForDSTransform(SegOnlyTransform):
|
|
|
22
24
|
results.append(segmentation)
|
|
23
25
|
else:
|
|
24
26
|
new_shape = [round(i * j) for i, j in zip(segmentation.shape[1:], s)]
|
|
25
|
-
dtype = segmentation.dtype
|
|
26
27
|
# interpolate is not defined for short etc
|
|
27
|
-
|
|
28
|
+
if seg_float is None:
|
|
29
|
+
seg_float = segmentation[None].float()
|
|
30
|
+
results.append(interpolate(seg_float, new_shape, mode='nearest-exact')[0].to(dtype))
|
|
28
31
|
return results
|
|
29
32
|
|
|
30
33
|
|
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/benchmarks/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/benchmarks/unique_values.py
RENAMED
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/dataloading/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/helpers/scalar_type.py
RENAMED
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/__init__.py
RENAMED
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/base/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/local/__init__.py
RENAMED
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/nnunet/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/noise/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/spatial/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/spatial/rot90.py
RENAMED
|
File without changes
|
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/__init__.py
RENAMED
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/compose.py
RENAMED
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/cropping.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/pseudo2d.py
RENAMED
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2/transforms/utils/random.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{batchgeneratorsv2-0.3.3 → batchgeneratorsv2-0.3.5}/batchgeneratorsv2.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|