Commit 13163add78ab61b1815767cccdf0887a559ab62e
Committed by
GitHub
1 parent
b2b44bbc
Exists in
master
Peel creation using mask and image already loaded (#359)
* Created dialog * some testings * Using ww and wl to set mesh colors * Using ww and wl to set mesh colors * Not cleaning surface before upsample * ww and wl -> window_width and window_level * setting affine_vtk as matrix identity * Some cleaning and setting specular to 0.25 to make peel brighter * created an method to create brain peel from mask * created an method to create brain peel from files * Starting to give support to peel using files * Improvements in GUI * Creating peels from files * Added nifti wildcard * checking if torus orientation and arrow project exists before setting visibility * ADD: Title to the T1 and Mask dialogs for creating peel * ADD: Last directory to load peel files * Using image from invesalius project * FIX: applies vtk affine only for peel from file and decouples self affine variable Co-authored-by: Victor Hugo Souza <victor.souza@aalto.fi> Co-authored-by: Renan <renan_hiroshi@hotmail.com>
Showing
3 changed files
with
277 additions
and
100 deletions
Show diff stats
invesalius/data/brainmesh_handler.py
@@ -2,37 +2,95 @@ import vtk | @@ -2,37 +2,95 @@ import vtk | ||
2 | import pyacvd | 2 | import pyacvd |
3 | # import os | 3 | # import os |
4 | import pyvista | 4 | import pyvista |
5 | -# import numpy as np | 5 | +import numpy as np |
6 | # import Trekker | 6 | # import Trekker |
7 | 7 | ||
8 | +import invesalius.data.slice_ as sl | ||
9 | +from invesalius.data.converters import to_vtk | ||
10 | + | ||
8 | 11 | ||
9 | class Brain: | 12 | class Brain: |
10 | - def __init__(self, img_path, mask_path, n_peels, affine_vtk): | 13 | + def __init__(self, n_peels, window_width, window_level, affine_vtk=None): |
11 | # Create arrays to access the peel data and peel Actors | 14 | # Create arrays to access the peel data and peel Actors |
12 | self.peel = [] | 15 | self.peel = [] |
13 | self.peelActors = [] | 16 | self.peelActors = [] |
14 | - # Read the image | ||
15 | - T1_reader = vtk.vtkNIFTIImageReader() | ||
16 | - T1_reader.SetFileName(img_path) | ||
17 | - T1_reader.Update() | 17 | + self.window_width = window_width |
18 | + self.window_level = window_level | ||
19 | + self.numberOfPeels = n_peels | ||
20 | + self.affine_vtk = affine_vtk | ||
21 | + | ||
22 | + def from_mask(self, mask): | ||
23 | + mask= np.array(mask.matrix[1:, 1:, 1:]) | ||
24 | + slic = sl.Slice() | ||
25 | + image = slic.matrix | ||
26 | + | ||
27 | + mask = to_vtk(mask, spacing=slic.spacing) | ||
28 | + image = to_vtk(image, spacing=slic.spacing) | ||
29 | + | ||
30 | + flip = vtk.vtkImageFlip() | ||
31 | + flip.SetInputData(image) | ||
32 | + flip.SetFilteredAxis(1) | ||
33 | + flip.FlipAboutOriginOn() | ||
34 | + flip.ReleaseDataFlagOn() | ||
35 | + flip.Update() | ||
36 | + image = flip.GetOutput() | ||
37 | + | ||
38 | + flip = vtk.vtkImageFlip() | ||
39 | + flip.SetInputData(mask) | ||
40 | + flip.SetFilteredAxis(1) | ||
41 | + flip.FlipAboutOriginOn() | ||
42 | + flip.ReleaseDataFlagOn() | ||
43 | + flip.Update() | ||
44 | + mask = flip.GetOutput() | ||
45 | + | ||
18 | # Image | 46 | # Image |
19 | - self.refImage = T1_reader.GetOutput() | 47 | + self.refImage = image |
48 | + | ||
49 | + self._do_surface_creation(mask) | ||
50 | + | ||
51 | + | ||
52 | + def from_mask_file(self, mask_path): | ||
53 | + slic = sl.Slice() | ||
54 | + image = slic.matrix | ||
55 | + image = to_vtk(image, spacing=slic.spacing) | ||
56 | + | ||
20 | # Read the mask | 57 | # Read the mask |
21 | mask_reader = vtk.vtkNIFTIImageReader() | 58 | mask_reader = vtk.vtkNIFTIImageReader() |
22 | mask_reader.SetFileName(mask_path) | 59 | mask_reader.SetFileName(mask_path) |
23 | mask_reader.Update() | 60 | mask_reader.Update() |
61 | + | ||
62 | + mask = mask_reader.GetOutput() | ||
63 | + | ||
64 | + mask_sFormMatrix = mask_reader.GetSFormMatrix() | ||
65 | + | ||
66 | + # Image | ||
67 | + self.refImage = image | ||
68 | + | ||
69 | + self._do_surface_creation(mask, mask_sFormMatrix) | ||
70 | + | ||
71 | + | ||
72 | + def _do_surface_creation(self, mask, mask_sFormMatrix=None, qFormMatrix=None): | ||
73 | + if mask_sFormMatrix is None: | ||
74 | + mask_sFormMatrix = vtk.vtkMatrix4x4() | ||
75 | + | ||
76 | + if qFormMatrix is None: | ||
77 | + qFormMatrix = vtk.vtkMatrix4x4() | ||
78 | + | ||
79 | + value = np.mean(mask.GetScalarRange()) | ||
80 | + | ||
24 | # Use the mask to create isosurface | 81 | # Use the mask to create isosurface |
25 | mc = vtk.vtkContourFilter() | 82 | mc = vtk.vtkContourFilter() |
26 | - mc.SetInputConnection(mask_reader.GetOutputPort()) | ||
27 | - mc.SetValue(0, 1) | 83 | + mc.SetInputData(mask) |
84 | + mc.SetValue(0, value) | ||
85 | + mc.ComputeNormalsOn() | ||
28 | mc.Update() | 86 | mc.Update() |
29 | 87 | ||
30 | # Mask isosurface | 88 | # Mask isosurface |
31 | refSurface = mc.GetOutput() | 89 | refSurface = mc.GetOutput() |
90 | + | ||
32 | # Create a uniformly meshed surface | 91 | # Create a uniformly meshed surface |
33 | tmpPeel = downsample(refSurface) | 92 | tmpPeel = downsample(refSurface) |
34 | # Standard space coordinates | 93 | # Standard space coordinates |
35 | - mask_sFormMatrix = mask_reader.GetSFormMatrix() | ||
36 | 94 | ||
37 | # Apply coordinate transform to the meshed mask | 95 | # Apply coordinate transform to the meshed mask |
38 | mask_ijk2xyz = vtk.vtkTransform() | 96 | mask_ijk2xyz = vtk.vtkTransform() |
@@ -48,7 +106,7 @@ class Brain: | @@ -48,7 +106,7 @@ class Brain: | ||
48 | # Configure calculation of normals | 106 | # Configure calculation of normals |
49 | tmpPeel = fixMesh(tmpPeel) | 107 | tmpPeel = fixMesh(tmpPeel) |
50 | # Remove duplicate points etc | 108 | # Remove duplicate points etc |
51 | - tmpPeel = cleanMesh(tmpPeel) | 109 | + # tmpPeel = cleanMesh(tmpPeel) |
52 | # Generate triangles | 110 | # Generate triangles |
53 | tmpPeel = upsample(tmpPeel) | 111 | tmpPeel = upsample(tmpPeel) |
54 | 112 | ||
@@ -56,9 +114,6 @@ class Brain: | @@ -56,9 +114,6 @@ class Brain: | ||
56 | tmpPeel = fixMesh(tmpPeel) | 114 | tmpPeel = fixMesh(tmpPeel) |
57 | tmpPeel = cleanMesh(tmpPeel) | 115 | tmpPeel = cleanMesh(tmpPeel) |
58 | 116 | ||
59 | - # Scanner coordinates from image | ||
60 | - qFormMatrix = T1_reader.GetQFormMatrix() | ||
61 | - | ||
62 | refImageSpace2_xyz_transform = vtk.vtkTransform() | 117 | refImageSpace2_xyz_transform = vtk.vtkTransform() |
63 | refImageSpace2_xyz_transform.SetMatrix(qFormMatrix) | 118 | refImageSpace2_xyz_transform.SetMatrix(qFormMatrix) |
64 | 119 | ||
@@ -83,16 +138,16 @@ class Brain: | @@ -83,16 +138,16 @@ class Brain: | ||
83 | self.peel_centers = vtk.vtkFloatArray() | 138 | self.peel_centers = vtk.vtkFloatArray() |
84 | self.peel.append(newPeel) | 139 | self.peel.append(newPeel) |
85 | self.currentPeelActor = vtk.vtkActor() | 140 | self.currentPeelActor = vtk.vtkActor() |
86 | - self.currentPeelActor.SetUserMatrix(affine_vtk) | 141 | + if self.affine_vtk: |
142 | + self.currentPeelActor.SetUserMatrix(self.affine_vtk) | ||
87 | self.GetCurrentPeelActor(currentPeel) | 143 | self.GetCurrentPeelActor(currentPeel) |
88 | self.peelActors.append(self.currentPeelActor) | 144 | self.peelActors.append(self.currentPeelActor) |
89 | # locator will later find the triangle on the peel surface where the coil's normal intersect | 145 | # locator will later find the triangle on the peel surface where the coil's normal intersect |
90 | self.locator = vtk.vtkCellLocator() | 146 | self.locator = vtk.vtkCellLocator() |
91 | - self.numberOfPeels = n_peels | ||
92 | self.PeelDown(currentPeel) | 147 | self.PeelDown(currentPeel) |
93 | 148 | ||
94 | - def get_actor(self, n, affine_vtk): | ||
95 | - return self.GetPeelActor(n, affine_vtk) | 149 | + def get_actor(self, n): |
150 | + return self.GetPeelActor(n) | ||
96 | 151 | ||
97 | def SliceDown(self, currentPeel): | 152 | def SliceDown(self, currentPeel): |
98 | # Warp using the normals | 153 | # Warp using the normals |
@@ -159,9 +214,10 @@ class Brain: | @@ -159,9 +214,10 @@ class Brain: | ||
159 | 214 | ||
160 | self.currentPeelNo += 1 | 215 | self.currentPeelNo += 1 |
161 | 216 | ||
162 | - def TransformPeelPosition(self, p, affine_vtk): | 217 | + def TransformPeelPosition(self, p): |
163 | peel_transform = vtk.vtkTransform() | 218 | peel_transform = vtk.vtkTransform() |
164 | - peel_transform.SetMatrix(affine_vtk) | 219 | + if self.affine_vtk: |
220 | + peel_transform.SetMatrix(self.affine_vtk) | ||
165 | refpeelspace = vtk.vtkTransformPolyDataFilter() | 221 | refpeelspace = vtk.vtkTransformPolyDataFilter() |
166 | refpeelspace.SetInputData(self.peel[p]) | 222 | refpeelspace.SetInputData(self.peel[p]) |
167 | refpeelspace.SetTransform(peel_transform) | 223 | refpeelspace.SetTransform(peel_transform) |
@@ -169,34 +225,26 @@ class Brain: | @@ -169,34 +225,26 @@ class Brain: | ||
169 | currentPeel = refpeelspace.GetOutput() | 225 | currentPeel = refpeelspace.GetOutput() |
170 | return currentPeel | 226 | return currentPeel |
171 | 227 | ||
172 | - def GetPeelActor(self, p, affine_vtk): | ||
173 | - colors = vtk.vtkNamedColors() | ||
174 | - # Create the color map | ||
175 | - colorLookupTable = vtk.vtkLookupTable() | ||
176 | - colorLookupTable.SetNumberOfColors(512) | ||
177 | - colorLookupTable.SetSaturationRange(0, 0) | ||
178 | - colorLookupTable.SetHueRange(0, 0) | ||
179 | - colorLookupTable.SetValueRange(0, 1) | ||
180 | - # colorLookupTable.SetTableRange(0, 1000) | ||
181 | - # colorLookupTable.SetTableRange(0, 250) | ||
182 | - colorLookupTable.SetTableRange(0, 200) | ||
183 | - # colorLookupTable.SetTableRange(0, 150) | ||
184 | - colorLookupTable.Build() | 228 | + def GetPeelActor(self, p): |
229 | + lut = vtk.vtkWindowLevelLookupTable() | ||
230 | + lut.SetWindow(self.window_width) | ||
231 | + lut.SetLevel(self.window_level) | ||
232 | + lut.Build() | ||
233 | + | ||
234 | + init = self.window_level - self.window_width / 2 | ||
235 | + end = self.window_level + self.window_width / 2 | ||
185 | 236 | ||
186 | # Set mapper auto | 237 | # Set mapper auto |
187 | - mapper = vtk.vtkOpenGLPolyDataMapper() | 238 | + mapper = vtk.vtkPolyDataMapper() |
188 | mapper.SetInputData(self.peel[p]) | 239 | mapper.SetInputData(self.peel[p]) |
189 | - # mapper.SetScalarRange(0, 1000) | ||
190 | - # mapper.SetScalarRange(0, 250) | ||
191 | - mapper.SetScalarRange(0, 200) | ||
192 | - # mapper.SetScalarRange(0, 150) | ||
193 | - mapper.SetLookupTable(colorLookupTable) | 240 | + mapper.SetScalarRange(init, end) |
241 | + mapper.SetLookupTable(lut) | ||
194 | mapper.InterpolateScalarsBeforeMappingOn() | 242 | mapper.InterpolateScalarsBeforeMappingOn() |
195 | 243 | ||
196 | # Set actor | 244 | # Set actor |
197 | self.currentPeelActor.SetMapper(mapper) | 245 | self.currentPeelActor.SetMapper(mapper) |
198 | 246 | ||
199 | - currentPeel = self.TransformPeelPosition(p, affine_vtk) | 247 | + currentPeel = self.TransformPeelPosition(p) |
200 | 248 | ||
201 | self.locator.SetDataSet(currentPeel) | 249 | self.locator.SetDataSet(currentPeel) |
202 | self.locator.BuildLocator() | 250 | self.locator.BuildLocator() |
@@ -206,34 +254,26 @@ class Brain: | @@ -206,34 +254,26 @@ class Brain: | ||
206 | return self.currentPeelActor | 254 | return self.currentPeelActor |
207 | 255 | ||
208 | def GetCurrentPeelActor(self, currentPeel): | 256 | def GetCurrentPeelActor(self, currentPeel): |
209 | - colors = vtk.vtkNamedColors() | ||
210 | - | ||
211 | - # Create the color map | ||
212 | - colorLookupTable = vtk.vtkLookupTable() | ||
213 | - colorLookupTable.SetNumberOfColors(512) | ||
214 | - colorLookupTable.SetSaturationRange(0, 0) | ||
215 | - colorLookupTable.SetHueRange(0, 0) | ||
216 | - colorLookupTable.SetValueRange(0, 1) | ||
217 | - # colorLookupTable.SetTableRange(0, 1000) | ||
218 | - # colorLookupTable.SetTableRange(0, 250) | ||
219 | - colorLookupTable.SetTableRange(0, 200) | ||
220 | - # colorLookupTable.SetTableRange(0, 150) | ||
221 | - colorLookupTable.Build() | 257 | + lut = vtk.vtkWindowLevelLookupTable() |
258 | + lut.SetWindow(self.window_width) | ||
259 | + lut.SetLevel(self.window_level) | ||
260 | + lut.Build() | ||
261 | + | ||
262 | + init = self.window_level - self.window_width / 2 | ||
263 | + end = self.window_level + self.window_width / 2 | ||
222 | 264 | ||
223 | # Set mapper auto | 265 | # Set mapper auto |
224 | - mapper = vtk.vtkOpenGLPolyDataMapper() | 266 | + mapper = vtk.vtkPolyDataMapper() |
225 | mapper.SetInputData(currentPeel) | 267 | mapper.SetInputData(currentPeel) |
226 | - # mapper.SetScalarRange(0, 1000) | ||
227 | - # mapper.SetScalarRange(0, 250) | ||
228 | - mapper.SetScalarRange(0, 200) | ||
229 | - # mapper.SetScalarRange(0, 150) | ||
230 | - mapper.SetLookupTable(colorLookupTable) | 268 | + mapper.SetScalarRange(init, end) |
269 | + mapper.SetLookupTable(lut) | ||
231 | mapper.InterpolateScalarsBeforeMappingOn() | 270 | mapper.InterpolateScalarsBeforeMappingOn() |
232 | 271 | ||
233 | # Set actor | 272 | # Set actor |
234 | self.currentPeelActor.SetMapper(mapper) | 273 | self.currentPeelActor.SetMapper(mapper) |
235 | self.currentPeelActor.GetProperty().SetBackfaceCulling(1) | 274 | self.currentPeelActor.GetProperty().SetBackfaceCulling(1) |
236 | self.currentPeelActor.GetProperty().SetOpacity(0.5) | 275 | self.currentPeelActor.GetProperty().SetOpacity(0.5) |
276 | + self.currentPeelActor.GetProperty().SetSpecular(0.25) | ||
237 | 277 | ||
238 | return self.currentPeelActor | 278 | return self.currentPeelActor |
239 | 279 |
invesalius/gui/dialogs.py
@@ -46,6 +46,7 @@ except ImportError: | @@ -46,6 +46,7 @@ except ImportError: | ||
46 | from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor | 46 | from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor |
47 | from wx.lib import masked | 47 | from wx.lib import masked |
48 | from wx.lib.agw import floatspin | 48 | from wx.lib.agw import floatspin |
49 | +import wx.lib.filebrowsebutton as filebrowse | ||
49 | from wx.lib.wordwrap import wordwrap | 50 | from wx.lib.wordwrap import wordwrap |
50 | from invesalius.pubsub import pub as Publisher | 51 | from invesalius.pubsub import pub as Publisher |
51 | import csv | 52 | import csv |
@@ -4995,3 +4996,134 @@ class SetSpacingDialog(wx.Dialog): | @@ -4995,3 +4996,134 @@ class SetSpacingDialog(wx.Dialog): | ||
4995 | 4996 | ||
4996 | def OnCancel(self, evt): | 4997 | def OnCancel(self, evt): |
4997 | self.EndModal(wx.ID_CANCEL) | 4998 | self.EndModal(wx.ID_CANCEL) |
4999 | + | ||
5000 | + | ||
5001 | +class PeelsCreationDlg(wx.Dialog): | ||
5002 | + FROM_MASK = 1 | ||
5003 | + FROM_FILES = 2 | ||
5004 | + def __init__(self, parent, *args, **kwds): | ||
5005 | + wx.Dialog.__init__(self, parent, *args, **kwds) | ||
5006 | + | ||
5007 | + self.mask_path = '' | ||
5008 | + self.method = self.FROM_MASK | ||
5009 | + | ||
5010 | + self._init_gui() | ||
5011 | + self._bind_events_wx() | ||
5012 | + self.get_all_masks() | ||
5013 | + | ||
5014 | + def _init_gui(self): | ||
5015 | + self.SetTitle("dialog") | ||
5016 | + | ||
5017 | + from_mask_stbox = self._from_mask_gui() | ||
5018 | + from_files_stbox = self._from_files_gui() | ||
5019 | + | ||
5020 | + main_sizer = wx.BoxSizer(wx.VERTICAL) | ||
5021 | + main_sizer.Add(from_mask_stbox, 0, wx.EXPAND | wx.ALL, 5) | ||
5022 | + main_sizer.Add(from_files_stbox, 0, wx.EXPAND | wx.ALL, 5) | ||
5023 | + | ||
5024 | + btn_sizer = wx.StdDialogButtonSizer() | ||
5025 | + main_sizer.Add(btn_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 4) | ||
5026 | + | ||
5027 | + self.btn_ok = wx.Button(self, wx.ID_OK, "") | ||
5028 | + self.btn_ok.SetDefault() | ||
5029 | + btn_sizer.AddButton(self.btn_ok) | ||
5030 | + | ||
5031 | + self.btn_cancel = wx.Button(self, wx.ID_CANCEL, "") | ||
5032 | + btn_sizer.AddButton(self.btn_cancel) | ||
5033 | + | ||
5034 | + btn_sizer.Realize() | ||
5035 | + | ||
5036 | + self.SetSizer(main_sizer) | ||
5037 | + main_sizer.Fit(self) | ||
5038 | + | ||
5039 | + self.SetAffirmativeId(self.btn_ok.GetId()) | ||
5040 | + self.SetEscapeId(self.btn_cancel.GetId()) | ||
5041 | + | ||
5042 | + self.Layout() | ||
5043 | + | ||
5044 | + def _from_mask_gui(self): | ||
5045 | + mask_box = wx.StaticBox(self, -1, _("From mask")) | ||
5046 | + from_mask_stbox = wx.StaticBoxSizer(mask_box, wx.VERTICAL) | ||
5047 | + | ||
5048 | + self.cb_masks = wx.ComboBox(self, wx.ID_ANY, choices=[]) | ||
5049 | + self.from_mask_rb = wx.RadioButton(self, -1, "", style = wx.RB_GROUP) | ||
5050 | + | ||
5051 | + internal_sizer = wx.BoxSizer(wx.HORIZONTAL) | ||
5052 | + internal_sizer.Add(self.from_mask_rb, 0, wx.ALL | wx.EXPAND, 5) | ||
5053 | + internal_sizer.Add(self.cb_masks, 1, wx.ALL | wx.EXPAND, 5) | ||
5054 | + | ||
5055 | + from_mask_stbox.Add(internal_sizer, 0, wx.EXPAND) | ||
5056 | + | ||
5057 | + return from_mask_stbox | ||
5058 | + | ||
5059 | + def _from_files_gui(self): | ||
5060 | + session = ses.Session() | ||
5061 | + last_directory = session.get('paths', 'last_directory_%d' % const.ID_NIFTI_IMPORT, '') | ||
5062 | + | ||
5063 | + files_box = wx.StaticBox(self, -1, _("From files")) | ||
5064 | + from_files_stbox = wx.StaticBoxSizer(files_box, wx.VERTICAL) | ||
5065 | + | ||
5066 | + self.mask_file_browse = filebrowse.FileBrowseButton(self, -1, labelText=_("Mask file"), | ||
5067 | + fileMask=WILDCARD_NIFTI, dialogTitle=_("Choose Mask file"), startDirectory = last_directory, | ||
5068 | + changeCallback=lambda evt: self._set_files_callback(mask_path=evt.GetString())) | ||
5069 | + self.from_files_rb = wx.RadioButton(self, -1, "") | ||
5070 | + | ||
5071 | + ctrl_sizer = wx.BoxSizer(wx.VERTICAL) | ||
5072 | + ctrl_sizer.Add(self.mask_file_browse, 0, wx.ALL | wx.EXPAND, 5) | ||
5073 | + | ||
5074 | + internal_sizer = wx.BoxSizer(wx.HORIZONTAL) | ||
5075 | + internal_sizer.Add(self.from_files_rb, 0, wx.ALL | wx.EXPAND, 5) | ||
5076 | + internal_sizer.Add(ctrl_sizer, 0, wx.ALL | wx.EXPAND, 5) | ||
5077 | + | ||
5078 | + from_files_stbox.Add(internal_sizer, 0, wx.EXPAND) | ||
5079 | + | ||
5080 | + return from_files_stbox | ||
5081 | + | ||
5082 | + def _bind_events_wx(self): | ||
5083 | + self.from_mask_rb.Bind(wx.EVT_RADIOBUTTON, self.on_select_method) | ||
5084 | + self.from_files_rb.Bind(wx.EVT_RADIOBUTTON, self.on_select_method) | ||
5085 | + | ||
5086 | + def get_all_masks(self): | ||
5087 | + import invesalius.project as prj | ||
5088 | + inv_proj = prj.Project() | ||
5089 | + choices = [i.name for i in inv_proj.mask_dict.values()] | ||
5090 | + try: | ||
5091 | + initial_value = choices[0] | ||
5092 | + enable = True | ||
5093 | + except IndexError: | ||
5094 | + initial_value = "" | ||
5095 | + enable = False | ||
5096 | + | ||
5097 | + self.cb_masks.SetItems(choices) | ||
5098 | + self.cb_masks.SetValue(initial_value) | ||
5099 | + self.btn_ok.Enable(enable) | ||
5100 | + | ||
5101 | + def on_select_method(self, evt): | ||
5102 | + radio_selected = evt.GetEventObject() | ||
5103 | + if radio_selected is self.from_mask_rb: | ||
5104 | + self.method = self.FROM_MASK | ||
5105 | + if self.cb_masks.GetItems(): | ||
5106 | + self.btn_ok.Enable(True) | ||
5107 | + else: | ||
5108 | + self.btn_ok.Enable(False) | ||
5109 | + else: | ||
5110 | + self.method = self.FROM_FILES | ||
5111 | + if self._check_if_files_exists(): | ||
5112 | + self.btn_ok.Enable(True) | ||
5113 | + else: | ||
5114 | + self.btn_ok.Enable(False) | ||
5115 | + | ||
5116 | + def _set_files_callback(self, mask_path=''): | ||
5117 | + if mask_path: | ||
5118 | + self.mask_path = mask_path | ||
5119 | + if self.method == self.FROM_FILES: | ||
5120 | + if self._check_if_files_exists(): | ||
5121 | + self.btn_ok.Enable(True) | ||
5122 | + else: | ||
5123 | + self.btn_ok.Enable(False) | ||
5124 | + | ||
5125 | + def _check_if_files_exists(self): | ||
5126 | + if self.mask_path and os.path.exists(self.mask_path): | ||
5127 | + return True | ||
5128 | + else: | ||
5129 | + return False |
invesalius/gui/task_navigator.py
@@ -31,7 +31,8 @@ try: | @@ -31,7 +31,8 @@ try: | ||
31 | import Trekker | 31 | import Trekker |
32 | has_trekker = True | 32 | has_trekker = True |
33 | except ImportError: | 33 | except ImportError: |
34 | - has_trekker = False | 34 | + has_trekker = True |
35 | + | ||
35 | try: | 36 | try: |
36 | import invesalius.data.elfin as elfin | 37 | import invesalius.data.elfin as elfin |
37 | import invesalius.data.elfin_processing as elfin_process | 38 | import invesalius.data.elfin_processing as elfin_process |
@@ -40,6 +41,7 @@ except ImportError: | @@ -40,6 +41,7 @@ except ImportError: | ||
40 | has_robot = False | 41 | has_robot = False |
41 | 42 | ||
42 | import wx | 43 | import wx |
44 | +import vtk | ||
43 | 45 | ||
44 | try: | 46 | try: |
45 | import wx.lib.agw.foldpanelbar as fpb | 47 | import wx.lib.agw.foldpanelbar as fpb |
@@ -72,6 +74,7 @@ from invesalius.navigation.icp import ICP | @@ -72,6 +74,7 @@ from invesalius.navigation.icp import ICP | ||
72 | from invesalius.navigation.navigation import Navigation | 74 | from invesalius.navigation.navigation import Navigation |
73 | from invesalius.navigation.tracker import Tracker | 75 | from invesalius.navigation.tracker import Tracker |
74 | from invesalius.navigation.robot import Robot | 76 | from invesalius.navigation.robot import Robot |
77 | +from invesalius.data.converters import to_vtk | ||
75 | 78 | ||
76 | from invesalius.net.neuronavigation_api import NeuronavigationApi | 79 | from invesalius.net.neuronavigation_api import NeuronavigationApi |
77 | 80 | ||
@@ -1939,7 +1942,7 @@ class TractographyPanel(wx.Panel): | @@ -1939,7 +1942,7 @@ class TractographyPanel(wx.Panel): | ||
1939 | def OnSelectPeelingDepth(self, evt, ctrl): | 1942 | def OnSelectPeelingDepth(self, evt, ctrl): |
1940 | self.peel_depth = ctrl.GetValue() | 1943 | self.peel_depth = ctrl.GetValue() |
1941 | if self.checkpeeling.GetValue(): | 1944 | if self.checkpeeling.GetValue(): |
1942 | - actor = self.brain_peel.get_actor(self.peel_depth, self.affine_vtk) | 1945 | + actor = self.brain_peel.get_actor(self.peel_depth) |
1943 | Publisher.sendMessage('Update peel', flag=True, actor=actor) | 1946 | Publisher.sendMessage('Update peel', flag=True, actor=actor) |
1944 | Publisher.sendMessage('Get peel centers and normals', centers=self.brain_peel.peel_centers, | 1947 | Publisher.sendMessage('Get peel centers and normals', centers=self.brain_peel.peel_centers, |
1945 | normals=self.brain_peel.peel_normals) | 1948 | normals=self.brain_peel.peel_normals) |
@@ -1972,7 +1975,7 @@ class TractographyPanel(wx.Panel): | @@ -1972,7 +1975,7 @@ class TractographyPanel(wx.Panel): | ||
1972 | def OnShowPeeling(self, evt, ctrl): | 1975 | def OnShowPeeling(self, evt, ctrl): |
1973 | # self.view_peeling = ctrl.GetValue() | 1976 | # self.view_peeling = ctrl.GetValue() |
1974 | if ctrl.GetValue(): | 1977 | if ctrl.GetValue(): |
1975 | - actor = self.brain_peel.get_actor(self.peel_depth, self.affine_vtk) | 1978 | + actor = self.brain_peel.get_actor(self.peel_depth) |
1976 | self.peel_loaded = True | 1979 | self.peel_loaded = True |
1977 | Publisher.sendMessage('Update peel visualization', data=self.peel_loaded) | 1980 | Publisher.sendMessage('Update peel visualization', data=self.peel_loaded) |
1978 | else: | 1981 | else: |
@@ -2002,46 +2005,48 @@ class TractographyPanel(wx.Panel): | @@ -2002,46 +2005,48 @@ class TractographyPanel(wx.Panel): | ||
2002 | 2005 | ||
2003 | def OnLinkBrain(self, event=None): | 2006 | def OnLinkBrain(self, event=None): |
2004 | Publisher.sendMessage('Begin busy cursor') | 2007 | Publisher.sendMessage('Begin busy cursor') |
2005 | - mask_path = dlg.ShowImportOtherFilesDialog(const.ID_NIFTI_IMPORT, _("Import brain mask")) | ||
2006 | - img_path = dlg.ShowImportOtherFilesDialog(const.ID_NIFTI_IMPORT, _("Import T1 anatomical image")) | ||
2007 | - # data_dir = os.environ.get('OneDrive') + r'\data\dti_navigation\baran\anat_reg_improve_20200609' | ||
2008 | - # mask_file = 'Baran_brain_mask.nii' | ||
2009 | - # mask_path = os.path.join(data_dir, mask_file) | ||
2010 | - # img_file = 'Baran_T1_inFODspace.nii' | ||
2011 | - # img_path = os.path.join(data_dir, img_file) | ||
2012 | - | ||
2013 | - if not self.affine_vtk: | 2008 | + inv_proj = prj.Project() |
2009 | + peels_dlg = dlg.PeelsCreationDlg(wx.GetApp().GetTopWindow()) | ||
2010 | + ret = peels_dlg.ShowModal() | ||
2011 | + method = peels_dlg.method | ||
2012 | + if ret == wx.ID_OK: | ||
2014 | slic = sl.Slice() | 2013 | slic = sl.Slice() |
2015 | - prj_data = prj.Project() | ||
2016 | - matrix_shape = tuple(prj_data.matrix_shape) | ||
2017 | - spacing = tuple(prj_data.spacing) | ||
2018 | - img_shift = spacing[1] * (matrix_shape[1] - 1) | ||
2019 | - self.affine = slic.affine.copy() | ||
2020 | - self.affine[1, -1] -= img_shift | ||
2021 | - self.affine_vtk = vtk_utils.numpy_to_vtkMatrix4x4(self.affine) | ||
2022 | - | ||
2023 | - if mask_path and img_path: | ||
2024 | - Publisher.sendMessage('Update status text in GUI', label=_("Busy")) | ||
2025 | - try: | ||
2026 | - self.brain_peel = brain.Brain(img_path, mask_path, self.n_peels, self.affine_vtk) | ||
2027 | - self.brain_actor = self.brain_peel.get_actor(self.peel_depth, self.affine_vtk) | ||
2028 | - self.brain_actor.GetProperty().SetOpacity(self.brain_opacity) | ||
2029 | - | ||
2030 | - self.checkpeeling.Enable(1) | ||
2031 | - self.checkpeeling.SetValue(True) | ||
2032 | - self.spin_opacity.Enable(1) | ||
2033 | - self.peel_loaded = True | ||
2034 | - | ||
2035 | - Publisher.sendMessage('Update peel', flag=True, actor=self.brain_actor) | ||
2036 | - Publisher.sendMessage('Get peel centers and normals', centers=self.brain_peel.peel_centers, | ||
2037 | - normals=self.brain_peel.peel_normals) | ||
2038 | - Publisher.sendMessage('Get init locator', locator=self.brain_peel.locator) | ||
2039 | - Publisher.sendMessage('Update status text in GUI', label=_("Brain model loaded")) | ||
2040 | - Publisher.sendMessage('Update peel visualization', data= self.peel_loaded) | ||
2041 | - except: | ||
2042 | - Publisher.sendMessage('Update status text in GUI', label=_("Brain mask initialization failed.")) | ||
2043 | - wx.MessageBox(_("Unable to load brain mask."), _("InVesalius 3")) | 2014 | + ww = slic.window_width |
2015 | + wl = slic.window_level | ||
2016 | + affine_vtk = vtk.vtkMatrix4x4() | ||
2017 | + | ||
2018 | + if method == peels_dlg.FROM_FILES: | ||
2019 | + matrix_shape = tuple(inv_proj.matrix_shape) | ||
2020 | + try: | ||
2021 | + affine = slic.affine.copy() | ||
2022 | + except AttributeError: | ||
2023 | + affine = np.eye(4) | ||
2024 | + affine[1, -1] -= matrix_shape[1] | ||
2025 | + affine_vtk = vtk_utils.numpy_to_vtkMatrix4x4(affine) | ||
2026 | + | ||
2027 | + self.brain_peel = brain.Brain(self.n_peels, ww, wl, affine_vtk) | ||
2028 | + if method == peels_dlg.FROM_MASK: | ||
2029 | + choices = [i for i in inv_proj.mask_dict.values()] | ||
2030 | + mask_index = peels_dlg.cb_masks.GetSelection() | ||
2031 | + mask = choices[mask_index] | ||
2032 | + self.brain_peel.from_mask(mask) | ||
2033 | + else: | ||
2034 | + mask_path = peels_dlg.mask_path | ||
2035 | + self.brain_peel.from_mask_file(mask_path) | ||
2036 | + self.brain_actor = self.brain_peel.get_actor(self.peel_depth) | ||
2037 | + self.brain_actor.GetProperty().SetOpacity(self.brain_opacity) | ||
2038 | + Publisher.sendMessage('Update peel', flag=True, actor=self.brain_actor) | ||
2039 | + Publisher.sendMessage('Get peel centers and normals', centers=self.brain_peel.peel_centers, | ||
2040 | + normals=self.brain_peel.peel_normals) | ||
2041 | + Publisher.sendMessage('Get init locator', locator=self.brain_peel.locator) | ||
2042 | + self.checkpeeling.Enable(1) | ||
2043 | + self.checkpeeling.SetValue(True) | ||
2044 | + self.spin_opacity.Enable(1) | ||
2045 | + Publisher.sendMessage('Update status text in GUI', label=_("Brain model loaded")) | ||
2046 | + self.peel_loaded = True | ||
2047 | + Publisher.sendMessage('Update peel visualization', data= self.peel_loaded) | ||
2044 | 2048 | ||
2049 | + peels_dlg.Destroy() | ||
2045 | Publisher.sendMessage('End busy cursor') | 2050 | Publisher.sendMessage('End busy cursor') |
2046 | 2051 | ||
2047 | def OnLinkFOD(self, event=None): | 2052 | def OnLinkFOD(self, event=None): |