Commit a21f0c3764214fc0171dccea0459695f157f478e
1 parent
ce061625
Exists in
master
and in
5 other branches
Saving inv3
Showing
8 changed files
with
126 additions
and
64 deletions
Show diff stats
invesalius/control.py
... | ... | @@ -236,6 +236,13 @@ class Controller(): |
236 | 236 | proj = prj.Project() |
237 | 237 | proj.OpenPlistProject(path) |
238 | 238 | proj.SetAcquisitionModality(proj.modality) |
239 | + self.Slice = sl.Slice() | |
240 | + self.Slice._open_image_matrix(proj.matrix_filename, | |
241 | + tuple(proj.matrix_shape), | |
242 | + proj.matrix_dtype) | |
243 | + | |
244 | + self.Slice.window_level = proj.level | |
245 | + self.Slice.window_width = proj.window | |
239 | 246 | |
240 | 247 | mask = msk.Mask() |
241 | 248 | mask._set_class_index(proj.last_mask_index) |
... | ... | @@ -246,6 +253,8 @@ class Controller(): |
246 | 253 | |
247 | 254 | self.LoadProject() |
248 | 255 | |
256 | + ps.Publisher().sendMessage('Update threshold limits', | |
257 | + proj.threshold_range) | |
249 | 258 | session = ses.Session() |
250 | 259 | session.OpenProject(filepath) |
251 | 260 | ps.Publisher().sendMessage("Enable state project", True) |
... | ... | @@ -329,8 +338,8 @@ class Controller(): |
329 | 338 | patients_groups = dcm.GetDicomGroups(directory) |
330 | 339 | if len(patients_groups): |
331 | 340 | group = dcm.SelectLargerDicomGroup(patients_groups) |
332 | - imagedata, dicom = self.OpenDicomGroup(group, 0, [0,0],gui=True) | |
333 | - self.CreateDicomProject(imagedata, dicom) | |
341 | + matrix, matrix_filename, dicom = self.OpenDicomGroup(group, 0, [0,0],gui=True) | |
342 | + self.CreateDicomProject(dicom, matrix, matrix_filename) | |
334 | 343 | # OPTION 2: ANALYZE? |
335 | 344 | else: |
336 | 345 | imagedata = analyze.ReadDirectory(directory) |
... | ... | @@ -352,6 +361,9 @@ class Controller(): |
352 | 361 | const.WINDOW_LEVEL[_('Default')] = (proj.window, proj.level) |
353 | 362 | const.WINDOW_LEVEL[_('Manual')] = (proj.window, proj.level) |
354 | 363 | |
364 | + self.Slice = sl.Slice() | |
365 | + self.Slice.spacing = proj.spacing | |
366 | + | |
355 | 367 | ps.Publisher().sendMessage('Load slice to viewer', |
356 | 368 | (proj.imagedata, |
357 | 369 | proj.mask_dict)) |
... | ... | @@ -375,6 +387,11 @@ class Controller(): |
375 | 387 | |
376 | 388 | if len(proj.mask_dict): |
377 | 389 | mask_index = len(proj.mask_dict) -1 |
390 | + for m in proj.mask_dict.values(): | |
391 | + ps.Publisher().sendMessage('Add mask', | |
392 | + (m.index, m.name, | |
393 | + m.threshold_range, m.colour)) | |
394 | + self.Slice.current_mask = proj.mask_dict[mask_index] | |
378 | 395 | ps.Publisher().sendMessage('Show mask', (mask_index, True)) |
379 | 396 | |
380 | 397 | ps.Publisher().sendMessage('Load measurement dict', |
... | ... | @@ -419,7 +436,7 @@ class Controller(): |
419 | 436 | ps.Publisher().sendMessage('Update threshold limits', |
420 | 437 | proj.threshold_range) |
421 | 438 | |
422 | - def CreateDicomProject(self, imagedata, dicom): | |
439 | + def CreateDicomProject(self, dicom, matrix, matrix_filename): | |
423 | 440 | name_to_const = {"AXIAL":const.AXIAL, |
424 | 441 | "CORONAL":const.CORONAL, |
425 | 442 | "SAGITTAL":const.SAGITAL} |
... | ... | @@ -428,14 +445,17 @@ class Controller(): |
428 | 445 | proj.name = dicom.patient.name |
429 | 446 | proj.modality = dicom.acquisition.modality |
430 | 447 | proj.SetAcquisitionModality(dicom.acquisition.modality) |
431 | - proj.imagedata = imagedata | |
448 | + proj.matrix_shape = matrix.shape | |
449 | + proj.matrix_dtype = matrix.dtype.name | |
450 | + proj.matrix_filename = matrix_filename | |
451 | + #proj.imagedata = imagedata | |
432 | 452 | proj.dicom_sample = dicom |
433 | 453 | proj.original_orientation =\ |
434 | 454 | name_to_const[dicom.image.orientation_label] |
435 | 455 | proj.window = float(dicom.image.window) |
436 | 456 | proj.level = float(dicom.image.level) |
437 | 457 | proj.threshold_range = (-1024, 3033) |
438 | - | |
458 | + proj.spacing = self.Slice.spacing | |
439 | 459 | |
440 | 460 | ###### |
441 | 461 | session = ses.Session() |
... | ... | @@ -448,8 +468,8 @@ class Controller(): |
448 | 468 | |
449 | 469 | def OnOpenDicomGroup(self, pubsub_evt): |
450 | 470 | group, interval, file_range = pubsub_evt.data |
451 | - imagedata, dicom = self.OpenDicomGroup(group, interval, file_range, gui=True) | |
452 | - self.CreateDicomProject(imagedata, dicom) | |
471 | + matrix, matrix_filename, dicom = self.OpenDicomGroup(group, interval, file_range, gui=True) | |
472 | + self.CreateDicomProject(dicom, matrix, matrix_filename) | |
453 | 473 | self.LoadProject() |
454 | 474 | ps.Publisher().sendMessage("Enable state project", True) |
455 | 475 | |
... | ... | @@ -511,12 +531,13 @@ class Controller(): |
511 | 531 | elif orientation == 'SAGITTAL': |
512 | 532 | self.Slice.spacing = zspacing, xyspacing[1], xyspacing[0] |
513 | 533 | |
534 | + | |
514 | 535 | self.Slice.window_level = wl |
515 | 536 | self.Slice.window_width = ww |
516 | 537 | |
517 | 538 | ps.Publisher().sendMessage('Update threshold limits', scalar_range) |
518 | 539 | |
519 | - return imagedata, dicom | |
540 | + return self.matrix, self.filename, dicom | |
520 | 541 | |
521 | 542 | def LoadImagedataInfo(self): |
522 | 543 | proj = prj.Project() | ... | ... |
invesalius/data/imagedata_utils.py
... | ... | @@ -215,8 +215,8 @@ def Export(imagedata, filename, bin=False): |
215 | 215 | writer.SetDataModeToBinary() |
216 | 216 | else: |
217 | 217 | writer.SetDataModeToAscii() |
218 | - writer.SetInput(imagedata) | |
219 | - writer.Write() | |
218 | + #writer.SetInput(imagedata) | |
219 | + #writer.Write() | |
220 | 220 | |
221 | 221 | def Import(filename): |
222 | 222 | reader = vtk.vtkXMLImageDataReader() |
... | ... | @@ -497,6 +497,7 @@ def dcm2memmap(files, slice_size, orientation): |
497 | 497 | array.shape = matrix.shape[0], matrix.shape[1] |
498 | 498 | matrix[:, :, n] = array |
499 | 499 | else: |
500 | + print array.shape, matrix.shape | |
500 | 501 | array.shape = matrix.shape[1], matrix.shape[2] |
501 | 502 | matrix[n] = array |
502 | 503 | update_progress(cont,message) | ... | ... |
invesalius/data/mask.py
... | ... | @@ -20,6 +20,7 @@ |
20 | 20 | import os |
21 | 21 | import plistlib |
22 | 22 | import random |
23 | +import shutil | |
23 | 24 | import tempfile |
24 | 25 | |
25 | 26 | import numpy |
... | ... | @@ -44,42 +45,46 @@ class Mask(): |
44 | 45 | |
45 | 46 | def SavePlist(self, filename): |
46 | 47 | mask = {} |
47 | - filename = '%s$%s$%d' % (filename, 'mask', self.index) | |
48 | - | |
49 | - d = self.__dict__ | |
50 | - for key in d: | |
51 | - if isinstance(d[key], vtk.vtkImageData): | |
52 | - img_name = '%s_%s.vti' % (filename, key) | |
53 | - iu.Export(d[key], img_name, bin=True) | |
54 | - mask[key] = {'$vti': os.path.split(img_name)[1]} | |
55 | - elif key == 'edited_points': | |
56 | - edited_points = {} | |
57 | - for p in self.edited_points: | |
58 | - edited_points[str(p)] = self.edited_points[p] | |
59 | - mask[key] = edited_points | |
60 | - else: | |
61 | - mask[key] = d[key] | |
48 | + filename = u'%s_%s_%d_%s' % (filename, 'mask', self.index, self.name) | |
49 | + img_name = u'%s.dat' % filename | |
50 | + self._save_mask(img_name) | |
51 | + | |
52 | + mask['index'] = self.index | |
53 | + mask['colour'] = self.colour | |
54 | + mask['opacity'] = self.opacity | |
55 | + mask['threshold range'] = self.threshold_range | |
56 | + mask['name'] = self.name | |
57 | + mask['edition threshold range'] = self.edition_threshold_range | |
58 | + mask['show'] = self.is_shown | |
59 | + mask['mask file'] = os.path.split(img_name)[1] | |
60 | + mask['mask shape'] = self.matrix.shape | |
61 | + | |
62 | 62 | plistlib.writePlist(mask, filename + '.plist') |
63 | 63 | return os.path.split(filename)[1] + '.plist' |
64 | 64 | |
65 | 65 | def OpenPList(self, filename): |
66 | 66 | mask = plistlib.readPlist(filename) |
67 | + | |
68 | + self.index = mask['index'] | |
69 | + self.colour = mask['colour'] | |
70 | + self.opacity = mask['opacity'] | |
71 | + self.threshold_range = mask['threshold range'] | |
72 | + self.name = mask['name'] | |
73 | + self.edition_threshold_range = mask['edition threshold range'] | |
74 | + self.is_shown = mask['show'] | |
75 | + mask_file = mask['mask file'] | |
76 | + shape = mask['mask shape'] | |
67 | 77 | dirpath = os.path.abspath(os.path.split(filename)[0]) |
68 | - for key in mask: | |
69 | - print "Key", key | |
70 | - if key == 'imagedata': | |
71 | - filepath = os.path.split(mask[key]["$vti"])[-1] | |
72 | - path = os.path.join(dirpath, filepath) | |
73 | - self.imagedata = iu.Import(path) | |
74 | - elif key == 'edited_points': | |
75 | - edited_points = {} | |
76 | - for p in mask[key]: | |
77 | - k = [float(i) for i in p.replace('(', '').replace(')', '').split(',')] | |
78 | - edited_points[tuple(k)] = mask[key][p] | |
79 | - | |
80 | - setattr(self, key, edited_points) | |
81 | - else: | |
82 | - setattr(self, key, mask[key]) | |
78 | + path = os.path.join(dirpath, mask_file) | |
79 | + self._open_mask(path, tuple(shape)) | |
80 | + | |
81 | + def _save_mask(self, filename): | |
82 | + shutil.copyfile(self.temp_file, filename) | |
83 | + | |
84 | + def _open_mask(self, filename, shape, dtype='uint8'): | |
85 | + print ">>", filename, shape | |
86 | + self.temp_file = filename | |
87 | + self.matrix = numpy.memmap(filename, shape=shape, dtype=dtype, mode="r+") | |
83 | 88 | |
84 | 89 | def _set_class_index(self, index): |
85 | 90 | Mask.general_index = index | ... | ... |
invesalius/data/slice_.py
... | ... | @@ -75,6 +75,7 @@ class Slice(object): |
75 | 75 | self.current_mask = None |
76 | 76 | self.blend_filter = None |
77 | 77 | self.matrix = None |
78 | + self.spacing = (1.0, 1.0, 1.0) | |
78 | 79 | |
79 | 80 | self.number_of_colours = 256 |
80 | 81 | self.saturation_range = (0, 0) |
... | ... | @@ -542,6 +543,7 @@ class Slice(object): |
542 | 543 | |
543 | 544 | def ShowMask(self, index, value): |
544 | 545 | "Show a mask given its index and 'show' value (0: hide, other: show)" |
546 | + print "Showing Mask" | |
545 | 547 | proj = Project() |
546 | 548 | proj.mask_dict[index].is_shown = value |
547 | 549 | if (index == self.current_mask.index): |
... | ... | @@ -946,6 +948,12 @@ class Slice(object): |
946 | 948 | |
947 | 949 | return imagedata_mask |
948 | 950 | |
951 | + def _open_image_matrix(self, filename, shape, dtype): | |
952 | + self.matrix_filename = filename | |
953 | + print ">>>", filename | |
954 | + self.matrix = numpy.memmap(filename, shape=shape, dtype=dtype, | |
955 | + mode='r+') | |
956 | + | |
949 | 957 | def OnExportMask(self, pubsub_evt): |
950 | 958 | #imagedata = self.current_mask.imagedata |
951 | 959 | imagedata = self.imagedata | ... | ... |
invesalius/data/viewer_slice.py
... | ... | @@ -1172,7 +1172,7 @@ class Viewer(wx.Panel): |
1172 | 1172 | max_slice_number) |
1173 | 1173 | |
1174 | 1174 | self.slice_data = self.create_slice_window() |
1175 | - self.slice_data.actor.SetInput(imagedata) | |
1175 | + #self.slice_data.actor.SetInput(imagedata) | |
1176 | 1176 | self.slice_data.SetCursor(self.__create_cursor()) |
1177 | 1177 | self.cam = self.slice_data.renderer.GetActiveCamera() |
1178 | 1178 | self.__build_cross_lines(imagedata) | ... | ... |
invesalius/gui/task_slice.py
... | ... | @@ -479,6 +479,7 @@ class MaskProperties(wx.Panel): |
479 | 479 | (thresh_min, thresh_max) = Project().threshold_modes[evt.GetString()] |
480 | 480 | self.gradient.SetMinValue(thresh_min) |
481 | 481 | self.gradient.SetMaxValue(thresh_max) |
482 | + self.OnSlideChanging(None) | |
482 | 483 | self.OnSlideChanged(None) |
483 | 484 | |
484 | 485 | def OnSlideChanged(self, evt): | ... | ... |
invesalius/gui/widgets/gradient.py
... | ... | @@ -320,6 +320,7 @@ class GradientCtrl(wx.Panel): |
320 | 320 | self.minimun = minValue |
321 | 321 | self.maximun = maxValue |
322 | 322 | self.colour = colour |
323 | + self.changed = False | |
323 | 324 | self._draw_controls() |
324 | 325 | self._bind_events_wx() |
325 | 326 | self.SetBackgroundColour((0, 255, 0)) |
... | ... | @@ -353,13 +354,15 @@ class GradientCtrl(wx.Panel): |
353 | 354 | self.gradient_slider.Bind(EVT_SLIDER_CHANGED, self.OnSlider) |
354 | 355 | |
355 | 356 | # self.spin_min.Bind(wx.lib.intctrl.EVT_INT, self.ChangeMinValue) |
356 | - self.spin_min.Bind(wx.EVT_KILL_FOCUS, self._FireSpinMinChange) | |
357 | - self.spin_min.Bind(wx.EVT_TEXT_ENTER, self._FireSpinMinChange) | |
357 | + self.spin_min.Bind(wx.EVT_LEAVE_WINDOW, self._FireSpinMinChanged) | |
358 | + self.spin_min.Bind(wx.EVT_KILL_FOCUS, self._FireSpinMinChanged) | |
359 | + self.spin_min.Bind(wx.EVT_KEY_DOWN, self._FireSpinMinChange) | |
358 | 360 | self.spin_min.Bind(wx.EVT_MOUSEWHEEL, self.OnMinMouseWheel) |
359 | 361 | |
360 | 362 | # self.spin_max.Bind(wx.lib.intctrl.EVT_INT, self.ChangeMaxValue) |
361 | - self.spin_max.Bind(wx.EVT_KILL_FOCUS, self._FireSpinMaxChange) | |
362 | - self.spin_max.Bind(wx.EVT_TEXT_ENTER, self._FireSpinMaxChange) | |
363 | + self.spin_max.Bind(wx.EVT_LEAVE_WINDOW, self._FireSpinMaxChanged) | |
364 | + self.spin_max.Bind(wx.EVT_KILL_FOCUS, self._FireSpinMaxChanged) | |
365 | + self.spin_max.Bind(wx.EVT_KEY_DOWN, self._FireSpinMaxChange) | |
363 | 366 | self.spin_max.Bind(wx.EVT_MOUSEWHEEL, self.OnMaxMouseWheel) |
364 | 367 | |
365 | 368 | def OnSlider(self, evt): |
... | ... | @@ -377,17 +380,27 @@ class GradientCtrl(wx.Panel): |
377 | 380 | self._GenerateEvent(myEVT_THRESHOLD_CHANGING) |
378 | 381 | |
379 | 382 | def _FireSpinMinChange(self, evt): |
383 | + evt.Skip() | |
380 | 384 | value = int(self.spin_min.GetValue()) |
381 | 385 | if value != self.GetMinValue(): |
382 | 386 | self.SetMinValue(value) |
383 | 387 | self._GenerateEvent(myEVT_THRESHOLD_CHANGING) |
384 | 388 | |
389 | + def _FireSpinMinChanged(self, evt): | |
390 | + if self.changed: | |
391 | + self._GenerateEvent(myEVT_THRESHOLD_CHANGED) | |
392 | + | |
385 | 393 | def _FireSpinMaxChange(self, evt): |
394 | + evt.Skip() | |
386 | 395 | value = int(self.spin_max.GetValue()) |
387 | 396 | if value != self.GetMaxValue(): |
388 | 397 | self.SetMaxValue(value) |
389 | 398 | self._GenerateEvent(myEVT_THRESHOLD_CHANGING) |
390 | 399 | |
400 | + def _FireSpinMaxChanged(self, evt): | |
401 | + if self.changed: | |
402 | + self._GenerateEvent(myEVT_THRESHOLD_CHANGED) | |
403 | + | |
391 | 404 | def OnMinMouseWheel(self, e): |
392 | 405 | """ |
393 | 406 | When the user wheel the mouse over min texbox |
... | ... | @@ -464,6 +477,13 @@ class GradientCtrl(wx.Panel): |
464 | 477 | return self.minimun |
465 | 478 | |
466 | 479 | def _GenerateEvent(self, event): |
480 | + if event == myEVT_THRESHOLD_CHANGING: | |
481 | + self.changed = True | |
482 | + print 'changing' | |
483 | + elif event == myEVT_THRESHOLD_CHANGED : | |
484 | + self.changed = False | |
485 | + print 'changed' | |
486 | + | |
467 | 487 | evt = SliderEvent(event, self.GetId(), self.min_range, |
468 | 488 | self.max_range, self.minimun, self.maximun) |
469 | 489 | self.GetEventHandler().ProcessEvent(evt) | ... | ... |
invesalius/project.py
... | ... | @@ -211,7 +211,7 @@ class Project(object): |
211 | 211 | # that we encode in utf-8. |
212 | 212 | filename = filename.encode('utf-8') |
213 | 213 | dir_temp = tempfile.mkdtemp(filename) |
214 | - filename_tmp = os.path.join(dir_temp, filename) | |
214 | + filename_tmp = os.path.join(dir_temp, 'matrix.dat') | |
215 | 215 | |
216 | 216 | project = {} |
217 | 217 | |
... | ... | @@ -220,18 +220,21 @@ class Project(object): |
220 | 220 | project[key] = {'#plist': |
221 | 221 | self.__dict__[key].SavePlist(filename_tmp).decode('utf-8')} |
222 | 222 | elif key == 'dicom_sample': |
223 | - sample_path = os.path.join(dir_temp, 'sample.dcm') | |
224 | - shutil.copy(self.dicom_sample.parser.filename,sample_path) | |
225 | - os.chmod(sample_path, stat.S_IREAD|stat.S_IWRITE) | |
223 | + #sample_path = os.path.join(dir_temp, 'sample.dcm') | |
224 | + #shutil.copy(self.dicom_sample.parser.filename,sample_path) | |
225 | + #os.chmod(sample_path, stat.S_IREAD|stat.S_IWRITE) | |
226 | 226 | |
227 | - project[key] = 'sample.dcm' | |
227 | + #project[key] = 'sample.dcm' | |
228 | + pass | |
229 | + elif key.startswith('matrix'): | |
230 | + continue | |
228 | 231 | else: |
229 | 232 | project[key] = self.__dict__[key] |
230 | 233 | |
231 | 234 | masks = {} |
232 | 235 | for index in self.mask_dict: |
233 | 236 | masks[str(index)] = {'#mask':\ |
234 | - self.mask_dict[index].SavePlist(filename_tmp).decode('utf-8')} | |
237 | + self.mask_dict[index].SavePlist(filename_tmp)} | |
235 | 238 | |
236 | 239 | surfaces = {} |
237 | 240 | for index in self.surface_dict: |
... | ... | @@ -241,9 +244,10 @@ class Project(object): |
241 | 244 | project['surface_dict'] = surfaces |
242 | 245 | project['mask_dict'] = masks |
243 | 246 | project['measurement_dict'] = self.GetMeasuresDict() |
244 | - img_file = '%s_%s.vti' % (filename_tmp, 'imagedata') | |
245 | - iu.Export(self.imagedata, img_file, bin=True) | |
246 | - project['imagedata'] = {'$vti':os.path.split(img_file)[1].decode('utf-8')} | |
247 | + shutil.copyfile(self.matrix_filename, filename_tmp) | |
248 | + project['matrix'] = {'filename':os.path.split(filename_tmp)[1].decode('utf-8'), | |
249 | + 'shape': self.matrix_shape, | |
250 | + 'dtype': self.matrix_dtype} | |
247 | 251 | |
248 | 252 | plistlib.writePlist(project, filename_tmp + '.plist') |
249 | 253 | |
... | ... | @@ -268,23 +272,25 @@ class Project(object): |
268 | 272 | dirpath = os.path.abspath(os.path.split(filelist[0])[0]) |
269 | 273 | |
270 | 274 | for key in project: |
271 | - if key == 'imagedata': | |
272 | - filepath = os.path.split(project[key]["$vti"])[-1] | |
275 | + if key == 'matrix': | |
276 | + filepath = os.path.split(project[key]["filename"])[-1] | |
273 | 277 | path = os.path.join(dirpath, filepath) |
274 | - self.imagedata = iu.Import(path) | |
278 | + self.matrix_filename = path | |
279 | + self.matrix_shape = project[key]['shape'] | |
280 | + self.matrix_dtype = project[key]['dtype'] | |
275 | 281 | elif key == 'presets': |
276 | 282 | filepath = os.path.split(project[key]["#plist"])[-1] |
277 | 283 | path = os.path.join(dirpath, filepath) |
278 | 284 | p = Presets() |
279 | 285 | p.OpenPlist(path) |
280 | 286 | self.presets = p |
281 | - elif key == 'dicom_sample': | |
282 | - path = os.path.join(dirpath, project[key]) | |
283 | - p = dicom.Parser() | |
284 | - p.SetFileName(path) | |
285 | - d = dicom.Dicom() | |
286 | - d.SetParser(p) | |
287 | - self.dicom_sample = d | |
287 | + #elif key == 'dicom_sample': | |
288 | + #path = os.path.join(dirpath, project[key]) | |
289 | + #p = dicom.Parser() | |
290 | + #p.SetFileName(path) | |
291 | + #d = dicom.Dicom() | |
292 | + #d.SetParser(p) | |
293 | + #self.dicom_sample = d | |
288 | 294 | |
289 | 295 | elif key == 'mask_dict': |
290 | 296 | self.mask_dict = {} | ... | ... |