-
Notifications
You must be signed in to change notification settings - Fork 0
/
artificial_anomalies.py
188 lines (151 loc) · 5.6 KB
/
artificial_anomalies.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
import random
import numpy as np
from skimage.draw import disk
from typing import Tuple
def sample_position(img: np.ndarray) -> Tuple[int, int]:
"""Sample a random position in the brain
:param: img: The image to sample the position on
:return: A tuple of the x,y position
"""
obj_inds = np.where(img > 0)
location_idx = random.randint(0, len(obj_inds[0]) - 1)
position = (obj_inds[0][location_idx], obj_inds[1][location_idx])
return position
def disk_anomaly(img: np.ndarray, position: Tuple[int, int], radius: int,
intensity: float) -> np.ndarray:
"""Draw a disk on a grayscale image.
Args:
img (np.ndarray): Grayscale image
position (Tuple[int, int]): Position of disk
radius (int): Radius of disk
intensity (float): Intensity of pixels inside the disk
Returns:
disk_img (np.ndarray): img with ball drawn on it
label (np.ndarray): target segmentation mask
"""
assert img.ndim == 2, f"Invalid shape {img.shape}. Use a grayscale image"
# Create disk
rr, cc = disk(position, radius)
rr = rr.clip(0, img.shape[0] - 1)
cc = cc.clip(0, img.shape[1] - 1)
# Draw disk on image
disk_img = img.copy()
disk_img[rr, cc] = intensity
# Create label
label = np.zeros(img.shape, dtype=np.uint8)
label[rr, cc] = 1
# Remove anomaly at background pixels
mask = img > 0
disk_img *= mask
label *= mask
return disk_img, label
def source_deformation_anomaly(img: np.ndarray, position: Tuple[int, int],
radius: int):
"""Pixels are shifted away from the center of the sphere.
Args:
img (np.ndarray): Image to be augmented, shape [h, w]
position (Tuple[int int]): Center pixel of the mask
radius (int): Radius
Returns:
img_deformed (np.ndarray): img with source deformation
label (np.ndarray): target segmentation mask
"""
# Create label mask
rr, cc = disk(position, radius)
rr = rr.clip(0, img.shape[0] - 1)
cc = cc.clip(0, img.shape[1] - 1)
label = np.zeros(img.shape, dtype=np.uint8)
label[rr, cc] = 1
# Remove anomaly at background pixels
mask = img > 0
label *= mask
# Center voxel of deformation
C = np.array(position)
# Create copy of image for reference
img_deformed = img.copy()
copy = img.copy()
# Iterate over indices of all voxels in mask
inds = np.where(label > 0)
for x, y in zip(*inds[-2:]):
# Voxel at current location
I = np.array([x, y])
# Source pixel shift
s = np.square(np.linalg.norm(I - C, ord=2) / radius)
V = np.round(C + s * (I - C)).astype(np.int)
x_, y_ = V
# Assure that z_, y_ and x_ are valid indices
x_ = max(min(x_, img.shape[-1] - 1), 0)
y_ = max(min(y_, img.shape[-2] - 1), 0)
if img_deformed[..., x, y] > 0:
img_deformed[..., x, y] = copy[..., x_, y_]
return img_deformed, label
def sink_deformation_anomaly(img: np.ndarray, position: Tuple[int, int],
radius: int):
"""Pixels are shifted toward from the center of the sphere.
Args:
img (np.ndarray): Image to be augmented, shape [h, w]
position (Tuple[int int]): Center pixel of the mask
radius (int): Radius
Returns:
img_deformed (np.ndarray): img with sink deformation
label (np.ndarray): target segmentation mask
"""
# Create label mask
rr, cc = disk(position, radius)
rr = rr.clip(0, img.shape[0] - 1)
cc = cc.clip(0, img.shape[1] - 1)
label = np.zeros(img.shape, dtype=np.uint8)
label[rr, cc] = 1
# Remove anomaly at background pixels
mask = img > 0
label *= mask
# Center voxel of deformation
C = np.array(position)
# Create copy of image for reference
img_deformed = img.copy()
copy = img.copy()
# Iterate over indices of all voxels in mask
inds = np.where(label > 0)
for x, y in zip(*inds[-2:]):
# Voxel at current location
I = np.array([x, y])
# Sink pixel shift
s = np.square(np.linalg.norm(I - C, ord=2) / radius)
V = np.round(I + (1 - s) * (I - C)).astype(np.int)
x_, y_ = V
# Assure that z_, y_ and x_ are valid indices
x_ = max(min(x_, img.shape[-2] - 1), 0)
y_ = max(min(y_, img.shape[-1] - 1), 0)
if img_deformed[..., x, y] > 0:
img_deformed[..., x, y] = copy[..., x_, y_]
return img_deformed, label
def pixel_shuffle_anomaly(img: np.ndarray, position: Tuple[int, int],
radius: int):
"""Pixels in the label mask are randomly shuffled
Args:
img (np.ndarray): Image to be augmented, shape [h, w]
position (Tuple[int int]): Center pixel of the mask
radius (int): Radius
Returns:
img_deformed (np.ndarray): img with sink deformation
label (np.ndarray): target segmentation mask
"""
# Create label mask
rr, cc = disk(position, radius)
rr = rr.clip(0, img.shape[0] - 1)
cc = cc.clip(0, img.shape[1] - 1)
label = np.zeros(img.shape, dtype=np.uint8)
label[rr, cc] = 1
# Remove anomaly at background pixels
mask = img > 0
label *= mask
# Create copy of image for reference
img_deformed = img.copy()
# Create permutation of indices in label mask
inds = np.where(label > 0)
perm = np.random.permutation(len(inds[0]))
inds_shuffled = [axis[perm] for axis in inds]
# Apply permutation
for x, y, x_, y_ in zip(*inds, *inds_shuffled):
img_deformed[x, y] = img[x_, y_]
return img_deformed, label