Vemund Fredriksen commited on
Commit
c35dad1
·
1 Parent(s): c7c329a

Initial working pipeline

Browse files
__init__.py ADDED
File without changes
lungtumormask/__init__.py ADDED
File without changes
lungtumormask/dataprocessing.py CHANGED
@@ -3,6 +3,7 @@ from lungmask import mask
3
  from monai import transforms
4
  from monai.transforms.intensity.array import ThresholdIntensity
5
  from monai.transforms.spatial.array import Resize, Spacing
 
6
  import torch
7
  from tqdm import tqdm
8
  import numpy as np
@@ -113,8 +114,9 @@ def process_lung_scan(scan_dict, extremes):
113
  transformer_1 = Compose(
114
  [
115
  DivisiblePadd(keys=["image"], k=16, mode='constant'),
116
- SqueezeDimd(keys=["image"], dim = 0),
117
- ToNumpyd(keys=["image"]),
 
118
  ]
119
  )
120
 
@@ -151,8 +153,8 @@ def preprocess(image_path):
151
 
152
  preprocess_dump['affine'] = left_lung_processed[1]
153
 
154
- preprocess_dump['right_lung'] = right_lung_processed[0]
155
- preprocess_dump['left_lung'] = left_lung_processed[0]
156
 
157
  return preprocess_dump
158
 
@@ -223,8 +225,19 @@ def stitch(org_shape, cropped, roi):
223
  return holder
224
 
225
  def post_process(left_mask, right_mask, preprocess_dump):
226
- left = remove_pad(left_mask, preprocess_dump['left_lung'])
227
- right = remove_pad(right_mask, preprocess_dump['right_lung'])
 
 
 
 
 
 
 
 
 
 
 
228
 
229
  left = voxel_space(left, preprocess_dump['left_extremes'])
230
  right = voxel_space(right, preprocess_dump['right_extremes'])
 
3
  from monai import transforms
4
  from monai.transforms.intensity.array import ThresholdIntensity
5
  from monai.transforms.spatial.array import Resize, Spacing
6
+ from monai.transforms.utility.dictionary import ToTensord
7
  import torch
8
  from tqdm import tqdm
9
  import numpy as np
 
114
  transformer_1 = Compose(
115
  [
116
  DivisiblePadd(keys=["image"], k=16, mode='constant'),
117
+ ToTensord(keys=['image'])
118
+ #SqueezeDimd(keys=["image"], dim = 0),
119
+ #ToNumpyd(keys=["image"]),
120
  ]
121
  )
122
 
 
153
 
154
  preprocess_dump['affine'] = left_lung_processed[1]
155
 
156
+ preprocess_dump['right_lung'] = right_lung_processed[0].unsqueeze(0)
157
+ preprocess_dump['left_lung'] = left_lung_processed[0].unsqueeze(0)
158
 
159
  return preprocess_dump
160
 
 
225
  return holder
226
 
227
  def post_process(left_mask, right_mask, preprocess_dump):
228
+
229
+ left_mask[left_mask >= 0.5] = 1
230
+ left_mask[left_mask < 0.5] = 0
231
+
232
+ left_mask = left_mask.astype(int)
233
+
234
+ right_mask[right_mask >= 0.5] = 1
235
+ right_mask[right_mask < 0.5] = 0
236
+
237
+ right_mask = right_mask.astype(int)
238
+
239
+ left = remove_pad(left_mask, preprocess_dump['left_lung'].squeeze(0).squeeze(0).numpy())
240
+ right = remove_pad(right_mask, preprocess_dump['right_lung'].squeeze(0).squeeze(0).numpy())
241
 
242
  left = voxel_space(left, preprocess_dump['left_extremes'])
243
  right = voxel_space(right, preprocess_dump['right_extremes'])
lungtumormask/mask.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from numpy import load
2
+ from lungtumormask.dataprocessing import preprocess, post_process
3
+ from lungtumormask.network import UNet_double
4
+ import torch as T
5
+ import nibabel
6
+
7
+ def load_model():
8
+ model = UNet_double(3, 1, 1, tuple([64, 128, 256, 512, 1024]), tuple([2 for i in range(4)]), num_res_units = 0)
9
+ state_dict = T.hub.load_state_dict_from_url("https://github.com/VemundFredriksen/LungTumorMask/releases/download/0.0/dc_student.pth", progress=True, map_location=T.device('cuda:0'))
10
+ #model.load_state_dict(T.load("D:\\OneDrive\\Skole\\Universitet\\10. Semester\\Masteroppgave\\bruk_for_full_model.pth", map_location="cuda:0"))
11
+ model.load_state_dict(state_dict)
12
+ model.eval()
13
+ return model
14
+
15
+ def mask(image_path, save_path):
16
+ print("Loading model...")
17
+ model = load_model()
18
+
19
+ print("Preprocessing image...")
20
+ preprocess_dump = preprocess(image_path)
21
+
22
+ print("Looking for tumors...")
23
+ left = model(preprocess_dump['left_lung']).squeeze(0).squeeze(0).detach().numpy()
24
+ right = model(preprocess_dump['right_lung']).squeeze(0).squeeze(0).detach().numpy()
25
+
26
+ print("Post-processing image...")
27
+ infered = post_process(left, right, preprocess_dump)
28
+
29
+ print(f"Storing segmentation at {save_path}")
30
+ nimage = nibabel.Nifti1Image(infered, preprocess_dump['org_affine'])
31
+ nibabel.save(nimage, save_path)
32
+
33
+ if __name__ == "__main__":
34
+ mask("D:\\Datasets\\MSD\\Images\\lung_003.nii.gz", "D:\\Datasets\\MSD\\Images\\out3.nii.gz")
lungtumormask/network.py ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Sequence, Union
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+
6
+ from monai.networks.blocks.convolutions import Convolution, ResidualUnit
7
+ from monai.networks.layers.factories import Act, Norm
8
+ from monai.networks.layers.simplelayers import SkipConnection
9
+ from monai.utils import alias, export
10
+
11
+ class UNet_double(nn.Module):
12
+ def __init__(
13
+ self,
14
+ dimensions: int,
15
+ in_channels: int,
16
+ out_channels: int,
17
+ channels: Sequence[int],
18
+ strides: Sequence[int],
19
+ kernel_size: Union[Sequence[int], int] = 3,
20
+ up_kernel_size: Union[Sequence[int], int] = 3,
21
+ num_res_units: int = 0,
22
+ act=Act.PRELU,
23
+ norm=Norm.INSTANCE,
24
+ dropout=0.0,) -> None:
25
+
26
+ super().__init__()
27
+
28
+ self.dimensions = dimensions
29
+ self.in_channels = in_channels
30
+ self.out_channels = out_channels
31
+ self.channels = channels
32
+ self.strides = strides
33
+ self.kernel_size = kernel_size
34
+ self.up_kernel_size = up_kernel_size
35
+ self.num_res_units = num_res_units
36
+ self.act = act
37
+ self.norm = norm
38
+ self.dropout = dropout
39
+
40
+ def _create_block(
41
+ inc: int, outc: int, channels: Sequence[int], strides: Sequence[int], is_top: bool) -> nn.Sequential:
42
+
43
+ c = channels[0]
44
+ s = strides[0]
45
+
46
+ subblock: nn.Module
47
+
48
+ if len(channels) > 2:
49
+ subblock1, subblock2 = _create_block(c, c, channels[1:], strides[1:], False) # continue recursion down
50
+ upc = c * 2
51
+ else:
52
+ # the next layer is the bottom so stop recursion, create the bottom layer as the sublock for this layer
53
+ subblock = self._get_bottom_layer(c, channels[1])
54
+ upc = c + channels[1]
55
+
56
+ down = self._get_down_layer(inc, c, s, is_top) # create layer in downsampling path
57
+ up1 = self._get_up_layer(upc, outc, s, is_top) # create layer in upsampling path
58
+ up2 = self._get_up_layer(upc, outc, s, is_top)
59
+
60
+ return nn.Sequential(down, SkipConnection(subblock), up1), nn.Sequential(down, SkipConnection(subblock), up2)
61
+
62
+ down = self._get_down_layer(inc, c, s, is_top) # create layer in downsampling path
63
+ up1 = self._get_up_layer(upc, outc, s, is_top) # create layer in upsampling path
64
+ up2 = self._get_up_layer(upc, outc, s, is_top)
65
+
66
+ return nn.Sequential(down, SkipConnection(subblock1), up1), nn.Sequential(down, SkipConnection(subblock2), up2)
67
+
68
+ self.model1, self.model2 = _create_block(in_channels, out_channels, self.channels, self.strides, True)
69
+ self.activation = nn.Sigmoid()
70
+
71
+ def _get_down_layer(self, in_channels: int, out_channels: int, strides: int, is_top: bool) -> nn.Module:
72
+ """
73
+ Args:
74
+ in_channels: number of input channels.
75
+ out_channels: number of output channels.
76
+ strides: convolution stride.
77
+ is_top: True if this is the top block.
78
+ """
79
+ if self.num_res_units > 0:
80
+ return ResidualUnit(
81
+ self.dimensions,
82
+ in_channels,
83
+ out_channels,
84
+ strides=strides,
85
+ kernel_size=self.kernel_size,
86
+ subunits=self.num_res_units,
87
+ act=self.act,
88
+ norm=self.norm,
89
+ dropout=self.dropout,
90
+ )
91
+ return Convolution(
92
+ self.dimensions,
93
+ in_channels,
94
+ out_channels,
95
+ strides=strides,
96
+ kernel_size=self.kernel_size,
97
+ act=self.act,
98
+ norm=self.norm,
99
+ dropout=self.dropout,
100
+ )
101
+
102
+ def _get_bottom_layer(self, in_channels: int, out_channels: int) -> nn.Module:
103
+ """
104
+ Args:
105
+ in_channels: number of input channels.
106
+ out_channels: number of output channels.
107
+ """
108
+ return self._get_down_layer(in_channels, out_channels, 1, False)
109
+
110
+ def _get_up_layer(self, in_channels: int, out_channels: int, strides: int, is_top: bool) -> nn.Module:
111
+ """
112
+ Args:
113
+ in_channels: number of input channels.
114
+ out_channels: number of output channels.
115
+ strides: convolution stride.
116
+ is_top: True if this is the top block.
117
+ """
118
+ conv: Union[Convolution, nn.Sequential]
119
+
120
+ conv = Convolution(
121
+ self.dimensions,
122
+ in_channels,
123
+ out_channels,
124
+ strides=strides,
125
+ kernel_size=self.up_kernel_size,
126
+ act=self.act,
127
+ norm=self.norm,
128
+ dropout=self.dropout,
129
+ conv_only=is_top and self.num_res_units == 0,
130
+ is_transposed=True,
131
+ )
132
+
133
+ if self.num_res_units > 0:
134
+ ru = ResidualUnit(
135
+ self.dimensions,
136
+ out_channels,
137
+ out_channels,
138
+ strides=1,
139
+ kernel_size=self.kernel_size,
140
+ subunits=1,
141
+ act=self.act,
142
+ norm=self.norm,
143
+ dropout=self.dropout,
144
+ last_conv_only=is_top,
145
+ )
146
+ conv = nn.Sequential(conv, ru)
147
+
148
+ return conv
149
+
150
+ def forward(self, x, box = None) -> torch.Tensor:
151
+ return self.activation(self.model1(x))
setup.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="LungTumorMask",
5
+ packages=find_packages(),
6
+ version='1.0.1',
7
+ author="Svein Ole M Sevle, Vemund Fredriksen",
8
+ url="https://github.com/VemundFredriksen/LungTumorMask",
9
+ license="MIT",
10
+ python_requires='>=3.6'
11
+ )