diff --git a/invesalius/control.py b/invesalius/control.py index 5aaf02c..b7a3c85 100755 --- a/invesalius/control.py +++ b/invesalius/control.py @@ -236,6 +236,13 @@ class Controller(): proj = prj.Project() proj.OpenPlistProject(path) proj.SetAcquisitionModality(proj.modality) + self.Slice = sl.Slice() + self.Slice._open_image_matrix(proj.matrix_filename, + tuple(proj.matrix_shape), + proj.matrix_dtype) + + self.Slice.window_level = proj.level + self.Slice.window_width = proj.window mask = msk.Mask() mask._set_class_index(proj.last_mask_index) @@ -246,6 +253,8 @@ class Controller(): self.LoadProject() + ps.Publisher().sendMessage('Update threshold limits', + proj.threshold_range) session = ses.Session() session.OpenProject(filepath) ps.Publisher().sendMessage("Enable state project", True) @@ -329,8 +338,8 @@ class Controller(): patients_groups = dcm.GetDicomGroups(directory) if len(patients_groups): group = dcm.SelectLargerDicomGroup(patients_groups) - imagedata, dicom = self.OpenDicomGroup(group, 0, [0,0],gui=True) - self.CreateDicomProject(imagedata, dicom) + matrix, matrix_filename, dicom = self.OpenDicomGroup(group, 0, [0,0],gui=True) + self.CreateDicomProject(dicom, matrix, matrix_filename) # OPTION 2: ANALYZE? else: imagedata = analyze.ReadDirectory(directory) @@ -352,6 +361,9 @@ class Controller(): const.WINDOW_LEVEL[_('Default')] = (proj.window, proj.level) const.WINDOW_LEVEL[_('Manual')] = (proj.window, proj.level) + self.Slice = sl.Slice() + self.Slice.spacing = proj.spacing + ps.Publisher().sendMessage('Load slice to viewer', (proj.imagedata, proj.mask_dict)) @@ -375,6 +387,11 @@ class Controller(): if len(proj.mask_dict): mask_index = len(proj.mask_dict) -1 + for m in proj.mask_dict.values(): + ps.Publisher().sendMessage('Add mask', + (m.index, m.name, + m.threshold_range, m.colour)) + self.Slice.current_mask = proj.mask_dict[mask_index] ps.Publisher().sendMessage('Show mask', (mask_index, True)) ps.Publisher().sendMessage('Load measurement dict', @@ -419,7 +436,7 @@ class Controller(): ps.Publisher().sendMessage('Update threshold limits', proj.threshold_range) - def CreateDicomProject(self, imagedata, dicom): + def CreateDicomProject(self, dicom, matrix, matrix_filename): name_to_const = {"AXIAL":const.AXIAL, "CORONAL":const.CORONAL, "SAGITTAL":const.SAGITAL} @@ -428,14 +445,17 @@ class Controller(): proj.name = dicom.patient.name proj.modality = dicom.acquisition.modality proj.SetAcquisitionModality(dicom.acquisition.modality) - proj.imagedata = imagedata + proj.matrix_shape = matrix.shape + proj.matrix_dtype = matrix.dtype.name + proj.matrix_filename = matrix_filename + #proj.imagedata = imagedata proj.dicom_sample = dicom proj.original_orientation =\ name_to_const[dicom.image.orientation_label] proj.window = float(dicom.image.window) proj.level = float(dicom.image.level) proj.threshold_range = (-1024, 3033) - + proj.spacing = self.Slice.spacing ###### session = ses.Session() @@ -448,8 +468,8 @@ class Controller(): def OnOpenDicomGroup(self, pubsub_evt): group, interval, file_range = pubsub_evt.data - imagedata, dicom = self.OpenDicomGroup(group, interval, file_range, gui=True) - self.CreateDicomProject(imagedata, dicom) + matrix, matrix_filename, dicom = self.OpenDicomGroup(group, interval, file_range, gui=True) + self.CreateDicomProject(dicom, matrix, matrix_filename) self.LoadProject() ps.Publisher().sendMessage("Enable state project", True) @@ -511,12 +531,13 @@ class Controller(): elif orientation == 'SAGITTAL': self.Slice.spacing = zspacing, xyspacing[1], xyspacing[0] + self.Slice.window_level = wl self.Slice.window_width = ww ps.Publisher().sendMessage('Update threshold limits', scalar_range) - return imagedata, dicom + return self.matrix, self.filename, dicom def LoadImagedataInfo(self): proj = prj.Project() diff --git a/invesalius/data/imagedata_utils.py b/invesalius/data/imagedata_utils.py index a6c3f4d..684f78c 100644 --- a/invesalius/data/imagedata_utils.py +++ b/invesalius/data/imagedata_utils.py @@ -215,8 +215,8 @@ def Export(imagedata, filename, bin=False): writer.SetDataModeToBinary() else: writer.SetDataModeToAscii() - writer.SetInput(imagedata) - writer.Write() + #writer.SetInput(imagedata) + #writer.Write() def Import(filename): reader = vtk.vtkXMLImageDataReader() @@ -497,6 +497,7 @@ def dcm2memmap(files, slice_size, orientation): array.shape = matrix.shape[0], matrix.shape[1] matrix[:, :, n] = array else: + print array.shape, matrix.shape array.shape = matrix.shape[1], matrix.shape[2] matrix[n] = array update_progress(cont,message) diff --git a/invesalius/data/mask.py b/invesalius/data/mask.py index 39c675a..da2353f 100644 --- a/invesalius/data/mask.py +++ b/invesalius/data/mask.py @@ -20,6 +20,7 @@ import os import plistlib import random +import shutil import tempfile import numpy @@ -44,42 +45,46 @@ class Mask(): def SavePlist(self, filename): mask = {} - filename = '%s$%s$%d' % (filename, 'mask', self.index) - - d = self.__dict__ - for key in d: - if isinstance(d[key], vtk.vtkImageData): - img_name = '%s_%s.vti' % (filename, key) - iu.Export(d[key], img_name, bin=True) - mask[key] = {'$vti': os.path.split(img_name)[1]} - elif key == 'edited_points': - edited_points = {} - for p in self.edited_points: - edited_points[str(p)] = self.edited_points[p] - mask[key] = edited_points - else: - mask[key] = d[key] + filename = u'%s_%s_%d_%s' % (filename, 'mask', self.index, self.name) + img_name = u'%s.dat' % filename + self._save_mask(img_name) + + mask['index'] = self.index + mask['colour'] = self.colour + mask['opacity'] = self.opacity + mask['threshold range'] = self.threshold_range + mask['name'] = self.name + mask['edition threshold range'] = self.edition_threshold_range + mask['show'] = self.is_shown + mask['mask file'] = os.path.split(img_name)[1] + mask['mask shape'] = self.matrix.shape + plistlib.writePlist(mask, filename + '.plist') return os.path.split(filename)[1] + '.plist' def OpenPList(self, filename): mask = plistlib.readPlist(filename) + + self.index = mask['index'] + self.colour = mask['colour'] + self.opacity = mask['opacity'] + self.threshold_range = mask['threshold range'] + self.name = mask['name'] + self.edition_threshold_range = mask['edition threshold range'] + self.is_shown = mask['show'] + mask_file = mask['mask file'] + shape = mask['mask shape'] dirpath = os.path.abspath(os.path.split(filename)[0]) - for key in mask: - print "Key", key - if key == 'imagedata': - filepath = os.path.split(mask[key]["$vti"])[-1] - path = os.path.join(dirpath, filepath) - self.imagedata = iu.Import(path) - elif key == 'edited_points': - edited_points = {} - for p in mask[key]: - k = [float(i) for i in p.replace('(', '').replace(')', '').split(',')] - edited_points[tuple(k)] = mask[key][p] - - setattr(self, key, edited_points) - else: - setattr(self, key, mask[key]) + path = os.path.join(dirpath, mask_file) + self._open_mask(path, tuple(shape)) + + def _save_mask(self, filename): + shutil.copyfile(self.temp_file, filename) + + def _open_mask(self, filename, shape, dtype='uint8'): + print ">>", filename, shape + self.temp_file = filename + self.matrix = numpy.memmap(filename, shape=shape, dtype=dtype, mode="r+") def _set_class_index(self, index): Mask.general_index = index diff --git a/invesalius/data/slice_.py b/invesalius/data/slice_.py index 32b83f4..2baa728 100644 --- a/invesalius/data/slice_.py +++ b/invesalius/data/slice_.py @@ -75,6 +75,7 @@ class Slice(object): self.current_mask = None self.blend_filter = None self.matrix = None + self.spacing = (1.0, 1.0, 1.0) self.number_of_colours = 256 self.saturation_range = (0, 0) @@ -542,6 +543,7 @@ class Slice(object): def ShowMask(self, index, value): "Show a mask given its index and 'show' value (0: hide, other: show)" + print "Showing Mask" proj = Project() proj.mask_dict[index].is_shown = value if (index == self.current_mask.index): @@ -946,6 +948,12 @@ class Slice(object): return imagedata_mask + def _open_image_matrix(self, filename, shape, dtype): + self.matrix_filename = filename + print ">>>", filename + self.matrix = numpy.memmap(filename, shape=shape, dtype=dtype, + mode='r+') + def OnExportMask(self, pubsub_evt): #imagedata = self.current_mask.imagedata imagedata = self.imagedata diff --git a/invesalius/data/viewer_slice.py b/invesalius/data/viewer_slice.py index befeb4e..784ca00 100755 --- a/invesalius/data/viewer_slice.py +++ b/invesalius/data/viewer_slice.py @@ -1172,7 +1172,7 @@ class Viewer(wx.Panel): max_slice_number) self.slice_data = self.create_slice_window() - self.slice_data.actor.SetInput(imagedata) + #self.slice_data.actor.SetInput(imagedata) self.slice_data.SetCursor(self.__create_cursor()) self.cam = self.slice_data.renderer.GetActiveCamera() self.__build_cross_lines(imagedata) diff --git a/invesalius/gui/task_slice.py b/invesalius/gui/task_slice.py index ef9ab9c..9bb4d01 100644 --- a/invesalius/gui/task_slice.py +++ b/invesalius/gui/task_slice.py @@ -479,6 +479,7 @@ class MaskProperties(wx.Panel): (thresh_min, thresh_max) = Project().threshold_modes[evt.GetString()] self.gradient.SetMinValue(thresh_min) self.gradient.SetMaxValue(thresh_max) + self.OnSlideChanging(None) self.OnSlideChanged(None) def OnSlideChanged(self, evt): diff --git a/invesalius/gui/widgets/gradient.py b/invesalius/gui/widgets/gradient.py index 35ce57b..881e675 100755 --- a/invesalius/gui/widgets/gradient.py +++ b/invesalius/gui/widgets/gradient.py @@ -320,6 +320,7 @@ class GradientCtrl(wx.Panel): self.minimun = minValue self.maximun = maxValue self.colour = colour + self.changed = False self._draw_controls() self._bind_events_wx() self.SetBackgroundColour((0, 255, 0)) @@ -353,13 +354,15 @@ class GradientCtrl(wx.Panel): self.gradient_slider.Bind(EVT_SLIDER_CHANGED, self.OnSlider) # self.spin_min.Bind(wx.lib.intctrl.EVT_INT, self.ChangeMinValue) - self.spin_min.Bind(wx.EVT_KILL_FOCUS, self._FireSpinMinChange) - self.spin_min.Bind(wx.EVT_TEXT_ENTER, self._FireSpinMinChange) + self.spin_min.Bind(wx.EVT_LEAVE_WINDOW, self._FireSpinMinChanged) + self.spin_min.Bind(wx.EVT_KILL_FOCUS, self._FireSpinMinChanged) + self.spin_min.Bind(wx.EVT_KEY_DOWN, self._FireSpinMinChange) self.spin_min.Bind(wx.EVT_MOUSEWHEEL, self.OnMinMouseWheel) # self.spin_max.Bind(wx.lib.intctrl.EVT_INT, self.ChangeMaxValue) - self.spin_max.Bind(wx.EVT_KILL_FOCUS, self._FireSpinMaxChange) - self.spin_max.Bind(wx.EVT_TEXT_ENTER, self._FireSpinMaxChange) + self.spin_max.Bind(wx.EVT_LEAVE_WINDOW, self._FireSpinMaxChanged) + self.spin_max.Bind(wx.EVT_KILL_FOCUS, self._FireSpinMaxChanged) + self.spin_max.Bind(wx.EVT_KEY_DOWN, self._FireSpinMaxChange) self.spin_max.Bind(wx.EVT_MOUSEWHEEL, self.OnMaxMouseWheel) def OnSlider(self, evt): @@ -377,17 +380,27 @@ class GradientCtrl(wx.Panel): self._GenerateEvent(myEVT_THRESHOLD_CHANGING) def _FireSpinMinChange(self, evt): + evt.Skip() value = int(self.spin_min.GetValue()) if value != self.GetMinValue(): self.SetMinValue(value) self._GenerateEvent(myEVT_THRESHOLD_CHANGING) + def _FireSpinMinChanged(self, evt): + if self.changed: + self._GenerateEvent(myEVT_THRESHOLD_CHANGED) + def _FireSpinMaxChange(self, evt): + evt.Skip() value = int(self.spin_max.GetValue()) if value != self.GetMaxValue(): self.SetMaxValue(value) self._GenerateEvent(myEVT_THRESHOLD_CHANGING) + def _FireSpinMaxChanged(self, evt): + if self.changed: + self._GenerateEvent(myEVT_THRESHOLD_CHANGED) + def OnMinMouseWheel(self, e): """ When the user wheel the mouse over min texbox @@ -464,6 +477,13 @@ class GradientCtrl(wx.Panel): return self.minimun def _GenerateEvent(self, event): + if event == myEVT_THRESHOLD_CHANGING: + self.changed = True + print 'changing' + elif event == myEVT_THRESHOLD_CHANGED : + self.changed = False + print 'changed' + evt = SliderEvent(event, self.GetId(), self.min_range, self.max_range, self.minimun, self.maximun) self.GetEventHandler().ProcessEvent(evt) diff --git a/invesalius/project.py b/invesalius/project.py index 8cfec1e..9167426 100755 --- a/invesalius/project.py +++ b/invesalius/project.py @@ -211,7 +211,7 @@ class Project(object): # that we encode in utf-8. filename = filename.encode('utf-8') dir_temp = tempfile.mkdtemp(filename) - filename_tmp = os.path.join(dir_temp, filename) + filename_tmp = os.path.join(dir_temp, 'matrix.dat') project = {} @@ -220,18 +220,21 @@ class Project(object): project[key] = {'#plist': self.__dict__[key].SavePlist(filename_tmp).decode('utf-8')} elif key == 'dicom_sample': - sample_path = os.path.join(dir_temp, 'sample.dcm') - shutil.copy(self.dicom_sample.parser.filename,sample_path) - os.chmod(sample_path, stat.S_IREAD|stat.S_IWRITE) + #sample_path = os.path.join(dir_temp, 'sample.dcm') + #shutil.copy(self.dicom_sample.parser.filename,sample_path) + #os.chmod(sample_path, stat.S_IREAD|stat.S_IWRITE) - project[key] = 'sample.dcm' + #project[key] = 'sample.dcm' + pass + elif key.startswith('matrix'): + continue else: project[key] = self.__dict__[key] masks = {} for index in self.mask_dict: masks[str(index)] = {'#mask':\ - self.mask_dict[index].SavePlist(filename_tmp).decode('utf-8')} + self.mask_dict[index].SavePlist(filename_tmp)} surfaces = {} for index in self.surface_dict: @@ -241,9 +244,10 @@ class Project(object): project['surface_dict'] = surfaces project['mask_dict'] = masks project['measurement_dict'] = self.GetMeasuresDict() - img_file = '%s_%s.vti' % (filename_tmp, 'imagedata') - iu.Export(self.imagedata, img_file, bin=True) - project['imagedata'] = {'$vti':os.path.split(img_file)[1].decode('utf-8')} + shutil.copyfile(self.matrix_filename, filename_tmp) + project['matrix'] = {'filename':os.path.split(filename_tmp)[1].decode('utf-8'), + 'shape': self.matrix_shape, + 'dtype': self.matrix_dtype} plistlib.writePlist(project, filename_tmp + '.plist') @@ -268,23 +272,25 @@ class Project(object): dirpath = os.path.abspath(os.path.split(filelist[0])[0]) for key in project: - if key == 'imagedata': - filepath = os.path.split(project[key]["$vti"])[-1] + if key == 'matrix': + filepath = os.path.split(project[key]["filename"])[-1] path = os.path.join(dirpath, filepath) - self.imagedata = iu.Import(path) + self.matrix_filename = path + self.matrix_shape = project[key]['shape'] + self.matrix_dtype = project[key]['dtype'] elif key == 'presets': filepath = os.path.split(project[key]["#plist"])[-1] path = os.path.join(dirpath, filepath) p = Presets() p.OpenPlist(path) self.presets = p - elif key == 'dicom_sample': - path = os.path.join(dirpath, project[key]) - p = dicom.Parser() - p.SetFileName(path) - d = dicom.Dicom() - d.SetParser(p) - self.dicom_sample = d + #elif key == 'dicom_sample': + #path = os.path.join(dirpath, project[key]) + #p = dicom.Parser() + #p.SetFileName(path) + #d = dicom.Dicom() + #d.SetParser(p) + #self.dicom_sample = d elif key == 'mask_dict': self.mask_dict = {} -- libgit2 0.21.2