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 | 27 | import data.imagedata_utils as utils |
28 | 28 | import data.mask as msk |
29 | 29 | import data.measures |
30 | +import data.slice_ as sl | |
30 | 31 | import data.surface as srf |
31 | 32 | import data.volume as volume |
32 | 33 | import gui.dialogs as dialog |
... | ... | @@ -76,7 +77,6 @@ class Controller(): |
76 | 77 | ps.Publisher().subscribe(self.OnOpenProject, 'Open project') |
77 | 78 | ps.Publisher().subscribe(self.OnOpenRecentProject, 'Open recent project') |
78 | 79 | ps.Publisher().subscribe(self.OnShowAnalyzeFile, 'Show analyze dialog') |
79 | - | |
80 | 80 | |
81 | 81 | def OnCancelImport(self, pubsub_evt): |
82 | 82 | #self.cancel_import = True |
... | ... | @@ -466,6 +466,10 @@ class Controller(): |
466 | 466 | tilt_value = -1*tilt_value |
467 | 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 | 473 | return imagedata, dicom |
470 | 474 | |
471 | 475 | def LoadImagedataInfo(self): |
... | ... | @@ -524,7 +528,3 @@ class Controller(): |
524 | 528 | preset_name + '.plist') |
525 | 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 | 478 | def dcm2memmap(files, slice_size): |
479 | 479 | """ |
480 | 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 | 483 | temp_file = tempfile.mktemp() |
484 | 484 | shape = len(files), slice_size[0], slice_size[1] |
... | ... | @@ -498,3 +498,30 @@ def dcm2memmap(files, slice_size): |
498 | 498 | array = numpy.frombuffer(dcm_array, dtype) |
499 | 499 | array.shape = slice_size |
500 | 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 | 16 | # PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais |
17 | 17 | # detalhes. |
18 | 18 | #-------------------------------------------------------------------------- |
19 | +import numpy | |
19 | 20 | import vtk |
20 | 21 | import wx.lib.pubsub as ps |
21 | 22 | |
... | ... | @@ -38,6 +39,7 @@ class Slice(object): |
38 | 39 | self.imagedata = None |
39 | 40 | self.current_mask = None |
40 | 41 | self.blend_filter = None |
42 | + self.matrix = None | |
41 | 43 | |
42 | 44 | self.num_gradient = 0 |
43 | 45 | self.interaction_style = st.StyleStateManager() |
... | ... | @@ -234,6 +236,28 @@ class Slice(object): |
234 | 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 | 262 | def SetMaskColour(self, index, colour, update=True): |
239 | 263 | "Set a mask colour given its index and colour (RGB 0-1 values)" |
... | ... | @@ -448,8 +472,6 @@ class Slice(object): |
448 | 472 | self.window_level.SetInput(self.imagedata) |
449 | 473 | |
450 | 474 | def __create_background(self, imagedata): |
451 | - self.imagedata = imagedata | |
452 | - | |
453 | 475 | thresh_min, thresh_max = imagedata.GetScalarRange() |
454 | 476 | ps.Publisher().sendMessage('Update threshold limits list', (thresh_min, |
455 | 477 | thresh_max)) |
... | ... | @@ -471,21 +493,21 @@ class Slice(object): |
471 | 493 | return img_colours_bg.GetOutput() |
472 | 494 | |
473 | 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 | 512 | def UpdateColourTableBackground(self, pubsub_evt): |
491 | 513 | values = pubsub_evt.data |
... | ... | @@ -502,15 +524,16 @@ class Slice(object): |
502 | 524 | |
503 | 525 | |
504 | 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 | 539 | def CreateMask(self, imagedata=None, name=None, colour=None, |
... | ... | @@ -595,6 +618,16 @@ class Slice(object): |
595 | 618 | ps.Publisher().sendMessage('Change mask selected', mask.index) |
596 | 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 | 631 | def __build_mask(self, imagedata, create=True): |
599 | 632 | # create new mask instance and insert it into project |
600 | 633 | if create: | ... | ... |
invesalius/data/viewer_slice.py
... | ... | @@ -88,7 +88,7 @@ class Viewer(wx.Panel): |
88 | 88 | self.on_wl = False |
89 | 89 | self.on_text = False |
90 | 90 | # VTK pipeline and actors |
91 | - #self.__config_interactor() | |
91 | + self.__config_interactor() | |
92 | 92 | self.pick = vtk.vtkPropPicker() |
93 | 93 | self.cross_actor = vtk.vtkActor() |
94 | 94 | |
... | ... | @@ -102,7 +102,6 @@ class Viewer(wx.Panel): |
102 | 102 | |
103 | 103 | scroll = wx.ScrollBar(self, -1, style=wx.SB_VERTICAL) |
104 | 104 | self.scroll = scroll |
105 | - | |
106 | 105 | sizer = wx.BoxSizer(wx.HORIZONTAL) |
107 | 106 | sizer.Add(interactor, 1, wx.EXPAND|wx.GROW) |
108 | 107 | |
... | ... | @@ -164,10 +163,11 @@ class Viewer(wx.Panel): |
164 | 163 | self.SetLayout(layout) |
165 | 164 | |
166 | 165 | def __config_interactor(self): |
167 | - | |
168 | 166 | ren = vtk.vtkRenderer() |
167 | + style = vtk.vtkInteractorStyleImage() | |
169 | 168 | |
170 | 169 | interactor = self.interactor |
170 | + interactor.SetInteractorStyle(style) | |
171 | 171 | interactor.GetRenderWindow().AddRenderer(ren) |
172 | 172 | |
173 | 173 | self.cam = ren.GetActiveCamera() |
... | ... | @@ -1056,48 +1056,50 @@ class Viewer(wx.Panel): |
1056 | 1056 | return cursor |
1057 | 1057 | |
1058 | 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 | 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 | 1092 | self.scroll.SetScrollbar(wx.SB_VERTICAL, 1, max_slice_number, |
1091 | 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 | 1104 | def __build_cross_lines(self): |
1103 | 1105 | actor = self.slice_data_list[0].actor |
... | ... | @@ -1339,15 +1341,21 @@ class Viewer(wx.Panel): |
1339 | 1341 | |
1340 | 1342 | def OnScrollBar(self, evt=None): |
1341 | 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 | 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 | 1357 | def OnScrollBarRelease(self, evt): |
1350 | - self.UpdateSlice3D(self.pos) | |
1358 | + #self.UpdateSlice3D(self.pos) | |
1351 | 1359 | evt.Skip() |
1352 | 1360 | |
1353 | 1361 | def OnKeyDown(self, evt=None, obj=None): | ... | ... |