Commit 0f3937003464e9946a3f728ac8e8c35f26c147bc

Authored by Thiago Franco de Moraes
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
ai/brain_mri_t1/model.h5 0 → 100644
No preview for this file type
ai/brain_mri_t1/model.json 0 → 100644
... ... @@ -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
... ... @@ -46,6 +46,7 @@ RAYCASTING_PRESETS_COLOR_DIRECTORY = INV_TOP_DIR.joinpath(
46 46 "presets", "raycasting", "color_list"
47 47 )
48 48  
  49 +MODELS_DIR = INV_TOP_DIR.joinpath("ai")
49 50  
50 51 # Inside the windows executable
51 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   -{"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
... ...