Commit 1d943e8d147ffac0538373624700f23c076a8d60
1 parent
fe94b6bb
Exists in
master
and in
67 other branches
ENH: Loading images from memmap in viewer slices without the masks.
* The images are being loaded in viewer slices without the masks; * The imagedata with all slices are being loaded too, but not showed * The images are loaded with a hardcoded WL & WW
Showing
4 changed files
with
134 additions
and
66 deletions
Show diff stats
invesalius/control.py
@@ -27,6 +27,7 @@ import constants as const | @@ -27,6 +27,7 @@ import constants as const | ||
27 | import data.imagedata_utils as utils | 27 | import data.imagedata_utils as utils |
28 | import data.mask as msk | 28 | import data.mask as msk |
29 | import data.measures | 29 | import data.measures |
30 | +import data.slice_ as sl | ||
30 | import data.surface as srf | 31 | import data.surface as srf |
31 | import data.volume as volume | 32 | import data.volume as volume |
32 | import gui.dialogs as dialog | 33 | import gui.dialogs as dialog |
@@ -76,7 +77,6 @@ class Controller(): | @@ -76,7 +77,6 @@ class Controller(): | ||
76 | ps.Publisher().subscribe(self.OnOpenProject, 'Open project') | 77 | ps.Publisher().subscribe(self.OnOpenProject, 'Open project') |
77 | ps.Publisher().subscribe(self.OnOpenRecentProject, 'Open recent project') | 78 | ps.Publisher().subscribe(self.OnOpenRecentProject, 'Open recent project') |
78 | ps.Publisher().subscribe(self.OnShowAnalyzeFile, 'Show analyze dialog') | 79 | ps.Publisher().subscribe(self.OnShowAnalyzeFile, 'Show analyze dialog') |
79 | - | ||
80 | 80 | ||
81 | def OnCancelImport(self, pubsub_evt): | 81 | def OnCancelImport(self, pubsub_evt): |
82 | #self.cancel_import = True | 82 | #self.cancel_import = True |
@@ -466,6 +466,10 @@ class Controller(): | @@ -466,6 +466,10 @@ class Controller(): | ||
466 | tilt_value = -1*tilt_value | 466 | tilt_value = -1*tilt_value |
467 | imagedata = utils.FixGantryTilt(imagedata, tilt_value) | 467 | imagedata = utils.FixGantryTilt(imagedata, tilt_value) |
468 | 468 | ||
469 | + self.matrix, self.filename = utils.dcm2memmap(filelist, size) | ||
470 | + self.Slice = sl.Slice() | ||
471 | + self.Slice.matrix = self.matrix | ||
472 | + self.Slice.spacing = xyspacing[0], xyspacing[1], zspacing | ||
469 | return imagedata, dicom | 473 | return imagedata, dicom |
470 | 474 | ||
471 | def LoadImagedataInfo(self): | 475 | def LoadImagedataInfo(self): |
@@ -524,7 +528,3 @@ class Controller(): | @@ -524,7 +528,3 @@ class Controller(): | ||
524 | preset_name + '.plist') | 528 | preset_name + '.plist') |
525 | plistlib.writePlist(preset, preset_dir) | 529 | plistlib.writePlist(preset, preset_dir) |
526 | 530 | ||
527 | - | ||
528 | - | ||
529 | - | ||
530 | - |
invesalius/data/imagedata_utils.py
@@ -478,7 +478,7 @@ def get_numpy_array_type(gdcm_pixel_format): | @@ -478,7 +478,7 @@ def get_numpy_array_type(gdcm_pixel_format): | ||
478 | def dcm2memmap(files, slice_size): | 478 | def dcm2memmap(files, slice_size): |
479 | """ | 479 | """ |
480 | From a list of dicom files it creates memmap file in the temp folder and | 480 | From a list of dicom files it creates memmap file in the temp folder and |
481 | - returns. | 481 | + returns it and its related filename. |
482 | """ | 482 | """ |
483 | temp_file = tempfile.mktemp() | 483 | temp_file = tempfile.mktemp() |
484 | shape = len(files), slice_size[0], slice_size[1] | 484 | shape = len(files), slice_size[0], slice_size[1] |
@@ -498,3 +498,30 @@ def dcm2memmap(files, slice_size): | @@ -498,3 +498,30 @@ def dcm2memmap(files, slice_size): | ||
498 | array = numpy.frombuffer(dcm_array, dtype) | 498 | array = numpy.frombuffer(dcm_array, dtype) |
499 | array.shape = slice_size | 499 | array.shape = slice_size |
500 | matrix[n] = array | 500 | matrix[n] = array |
501 | + | ||
502 | + matrix.flush() | ||
503 | + return matrix, temp_file | ||
504 | + | ||
505 | +def to_vtk(n_array, spacing): | ||
506 | + dy, dx = n_array.shape | ||
507 | + n_array.shape = dx * dy | ||
508 | + | ||
509 | + v_image = numpy_support.numpy_to_vtk(n_array) | ||
510 | + | ||
511 | + # Generating the vtkImageData | ||
512 | + image = vtk.vtkImageData() | ||
513 | + image.SetDimensions(dx, dy, 1) | ||
514 | + image.SetOrigin(0, 0, 0) | ||
515 | + image.SetSpacing(spacing) | ||
516 | + image.SetNumberOfScalarComponents(1) | ||
517 | + image.SetExtent(0, dx -1, 0, dy -1, 0, 0) | ||
518 | + image.SetScalarType(numpy_support.get_vtk_array_type(n_array.dtype)) | ||
519 | + image.AllocateScalars() | ||
520 | + image.GetPointData().SetScalars(v_image) | ||
521 | + image.Update() | ||
522 | + | ||
523 | + image_copy = vtk.vtkImageData() | ||
524 | + image_copy.DeepCopy(image) | ||
525 | + image_copy.Update() | ||
526 | + | ||
527 | + return image_copy |
invesalius/data/slice_.py
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | # PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais | 16 | # PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais |
17 | # detalhes. | 17 | # detalhes. |
18 | #-------------------------------------------------------------------------- | 18 | #-------------------------------------------------------------------------- |
19 | +import numpy | ||
19 | import vtk | 20 | import vtk |
20 | import wx.lib.pubsub as ps | 21 | import wx.lib.pubsub as ps |
21 | 22 | ||
@@ -38,6 +39,7 @@ class Slice(object): | @@ -38,6 +39,7 @@ class Slice(object): | ||
38 | self.imagedata = None | 39 | self.imagedata = None |
39 | self.current_mask = None | 40 | self.current_mask = None |
40 | self.blend_filter = None | 41 | self.blend_filter = None |
42 | + self.matrix = None | ||
41 | 43 | ||
42 | self.num_gradient = 0 | 44 | self.num_gradient = 0 |
43 | self.interaction_style = st.StyleStateManager() | 45 | self.interaction_style = st.StyleStateManager() |
@@ -234,6 +236,28 @@ class Slice(object): | @@ -234,6 +236,28 @@ class Slice(object): | ||
234 | # END PUBSUB_EVT METHODS | 236 | # END PUBSUB_EVT METHODS |
235 | #--------------------------------------------------------------------------- | 237 | #--------------------------------------------------------------------------- |
236 | 238 | ||
239 | + def GetSlices(self, orientation, slice_number): | ||
240 | + if orientation == 'AXIAL': | ||
241 | + n_array = numpy.array(self.matrix[slice_number]) | ||
242 | + spacing = self.spacing | ||
243 | + elif orientation == 'CORONAL': | ||
244 | + n_array = numpy.array(self.matrix[..., slice_number, ...]) | ||
245 | + spacing = self.spacing[0], self.spacing[2], self.spacing[1] | ||
246 | + elif orientation == 'SAGITAL': | ||
247 | + n_array = numpy.array(self.matrix[..., ..., slice_number]) | ||
248 | + spacing = self.spacing[1], self.spacing[2], self.spacing[0] | ||
249 | + | ||
250 | + image = iu.to_vtk(n_array, spacing) | ||
251 | + image = self.do_ww_wl(image) | ||
252 | + return image | ||
253 | + | ||
254 | + def GetNumberOfSlices(self, orientation): | ||
255 | + if orientation == 'AXIAL': | ||
256 | + return self.matrix.shape[0] | ||
257 | + elif orientation == 'CORONAL': | ||
258 | + return self.matrix.shape[1] | ||
259 | + elif orientation == 'SAGITAL': | ||
260 | + return self.matrix.shape[2] | ||
237 | 261 | ||
238 | def SetMaskColour(self, index, colour, update=True): | 262 | def SetMaskColour(self, index, colour, update=True): |
239 | "Set a mask colour given its index and colour (RGB 0-1 values)" | 263 | "Set a mask colour given its index and colour (RGB 0-1 values)" |
@@ -448,8 +472,6 @@ class Slice(object): | @@ -448,8 +472,6 @@ class Slice(object): | ||
448 | self.window_level.SetInput(self.imagedata) | 472 | self.window_level.SetInput(self.imagedata) |
449 | 473 | ||
450 | def __create_background(self, imagedata): | 474 | def __create_background(self, imagedata): |
451 | - self.imagedata = imagedata | ||
452 | - | ||
453 | thresh_min, thresh_max = imagedata.GetScalarRange() | 475 | thresh_min, thresh_max = imagedata.GetScalarRange() |
454 | ps.Publisher().sendMessage('Update threshold limits list', (thresh_min, | 476 | ps.Publisher().sendMessage('Update threshold limits list', (thresh_min, |
455 | thresh_max)) | 477 | thresh_max)) |
@@ -471,21 +493,21 @@ class Slice(object): | @@ -471,21 +493,21 @@ class Slice(object): | ||
471 | return img_colours_bg.GetOutput() | 493 | return img_colours_bg.GetOutput() |
472 | 494 | ||
473 | def UpdateWindowLevelBackground(self, pubsub_evt): | 495 | def UpdateWindowLevelBackground(self, pubsub_evt): |
496 | + pass | ||
497 | + #window, level = pubsub_evt.data | ||
498 | + #window_level = self.window_level | ||
474 | 499 | ||
475 | - window, level = pubsub_evt.data | ||
476 | - window_level = self.window_level | ||
477 | - | ||
478 | - if not((window == window_level.GetWindow()) and\ | ||
479 | - (level == window_level.GetLevel())): | 500 | + #if not((window == window_level.GetWindow()) and\ |
501 | + #(level == window_level.GetLevel())): | ||
480 | 502 | ||
481 | - window_level.SetWindow(window) | ||
482 | - window_level.SetLevel(level) | ||
483 | - window_level.SetOutputFormatToLuminance() | ||
484 | - window_level.Update() | 503 | + #window_level.SetWindow(window) |
504 | + #window_level.SetLevel(level) | ||
505 | + #window_level.SetOutputFormatToLuminance() | ||
506 | + #window_level.Update() | ||
485 | 507 | ||
486 | - thresh_min, thresh_max = window_level.GetOutput().GetScalarRange() | ||
487 | - self.lut_bg.SetTableRange(thresh_min, thresh_max) | ||
488 | - self.img_colours_bg.SetInput(window_level.GetOutput()) | 508 | + #thresh_min, thresh_max = window_level.GetOutput().GetScalarRange() |
509 | + #self.lut_bg.SetTableRange(thresh_min, thresh_max) | ||
510 | + #self.img_colours_bg.SetInput(window_level.GetOutput()) | ||
489 | 511 | ||
490 | def UpdateColourTableBackground(self, pubsub_evt): | 512 | def UpdateColourTableBackground(self, pubsub_evt): |
491 | values = pubsub_evt.data | 513 | values = pubsub_evt.data |
@@ -502,15 +524,16 @@ class Slice(object): | @@ -502,15 +524,16 @@ class Slice(object): | ||
502 | 524 | ||
503 | 525 | ||
504 | def InputImageWidget(self, pubsub_evt): | 526 | def InputImageWidget(self, pubsub_evt): |
505 | - widget = pubsub_evt.data | 527 | + #widget = pubsub_evt.data |
506 | 528 | ||
507 | - flip = vtk.vtkImageFlip() | ||
508 | - flip.SetInput(self.window_level.GetOutput()) | ||
509 | - flip.SetFilteredAxis(1) | ||
510 | - flip.FlipAboutOriginOn() | ||
511 | - flip.Update() | 529 | + #flip = vtk.vtkImageFlip() |
530 | + #flip.SetInput(self.window_level.GetOutput()) | ||
531 | + #flip.SetFilteredAxis(1) | ||
532 | + #flip.FlipAboutOriginOn() | ||
533 | + #flip.Update() | ||
512 | 534 | ||
513 | - widget.SetInput(flip.GetOutput()) | 535 | + #widget.SetInput(flip.GetOutput()) |
536 | + pass | ||
514 | 537 | ||
515 | 538 | ||
516 | def CreateMask(self, imagedata=None, name=None, colour=None, | 539 | def CreateMask(self, imagedata=None, name=None, colour=None, |
@@ -595,6 +618,16 @@ class Slice(object): | @@ -595,6 +618,16 @@ class Slice(object): | ||
595 | ps.Publisher().sendMessage('Change mask selected', mask.index) | 618 | ps.Publisher().sendMessage('Change mask selected', mask.index) |
596 | ps.Publisher().sendMessage('Update slice viewer') | 619 | ps.Publisher().sendMessage('Update slice viewer') |
597 | 620 | ||
621 | + def do_ww_wl(self, image): | ||
622 | + colorer = vtk.vtkImageMapToWindowLevelColors() | ||
623 | + colorer.SetInput(image) | ||
624 | + colorer.SetWindow(255) | ||
625 | + colorer.SetLevel(127) | ||
626 | + colorer.SetOutputFormatToRGBA() | ||
627 | + colorer.Update() | ||
628 | + | ||
629 | + return colorer.GetOutput() | ||
630 | + | ||
598 | def __build_mask(self, imagedata, create=True): | 631 | def __build_mask(self, imagedata, create=True): |
599 | # create new mask instance and insert it into project | 632 | # create new mask instance and insert it into project |
600 | if create: | 633 | if create: |
invesalius/data/viewer_slice.py
@@ -88,7 +88,7 @@ class Viewer(wx.Panel): | @@ -88,7 +88,7 @@ class Viewer(wx.Panel): | ||
88 | self.on_wl = False | 88 | self.on_wl = False |
89 | self.on_text = False | 89 | self.on_text = False |
90 | # VTK pipeline and actors | 90 | # VTK pipeline and actors |
91 | - #self.__config_interactor() | 91 | + self.__config_interactor() |
92 | self.pick = vtk.vtkPropPicker() | 92 | self.pick = vtk.vtkPropPicker() |
93 | self.cross_actor = vtk.vtkActor() | 93 | self.cross_actor = vtk.vtkActor() |
94 | 94 | ||
@@ -102,7 +102,6 @@ class Viewer(wx.Panel): | @@ -102,7 +102,6 @@ class Viewer(wx.Panel): | ||
102 | 102 | ||
103 | scroll = wx.ScrollBar(self, -1, style=wx.SB_VERTICAL) | 103 | scroll = wx.ScrollBar(self, -1, style=wx.SB_VERTICAL) |
104 | self.scroll = scroll | 104 | self.scroll = scroll |
105 | - | ||
106 | sizer = wx.BoxSizer(wx.HORIZONTAL) | 105 | sizer = wx.BoxSizer(wx.HORIZONTAL) |
107 | sizer.Add(interactor, 1, wx.EXPAND|wx.GROW) | 106 | sizer.Add(interactor, 1, wx.EXPAND|wx.GROW) |
108 | 107 | ||
@@ -164,10 +163,11 @@ class Viewer(wx.Panel): | @@ -164,10 +163,11 @@ class Viewer(wx.Panel): | ||
164 | self.SetLayout(layout) | 163 | self.SetLayout(layout) |
165 | 164 | ||
166 | def __config_interactor(self): | 165 | def __config_interactor(self): |
167 | - | ||
168 | ren = vtk.vtkRenderer() | 166 | ren = vtk.vtkRenderer() |
167 | + style = vtk.vtkInteractorStyleImage() | ||
169 | 168 | ||
170 | interactor = self.interactor | 169 | interactor = self.interactor |
170 | + interactor.SetInteractorStyle(style) | ||
171 | interactor.GetRenderWindow().AddRenderer(ren) | 171 | interactor.GetRenderWindow().AddRenderer(ren) |
172 | 172 | ||
173 | self.cam = ren.GetActiveCamera() | 173 | self.cam = ren.GetActiveCamera() |
@@ -1056,48 +1056,50 @@ class Viewer(wx.Panel): | @@ -1056,48 +1056,50 @@ class Viewer(wx.Panel): | ||
1056 | return cursor | 1056 | return cursor |
1057 | 1057 | ||
1058 | def SetInput(self, imagedata, mask_dict): | 1058 | def SetInput(self, imagedata, mask_dict): |
1059 | - self.imagedata = imagedata | 1059 | + pass |
1060 | + #self.imagedata = imagedata | ||
1060 | 1061 | ||
1061 | - #ren = self.ren | ||
1062 | - interactor = self.interactor | 1062 | + ##ren = self.ren |
1063 | + #interactor = self.interactor | ||
1063 | 1064 | ||
1064 | - # Slice pipeline, to be inserted into current viewer | ||
1065 | - slice_ = sl.Slice() | ||
1066 | - if slice_.imagedata is None: | ||
1067 | - slice_.SetInput(imagedata, mask_dict) | 1065 | + ## Slice pipeline, to be inserted into current viewer |
1066 | + #slice_ = sl.Slice() | ||
1067 | + #if slice_.imagedata is None: | ||
1068 | + #slice_.SetInput(imagedata, mask_dict) | ||
1068 | 1069 | ||
1069 | - #actor = vtk.vtkImageActor() | ||
1070 | - #actor.SetInput(slice_.GetOutput()) | ||
1071 | - self.LoadRenderers(slice_.GetOutput()) | ||
1072 | - self.__configure_renderers() | ||
1073 | - ren = self.slice_data_list[0].renderer | ||
1074 | - actor = self.slice_data_list[0].actor | ||
1075 | - actor_bound = actor.GetBounds() | 1070 | + actor = vtk.vtkImageActor() |
1071 | + ##actor.SetInput(slice_.GetOutput()) | ||
1072 | + #self.LoadRenderers(slice_.GetOutput()) | ||
1073 | + #self.__configure_renderers() | ||
1074 | + #ren = self.slice_data_list[0].renderer | ||
1075 | + #actor = self.slice_data_list[0].actor | ||
1076 | + #actor_bound = actor.GetBounds() | ||
1076 | self.actor = actor | 1077 | self.actor = actor |
1077 | - self.ren = ren | ||
1078 | - self.cam = ren.GetActiveCamera() | 1078 | + self.ren.AddActor(self.actor) |
1079 | + #self.cam = ren.GetActiveCamera() | ||
1079 | 1080 | ||
1080 | - for slice_data in self.slice_data_list: | ||
1081 | - self.__update_camera(slice_data) | ||
1082 | - self.Reposition(slice_data) | 1081 | + #for slice_data in self.slice_data_list: |
1082 | + #self.__update_camera(slice_data) | ||
1083 | + #self.Reposition(slice_data) | ||
1083 | 1084 | ||
1084 | - number_of_slices = self.layout[0] * self.layout[1] | ||
1085 | - max_slice_number = actor.GetSliceNumberMax() + 1/ \ | ||
1086 | - number_of_slices | 1085 | + #number_of_slices = self.layout[0] * self.layout[1] |
1086 | + #max_slice_number = actor.GetSliceNumberMax() + 1/ \ | ||
1087 | + #number_of_slices | ||
1087 | 1088 | ||
1088 | - if actor.GetSliceNumberMax() % number_of_slices: | ||
1089 | - max_slice_number += 1 | 1089 | + #if actor.GetSliceNumberMax() % number_of_slices: |
1090 | + #max_slice_number += 1 | ||
1091 | + max_slice_number = sl.Slice().GetNumberOfSlices(self.orientation) | ||
1090 | self.scroll.SetScrollbar(wx.SB_VERTICAL, 1, max_slice_number, | 1092 | self.scroll.SetScrollbar(wx.SB_VERTICAL, 1, max_slice_number, |
1091 | max_slice_number) | 1093 | max_slice_number) |
1092 | - self.set_scroll_position(0) | 1094 | + #self.set_scroll_position(0) |
1093 | 1095 | ||
1094 | - actor_bound = actor.GetBounds() | 1096 | + #actor_bound = actor.GetBounds() |
1095 | 1097 | ||
1096 | - self.EnableText() | ||
1097 | - # Insert cursor | ||
1098 | - self.SetInteractorStyle(const.STATE_DEFAULT) | 1098 | + #self.EnableText() |
1099 | + ## Insert cursor | ||
1100 | + #self.SetInteractorStyle(const.STATE_DEFAULT) | ||
1099 | 1101 | ||
1100 | - self.__build_cross_lines() | 1102 | + #self.__build_cross_lines() |
1101 | 1103 | ||
1102 | def __build_cross_lines(self): | 1104 | def __build_cross_lines(self): |
1103 | actor = self.slice_data_list[0].actor | 1105 | actor = self.slice_data_list[0].actor |
@@ -1339,15 +1341,21 @@ class Viewer(wx.Panel): | @@ -1339,15 +1341,21 @@ class Viewer(wx.Panel): | ||
1339 | 1341 | ||
1340 | def OnScrollBar(self, evt=None): | 1342 | def OnScrollBar(self, evt=None): |
1341 | pos = self.scroll.GetThumbPosition() | 1343 | pos = self.scroll.GetThumbPosition() |
1342 | - self.set_slice_number(pos) | ||
1343 | - #self.UpdateSlice3D(pos) | ||
1344 | - self.pos = pos | 1344 | + slice_ = sl.Slice() |
1345 | + image = slice_.GetSlices(self.orientation, pos) | ||
1346 | + self.actor.SetInput(image) | ||
1347 | + self.ren.ResetCamera() | ||
1345 | self.interactor.Render() | 1348 | self.interactor.Render() |
1346 | - if evt: | ||
1347 | - evt.Skip() | 1349 | + print "slice", pos |
1350 | + #self.set_slice_number(pos) | ||
1351 | + ##self.UpdateSlice3D(pos) | ||
1352 | + #self.pos = pos | ||
1353 | + #self.interactor.Render() | ||
1354 | + #if evt: | ||
1355 | + #evt.Skip() | ||
1348 | 1356 | ||
1349 | def OnScrollBarRelease(self, evt): | 1357 | def OnScrollBarRelease(self, evt): |
1350 | - self.UpdateSlice3D(self.pos) | 1358 | + #self.UpdateSlice3D(self.pos) |
1351 | evt.Skip() | 1359 | evt.Skip() |
1352 | 1360 | ||
1353 | def OnKeyDown(self, evt=None, obj=None): | 1361 | def OnKeyDown(self, evt=None, obj=None): |