Commit 1aaf2ccb100d3fcc4fee87eb4f0f9bc58f8d78ef

Authored by tfmoraes
1 parent f739fdf5

ENH: Saving InVesalius3 using the proposed file format

invesalius/data/mask.py
... ... @@ -51,37 +51,40 @@ class Mask():
51 51 Publisher.subscribe(self.OnFlipVolume, 'Flip volume')
52 52 Publisher.subscribe(self.OnSwapVolumeAxes, 'Swap volume axes')
53 53  
54   - def SavePlist(self, filename):
  54 + def SavePlist(self, dir_temp):
55 55 mask = {}
56   - filename = u'%s_%s_%d_%s' % (filename, 'mask', self.index, self.name)
57   - img_name = u'%s.dat' % filename
58   - self._save_mask(img_name)
  56 + filename = u'mask%d_%s' % (self.index, self.name)
  57 + mask_filename = u'%s.dat' % filename
  58 + mask_filepath = os.path.join(dir_temp, mask_filename)
  59 + self._save_mask(mask_filepath)
59 60  
60 61 mask['index'] = self.index
  62 + mask['name'] = self.name
61 63 mask['colour'] = self.colour
62 64 mask['opacity'] = self.opacity
63   - mask['threshold range'] = self.threshold_range
64   - mask['name'] = self.name
65   - mask['edition threshold range'] = self.edition_threshold_range
66   - mask['show'] = self.is_shown
67   - mask['mask file'] = os.path.split(img_name)[1]
68   - mask['mask shape'] = self.matrix.shape
  65 + mask['threshold_range'] = self.threshold_range
  66 + mask['edition_threshold_range'] = self.edition_threshold_range
  67 + mask['visible'] = self.is_shown
  68 + mask['mask_file'] = mask_filename
  69 + mask['mask_shape'] = self.matrix.shape
69 70  
70   - plistlib.writePlist(mask, filename + '.plist')
71   - return os.path.split(filename)[1] + '.plist'
  71 + plist_filename = filename + '.plist'
  72 + plist_filepath = os.path.join(dir_temp, plist_filename)
  73 + plistlib.writePlist(mask, plist_filepath)
  74 + return plist_filename
72 75  
73 76 def OpenPList(self, filename):
74 77 mask = plistlib.readPlist(filename)
75 78  
76 79 self.index = mask['index']
  80 + self.name = mask['name']
77 81 self.colour = mask['colour']
78 82 self.opacity = mask['opacity']
79   - self.threshold_range = mask['threshold range']
80   - self.name = mask['name']
81   - self.edition_threshold_range = mask['edition threshold range']
82   - self.is_shown = mask['show']
83   - mask_file = mask['mask file']
84   - shape = mask['mask shape']
  83 + self.threshold_range = mask['threshold_range']
  84 + self.edition_threshold_range = mask['edition_threshold_range']
  85 + self.is_shown = mask['visible']
  86 + mask_file = mask['mask_file']
  87 + shape = mask['mask_shape']
85 88 dirpath = os.path.abspath(os.path.split(filename)[0])
86 89 path = os.path.join(dirpath, mask_file)
87 90 self._open_mask(path, tuple(shape))
... ...
invesalius/data/measures.py
... ... @@ -198,7 +198,7 @@ class Measurement():
198 198 self.type = info["type"]
199 199 self.slice_number = info["slice_number"]
200 200 self.points = info["points"]
201   - self.is_shown = info["is_shown"]
  201 + self.is_shown = info["visible"]
202 202  
203 203 class CirclePointRepresentation(object):
204 204 """
... ...
invesalius/data/polydata_utils.py
... ... @@ -17,7 +17,10 @@
17 17 # detalhes.
18 18 #--------------------------------------------------------------------------
19 19  
  20 +import sys
  21 +
20 22 import vtk
  23 +import wx
21 24 from wx.lib.pubsub import pub as Publisher
22 25  
23 26 import vtk_utils as vu
... ... @@ -103,7 +106,8 @@ def Merge(polydata_list):
103 106  
104 107 def Export(polydata, filename, bin=False):
105 108 writer = vtk.vtkXMLPolyDataWriter()
106   - writer.SetFileName(filename)
  109 + print filename, type(filename)
  110 + writer.SetFileName(filename.encode('utf-8'))
107 111 if bin:
108 112 writer.SetDataModeToBinary()
109 113 else:
... ... @@ -113,7 +117,7 @@ def Export(polydata, filename, bin=False):
113 117  
114 118 def Import(filename):
115 119 reader = vtk.vtkXMLPolyDataReader()
116   - reader.SetFileName(filename)
  120 + reader.SetFileName(filename.encode('utf-8'))
117 121 reader.Update()
118 122 return reader.GetOutput()
119 123  
... ...
invesalius/data/surface.py
... ... @@ -62,32 +62,35 @@ class Surface():
62 62 else:
63 63 self.name = name
64 64  
65   - def SavePlist(self, filename):
66   - surface = {}
67   - filename = '%s$%s$%d' % (filename, 'surface', self.index)
68   - d = self.__dict__
69   - for key in d:
70   - if isinstance(d[key], vtk.vtkPolyData):
71   - img_name = '%s_%s.vtp' % (filename, key)
72   - pu.Export(d[key], img_name, bin=True)
73   - surface[key] = {'$vtp': os.path.split(img_name)[1]}
74   - else:
75   - surface[key] = d[key]
76   -
77   -
78   - plistlib.writePlist(surface, filename + '.plist')
79   - return os.path.split(filename)[1] + '.plist'
  65 + def SavePlist(self, dir_temp):
  66 + filename = 'surface_%d_%s' % (self.index, self.name)
  67 + vtp_filename = filename + '.vtp'
  68 + vtp_filepath = os.path.join(dir_temp, vtp_filename)
  69 + pu.Export(self.polydata, vtp_filepath, bin=True)
  70 + surface = {'colour': self.colour,
  71 + 'index': self.index,
  72 + 'name': self.name,
  73 + 'polydata': vtp_filename,
  74 + 'transparency': self.transparency,
  75 + 'visible': bool(self.is_shown),
  76 + 'volume': self.volume,
  77 + }
  78 + plist_filename = filename + '.plist'
  79 + plist_filepath = os.path.join(dir_temp, filename + '.plist')
  80 + plistlib.writePlist(surface, plist_filepath)
  81 + return plist_filename
80 82  
81 83 def OpenPList(self, filename):
82   - surface = plistlib.readPlist(filename)
  84 + sp = plistlib.readPlist(filename)
83 85 dirpath = os.path.abspath(os.path.split(filename)[0])
84   - for key in surface:
85   - if key == 'polydata':
86   - filepath = os.path.split(surface[key]["$vtp"])[-1]
87   - path = os.path.join(dirpath, filepath)
88   - self.polydata = pu.Import(path)
89   - else:
90   - setattr(self, key, surface[key])
  86 + self.index = sp['index']
  87 + self.name = sp['name']
  88 + self.colour = sp['colour']
  89 + self.transparency = sp['transparency']
  90 + self.is_shown = sp['visible']
  91 + self.volume = sp['volume']
  92 + self.polydata = pu.Import(os.path.join(dirpath, sp['polydata']))
  93 + Surface.general_index = max(Surface.general_index, self.index)
91 94  
92 95 def _set_class_index(self, index):
93 96 Surface.general_index = index
... ... @@ -319,6 +322,7 @@ class SurfaceManager():
319 322 self.last_surface_index = index
320 323 self.ShowActor(index, True)
321 324  
  325 +
322 326 def OnLoadSurfaceDict(self, pubsub_evt):
323 327 surface_dict = pubsub_evt.data
324 328 for key in surface_dict:
... ...
invesalius/project.py
... ... @@ -17,6 +17,7 @@
17 17 # detalhes.
18 18 #--------------------------------------------------------------------------
19 19  
  20 +import datetime
20 21 import glob
21 22 import os
22 23 import plistlib
... ... @@ -49,8 +50,6 @@ class Project(object):
49 50 self.dicom_sample = ''
50 51 self.modality = ''
51 52 self.original_orientation = ''
52   - self.min_threshold = ''
53   - self.max_threshold = ''
54 53 self.window = ''
55 54 self.level = ''
56 55  
... ... @@ -199,61 +198,71 @@ class Project(object):
199 198 item["type"] = m.type
200 199 item["slice_number"] = m.slice_number
201 200 item["points"] = m.points
202   - item["is_shown"] = m.is_shown
  201 + item["visible"] = m.is_shown
203 202 measures[str(m.index)] = item
204 203 return measures
205   -
206   - def SavePlistProject(self, dir_, filename):
207 204  
208   - # Some filenames have non-ascii characters and encoded in a strange
209   - # encoding, in that cases a UnicodeEncodeError is raised. To avoid
210   - # that we encode in utf-8.
211   - filename = filename.encode('utf-8')
  205 + def SavePlistProject(self, dir_, filename):
212 206 dir_temp = tempfile.mkdtemp(filename)
213 207 filename_tmp = os.path.join(dir_temp, 'matrix.dat')
214 208  
215   - project = {}
216   -
217   - for key in self.__dict__:
218   - if getattr(self.__dict__[key], 'SavePlist', None):
219   - project[key] = {'#plist':
220   - self.__dict__[key].SavePlist(filename_tmp).decode('utf-8')}
221   - elif key == 'dicom_sample':
222   - #sample_path = os.path.join(dir_temp, 'sample.dcm')
223   - #shutil.copy(self.dicom_sample.parser.filename,sample_path)
224   - #os.chmod(sample_path, stat.S_IREAD|stat.S_IWRITE)
225   -
226   - #project[key] = 'sample.dcm'
227   - pass
228   - elif key.startswith('matrix'):
229   - continue
230   - else:
231   - project[key] = self.__dict__[key]
  209 + project = {
  210 + # Format info
  211 + "format_version": 1,
  212 + "invesalius_version": "invesalius3b3",
  213 + "date": datetime.datetime.now().isoformat(),
  214 +
  215 + # case info
  216 + "name": self.name, # patient's name
  217 + "modality": self.modality, # CT, RMI, ...
  218 + "orientation": self.original_orientation,
  219 + "window_width": self.window,
  220 + "window_level": self.level,
  221 + "scalar_range": self.threshold_range,
  222 + "spacing": self.spacing,
  223 + }
  224 +
  225 + # Saving the matrix containing the slices
  226 + matrix = {'filename': u'matrix.dat',
  227 + 'shape': self.matrix_shape,
  228 + 'dtype': self.matrix_dtype,
  229 + }
  230 + project['matrix'] = matrix
  231 + shutil.copyfile(self.matrix_filename, filename_tmp)
232 232  
  233 + # Saving the masks
233 234 masks = {}
234 235 for index in self.mask_dict:
235   - masks[str(index)] = {'#mask':\
236   - self.mask_dict[index].SavePlist(filename_tmp)}
  236 + masks[str(index)] = self.mask_dict[index].SavePlist(dir_temp)
  237 + project['masks'] = masks
237 238  
  239 + # Saving the surfaces
238 240 surfaces = {}
239 241 for index in self.surface_dict:
240   - surfaces[str(index)] = {'#surface':\
241   - self.surface_dict[index].SavePlist(filename_tmp)}
242   -
243   - project['surface_dict'] = surfaces
244   - project['mask_dict'] = masks
245   - project['measurement_dict'] = self.GetMeasuresDict()
246   - shutil.copyfile(self.matrix_filename, filename_tmp)
247   - project['matrix'] = {'filename':os.path.split(filename_tmp)[1].decode('utf-8'),
248   - 'shape': self.matrix_shape,
249   - 'dtype': self.matrix_dtype}
  242 + surfaces[str(index)] = self.surface_dict[index].SavePlist(dir_temp)
  243 + project['surfaces'] = surfaces
  244 +
  245 + # Saving the measurements
  246 + measurements = self.GetMeasuresDict()
  247 + measurements_filename = 'measurements.plist'
  248 + plistlib.writePlist(measurements,
  249 + os.path.join(dir_temp, measurements_filename))
  250 + project['measurements'] = measurements_filename
  251 +
  252 + # Saving the annotations (empty in this version)
  253 + project['annotations'] = {}
250 254  
251   - plistlib.writePlist(project, filename_tmp + '.plist')
  255 + # Saving the main plist
  256 + plistlib.writePlist(project, os.path.join(dir_temp, 'main.plist'))
252 257  
  258 + # Compressing and generating the .inv3 file
253 259 path = os.path.join(dir_,filename)
254   - Compress(dir_temp, path)#os.path.join("~/Desktop/","teste.inv3"))
  260 + Compress(dir_temp, path)
  261 +
  262 + # Removing the temp folder.
255 263 shutil.rmtree(dir_temp)
256 264  
  265 +
257 266 def OpenPlistProject(self, filename):
258 267 import data.measures as ms
259 268  
... ... @@ -265,57 +274,53 @@ class Project(object):
265 274 ow.SetInstance(fow)
266 275  
267 276 filelist = Extract(filename, tempfile.mkdtemp())
268   - main_plist = min(filter(lambda x: x.endswith('.plist'), filelist),
269   - key=lambda x: len(x))
  277 + dirpath = os.path.abspath(os.path.split(filelist[0])[0]).decode(wx.GetDefaultPyEncoding())
  278 +
  279 + # Opening the main file from invesalius 3 project
  280 + main_plist = os.path.join(dirpath ,'main.plist')
270 281 project = plistlib.readPlist(main_plist)
271   - dirpath = os.path.abspath(os.path.split(filelist[0])[0])
272   -
273   - for key in project:
274   - if key == 'matrix':
275   - filepath = os.path.split(project[key]["filename"])[-1]
276   - path = os.path.join(dirpath, filepath)
277   - self.matrix_filename = path
278   - self.matrix_shape = project[key]['shape']
279   - self.matrix_dtype = project[key]['dtype']
280   - elif key == 'presets':
281   - filepath = os.path.split(project[key]["#plist"])[-1]
282   - path = os.path.join(dirpath, filepath)
283   - p = Presets()
284   - p.OpenPlist(path)
285   - self.presets = p
286   - #elif key == 'dicom_sample':
287   - #path = os.path.join(dirpath, project[key])
288   - #p = dicom.Parser()
289   - #p.SetFileName(path)
290   - #d = dicom.Dicom()
291   - #d.SetParser(p)
292   - #self.dicom_sample = d
293   -
294   - elif key == 'mask_dict':
295   - self.mask_dict = {}
296   - for mask in project[key]:
297   - filepath = os.path.split(project[key][mask]["#mask"])[-1]
298   - path = os.path.join(dirpath, filepath)
299   - m = msk.Mask()
300   - m.OpenPList(path)
301   - self.mask_dict[m.index] = m
302   - elif key == 'surface_dict':
303   - self.surface_dict = {}
304   - for surface in project[key]:
305   - filepath = os.path.split(project[key][surface]["#surface"])[-1]
306   - path = os.path.join(dirpath, filepath)
307   - s = srf.Surface()
308   - s.OpenPList(path)
309   - self.surface_dict[s.index] = s
310   - elif key == 'measurement_dict':
311   - self.measurement_dict = {}
312   - d = project['measurement_dict']
313   - for index in d:
314   - measure = ms.Measurement()
315   - measure.Load(d[index])
316   - self.measurement_dict[int(index)] = measure
317   - else:
318   - setattr(self, key, project[key])
  282 +
  283 + # case info
  284 + self.name = project["name"]
  285 + self.modality = project["modality"]
  286 + self.original_orientation = project["orientation"]
  287 + self.window = project["window_width"]
  288 + self.level = project["window_level"]
  289 + self.threshold_range = project["scalar_range"]
  290 + self.spacing = project["spacing"]
  291 +
  292 + # Opening the matrix containing the slices
  293 + filepath = os.path.join(dirpath, project["matrix"]["filename"])
  294 + self.matrix_filename = filepath
  295 + self.matrix_shape = project["matrix"]['shape']
  296 + self.matrix_dtype = project["matrix"]['dtype']
  297 +
  298 + # Opening the masks
  299 + self.mask_dict = {}
  300 + for index in project["masks"]:
  301 + filename = project["masks"][index]
  302 + filepath = os.path.join(dirpath, filename)
  303 + m = msk.Mask()
  304 + m.OpenPList(filepath)
  305 + self.mask_dict[m.index] = m
  306 + self.surface_dict = {}
  307 +
  308 + # Opening the surfaces
  309 + for index in project["surfaces"]:
  310 + filename = project["surfaces"][index]
  311 + filepath = os.path.join(dirpath, filename)
  312 + s = srf.Surface()
  313 + s.OpenPList(filepath)
  314 + self.surface_dict[s.index] = s
  315 +
  316 + # Opening the measurements
  317 + self.measurement_dict = {}
  318 + measurements = plistlib.readPlist(os.path.join(dirpath,
  319 + project["measurements"]))
  320 + for index in measurements:
  321 + measure = ms.Measurement()
  322 + measure.Load(measurements[index])
  323 + self.measurement_dict[int(index)] = measure
319 324  
320 325  
321 326 def Compress(folder, filename):
... ... @@ -323,8 +328,8 @@ def Compress(folder, filename):
323 328 current_dir = os.path.abspath(".")
324 329 os.chdir(tmpdir)
325 330 file_list = glob.glob(os.path.join(tmpdir_,"*"))
326   -
327   - tar = tarfile.open(tmpdir_ + ".inv3", "w:gz")
  331 + tar_filename = tmpdir_ + ".inv3"
  332 + tar = tarfile.open(tar_filename.encode(wx.GetDefaultPyEncoding()), "w:gz")
328 333 for name in file_list:
329 334 tar.add(name)
330 335 tar.close()
... ...