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 | 2 | import pyacvd |
| 3 | 3 | # import os |
| 4 | 4 | import pyvista |
| 5 | -# import numpy as np | |
| 5 | +import numpy as np | |
| 6 | 6 | # import Trekker |
| 7 | 7 | |
| 8 | +import invesalius.data.slice_ as sl | |
| 9 | +from invesalius.data.converters import to_vtk | |
| 10 | + | |
| 8 | 11 | |
| 9 | 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 | 14 | # Create arrays to access the peel data and peel Actors |
| 12 | 15 | self.peel = [] |
| 13 | 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 | 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 | 57 | # Read the mask |
| 21 | 58 | mask_reader = vtk.vtkNIFTIImageReader() |
| 22 | 59 | mask_reader.SetFileName(mask_path) |
| 23 | 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 | 81 | # Use the mask to create isosurface |
| 25 | 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 | 86 | mc.Update() |
| 29 | 87 | |
| 30 | 88 | # Mask isosurface |
| 31 | 89 | refSurface = mc.GetOutput() |
| 90 | + | |
| 32 | 91 | # Create a uniformly meshed surface |
| 33 | 92 | tmpPeel = downsample(refSurface) |
| 34 | 93 | # Standard space coordinates |
| 35 | - mask_sFormMatrix = mask_reader.GetSFormMatrix() | |
| 36 | 94 | |
| 37 | 95 | # Apply coordinate transform to the meshed mask |
| 38 | 96 | mask_ijk2xyz = vtk.vtkTransform() |
| ... | ... | @@ -48,7 +106,7 @@ class Brain: |
| 48 | 106 | # Configure calculation of normals |
| 49 | 107 | tmpPeel = fixMesh(tmpPeel) |
| 50 | 108 | # Remove duplicate points etc |
| 51 | - tmpPeel = cleanMesh(tmpPeel) | |
| 109 | + # tmpPeel = cleanMesh(tmpPeel) | |
| 52 | 110 | # Generate triangles |
| 53 | 111 | tmpPeel = upsample(tmpPeel) |
| 54 | 112 | |
| ... | ... | @@ -56,9 +114,6 @@ class Brain: |
| 56 | 114 | tmpPeel = fixMesh(tmpPeel) |
| 57 | 115 | tmpPeel = cleanMesh(tmpPeel) |
| 58 | 116 | |
| 59 | - # Scanner coordinates from image | |
| 60 | - qFormMatrix = T1_reader.GetQFormMatrix() | |
| 61 | - | |
| 62 | 117 | refImageSpace2_xyz_transform = vtk.vtkTransform() |
| 63 | 118 | refImageSpace2_xyz_transform.SetMatrix(qFormMatrix) |
| 64 | 119 | |
| ... | ... | @@ -83,16 +138,16 @@ class Brain: |
| 83 | 138 | self.peel_centers = vtk.vtkFloatArray() |
| 84 | 139 | self.peel.append(newPeel) |
| 85 | 140 | self.currentPeelActor = vtk.vtkActor() |
| 86 | - self.currentPeelActor.SetUserMatrix(affine_vtk) | |
| 141 | + if self.affine_vtk: | |
| 142 | + self.currentPeelActor.SetUserMatrix(self.affine_vtk) | |
| 87 | 143 | self.GetCurrentPeelActor(currentPeel) |
| 88 | 144 | self.peelActors.append(self.currentPeelActor) |
| 89 | 145 | # locator will later find the triangle on the peel surface where the coil's normal intersect |
| 90 | 146 | self.locator = vtk.vtkCellLocator() |
| 91 | - self.numberOfPeels = n_peels | |
| 92 | 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 | 152 | def SliceDown(self, currentPeel): |
| 98 | 153 | # Warp using the normals |
| ... | ... | @@ -159,9 +214,10 @@ class Brain: |
| 159 | 214 | |
| 160 | 215 | self.currentPeelNo += 1 |
| 161 | 216 | |
| 162 | - def TransformPeelPosition(self, p, affine_vtk): | |
| 217 | + def TransformPeelPosition(self, p): | |
| 163 | 218 | peel_transform = vtk.vtkTransform() |
| 164 | - peel_transform.SetMatrix(affine_vtk) | |
| 219 | + if self.affine_vtk: | |
| 220 | + peel_transform.SetMatrix(self.affine_vtk) | |
| 165 | 221 | refpeelspace = vtk.vtkTransformPolyDataFilter() |
| 166 | 222 | refpeelspace.SetInputData(self.peel[p]) |
| 167 | 223 | refpeelspace.SetTransform(peel_transform) |
| ... | ... | @@ -169,34 +225,26 @@ class Brain: |
| 169 | 225 | currentPeel = refpeelspace.GetOutput() |
| 170 | 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 | 237 | # Set mapper auto |
| 187 | - mapper = vtk.vtkOpenGLPolyDataMapper() | |
| 238 | + mapper = vtk.vtkPolyDataMapper() | |
| 188 | 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 | 242 | mapper.InterpolateScalarsBeforeMappingOn() |
| 195 | 243 | |
| 196 | 244 | # Set actor |
| 197 | 245 | self.currentPeelActor.SetMapper(mapper) |
| 198 | 246 | |
| 199 | - currentPeel = self.TransformPeelPosition(p, affine_vtk) | |
| 247 | + currentPeel = self.TransformPeelPosition(p) | |
| 200 | 248 | |
| 201 | 249 | self.locator.SetDataSet(currentPeel) |
| 202 | 250 | self.locator.BuildLocator() |
| ... | ... | @@ -206,34 +254,26 @@ class Brain: |
| 206 | 254 | return self.currentPeelActor |
| 207 | 255 | |
| 208 | 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 | 265 | # Set mapper auto |
| 224 | - mapper = vtk.vtkOpenGLPolyDataMapper() | |
| 266 | + mapper = vtk.vtkPolyDataMapper() | |
| 225 | 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 | 270 | mapper.InterpolateScalarsBeforeMappingOn() |
| 232 | 271 | |
| 233 | 272 | # Set actor |
| 234 | 273 | self.currentPeelActor.SetMapper(mapper) |
| 235 | 274 | self.currentPeelActor.GetProperty().SetBackfaceCulling(1) |
| 236 | 275 | self.currentPeelActor.GetProperty().SetOpacity(0.5) |
| 276 | + self.currentPeelActor.GetProperty().SetSpecular(0.25) | |
| 237 | 277 | |
| 238 | 278 | return self.currentPeelActor |
| 239 | 279 | ... | ... |
invesalius/gui/dialogs.py
| ... | ... | @@ -46,6 +46,7 @@ except ImportError: |
| 46 | 46 | from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor |
| 47 | 47 | from wx.lib import masked |
| 48 | 48 | from wx.lib.agw import floatspin |
| 49 | +import wx.lib.filebrowsebutton as filebrowse | |
| 49 | 50 | from wx.lib.wordwrap import wordwrap |
| 50 | 51 | from invesalius.pubsub import pub as Publisher |
| 51 | 52 | import csv |
| ... | ... | @@ -4995,3 +4996,134 @@ class SetSpacingDialog(wx.Dialog): |
| 4995 | 4996 | |
| 4996 | 4997 | def OnCancel(self, evt): |
| 4997 | 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 | 31 | import Trekker |
| 32 | 32 | has_trekker = True |
| 33 | 33 | except ImportError: |
| 34 | - has_trekker = False | |
| 34 | + has_trekker = True | |
| 35 | + | |
| 35 | 36 | try: |
| 36 | 37 | import invesalius.data.elfin as elfin |
| 37 | 38 | import invesalius.data.elfin_processing as elfin_process |
| ... | ... | @@ -40,6 +41,7 @@ except ImportError: |
| 40 | 41 | has_robot = False |
| 41 | 42 | |
| 42 | 43 | import wx |
| 44 | +import vtk | |
| 43 | 45 | |
| 44 | 46 | try: |
| 45 | 47 | import wx.lib.agw.foldpanelbar as fpb |
| ... | ... | @@ -72,6 +74,7 @@ from invesalius.navigation.icp import ICP |
| 72 | 74 | from invesalius.navigation.navigation import Navigation |
| 73 | 75 | from invesalius.navigation.tracker import Tracker |
| 74 | 76 | from invesalius.navigation.robot import Robot |
| 77 | +from invesalius.data.converters import to_vtk | |
| 75 | 78 | |
| 76 | 79 | from invesalius.net.neuronavigation_api import NeuronavigationApi |
| 77 | 80 | |
| ... | ... | @@ -1939,7 +1942,7 @@ class TractographyPanel(wx.Panel): |
| 1939 | 1942 | def OnSelectPeelingDepth(self, evt, ctrl): |
| 1940 | 1943 | self.peel_depth = ctrl.GetValue() |
| 1941 | 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 | 1946 | Publisher.sendMessage('Update peel', flag=True, actor=actor) |
| 1944 | 1947 | Publisher.sendMessage('Get peel centers and normals', centers=self.brain_peel.peel_centers, |
| 1945 | 1948 | normals=self.brain_peel.peel_normals) |
| ... | ... | @@ -1972,7 +1975,7 @@ class TractographyPanel(wx.Panel): |
| 1972 | 1975 | def OnShowPeeling(self, evt, ctrl): |
| 1973 | 1976 | # self.view_peeling = ctrl.GetValue() |
| 1974 | 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 | 1979 | self.peel_loaded = True |
| 1977 | 1980 | Publisher.sendMessage('Update peel visualization', data=self.peel_loaded) |
| 1978 | 1981 | else: |
| ... | ... | @@ -2002,46 +2005,48 @@ class TractographyPanel(wx.Panel): |
| 2002 | 2005 | |
| 2003 | 2006 | def OnLinkBrain(self, event=None): |
| 2004 | 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 | 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 | 2050 | Publisher.sendMessage('End busy cursor') |
| 2046 | 2051 | |
| 2047 | 2052 | def OnLinkFOD(self, event=None): | ... | ... |