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): | ... | ... |