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 @@ | @@ -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 | \ No newline at end of file | 2 | \ No newline at end of file |
app.py
@@ -65,6 +65,7 @@ import invesalius.utils as utils | @@ -65,6 +65,7 @@ import invesalius.utils as utils | ||
65 | from invesalius import inv_paths | 65 | from invesalius import inv_paths |
66 | 66 | ||
67 | FS_ENCODE = sys.getfilesystemencoding() | 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,6 +79,17 @@ if sys.platform in ('linux2', 'linux', 'win32'): | ||
78 | del tmp_var | 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 | class InVesalius(wx.App): | 93 | class InVesalius(wx.App): |
82 | """ | 94 | """ |
83 | InVesalius wxPython application class. | 95 | InVesalius wxPython application class. |
@@ -119,26 +131,18 @@ class Inv3SplashScreen(SplashScreen): | @@ -119,26 +131,18 @@ class Inv3SplashScreen(SplashScreen): | ||
119 | """ | 131 | """ |
120 | def __init__(self): | 132 | def __init__(self): |
121 | # Splash screen image will depend on currently language | 133 | # Splash screen image will depend on currently language |
122 | - lang = False | ||
123 | - | 134 | + lang = LANG |
124 | self.locale = wx.Locale(wx.LANGUAGE_DEFAULT) | 135 | self.locale = wx.Locale(wx.LANGUAGE_DEFAULT) |
125 | 136 | ||
126 | # Language information is available in session configuration | 137 | # Language information is available in session configuration |
127 | # file. First we need to check if this file exist, if now, it | 138 | # file. First we need to check if this file exist, if now, it |
128 | # should be created | 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 | install_lang = 0 | 142 | install_lang = 0 |
135 | - lang = session.GetLanguage() | ||
136 | if lang: | 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 | else: | 146 | else: |
143 | install_lang = 0 | 147 | install_lang = 0 |
144 | 148 | ||
@@ -262,7 +266,10 @@ class Inv3SplashScreen(SplashScreen): | @@ -262,7 +266,10 @@ class Inv3SplashScreen(SplashScreen): | ||
262 | 266 | ||
263 | 267 | ||
264 | def non_gui_startup(options, args): | 268 | def non_gui_startup(options, args): |
265 | - lang = 'en' | 269 | + if LANG: |
270 | + lang = LANG | ||
271 | + else: | ||
272 | + lang = 'en' | ||
266 | _ = i18n.InstallLanguage(lang) | 273 | _ = i18n.InstallLanguage(lang) |
267 | 274 | ||
268 | from invesalius.control import Controller | 275 | from invesalius.control import Controller |
invesalius/gui/brain_seg_dialog.py
@@ -2,76 +2,85 @@ | @@ -2,76 +2,85 @@ | ||
2 | # -*- coding: UTF-8 -*- | 2 | # -*- coding: UTF-8 -*- |
3 | 3 | ||
4 | import importlib | 4 | import importlib |
5 | +import multiprocessing | ||
5 | import os | 6 | import os |
6 | import pathlib | 7 | import pathlib |
8 | +import subprocess | ||
7 | import sys | 9 | import sys |
10 | +import tempfile | ||
8 | import time | 11 | import time |
9 | 12 | ||
13 | +import numpy as np | ||
10 | import wx | 14 | import wx |
11 | from pubsub import pub as Publisher | 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 | HAS_THEANO = bool(importlib.util.find_spec("theano")) | 20 | HAS_THEANO = bool(importlib.util.find_spec("theano")) |
27 | HAS_PLAIDML = bool(importlib.util.find_spec("plaidml")) | 21 | HAS_PLAIDML = bool(importlib.util.find_spec("plaidml")) |
28 | PLAIDML_DEVICES = {} | 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 | if HAS_PLAIDML: | 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 | class BrainSegmenterDialog(wx.Dialog): | 35 | class BrainSegmenterDialog(wx.Dialog): |
52 | def __init__(self, parent): | 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 | backends = [] | 44 | backends = [] |
55 | if HAS_PLAIDML: | 45 | if HAS_PLAIDML: |
56 | backends.append("PlaidML") | 46 | backends.append("PlaidML") |
57 | if HAS_THEANO: | 47 | if HAS_THEANO: |
58 | backends.append("Theano") | 48 | backends.append("Theano") |
59 | - self.segmenter = segment.BrainSegmenter() | 49 | + # self.segmenter = segment.BrainSegmenter() |
60 | # self.pg_dialog = None | 50 | # self.pg_dialog = None |
61 | self.plaidml_devices = PLAIDML_DEVICES | 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 | w, h = self.CalcSizeFromTextSize("MM" * (1 + max(len(i) for i in backends))) | 64 | w, h = self.CalcSizeFromTextSize("MM" * (1 + max(len(i) for i in backends))) |
64 | self.cb_backends.SetMinClientSize((w, -1)) | 65 | self.cb_backends.SetMinClientSize((w, -1)) |
65 | self.chk_use_gpu = wx.CheckBox(self, wx.ID_ANY, _("Use GPU")) | 66 | self.chk_use_gpu = wx.CheckBox(self, wx.ID_ANY, _("Use GPU")) |
66 | if HAS_PLAIDML: | 67 | if HAS_PLAIDML: |
67 | self.lbl_device = wx.StaticText(self, -1, _("Device")) | 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 | self.sld_threshold = wx.Slider(self, wx.ID_ANY, 75, 0, 100) | 76 | self.sld_threshold = wx.Slider(self, wx.ID_ANY, 75, 0, 100) |
70 | w, h = self.CalcSizeFromTextSize("M" * 20) | 77 | w, h = self.CalcSizeFromTextSize("M" * 20) |
71 | self.sld_threshold.SetMinClientSize((w, -1)) | 78 | self.sld_threshold.SetMinClientSize((w, -1)) |
72 | self.txt_threshold = wx.TextCtrl(self, wx.ID_ANY, "") | 79 | self.txt_threshold = wx.TextCtrl(self, wx.ID_ANY, "") |
73 | w, h = self.CalcSizeFromTextSize("MMMMM") | 80 | w, h = self.CalcSizeFromTextSize("MMMMM") |
74 | self.txt_threshold.SetMinClientSize((w, -1)) | 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 | self.progress = wx.Gauge(self, -1) | 84 | self.progress = wx.Gauge(self, -1) |
76 | self.lbl_progress_caption = wx.StaticText(self, -1, _("Elapsed time:")) | 85 | self.lbl_progress_caption = wx.StaticText(self, -1, _("Elapsed time:")) |
77 | self.lbl_time = wx.StaticText(self, -1, _("00:00:00")) | 86 | self.lbl_time = wx.StaticText(self, -1, _("00:00:00")) |
@@ -103,18 +112,30 @@ class BrainSegmenterDialog(wx.Dialog): | @@ -103,18 +112,30 @@ class BrainSegmenterDialog(wx.Dialog): | ||
103 | main_sizer.Add(sizer_devices, 0, wx.ALL | wx.EXPAND, 5) | 112 | main_sizer.Add(sizer_devices, 0, wx.ALL | wx.EXPAND, 5) |
104 | label_5 = wx.StaticText(self, wx.ID_ANY, _("Level of certainty")) | 113 | label_5 = wx.StaticText(self, wx.ID_ANY, _("Level of certainty")) |
105 | main_sizer.Add(label_5, 0, wx.ALL, 5) | 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 | sizer_3.Add(self.txt_threshold, 0, wx.ALL, 5) | 121 | sizer_3.Add(self.txt_threshold, 0, wx.ALL, 5) |
108 | main_sizer.Add(sizer_3, 0, wx.EXPAND, 0) | 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 | main_sizer.Add(self.progress, 0, wx.EXPAND | wx.ALL, 5) | 124 | main_sizer.Add(self.progress, 0, wx.EXPAND | wx.ALL, 5) |
110 | time_sizer = wx.BoxSizer(wx.HORIZONTAL) | 125 | time_sizer = wx.BoxSizer(wx.HORIZONTAL) |
111 | time_sizer.Add(self.lbl_progress_caption, 0, wx.EXPAND, 0) | 126 | time_sizer.Add(self.lbl_progress_caption, 0, wx.EXPAND, 0) |
112 | time_sizer.Add(self.lbl_time, 1, wx.EXPAND | wx.LEFT, 5) | 127 | time_sizer.Add(self.lbl_time, 1, wx.EXPAND | wx.LEFT, 5) |
113 | main_sizer.Add(time_sizer, 0, wx.EXPAND | wx.ALL, 5) | 128 | main_sizer.Add(time_sizer, 0, wx.EXPAND | wx.ALL, 5) |
114 | sizer_buttons = wx.BoxSizer(wx.HORIZONTAL) | 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 | main_sizer.Add(sizer_buttons, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT | wx.ALL, 0) | 139 | main_sizer.Add(sizer_buttons, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT | wx.ALL, 0) |
119 | self.SetSizer(main_sizer) | 140 | self.SetSizer(main_sizer) |
120 | main_sizer.Fit(self) | 141 | main_sizer.Fit(self) |
@@ -138,6 +159,13 @@ class BrainSegmenterDialog(wx.Dialog): | @@ -138,6 +159,13 @@ class BrainSegmenterDialog(wx.Dialog): | ||
138 | self.elapsed_time_timer.Bind(wx.EVT_TIMER, self.OnTickTimer) | 159 | self.elapsed_time_timer.Bind(wx.EVT_TIMER, self.OnTickTimer) |
139 | self.Bind(wx.EVT_CLOSE, self.OnClose) | 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 | def CalcSizeFromTextSize(self, text): | 169 | def CalcSizeFromTextSize(self, text): |
142 | dc = wx.WindowDC(self) | 170 | dc = wx.WindowDC(self) |
143 | dc.SetFont(self.GetFont()) | 171 | dc.SetFont(self.GetFont()) |
@@ -162,15 +190,12 @@ class BrainSegmenterDialog(wx.Dialog): | @@ -162,15 +190,12 @@ class BrainSegmenterDialog(wx.Dialog): | ||
162 | def OnScrollThreshold(self, evt): | 190 | def OnScrollThreshold(self, evt): |
163 | value = self.sld_threshold.GetValue() | 191 | value = self.sld_threshold.GetValue() |
164 | self.txt_threshold.SetValue("{:3d}%".format(self.sld_threshold.GetValue())) | 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 | def OnKillFocus(self, evt): | 196 | def OnKillFocus(self, evt): |
172 | value = self.txt_threshold.GetValue() | 197 | value = self.txt_threshold.GetValue() |
173 | - value = value.replace('%', '') | 198 | + value = value.replace("%", "") |
174 | try: | 199 | try: |
175 | value = int(value) | 200 | value = int(value) |
176 | except ValueError: | 201 | except ValueError: |
@@ -178,11 +203,8 @@ class BrainSegmenterDialog(wx.Dialog): | @@ -178,11 +203,8 @@ class BrainSegmenterDialog(wx.Dialog): | ||
178 | self.sld_threshold.SetValue(value) | 203 | self.sld_threshold.SetValue(value) |
179 | self.txt_threshold.SetValue("{:3d}%".format(value)) | 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 | def OnSegment(self, evt): | 209 | def OnSegment(self, evt): |
188 | self.ShowProgress() | 210 | self.ShowProgress() |
@@ -194,44 +216,97 @@ class BrainSegmenterDialog(wx.Dialog): | @@ -194,44 +216,97 @@ class BrainSegmenterDialog(wx.Dialog): | ||
194 | device_id = self.plaidml_devices[self.cb_devices.GetValue()] | 216 | device_id = self.plaidml_devices[self.cb_devices.GetValue()] |
195 | except (KeyError, AttributeError): | 217 | except (KeyError, AttributeError): |
196 | device_id = "llvm_cpu.0" | 218 | device_id = "llvm_cpu.0" |
219 | + create_new_mask = self.chk_new_mask.GetValue() | ||
197 | use_gpu = self.chk_use_gpu.GetValue() | 220 | use_gpu = self.chk_use_gpu.GetValue() |
198 | prob_threshold = self.sld_threshold.GetValue() / 100.0 | 221 | prob_threshold = self.sld_threshold.GetValue() / 100.0 |
199 | self.btn_close.Disable() | 222 | self.btn_close.Disable() |
200 | self.btn_stop.Enable() | 223 | self.btn_stop.Enable() |
201 | self.btn_segment.Disable() | 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 | def OnStop(self, evt): | 243 | def OnStop(self, evt): |
205 | - self.segmenter.stop = True | 244 | + if self.ps is not None: |
245 | + self.ps.terminate() | ||
206 | self.btn_close.Enable() | 246 | self.btn_close.Enable() |
207 | self.btn_stop.Disable() | 247 | self.btn_stop.Disable() |
208 | self.btn_segment.Enable() | 248 | self.btn_segment.Enable() |
249 | + self.chk_new_mask.Enable() | ||
209 | self.elapsed_time_timer.Stop() | 250 | self.elapsed_time_timer.Stop() |
210 | - evt.Skip() | ||
211 | 251 | ||
212 | def OnBtnClose(self, evt): | 252 | def OnBtnClose(self, evt): |
213 | self.Close() | 253 | self.Close() |
214 | 254 | ||
215 | def AfterSegment(self): | 255 | def AfterSegment(self): |
256 | + self.segmented = True | ||
216 | self.btn_close.Enable() | 257 | self.btn_close.Enable() |
217 | self.btn_stop.Disable() | 258 | self.btn_stop.Disable() |
218 | self.btn_segment.Disable() | 259 | self.btn_segment.Disable() |
219 | - Publisher.sendMessage('Reload actual slice') | 260 | + self.chk_new_mask.Disable() |
220 | self.elapsed_time_timer.Stop() | 261 | self.elapsed_time_timer.Stop() |
262 | + self.apply_segment_threshold() | ||
221 | 263 | ||
222 | def SetProgress(self, progress): | 264 | def SetProgress(self, progress): |
223 | self.progress.SetValue(progress * 100) | 265 | self.progress.SetValue(progress * 100) |
224 | wx.GetApp().Yield() | 266 | wx.GetApp().Yield() |
225 | 267 | ||
226 | def OnTickTimer(self, evt): | 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 | def OnClose(self, evt): | 299 | def OnClose(self, evt): |
231 | - self.segmenter.stop = True | 300 | + # self.segmenter.stop = True |
232 | self.btn_stop.Disable() | 301 | self.btn_stop.Disable() |
233 | self.btn_segment.Enable() | 302 | self.btn_segment.Enable() |
303 | + self.chk_new_mask.Enable() | ||
234 | self.progress.SetValue(0) | 304 | self.progress.SetValue(0) |
305 | + | ||
306 | + if self.ps is not None: | ||
307 | + self.ps.terminate() | ||
308 | + self.ps = None | ||
309 | + | ||
235 | self.Destroy() | 310 | self.Destroy() |
236 | 311 | ||
237 | def HideProgress(self): | 312 | def HideProgress(self): |
@@ -257,6 +332,7 @@ class MyApp(wx.App): | @@ -257,6 +332,7 @@ class MyApp(wx.App): | ||
257 | self.dlg_brain_seg.Destroy() | 332 | self.dlg_brain_seg.Destroy() |
258 | return True | 333 | return True |
259 | 334 | ||
335 | + | ||
260 | if __name__ == "__main__": | 336 | if __name__ == "__main__": |
261 | app = MyApp(0) | 337 | app = MyApp(0) |
262 | app.MainLoop() | 338 | app.MainLoop() |
invesalius/inv_paths.py
@@ -46,6 +46,7 @@ RAYCASTING_PRESETS_COLOR_DIRECTORY = INV_TOP_DIR.joinpath( | @@ -46,6 +46,7 @@ RAYCASTING_PRESETS_COLOR_DIRECTORY = INV_TOP_DIR.joinpath( | ||
46 | "presets", "raycasting", "color_list" | 46 | "presets", "raycasting", "color_list" |
47 | ) | 47 | ) |
48 | 48 | ||
49 | +MODELS_DIR = INV_TOP_DIR.joinpath("ai") | ||
49 | 50 | ||
50 | # Inside the windows executable | 51 | # Inside the windows executable |
51 | if hasattr(sys, "frozen") and ( | 52 | if hasattr(sys, "frozen") and ( |
invesalius/segmentation/brain/model.h5
No preview for this file type
invesalius/segmentation/brain/model.json
@@ -1 +0,0 @@ | @@ -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 | \ No newline at end of file | 0 | \ No newline at end of file |
invesalius/segmentation/brain/segment.py
1 | import itertools | 1 | import itertools |
2 | +import multiprocessing | ||
2 | import os | 3 | import os |
3 | import pathlib | 4 | import pathlib |
4 | import sys | 5 | import sys |
6 | +import tempfile | ||
7 | +import traceback | ||
5 | 8 | ||
6 | import numpy as np | 9 | import numpy as np |
7 | from skimage.transform import resize | 10 | from skimage.transform import resize |
8 | 11 | ||
12 | +import invesalius.data.slice_ as slc | ||
13 | +from invesalius import inv_paths | ||
9 | from invesalius.data import imagedata_utils | 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 | from . import utils | 17 | from . import utils |
13 | 18 | ||
@@ -17,11 +22,13 @@ OVERLAP = SIZE // 2 + 1 | @@ -17,11 +22,13 @@ OVERLAP = SIZE // 2 + 1 | ||
17 | 22 | ||
18 | def gen_patches(image, patch_size, overlap): | 23 | def gen_patches(image, patch_size, overlap): |
19 | sz, sy, sx = image.shape | 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 | sub_image = np.empty(shape=(patch_size, patch_size, patch_size), dtype="float32") | 32 | sub_image = np.empty(shape=(patch_size, patch_size, patch_size), dtype="float32") |
26 | for idx, (iz, iy, ix) in enumerate(i_cuts): | 33 | for idx, (iz, iy, ix) in enumerate(i_cuts): |
27 | sub_image[:] = 0 | 34 | sub_image[:] = 0 |
@@ -34,82 +41,128 @@ def gen_patches(image, patch_size, overlap): | @@ -34,82 +41,128 @@ def gen_patches(image, patch_size, overlap): | ||
34 | ey = iy + sy | 41 | ey = iy + sy |
35 | ex = ix + sx | 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 | def predict_patch(sub_image, patch, nn_model, patch_size=SIZE): | 47 | def predict_patch(sub_image, patch, nn_model, patch_size=SIZE): |
41 | (iz, ez), (iy, ey), (ix, ex) = patch | 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 | self.mask = None | 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 | else: | 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 | self.mask.matrix[:] = 1 | 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 | def get_plaidml_devices(gpu=False): | 36 | def get_plaidml_devices(gpu=False): |
37 | + prepare_plaidml() | ||
38 | + | ||
2 | import plaidml | 39 | import plaidml |
3 | 40 | ||
4 | ctx = plaidml.Context() | 41 | ctx = plaidml.Context() |
invesalius/utils.py
@@ -126,7 +126,16 @@ def next_copy_name(original_name, names_list): | @@ -126,7 +126,16 @@ def next_copy_name(original_name, names_list): | ||
126 | if not (next_copy in names_list): | 126 | if not (next_copy in names_list): |
127 | got_new_name = True | 127 | got_new_name = True |
128 | return next_copy | 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 | def VerifyInvalidPListCharacter(text): | 140 | def VerifyInvalidPListCharacter(text): |
132 | #print text | 141 | #print text |