-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.py
145 lines (113 loc) · 5.73 KB
/
utils.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
import json
from typing import Any
import numpy as np
import scipy.ndimage as nd
from keras.activations import elu
from keras.engine import Input
from keras.layers import Conv3D, add, concatenate, Conv3DTranspose
from keras.models import Model
def selu(x): # https://gist.github.com/naure/78bc7a881a9db17e366093c81425184f
"""Scaled Exponential Linear Unit. (Klambauer et al., 2017)
# Arguments
x: A tensor or variable to compute the activation function for.
# References
- [Self-Normalizing Neural Networks](https://arxiv.org/abs/1706.02515)
"""
alpha = 1.6732632423543772848170429916717
scale = 1.0507009873554804934193349852946
return scale * elu(x, alpha)
def downward_layer(input_layer, n_convolutions: int, n_output_channels: int) -> (Any, Any):
inl = input_layer
for _ in range(n_convolutions):
inl = Conv3D(filters=(n_output_channels // 2), kernel_size=5, activation=selu, padding='same', kernel_initializer='he_normal')(inl)
add_l = add([inl, input_layer])
downsample = Conv3D(filters=n_output_channels, kernel_size=2, strides=2, activation=selu, padding='same', kernel_initializer='he_normal')(add_l)
downsample = (downsample)
return downsample, add_l
def upward_layer(input0, input1, n_convolutions: int, n_output_channels: int) -> Any:
merged = concatenate([input0, input1], axis=4)
inl = merged
for _ in range(n_convolutions):
inl = Conv3D((n_output_channels * 4), kernel_size=5, padding='same', activation=selu, kernel_initializer='he_normal')(inl)
add_l = add([inl, merged])
shape = add_l.get_shape().as_list()
new_shape = (1, shape[1] * 2, shape[2] * 2, shape[3] * 2, n_output_channels)
upsample = Conv3DTranspose(n_output_channels, (2, 2, 2), strides=(2, 2, 2), activation=selu, padding='same', kernel_initializer='he_normal')(add_l)
return (upsample)
def iliopsoas_seg_net(input_size):
# Down 1
inputs = Input(input_size)
conv_1 = Conv3D(8, kernel_size=5, strides=1, activation=selu, padding='same', kernel_initializer='he_normal')(inputs)
repeat_1 = concatenate(8 * [inputs], axis=-1)
add_1 = add([conv_1, repeat_1])
down_1 = Conv3D(16, 2, strides=2, activation=selu, padding='same', kernel_initializer='he_normal')(add_1)
# Down 2,3,4
down_2, add_2 = downward_layer(down_1, 2, 32)
down_3, add_3 = downward_layer(down_2, 3, 64)
down_4, add_4 = downward_layer(down_3, 3, 128)
# Bottom
conv_5_1 = Conv3D(128, kernel_size=(5, 5, 5), activation=selu, padding='same', kernel_initializer='he_normal')(down_4)
conv_5_2 = Conv3D(128, kernel_size=(5, 5, 5), activation=selu, padding='same', kernel_initializer='he_normal')(conv_5_1)
conv_5_3 = Conv3D(128, kernel_size=(5, 5, 5), activation=selu, padding='same', kernel_initializer='he_normal')(conv_5_2)
add5 = add([conv_5_3, down_4])
aux_shape = add5.get_shape()
upsample_5 = Conv3DTranspose(64, (2, 2, 2), padding='same', activation=selu, strides=(2, 2, 2), kernel_initializer='he_normal')(add5)
# Up 6,7,8
upsample_6 = upward_layer(upsample_5, add_4, 3, 32)
upsample_7 = upward_layer(upsample_6, add_3, 3, 16)
upsample_8 = upward_layer(upsample_7, add_2, 2, 8)
# Up 9
merged_9 = concatenate([upsample_8, add_1], axis=4)
conv_9_1 = Conv3D(16, kernel_size=(5, 5, 5), activation=selu, padding='same', kernel_initializer='he_normal')(merged_9)
add_9 = add([conv_9_1, merged_9])
conv_9_2 = Conv3D(1, kernel_size=(1, 1, 1), activation=selu, padding='same', kernel_initializer='he_normal')(add_9)
sigmoid = Conv3D(1, kernel_size=(1, 1, 1), padding='same', kernel_initializer='he_normal', activation='sigmoid')(conv_9_2)
model = Model(inputs=inputs, outputs=sigmoid)
return model
BONE_LABELS = {
'shoulder': {'right': 1, 'left': 2},
'femur_head': {'right': 11, 'left': 12},
'femur_base': {'right': 21, 'left': 22},
}
BONE_LABEL_ALIASES = {
'hip': 'femur_head',
'knee': 'femur_base',
}
def load_landmarks() -> dict:
with open('landmarks/bone_joints.json', 'r') as json_file:
landmarks_dict = json.load(json_file)
output = dict()
for bone_type in BONE_LABELS:
output[bone_type] = dict()
bone_type_z = list()
for bone in BONE_LABELS[bone_type]:
bone_index = BONE_LABELS[bone_type][bone]
bone_str = str(bone_index)
if bone_str not in landmarks_dict.keys():
print('Cannot find {}, {} in detected bone data'.format(bone_type, bone))
output[bone_type][bone] = np.array([np.NAN, np.NAN, np.NAN])
else:
output[bone_type][bone] = np.array(landmarks_dict[bone_str], dtype='int')
bone_type_z.append(landmarks_dict[bone_str][2])
if np.any(np.isfinite(bone_type_z)):
output[bone_type]['z'] = int(np.nanmean(bone_type_z))
else:
output[bone_type]['z'] = None
for alias_key in BONE_LABEL_ALIASES:
output[alias_key] = output[BONE_LABEL_ALIASES[alias_key]]
return output
def largest_connected_components(img: np.ndarray, n_components: int = 1, structure: np.ndarray = None) -> np.ndarray:
labels, nb_labels = nd.label(img > 0, structure=structure)
res = np.zeros(img.shape, dtype='int')
if n_components > nb_labels:
print('requested number of components ({}) larger than image contains ({})'.format(n_components, nb_labels))
n_components = nb_labels
hist = nd.histogram(labels, 1, nb_labels, nb_labels)
i_sort = np.argsort(hist)[::-1][:n_components] + 1
for i_n, i in enumerate(i_sort, start=1):
res[labels == i] = i_n
return res
def normalize(img: np.ndarray) -> np.ndarray:
img = img.astype('float32') / np.percentile(img, 99)
img[img > 1.0] = 0.975
return img