-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpreprocessing.py
122 lines (99 loc) · 3.59 KB
/
preprocessing.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
import collections
from itertools import repeat
import numpy as np
import scipy
def crop_at_zyx_with_dhw(voxel, zyx, dhw, fill_with):
'''Crop and pad on the fly.'''
shape = voxel.shape
# z, y, x = zyx
# d, h, w = dhw
crop_pos = []
padding = [[0, 0], [0, 0], [0, 0]]
for i, (center, length) in enumerate(zip(zyx, dhw)):
assert length % 2 == 0
# assert center < shape[i] # it's not necessary for "moved center"
low = round(center) - length // 2
high = round(center) + length // 2
if low < 0:
padding[i][0] = int(0 - low)
low = 0
if high > shape[i]:
padding[i][1] = int(high - shape[i])
high = shape[i]
crop_pos.append([int(low), int(high)])
cropped = voxel[crop_pos[0][0]:crop_pos[0][1], crop_pos[1]
[0]:crop_pos[1][1], crop_pos[2][0]:crop_pos[2][1]]
if np.sum(padding) > 0:
cropped = np.lib.pad(cropped, padding, 'constant',
constant_values=fill_with)
return cropped
def window_clip(v, window_low=-1024, window_high=400, dtype=np.uint8):
'''Use lung windown to map CT voxel to grey.'''
# assert v.min() <= window_low
return np.round(np.clip((v - window_low) / (window_high - window_low) * 255., 0, 255)).astype(dtype)
def spatial_normalize(voxel, spacing, new_spacing=[1., 1., 1.]):
'''Resize `voxel` from `spacing` to `new_spacing`.'''
resize_factor = []
for sp, nsp in zip(spacing, new_spacing):
resize_factor.append(float(sp) / nsp)
resized = scipy.ndimage.interpolation.zoom(
voxel.astype(float), resize_factor, mode='constant')
for i, (sp, shape, rshape) in enumerate(zip(spacing, voxel.shape, resized.shape)):
new_spacing[i] = float(sp) * shape / rshape
return resized, new_spacing
def rotation(array, angle):
'''using Euler angles method.
@author: renchao
@params:
angle: 0: no rotation, 1: rotate 90 deg, 2: rotate 180 deg, 3: rotate 270 deg
'''
#
X = np.rot90(array, angle[0], axes=(0, 1)) # rotate in X-axis
Y = np.rot90(X, angle[1], axes=(0, 2)) # rotate in Y'-axis
Z = np.rot90(Y, angle[2], axes=(1, 2)) # rotate in Z"-axis
return Z
def reflection(array, axis):
'''
@author: renchao
@params:
axis: -1: no flip, 0: Z-axis, 1: Y-axis, 2: X-axis
'''
if axis != -1:
ref = np.flip(array, axis)
else:
ref = np.copy(array)
return ref
def crop(array, zyx, dhw):
z, y, x = zyx
d, h, w = dhw
cropped = array[z - d // 2:z + d // 2,
y - h // 2:y + h // 2,
x - w // 2:x + w // 2]
return cropped
def random_center(shape, move):
offset = np.random.randint(-move, move + 1, size=3)
zyx = np.array(shape) // 2 + offset
return zyx
def get_uniform_assign(length, subset):
assert subset > 0
per_length, remain = divmod(length, subset)
total_set = np.random.permutation(list(range(subset)) * per_length)
remain_set = np.random.permutation(list(range(subset)))[:remain]
return list(total_set) + list(remain_set)
def split_validation(df, subset, by):
df = df.copy()
for sset in df[by].unique():
length = (df[by] == sset).sum()
df.loc[df[by] == sset, 'subset'] = get_uniform_assign(length, subset)
df['subset'] = df['subset'].astype(int)
return df
def _ntuple(n):
def parse(x):
if isinstance(x, collections.Iterable):
return x
return tuple(repeat(x, n))
return parse
_single = _ntuple(1)
_pair = _ntuple(2)
_triple = _ntuple(3)
_quadruple = _ntuple(4)