Commit 0f3937003464e9946a3f728ac8e8c35f26c147bc
Committed by
GitHub
1 parent
dfac1497
Exists in
master
Brain segmentation in other process (#233)
* Using subprocess to start brain segmenter * Wrong mode in comm_array opening * Managing errors * calling get_plaidml_device out of main process to avoid crash with plaidml * Trying to use multiprocessing instead of subprocess * Trying to use multiprocessing instead of subprocess * Using a class to keep brain segmentation * Putting probability_array in SegmentProcess * Some cleaning and style modifications * Moved brainseg model to models/brain_mri_t1 * Setting _ on children process * Added option to create or no create a new mask * Setting lang and _ outside of InVesalius class * models -> ai
Showing
10 changed files
with
330 additions
and
147 deletions
Show diff stats
No preview for this file type
... | ... | @@ -0,0 +1 @@ |
1 | +{"class_name": "Model", "config": {"name": "model_1", "layers": [{"name": "img", "class_name": "InputLayer", "config": {"batch_input_shape": [null, 48, 48, 48, 1], "dtype": "float32", "sparse": false, "name": "img"}, "inbound_nodes": []}, {"name": "conv3d_1", "class_name": "Conv3D", "config": {"name": "conv3d_1", "trainable": true, "filters": 8, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["img", 0, 0, {}]]]}, {"name": "conv3d_2", "class_name": "Conv3D", "config": {"name": "conv3d_2", "trainable": true, "filters": 8, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["conv3d_1", 0, 0, {}]]]}, {"name": "max_pooling3d_1", "class_name": "MaxPooling3D", "config": {"name": "max_pooling3d_1", "trainable": true, "pool_size": [2, 2, 2], "padding": "valid", "strides": [2, 2, 2], "data_format": "channels_last"}, "inbound_nodes": [[["conv3d_2", 0, 0, {}]]]}, {"name": "dropout_1", "class_name": "Dropout", "config": {"name": "dropout_1", "trainable": true, "rate": 0.3, "noise_shape": null, "seed": null}, "inbound_nodes": [[["max_pooling3d_1", 0, 0, {}]]]}, {"name": "conv3d_3", "class_name": "Conv3D", "config": {"name": "conv3d_3", "trainable": true, "filters": 16, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dropout_1", 0, 0, {}]]]}, {"name": "conv3d_4", "class_name": "Conv3D", "config": {"name": "conv3d_4", "trainable": true, "filters": 16, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["conv3d_3", 0, 0, {}]]]}, {"name": "max_pooling3d_2", "class_name": "MaxPooling3D", "config": {"name": "max_pooling3d_2", "trainable": true, "pool_size": [2, 2, 2], "padding": "valid", "strides": [2, 2, 2], "data_format": "channels_last"}, "inbound_nodes": [[["conv3d_4", 0, 0, {}]]]}, {"name": "dropout_2", "class_name": "Dropout", "config": {"name": "dropout_2", "trainable": true, "rate": 0.3, "noise_shape": null, "seed": null}, "inbound_nodes": [[["max_pooling3d_2", 0, 0, {}]]]}, {"name": "conv3d_5", "class_name": "Conv3D", "config": {"name": "conv3d_5", "trainable": true, "filters": 32, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dropout_2", 0, 0, {}]]]}, {"name": "conv3d_6", "class_name": "Conv3D", "config": {"name": "conv3d_6", "trainable": true, "filters": 32, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["conv3d_5", 0, 0, {}]]]}, {"name": "max_pooling3d_3", "class_name": "MaxPooling3D", "config": {"name": "max_pooling3d_3", "trainable": true, "pool_size": [2, 2, 2], "padding": "valid", "strides": [2, 2, 2], "data_format": "channels_last"}, "inbound_nodes": [[["conv3d_6", 0, 0, {}]]]}, {"name": "dropout_3", "class_name": "Dropout", "config": {"name": "dropout_3", "trainable": true, "rate": 0.3, "noise_shape": null, "seed": null}, "inbound_nodes": [[["max_pooling3d_3", 0, 0, {}]]]}, {"name": "conv3d_transpose_1", "class_name": "Conv3DTranspose", "config": {"name": "conv3d_transpose_1", "trainable": true, "filters": 32, "kernel_size": [5, 5, 5], "strides": [2, 2, 2], "padding": "same", "data_format": "channels_last", "activation": "linear", "use_bias": false, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null, "output_padding": null}, "inbound_nodes": [[["dropout_3", 0, 0, {}]]]}, {"name": "concatenate_1", "class_name": "Concatenate", "config": {"name": "concatenate_1", "trainable": true, "axis": -1}, "inbound_nodes": [[["conv3d_transpose_1", 0, 0, {}], ["conv3d_6", 0, 0, {}]]]}, {"name": "conv3d_7", "class_name": "Conv3D", "config": {"name": "conv3d_7", "trainable": true, "filters": 32, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["concatenate_1", 0, 0, {}]]]}, {"name": "dropout_4", "class_name": "Dropout", "config": {"name": "dropout_4", "trainable": true, "rate": 0.3, "noise_shape": null, "seed": null}, "inbound_nodes": [[["conv3d_7", 0, 0, {}]]]}, {"name": "conv3d_transpose_2", "class_name": "Conv3DTranspose", "config": {"name": "conv3d_transpose_2", "trainable": true, "filters": 16, "kernel_size": [5, 5, 5], "strides": [2, 2, 2], "padding": "same", "data_format": "channels_last", "activation": "linear", "use_bias": false, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null, "output_padding": null}, "inbound_nodes": [[["dropout_4", 0, 0, {}]]]}, {"name": "concatenate_2", "class_name": "Concatenate", "config": {"name": "concatenate_2", "trainable": true, "axis": -1}, "inbound_nodes": [[["conv3d_transpose_2", 0, 0, {}], ["conv3d_4", 0, 0, {}]]]}, {"name": "conv3d_8", "class_name": "Conv3D", "config": {"name": "conv3d_8", "trainable": true, "filters": 16, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["concatenate_2", 0, 0, {}]]]}, {"name": "dropout_5", "class_name": "Dropout", "config": {"name": "dropout_5", "trainable": true, "rate": 0.3, "noise_shape": null, "seed": null}, "inbound_nodes": [[["conv3d_8", 0, 0, {}]]]}, {"name": "conv3d_transpose_3", "class_name": "Conv3DTranspose", "config": {"name": "conv3d_transpose_3", "trainable": true, "filters": 8, "kernel_size": [5, 5, 5], "strides": [2, 2, 2], "padding": "same", "data_format": "channels_last", "activation": "linear", "use_bias": false, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null, "output_padding": null}, "inbound_nodes": [[["dropout_5", 0, 0, {}]]]}, {"name": "concatenate_3", "class_name": "Concatenate", "config": {"name": "concatenate_3", "trainable": true, "axis": -1}, "inbound_nodes": [[["conv3d_transpose_3", 0, 0, {}], ["conv3d_2", 0, 0, {}]]]}, {"name": "conv3d_9", "class_name": "Conv3D", "config": {"name": "conv3d_9", "trainable": true, "filters": 8, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["concatenate_3", 0, 0, {}]]]}, {"name": "dropout_6", "class_name": "Dropout", "config": {"name": "dropout_6", "trainable": true, "rate": 0.3, "noise_shape": null, "seed": null}, "inbound_nodes": [[["conv3d_9", 0, 0, {}]]]}, {"name": "conv3d_10", "class_name": "Conv3D", "config": {"name": "conv3d_10", "trainable": true, "filters": 1, "kernel_size": [1, 1, 1], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dropout_6", 0, 0, {}]]]}, {"name": "dense_1", "class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "units": 1, "activation": "sigmoid", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["conv3d_10", 0, 0, {}]]]}], "input_layers": [["img", 0, 0]], "output_layers": [["dense_1", 0, 0]]}, "keras_version": "2.2.4", "backend": "plaidml.keras.backend"} | |
0 | 2 | \ No newline at end of file | ... | ... |
app.py
... | ... | @@ -65,6 +65,7 @@ import invesalius.utils as utils |
65 | 65 | from invesalius import inv_paths |
66 | 66 | |
67 | 67 | FS_ENCODE = sys.getfilesystemencoding() |
68 | +LANG = None | |
68 | 69 | |
69 | 70 | # ------------------------------------------------------------------ |
70 | 71 | |
... | ... | @@ -78,6 +79,17 @@ if sys.platform in ('linux2', 'linux', 'win32'): |
78 | 79 | del tmp_var |
79 | 80 | |
80 | 81 | |
82 | +session = ses.Session() | |
83 | +if session.ReadSession(): | |
84 | + lang = session.GetLanguage() | |
85 | + if lang: | |
86 | + LANG = lang | |
87 | + try: | |
88 | + _ = i18n.InstallLanguage(lang) | |
89 | + except FileNotFoundError: | |
90 | + LANG = None | |
91 | + | |
92 | + | |
81 | 93 | class InVesalius(wx.App): |
82 | 94 | """ |
83 | 95 | InVesalius wxPython application class. |
... | ... | @@ -119,26 +131,18 @@ class Inv3SplashScreen(SplashScreen): |
119 | 131 | """ |
120 | 132 | def __init__(self): |
121 | 133 | # Splash screen image will depend on currently language |
122 | - lang = False | |
123 | - | |
134 | + lang = LANG | |
124 | 135 | self.locale = wx.Locale(wx.LANGUAGE_DEFAULT) |
125 | 136 | |
126 | 137 | # Language information is available in session configuration |
127 | 138 | # file. First we need to check if this file exist, if now, it |
128 | 139 | # should be created |
129 | - create_session = False | |
130 | - session = ses.Session() | |
131 | - if not (session.ReadSession()): | |
132 | - create_session = True | |
140 | + create_session = LANG is None | |
133 | 141 | |
134 | 142 | install_lang = 0 |
135 | - lang = session.GetLanguage() | |
136 | 143 | if lang: |
137 | - if (lang != "False"): | |
138 | - _ = i18n.InstallLanguage(lang) | |
139 | - install_lang = 1 | |
140 | - else: | |
141 | - install_lang = 0 | |
144 | + _ = i18n.InstallLanguage(lang) | |
145 | + install_lang = 1 | |
142 | 146 | else: |
143 | 147 | install_lang = 0 |
144 | 148 | |
... | ... | @@ -262,7 +266,10 @@ class Inv3SplashScreen(SplashScreen): |
262 | 266 | |
263 | 267 | |
264 | 268 | def non_gui_startup(options, args): |
265 | - lang = 'en' | |
269 | + if LANG: | |
270 | + lang = LANG | |
271 | + else: | |
272 | + lang = 'en' | |
266 | 273 | _ = i18n.InstallLanguage(lang) |
267 | 274 | |
268 | 275 | from invesalius.control import Controller | ... | ... |
invesalius/gui/brain_seg_dialog.py
... | ... | @@ -2,76 +2,85 @@ |
2 | 2 | # -*- coding: UTF-8 -*- |
3 | 3 | |
4 | 4 | import importlib |
5 | +import multiprocessing | |
5 | 6 | import os |
6 | 7 | import pathlib |
8 | +import subprocess | |
7 | 9 | import sys |
10 | +import tempfile | |
8 | 11 | import time |
9 | 12 | |
13 | +import numpy as np | |
10 | 14 | import wx |
11 | 15 | from pubsub import pub as Publisher |
12 | 16 | |
13 | -# Linux if installed plaidml with pip3 install --user | |
14 | -if sys.platform.startswith("linux"): | |
15 | - local_user_plaidml = pathlib.Path("~/.local/share/plaidml/").expanduser().absolute() | |
16 | - if local_user_plaidml.exists(): | |
17 | - os.environ["RUNFILES_DIR"] = str(local_user_plaidml) | |
18 | - os.environ["PLAIDML_NATIVE_PATH"] = str(pathlib.Path("~/.local/lib/libplaidml.so").expanduser().absolute()) | |
19 | -# Mac if using python3 from homebrew | |
20 | -elif sys.platform == "darwin": | |
21 | - local_user_plaidml = pathlib.Path("/usr/local/share/plaidml") | |
22 | - if local_user_plaidml.exists(): | |
23 | - os.environ["RUNFILES_DIR"] = str(local_user_plaidml) | |
24 | - os.environ["PLAIDML_NATIVE_PATH"] = str(pathlib.Path("/usr/local/lib/libplaidml.dylib").expanduser().absolute()) | |
17 | +import invesalius.data.slice_ as slc | |
18 | +from invesalius.segmentation.brain import segment, utils | |
25 | 19 | |
26 | 20 | HAS_THEANO = bool(importlib.util.find_spec("theano")) |
27 | 21 | HAS_PLAIDML = bool(importlib.util.find_spec("plaidml")) |
28 | 22 | PLAIDML_DEVICES = {} |
29 | 23 | |
30 | -import invesalius.data.slice_ as slc | |
31 | -from invesalius.segmentation.brain import segment | |
32 | -from invesalius.segmentation.brain import utils | |
33 | - | |
34 | -try: | |
35 | - import theano | |
36 | -except ImportError: | |
37 | - HAS_THEANO = False | |
38 | - | |
39 | -try: | |
40 | - import plaidml | |
41 | -except ImportError: | |
42 | - HAS_PLAIDML = False | |
43 | 24 | |
44 | 25 | if HAS_PLAIDML: |
45 | - try: | |
46 | - PLAIDML_DEVICES = utils.get_plaidml_devices() | |
47 | - except OSError: | |
48 | - HAS_PLAIDML = False | |
26 | + with multiprocessing.Pool(1) as p: | |
27 | + try: | |
28 | + PLAIDML_DEVICES = p.apply(utils.get_plaidml_devices) | |
29 | + except Exception as err: | |
30 | + print(err) | |
31 | + PLAIDML_DEVICES = {} | |
32 | + HAS_PLAIDML = False | |
49 | 33 | |
50 | 34 | |
51 | 35 | class BrainSegmenterDialog(wx.Dialog): |
52 | 36 | def __init__(self, parent): |
53 | - wx.Dialog.__init__(self, parent, -1, _(u"Brain segmentation"), style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT) | |
37 | + wx.Dialog.__init__( | |
38 | + self, | |
39 | + parent, | |
40 | + -1, | |
41 | + _(u"Brain segmentation"), | |
42 | + style=wx.DEFAULT_DIALOG_STYLE | wx.FRAME_FLOAT_ON_PARENT, | |
43 | + ) | |
54 | 44 | backends = [] |
55 | 45 | if HAS_PLAIDML: |
56 | 46 | backends.append("PlaidML") |
57 | 47 | if HAS_THEANO: |
58 | 48 | backends.append("Theano") |
59 | - self.segmenter = segment.BrainSegmenter() | |
49 | + # self.segmenter = segment.BrainSegmenter() | |
60 | 50 | # self.pg_dialog = None |
61 | 51 | self.plaidml_devices = PLAIDML_DEVICES |
62 | - self.cb_backends = wx.ComboBox(self, wx.ID_ANY, choices=backends, value=backends[0], style=wx.CB_DROPDOWN | wx.CB_READONLY) | |
52 | + | |
53 | + self.ps = None | |
54 | + self.segmented = False | |
55 | + self.mask = None | |
56 | + | |
57 | + self.cb_backends = wx.ComboBox( | |
58 | + self, | |
59 | + wx.ID_ANY, | |
60 | + choices=backends, | |
61 | + value=backends[0], | |
62 | + style=wx.CB_DROPDOWN | wx.CB_READONLY, | |
63 | + ) | |
63 | 64 | w, h = self.CalcSizeFromTextSize("MM" * (1 + max(len(i) for i in backends))) |
64 | 65 | self.cb_backends.SetMinClientSize((w, -1)) |
65 | 66 | self.chk_use_gpu = wx.CheckBox(self, wx.ID_ANY, _("Use GPU")) |
66 | 67 | if HAS_PLAIDML: |
67 | 68 | self.lbl_device = wx.StaticText(self, -1, _("Device")) |
68 | - self.cb_devices = wx.ComboBox(self, wx.ID_ANY, choices=list(self.plaidml_devices.keys()), value=list(self.plaidml_devices.keys())[0],style=wx.CB_DROPDOWN | wx.CB_READONLY) | |
69 | + self.cb_devices = wx.ComboBox( | |
70 | + self, | |
71 | + wx.ID_ANY, | |
72 | + choices=list(self.plaidml_devices.keys()), | |
73 | + value=list(self.plaidml_devices.keys())[0], | |
74 | + style=wx.CB_DROPDOWN | wx.CB_READONLY, | |
75 | + ) | |
69 | 76 | self.sld_threshold = wx.Slider(self, wx.ID_ANY, 75, 0, 100) |
70 | 77 | w, h = self.CalcSizeFromTextSize("M" * 20) |
71 | 78 | self.sld_threshold.SetMinClientSize((w, -1)) |
72 | 79 | self.txt_threshold = wx.TextCtrl(self, wx.ID_ANY, "") |
73 | 80 | w, h = self.CalcSizeFromTextSize("MMMMM") |
74 | 81 | self.txt_threshold.SetMinClientSize((w, -1)) |
82 | + self.chk_new_mask = wx.CheckBox(self, wx.ID_ANY, _("Create new mask")) | |
83 | + self.chk_new_mask.SetValue(True) | |
75 | 84 | self.progress = wx.Gauge(self, -1) |
76 | 85 | self.lbl_progress_caption = wx.StaticText(self, -1, _("Elapsed time:")) |
77 | 86 | self.lbl_time = wx.StaticText(self, -1, _("00:00:00")) |
... | ... | @@ -103,18 +112,30 @@ class BrainSegmenterDialog(wx.Dialog): |
103 | 112 | main_sizer.Add(sizer_devices, 0, wx.ALL | wx.EXPAND, 5) |
104 | 113 | label_5 = wx.StaticText(self, wx.ID_ANY, _("Level of certainty")) |
105 | 114 | main_sizer.Add(label_5, 0, wx.ALL, 5) |
106 | - sizer_3.Add(self.sld_threshold, 1, wx.ALIGN_CENTER | wx.BOTTOM | wx.EXPAND | wx.LEFT | wx.RIGHT, 5) | |
115 | + sizer_3.Add( | |
116 | + self.sld_threshold, | |
117 | + 1, | |
118 | + wx.ALIGN_CENTER | wx.BOTTOM | wx.EXPAND | wx.LEFT | wx.RIGHT, | |
119 | + 5, | |
120 | + ) | |
107 | 121 | sizer_3.Add(self.txt_threshold, 0, wx.ALL, 5) |
108 | 122 | main_sizer.Add(sizer_3, 0, wx.EXPAND, 0) |
123 | + main_sizer.Add(self.chk_new_mask, 0, wx.EXPAND | wx.ALL, 5) | |
109 | 124 | main_sizer.Add(self.progress, 0, wx.EXPAND | wx.ALL, 5) |
110 | 125 | time_sizer = wx.BoxSizer(wx.HORIZONTAL) |
111 | 126 | time_sizer.Add(self.lbl_progress_caption, 0, wx.EXPAND, 0) |
112 | 127 | time_sizer.Add(self.lbl_time, 1, wx.EXPAND | wx.LEFT, 5) |
113 | 128 | main_sizer.Add(time_sizer, 0, wx.EXPAND | wx.ALL, 5) |
114 | 129 | sizer_buttons = wx.BoxSizer(wx.HORIZONTAL) |
115 | - sizer_buttons.Add(self.btn_close, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT | wx.ALL, 5) | |
116 | - sizer_buttons.Add(self.btn_stop, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT | wx.ALL, 5) | |
117 | - sizer_buttons.Add(self.btn_segment, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT | wx.ALL, 5) | |
130 | + sizer_buttons.Add( | |
131 | + self.btn_close, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT | wx.ALL, 5 | |
132 | + ) | |
133 | + sizer_buttons.Add( | |
134 | + self.btn_stop, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT | wx.ALL, 5 | |
135 | + ) | |
136 | + sizer_buttons.Add( | |
137 | + self.btn_segment, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT | wx.ALL, 5 | |
138 | + ) | |
118 | 139 | main_sizer.Add(sizer_buttons, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT | wx.ALL, 0) |
119 | 140 | self.SetSizer(main_sizer) |
120 | 141 | main_sizer.Fit(self) |
... | ... | @@ -138,6 +159,13 @@ class BrainSegmenterDialog(wx.Dialog): |
138 | 159 | self.elapsed_time_timer.Bind(wx.EVT_TIMER, self.OnTickTimer) |
139 | 160 | self.Bind(wx.EVT_CLOSE, self.OnClose) |
140 | 161 | |
162 | + def apply_segment_threshold(self): | |
163 | + threshold = self.sld_threshold.GetValue() / 100.0 | |
164 | + if self.ps is not None: | |
165 | + self.ps.apply_segment_threshold(threshold) | |
166 | + slc.Slice().discard_all_buffers() | |
167 | + Publisher.sendMessage("Reload actual slice") | |
168 | + | |
141 | 169 | def CalcSizeFromTextSize(self, text): |
142 | 170 | dc = wx.WindowDC(self) |
143 | 171 | dc.SetFont(self.GetFont()) |
... | ... | @@ -162,15 +190,12 @@ class BrainSegmenterDialog(wx.Dialog): |
162 | 190 | def OnScrollThreshold(self, evt): |
163 | 191 | value = self.sld_threshold.GetValue() |
164 | 192 | self.txt_threshold.SetValue("{:3d}%".format(self.sld_threshold.GetValue())) |
165 | - if self.segmenter.segmented: | |
166 | - threshold = value / 100.0 | |
167 | - self.segmenter.set_threshold(threshold) | |
168 | - image = slc.Slice().discard_all_buffers() | |
169 | - Publisher.sendMessage('Reload actual slice') | |
193 | + if self.segmented: | |
194 | + self.apply_segment_threshold() | |
170 | 195 | |
171 | 196 | def OnKillFocus(self, evt): |
172 | 197 | value = self.txt_threshold.GetValue() |
173 | - value = value.replace('%', '') | |
198 | + value = value.replace("%", "") | |
174 | 199 | try: |
175 | 200 | value = int(value) |
176 | 201 | except ValueError: |
... | ... | @@ -178,11 +203,8 @@ class BrainSegmenterDialog(wx.Dialog): |
178 | 203 | self.sld_threshold.SetValue(value) |
179 | 204 | self.txt_threshold.SetValue("{:3d}%".format(value)) |
180 | 205 | |
181 | - if self.segmenter.segmented: | |
182 | - threshold = value / 100.0 | |
183 | - self.segmenter.set_threshold(threshold) | |
184 | - image = slc.Slice().discard_all_buffers() | |
185 | - Publisher.sendMessage('Reload actual slice') | |
206 | + if self.segmented: | |
207 | + self.apply_segment_threshold() | |
186 | 208 | |
187 | 209 | def OnSegment(self, evt): |
188 | 210 | self.ShowProgress() |
... | ... | @@ -194,44 +216,97 @@ class BrainSegmenterDialog(wx.Dialog): |
194 | 216 | device_id = self.plaidml_devices[self.cb_devices.GetValue()] |
195 | 217 | except (KeyError, AttributeError): |
196 | 218 | device_id = "llvm_cpu.0" |
219 | + create_new_mask = self.chk_new_mask.GetValue() | |
197 | 220 | use_gpu = self.chk_use_gpu.GetValue() |
198 | 221 | prob_threshold = self.sld_threshold.GetValue() / 100.0 |
199 | 222 | self.btn_close.Disable() |
200 | 223 | self.btn_stop.Enable() |
201 | 224 | self.btn_segment.Disable() |
202 | - self.segmenter.segment(image, prob_threshold, backend, device_id, use_gpu, self.SetProgress, self.AfterSegment) | |
225 | + self.chk_new_mask.Disable() | |
226 | + | |
227 | + try: | |
228 | + self.ps = segment.SegmentProcess(image, create_new_mask, backend, device_id, use_gpu) | |
229 | + self.ps.start() | |
230 | + except (multiprocessing.ProcessError, OSError, ValueError) as err: | |
231 | + self.OnStop(None) | |
232 | + self.HideProgress() | |
233 | + dlg = wx.MessageDialog( | |
234 | + None, | |
235 | + "It was not possible to start brain segmentation because:" | |
236 | + + "\n" | |
237 | + + str(err), | |
238 | + "Brain segmentation error", | |
239 | + wx.ICON_ERROR | wx.OK, | |
240 | + ) | |
241 | + dlg.ShowModal() | |
203 | 242 | |
204 | 243 | def OnStop(self, evt): |
205 | - self.segmenter.stop = True | |
244 | + if self.ps is not None: | |
245 | + self.ps.terminate() | |
206 | 246 | self.btn_close.Enable() |
207 | 247 | self.btn_stop.Disable() |
208 | 248 | self.btn_segment.Enable() |
249 | + self.chk_new_mask.Enable() | |
209 | 250 | self.elapsed_time_timer.Stop() |
210 | - evt.Skip() | |
211 | 251 | |
212 | 252 | def OnBtnClose(self, evt): |
213 | 253 | self.Close() |
214 | 254 | |
215 | 255 | def AfterSegment(self): |
256 | + self.segmented = True | |
216 | 257 | self.btn_close.Enable() |
217 | 258 | self.btn_stop.Disable() |
218 | 259 | self.btn_segment.Disable() |
219 | - Publisher.sendMessage('Reload actual slice') | |
260 | + self.chk_new_mask.Disable() | |
220 | 261 | self.elapsed_time_timer.Stop() |
262 | + self.apply_segment_threshold() | |
221 | 263 | |
222 | 264 | def SetProgress(self, progress): |
223 | 265 | self.progress.SetValue(progress * 100) |
224 | 266 | wx.GetApp().Yield() |
225 | 267 | |
226 | 268 | def OnTickTimer(self, evt): |
227 | - fmt='%H:%M:%S' | |
228 | - self.lbl_time.SetLabel(time.strftime(fmt, time.gmtime(time.time()-self.t0))) | |
269 | + fmt = "%H:%M:%S" | |
270 | + self.lbl_time.SetLabel(time.strftime(fmt, time.gmtime(time.time() - self.t0))) | |
271 | + if self.ps is not None: | |
272 | + if not self.ps.is_alive() and self.ps.exception is not None: | |
273 | + error, traceback = self.ps.exception | |
274 | + self.OnStop(None) | |
275 | + self.HideProgress() | |
276 | + dlg = wx.MessageDialog( | |
277 | + None, | |
278 | + "It was not possible to use brain segmentation because:" | |
279 | + + "\n" | |
280 | + + str(error) | |
281 | + + "\n" | |
282 | + + traceback, | |
283 | + "Brain segmentation error", | |
284 | + wx.ICON_ERROR | wx.OK, | |
285 | + ) | |
286 | + dlg.ShowModal() | |
287 | + return | |
288 | + | |
289 | + progress = self.ps.get_completion() | |
290 | + if progress == np.Inf: | |
291 | + progress = 1 | |
292 | + self.AfterSegment() | |
293 | + if progress < 0: | |
294 | + progress = 0 | |
295 | + if progress > 1: | |
296 | + progress = 1 | |
297 | + self.SetProgress(float(progress)) | |
229 | 298 | |
230 | 299 | def OnClose(self, evt): |
231 | - self.segmenter.stop = True | |
300 | + # self.segmenter.stop = True | |
232 | 301 | self.btn_stop.Disable() |
233 | 302 | self.btn_segment.Enable() |
303 | + self.chk_new_mask.Enable() | |
234 | 304 | self.progress.SetValue(0) |
305 | + | |
306 | + if self.ps is not None: | |
307 | + self.ps.terminate() | |
308 | + self.ps = None | |
309 | + | |
235 | 310 | self.Destroy() |
236 | 311 | |
237 | 312 | def HideProgress(self): |
... | ... | @@ -257,6 +332,7 @@ class MyApp(wx.App): |
257 | 332 | self.dlg_brain_seg.Destroy() |
258 | 333 | return True |
259 | 334 | |
335 | + | |
260 | 336 | if __name__ == "__main__": |
261 | 337 | app = MyApp(0) |
262 | 338 | app.MainLoop() | ... | ... |
invesalius/inv_paths.py
invesalius/segmentation/brain/model.h5
No preview for this file type
invesalius/segmentation/brain/model.json
... | ... | @@ -1 +0,0 @@ |
1 | -{"class_name": "Model", "config": {"name": "model_1", "layers": [{"name": "img", "class_name": "InputLayer", "config": {"batch_input_shape": [null, 48, 48, 48, 1], "dtype": "float32", "sparse": false, "name": "img"}, "inbound_nodes": []}, {"name": "conv3d_1", "class_name": "Conv3D", "config": {"name": "conv3d_1", "trainable": true, "filters": 8, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["img", 0, 0, {}]]]}, {"name": "conv3d_2", "class_name": "Conv3D", "config": {"name": "conv3d_2", "trainable": true, "filters": 8, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["conv3d_1", 0, 0, {}]]]}, {"name": "max_pooling3d_1", "class_name": "MaxPooling3D", "config": {"name": "max_pooling3d_1", "trainable": true, "pool_size": [2, 2, 2], "padding": "valid", "strides": [2, 2, 2], "data_format": "channels_last"}, "inbound_nodes": [[["conv3d_2", 0, 0, {}]]]}, {"name": "dropout_1", "class_name": "Dropout", "config": {"name": "dropout_1", "trainable": true, "rate": 0.3, "noise_shape": null, "seed": null}, "inbound_nodes": [[["max_pooling3d_1", 0, 0, {}]]]}, {"name": "conv3d_3", "class_name": "Conv3D", "config": {"name": "conv3d_3", "trainable": true, "filters": 16, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dropout_1", 0, 0, {}]]]}, {"name": "conv3d_4", "class_name": "Conv3D", "config": {"name": "conv3d_4", "trainable": true, "filters": 16, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["conv3d_3", 0, 0, {}]]]}, {"name": "max_pooling3d_2", "class_name": "MaxPooling3D", "config": {"name": "max_pooling3d_2", "trainable": true, "pool_size": [2, 2, 2], "padding": "valid", "strides": [2, 2, 2], "data_format": "channels_last"}, "inbound_nodes": [[["conv3d_4", 0, 0, {}]]]}, {"name": "dropout_2", "class_name": "Dropout", "config": {"name": "dropout_2", "trainable": true, "rate": 0.3, "noise_shape": null, "seed": null}, "inbound_nodes": [[["max_pooling3d_2", 0, 0, {}]]]}, {"name": "conv3d_5", "class_name": "Conv3D", "config": {"name": "conv3d_5", "trainable": true, "filters": 32, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dropout_2", 0, 0, {}]]]}, {"name": "conv3d_6", "class_name": "Conv3D", "config": {"name": "conv3d_6", "trainable": true, "filters": 32, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["conv3d_5", 0, 0, {}]]]}, {"name": "max_pooling3d_3", "class_name": "MaxPooling3D", "config": {"name": "max_pooling3d_3", "trainable": true, "pool_size": [2, 2, 2], "padding": "valid", "strides": [2, 2, 2], "data_format": "channels_last"}, "inbound_nodes": [[["conv3d_6", 0, 0, {}]]]}, {"name": "dropout_3", "class_name": "Dropout", "config": {"name": "dropout_3", "trainable": true, "rate": 0.3, "noise_shape": null, "seed": null}, "inbound_nodes": [[["max_pooling3d_3", 0, 0, {}]]]}, {"name": "conv3d_transpose_1", "class_name": "Conv3DTranspose", "config": {"name": "conv3d_transpose_1", "trainable": true, "filters": 32, "kernel_size": [5, 5, 5], "strides": [2, 2, 2], "padding": "same", "data_format": "channels_last", "activation": "linear", "use_bias": false, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null, "output_padding": null}, "inbound_nodes": [[["dropout_3", 0, 0, {}]]]}, {"name": "concatenate_1", "class_name": "Concatenate", "config": {"name": "concatenate_1", "trainable": true, "axis": -1}, "inbound_nodes": [[["conv3d_transpose_1", 0, 0, {}], ["conv3d_6", 0, 0, {}]]]}, {"name": "conv3d_7", "class_name": "Conv3D", "config": {"name": "conv3d_7", "trainable": true, "filters": 32, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["concatenate_1", 0, 0, {}]]]}, {"name": "dropout_4", "class_name": "Dropout", "config": {"name": "dropout_4", "trainable": true, "rate": 0.3, "noise_shape": null, "seed": null}, "inbound_nodes": [[["conv3d_7", 0, 0, {}]]]}, {"name": "conv3d_transpose_2", "class_name": "Conv3DTranspose", "config": {"name": "conv3d_transpose_2", "trainable": true, "filters": 16, "kernel_size": [5, 5, 5], "strides": [2, 2, 2], "padding": "same", "data_format": "channels_last", "activation": "linear", "use_bias": false, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null, "output_padding": null}, "inbound_nodes": [[["dropout_4", 0, 0, {}]]]}, {"name": "concatenate_2", "class_name": "Concatenate", "config": {"name": "concatenate_2", "trainable": true, "axis": -1}, "inbound_nodes": [[["conv3d_transpose_2", 0, 0, {}], ["conv3d_4", 0, 0, {}]]]}, {"name": "conv3d_8", "class_name": "Conv3D", "config": {"name": "conv3d_8", "trainable": true, "filters": 16, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["concatenate_2", 0, 0, {}]]]}, {"name": "dropout_5", "class_name": "Dropout", "config": {"name": "dropout_5", "trainable": true, "rate": 0.3, "noise_shape": null, "seed": null}, "inbound_nodes": [[["conv3d_8", 0, 0, {}]]]}, {"name": "conv3d_transpose_3", "class_name": "Conv3DTranspose", "config": {"name": "conv3d_transpose_3", "trainable": true, "filters": 8, "kernel_size": [5, 5, 5], "strides": [2, 2, 2], "padding": "same", "data_format": "channels_last", "activation": "linear", "use_bias": false, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null, "output_padding": null}, "inbound_nodes": [[["dropout_5", 0, 0, {}]]]}, {"name": "concatenate_3", "class_name": "Concatenate", "config": {"name": "concatenate_3", "trainable": true, "axis": -1}, "inbound_nodes": [[["conv3d_transpose_3", 0, 0, {}], ["conv3d_2", 0, 0, {}]]]}, {"name": "conv3d_9", "class_name": "Conv3D", "config": {"name": "conv3d_9", "trainable": true, "filters": 8, "kernel_size": [5, 5, 5], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["concatenate_3", 0, 0, {}]]]}, {"name": "dropout_6", "class_name": "Dropout", "config": {"name": "dropout_6", "trainable": true, "rate": 0.3, "noise_shape": null, "seed": null}, "inbound_nodes": [[["conv3d_9", 0, 0, {}]]]}, {"name": "conv3d_10", "class_name": "Conv3D", "config": {"name": "conv3d_10", "trainable": true, "filters": 1, "kernel_size": [1, 1, 1], "strides": [1, 1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1, 1], "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dropout_6", 0, 0, {}]]]}, {"name": "dense_1", "class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "units": 1, "activation": "sigmoid", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["conv3d_10", 0, 0, {}]]]}], "input_layers": [["img", 0, 0]], "output_layers": [["dense_1", 0, 0]]}, "keras_version": "2.2.4", "backend": "plaidml.keras.backend"} | |
2 | 0 | \ No newline at end of file |
invesalius/segmentation/brain/segment.py
1 | 1 | import itertools |
2 | +import multiprocessing | |
2 | 3 | import os |
3 | 4 | import pathlib |
4 | 5 | import sys |
6 | +import tempfile | |
7 | +import traceback | |
5 | 8 | |
6 | 9 | import numpy as np |
7 | 10 | from skimage.transform import resize |
8 | 11 | |
12 | +import invesalius.data.slice_ as slc | |
13 | +from invesalius import inv_paths | |
9 | 14 | from invesalius.data import imagedata_utils |
10 | -from invesalius.utils import timing | |
15 | +from invesalius.utils import new_name_by_pattern | |
11 | 16 | |
12 | 17 | from . import utils |
13 | 18 | |
... | ... | @@ -17,11 +22,13 @@ OVERLAP = SIZE // 2 + 1 |
17 | 22 | |
18 | 23 | def gen_patches(image, patch_size, overlap): |
19 | 24 | sz, sy, sx = image.shape |
20 | - i_cuts = list(itertools.product( | |
21 | - range(0, sz, patch_size - OVERLAP), | |
22 | - range(0, sy, patch_size - OVERLAP), | |
23 | - range(0, sx, patch_size - OVERLAP), | |
24 | - )) | |
25 | + i_cuts = list( | |
26 | + itertools.product( | |
27 | + range(0, sz, patch_size - OVERLAP), | |
28 | + range(0, sy, patch_size - OVERLAP), | |
29 | + range(0, sx, patch_size - OVERLAP), | |
30 | + ) | |
31 | + ) | |
25 | 32 | sub_image = np.empty(shape=(patch_size, patch_size, patch_size), dtype="float32") |
26 | 33 | for idx, (iz, iy, ix) in enumerate(i_cuts): |
27 | 34 | sub_image[:] = 0 |
... | ... | @@ -34,82 +41,128 @@ def gen_patches(image, patch_size, overlap): |
34 | 41 | ey = iy + sy |
35 | 42 | ex = ix + sx |
36 | 43 | |
37 | - yield (idx + 1.0)/len(i_cuts), sub_image, ((iz, ez), (iy, ey), (ix, ex)) | |
44 | + yield (idx + 1.0) / len(i_cuts), sub_image, ((iz, ez), (iy, ey), (ix, ex)) | |
38 | 45 | |
39 | 46 | |
40 | 47 | def predict_patch(sub_image, patch, nn_model, patch_size=SIZE): |
41 | 48 | (iz, ez), (iy, ey), (ix, ex) = patch |
42 | - sub_mask = nn_model.predict(sub_image.reshape(1, patch_size, patch_size, patch_size, 1)) | |
43 | - return sub_mask.reshape(patch_size, patch_size, patch_size)[0:ez-iz, 0:ey-iy, 0:ex-ix] | |
49 | + sub_mask = nn_model.predict( | |
50 | + sub_image.reshape(1, patch_size, patch_size, patch_size, 1) | |
51 | + ) | |
52 | + return sub_mask.reshape(patch_size, patch_size, patch_size)[ | |
53 | + 0 : ez - iz, 0 : ey - iy, 0 : ex - ix | |
54 | + ] | |
55 | + | |
56 | + | |
57 | +def brain_segment(image, probability_array, comm_array): | |
58 | + import keras | |
59 | + | |
60 | + # Loading model | |
61 | + folder = inv_paths.MODELS_DIR.joinpath("brain_mri_t1") | |
62 | + with open(folder.joinpath("model.json"), "r") as json_file: | |
63 | + model = keras.models.model_from_json(json_file.read()) | |
64 | + model.load_weights(str(folder.joinpath("model.h5"))) | |
65 | + model.compile("Adam", "binary_crossentropy") | |
66 | + | |
67 | + image = imagedata_utils.image_normalize(image, 0.0, 1.0) | |
68 | + sums = np.zeros_like(image) | |
69 | + # segmenting by patches | |
70 | + for completion, sub_image, patch in gen_patches(image, SIZE, OVERLAP): | |
71 | + comm_array[0] = completion | |
72 | + (iz, ez), (iy, ey), (ix, ex) = patch | |
73 | + sub_mask = predict_patch(sub_image, patch, model, SIZE) | |
74 | + probability_array[iz:ez, iy:ey, ix:ex] += sub_mask | |
75 | + sums[iz:ez, iy:ey, ix:ex] += 1 | |
76 | + | |
77 | + probability_array /= sums | |
78 | + comm_array[0] = np.Inf | |
79 | + | |
80 | + | |
81 | +ctx = multiprocessing.get_context('spawn') | |
82 | +class SegmentProcess(ctx.Process): | |
83 | + def __init__(self, image, create_new_mask, backend, device_id, use_gpu): | |
84 | + multiprocessing.Process.__init__(self) | |
85 | + | |
86 | + self._image_filename = image.filename | |
87 | + self._image_dtype = image.dtype | |
88 | + self._image_shape = image.shape | |
89 | + | |
90 | + self._probability_array = np.memmap( | |
91 | + tempfile.mktemp(), shape=image.shape, dtype=np.float32, mode="w+" | |
92 | + ) | |
93 | + self._prob_array_filename = self._probability_array.filename | |
94 | + | |
95 | + self._comm_array = np.memmap( | |
96 | + tempfile.mktemp(), shape=(1,), dtype=np.float32, mode="w+" | |
97 | + ) | |
98 | + self._comm_array_filename = self._comm_array.filename | |
99 | + | |
100 | + self.create_new_mask = create_new_mask | |
101 | + self.backend = backend | |
102 | + self.device_id = device_id | |
103 | + self.use_gpu = use_gpu | |
104 | + | |
105 | + self._pconn, self._cconn = multiprocessing.Pipe() | |
106 | + self._exception = None | |
44 | 107 | |
45 | - | |
46 | -class BrainSegmenter: | |
47 | - def __init__(self): | |
48 | 108 | self.mask = None |
49 | - self.propability_array = None | |
50 | - self.stop = False | |
51 | - self.segmented = False | |
52 | - | |
53 | - def segment(self, image, prob_threshold, backend, device_id, use_gpu, progress_callback=None, after_segment=None): | |
54 | - print("backend", backend) | |
55 | - if backend.lower() == 'plaidml': | |
56 | - os.environ["KERAS_BACKEND"] = "plaidml.keras.backend" | |
57 | - os.environ["PLAIDML_DEVICE_IDS"] = device_id | |
58 | - elif backend.lower() == 'theano': | |
59 | - os.environ["KERAS_BACKEND"] = "theano" | |
60 | - if use_gpu: | |
61 | - os.environ["THEANO_FLAGS"] = "device=cuda0" | |
62 | - print("Use GPU theano", os.environ["THEANO_FLAGS"]) | |
63 | - else: | |
64 | - os.environ["THEANO_FLAGS"] = "device=cpu" | |
109 | + | |
110 | + def run(self): | |
111 | + try: | |
112 | + self._run_segmentation() | |
113 | + self._cconn.send(None) | |
114 | + except Exception as e: | |
115 | + tb = traceback.format_exc() | |
116 | + self._cconn.send((e, tb)) | |
117 | + | |
118 | + def _run_segmentation(self): | |
119 | + image = np.memmap( | |
120 | + self._image_filename, | |
121 | + dtype=self._image_dtype, | |
122 | + shape=self._image_shape, | |
123 | + mode="r", | |
124 | + ) | |
125 | + probability_array = np.memmap( | |
126 | + self._prob_array_filename, | |
127 | + dtype=np.float32, | |
128 | + shape=self._image_shape, | |
129 | + mode="r+", | |
130 | + ) | |
131 | + comm_array = np.memmap( | |
132 | + self._comm_array_filename, dtype=np.float32, shape=(1,), mode="r+" | |
133 | + ) | |
134 | + | |
135 | + utils.prepare_ambient(self.backend, self.device_id, self.use_gpu) | |
136 | + brain_segment(image, probability_array, comm_array) | |
137 | + | |
138 | + @property | |
139 | + def exception(self): | |
140 | + # Based on https://stackoverflow.com/a/33599967 | |
141 | + if self._pconn.poll(): | |
142 | + self._exception = self._pconn.recv() | |
143 | + return self._exception | |
144 | + | |
145 | + def apply_segment_threshold(self, threshold): | |
146 | + if self.create_new_mask: | |
147 | + if self.mask is None: | |
148 | + name = new_name_by_pattern("brainseg_mri_t1") | |
149 | + self.mask = slc.Slice().create_new_mask(name=name) | |
65 | 150 | else: |
66 | - raise TypeError("Wrong backend") | |
67 | - | |
68 | - import keras | |
69 | - import invesalius.data.slice_ as slc | |
70 | - | |
71 | - image = imagedata_utils.image_normalize(image, 0.0, 1.0) | |
72 | - | |
73 | - # Loading model | |
74 | - folder = pathlib.Path(__file__).parent.resolve() | |
75 | - with open(folder.joinpath("model.json"), "r") as json_file: | |
76 | - model = keras.models.model_from_json(json_file.read()) | |
77 | - model.load_weights(str(folder.joinpath("model.h5"))) | |
78 | - model.compile("Adam", "binary_crossentropy") | |
79 | - | |
80 | - # segmenting by patches | |
81 | - msk = np.zeros_like(image, dtype="float32") | |
82 | - sums = np.zeros_like(image) | |
83 | - for completion, sub_image, patch in gen_patches(image, SIZE, OVERLAP): | |
84 | - if self.stop: | |
85 | - self.stop = False | |
86 | - return | |
87 | - | |
88 | - if progress_callback is not None: | |
89 | - progress_callback(completion) | |
90 | - print("completion", completion) | |
91 | - (iz, ez), (iy, ey), (ix, ex) = patch | |
92 | - sub_mask = predict_patch(sub_image, patch, model, SIZE) | |
93 | - msk[iz:ez, iy:ey, ix:ex] += sub_mask | |
94 | - sums[iz:ez, iy:ey, ix:ex] += 1 | |
95 | - | |
96 | - propability_array = msk / sums | |
97 | - | |
98 | - mask = slc.Slice().create_new_mask() | |
99 | - mask.was_edited = True | |
100 | - mask.matrix[:] = 1 | |
101 | - mask.matrix[1:, 1:, 1:] = (propability_array >= prob_threshold) * 255 | |
102 | - | |
103 | - self.mask = mask | |
104 | - self.propability_array = propability_array | |
105 | - self.segmented = True | |
106 | - if after_segment is not None: | |
107 | - after_segment() | |
108 | - | |
109 | - def set_threshold(self, threshold): | |
110 | - if threshold < 0: | |
111 | - threshold = 0 | |
112 | - elif threshold > 1: | |
113 | - threshold = 1 | |
151 | + self.mask = slc.Slice().current_mask | |
152 | + if self.mask is None: | |
153 | + name = new_name_by_pattern("brainseg_mri_t1") | |
154 | + self.mask = slc.Slice().create_new_mask(name=name) | |
155 | + | |
156 | + self.mask.was_edited = True | |
114 | 157 | self.mask.matrix[:] = 1 |
115 | - self.mask.matrix[1:, 1:, 1:] = (self.propability_array >= threshold) * 255 | |
158 | + self.mask.matrix[1:, 1:, 1:] = (self._probability_array >= threshold) * 255 | |
159 | + | |
160 | + def get_completion(self): | |
161 | + return self._comm_array[0] | |
162 | + | |
163 | + def __del__(self): | |
164 | + del self._comm_array | |
165 | + os.remove(self._comm_array_filename) | |
166 | + | |
167 | + del self._probability_array | |
168 | + os.remove(self._prob_array_filename) | ... | ... |
invesalius/segmentation/brain/utils.py
1 | +import os | |
2 | +import pathlib | |
3 | +import sys | |
4 | + | |
5 | +def prepare_plaidml(): | |
6 | + # Linux if installed plaidml with pip3 install --user | |
7 | + if sys.platform.startswith("linux"): | |
8 | + local_user_plaidml = pathlib.Path("~/.local/share/plaidml/").expanduser().absolute() | |
9 | + if local_user_plaidml.exists(): | |
10 | + os.environ["RUNFILES_DIR"] = str(local_user_plaidml) | |
11 | + os.environ["PLAIDML_NATIVE_PATH"] = str(pathlib.Path("~/.local/lib/libplaidml.so").expanduser().absolute()) | |
12 | + # Mac if using python3 from homebrew | |
13 | + elif sys.platform == "darwin": | |
14 | + local_user_plaidml = pathlib.Path("/usr/local/share/plaidml") | |
15 | + if local_user_plaidml.exists(): | |
16 | + os.environ["RUNFILES_DIR"] = str(local_user_plaidml) | |
17 | + os.environ["PLAIDML_NATIVE_PATH"] = str(pathlib.Path("/usr/local/lib/libplaidml.dylib").expanduser().absolute()) | |
18 | + | |
19 | +def prepare_ambient(backend, device_id, use_gpu): | |
20 | + if backend.lower() == 'plaidml': | |
21 | + os.environ["KERAS_BACKEND"] = "plaidml.keras.backend" | |
22 | + os.environ["PLAIDML_DEVICE_IDS"] = device_id | |
23 | + prepare_plaidml() | |
24 | + elif backend.lower() == 'theano': | |
25 | + os.environ["KERAS_BACKEND"] = "theano" | |
26 | + if use_gpu: | |
27 | + os.environ["THEANO_FLAGS"] = "device=cuda0" | |
28 | + print("Use GPU theano", os.environ["THEANO_FLAGS"]) | |
29 | + else: | |
30 | + os.environ["THEANO_FLAGS"] = "device=cpu" | |
31 | + else: | |
32 | + raise TypeError("Wrong backend") | |
33 | + | |
34 | + | |
35 | + | |
1 | 36 | def get_plaidml_devices(gpu=False): |
37 | + prepare_plaidml() | |
38 | + | |
2 | 39 | import plaidml |
3 | 40 | |
4 | 41 | ctx = plaidml.Context() | ... | ... |
invesalius/utils.py
... | ... | @@ -126,7 +126,16 @@ def next_copy_name(original_name, names_list): |
126 | 126 | if not (next_copy in names_list): |
127 | 127 | got_new_name = True |
128 | 128 | return next_copy |
129 | - | |
129 | + | |
130 | + | |
131 | +def new_name_by_pattern(pattern): | |
132 | + from invesalius.project import Project | |
133 | + proj = Project() | |
134 | + mask_dict = proj.mask_dict | |
135 | + names_list = [i.name for i in mask_dict.values() if i.name.startswith(pattern + "_")] | |
136 | + count = len(names_list) + 1 | |
137 | + return "{}_{}".format(pattern, count) | |
138 | + | |
130 | 139 | |
131 | 140 | def VerifyInvalidPListCharacter(text): |
132 | 141 | #print text | ... | ... |