Commit b702ed1b3a1542226c903c8241cc39f8f7b94d7c

Authored by tfmoraes
1 parent 2f2deade

ENH: Starting to work with masks.

* Added a threshold function
* starting without masks, need to create one in the starting
invesalius/data/mask.py
@@ -85,5 +85,6 @@ class Mask(): @@ -85,5 +85,6 @@ class Mask():
85 Mask.general_index = index 85 Mask.general_index = index
86 86
87 def create_mask(self, shape): 87 def create_mask(self, shape):
  88 + print "Creating a mask"
88 self.temp_file = tempfile.mktemp() 89 self.temp_file = tempfile.mktemp()
89 self.matrix = numpy.memmap(self.temp_file, mode='w+', dtype='uint8', shape=shape) 90 self.matrix = numpy.memmap(self.temp_file, mode='w+', dtype='uint8', shape=shape)
invesalius/data/slice_.py
@@ -244,9 +244,23 @@ class Slice(object): @@ -244,9 +244,23 @@ class Slice(object):
244 elif orientation == 'SAGITAL': 244 elif orientation == 'SAGITAL':
245 n_array = numpy.array(self.matrix[..., ..., slice_number]) 245 n_array = numpy.array(self.matrix[..., ..., slice_number])
246 image = iu.to_vtk(n_array, self.spacing, slice_number, orientation) 246 image = iu.to_vtk(n_array, self.spacing, slice_number, orientation)
247 - image = self.do_ww_wl(image) 247 + if self.current_mask and self.current_mask.is_shown:
  248 + mask = self.GetSlicesMask(orientation, slice_number)
  249 + image = self.do_blend(self.do_ww_wl(image), mask)
  250 + else:
  251 + image = self.do_ww_wl(image)
248 return image 252 return image
249 253
  254 + def GetSlicesMask(self, orientation, slice_number):
  255 + if orientation == 'AXIAL':
  256 + n_mask = numpy.array(self.current_mask.matrix[slice_number])
  257 + elif orientation == 'CORONAL':
  258 + n_mask = numpy.array(self.current_mask.matrix[..., slice_number, ...])
  259 + elif orientation == 'SAGITAL':
  260 + n_mask = numpy.array(self.current_mask.matrix[..., ..., slice_number])
  261 + mask = iu.to_vtk(n_mask, self.spacing, slice_number, orientation)
  262 + return self.do_colour_mask(mask)
  263 +
250 def GetNumberOfSlices(self, orientation): 264 def GetNumberOfSlices(self, orientation):
251 if orientation == 'AXIAL': 265 if orientation == 'AXIAL':
252 return self.matrix.shape[0] 266 return self.matrix.shape[0]
@@ -298,22 +312,30 @@ class Slice(object): @@ -298,22 +312,30 @@ class Slice(object):
298 thresh_min, thresh_max = threshold_range 312 thresh_min, thresh_max = threshold_range
299 313
300 if self.current_mask.index == index: 314 if self.current_mask.index == index:
301 - # Update pipeline (this must be here, so pipeline is not broken)  
302 - self.img_thresh_mask.SetInput(self.imagedata)  
303 - self.img_thresh_mask.ThresholdBetween(float(thresh_min),  
304 - float(thresh_max))  
305 - self.img_thresh_mask.Update()  
306 -  
307 - # Create imagedata copy so the pipeline is not broken  
308 - imagedata = self.img_thresh_mask.GetOutput()  
309 - self.current_mask.imagedata.DeepCopy(imagedata)  
310 - self.current_mask.threshold_range = threshold_range  
311 -  
312 - # Update pipeline (this must be here, so pipeline is not broken)  
313 - self.img_colours_mask.SetInput(self.current_mask.imagedata) 315 + ## Update pipeline (this must be here, so pipeline is not broken)
  316 + #self.img_thresh_mask.SetInput(self.imagedata)
  317 + #self.img_thresh_mask.ThresholdBetween(float(thresh_min),
  318 + #float(thresh_max))
  319 + #self.img_thresh_mask.Update()
  320 +
  321 + ## Create imagedata copy so the pipeline is not broken
  322 + #imagedata = self.img_thresh_mask.GetOutput()
  323 + #self.current_mask.imagedata.DeepCopy(imagedata)
  324 + #self.current_mask.threshold_range = threshold_range
  325 +
  326 + ## Update pipeline (this must be here, so pipeline is not broken)
  327 + #self.img_colours_mask.SetInput(self.current_mask.imagedata)
  328 +
  329 + # TODO: find out a better way to do threshold
  330 + for n, slice_ in enumerate(self.matrix):
  331 + m = numpy.ones(slice_.shape, self.current_mask.matrix.dtype)
  332 + m[slice_ < thresh_min] = 0
  333 + m[slice_ > thresh_max] = 0
  334 + m[m == 1] = 255
  335 + self.current_mask.matrix[n] = m
314 336
315 # Update viewer 337 # Update viewer
316 - ps.Publisher().sendMessage('Update slice viewer') 338 + #ps.Publisher().sendMessage('Update slice viewer')
317 339
318 # Update data notebook (GUI) 340 # Update data notebook (GUI)
319 ps.Publisher().sendMessage('Set mask threshold in notebook', 341 ps.Publisher().sendMessage('Set mask threshold in notebook',
@@ -541,8 +563,6 @@ class Slice(object): @@ -541,8 +563,6 @@ class Slice(object):
541 future_mask = Mask() 563 future_mask = Mask()
542 future_mask.create_mask(self.matrix.shape) 564 future_mask.create_mask(self.matrix.shape)
543 565
544 -  
545 - future_mask = Mask()  
546 if colour: 566 if colour:
547 future_mask.colour = colour 567 future_mask.colour = colour
548 if opacity: 568 if opacity:
@@ -594,6 +614,8 @@ class Slice(object): @@ -594,6 +614,8 @@ class Slice(object):
594 614
595 self.current_mask = future_mask 615 self.current_mask = future_mask
596 616
  617 + print self.current_mask.matrix
  618 +
597 ps.Publisher().sendMessage('Change mask selected', future_mask.index) 619 ps.Publisher().sendMessage('Change mask selected', future_mask.index)
598 ps.Publisher().sendMessage('Update slice viewer') 620 ps.Publisher().sendMessage('Update slice viewer')
599 621
@@ -631,6 +653,52 @@ class Slice(object): @@ -631,6 +653,52 @@ class Slice(object):
631 653
632 return colorer.GetOutput() 654 return colorer.GetOutput()
633 655
  656 + def do_colour_mask(self, imagedata):
  657 + scalar_range = int(imagedata.GetScalarRange()[1])
  658 + r, g, b = self.current_mask.colour
  659 +
  660 + # map scalar values into colors
  661 + lut_mask = vtk.vtkLookupTable()
  662 + lut_mask.SetNumberOfColors(255)
  663 + lut_mask.SetHueRange(const.THRESHOLD_HUE_RANGE)
  664 + lut_mask.SetSaturationRange(1, 1)
  665 + lut_mask.SetValueRange(0, 1)
  666 + lut_mask.SetNumberOfTableValues(256)
  667 + lut_mask.SetTableValue(0, 0, 0, 0, 0.0)
  668 + lut_mask.SetTableValue(1, 0, 0, 0, 0.0)
  669 + lut_mask.SetTableValue(2, 0, 0, 0, 0.0)
  670 + lut_mask.SetTableValue(255, r, g, b, 1.0)
  671 + lut_mask.SetRampToLinear()
  672 + lut_mask.Build()
  673 + # self.lut_mask = lut_mask
  674 +
  675 + # map the input image through a lookup table
  676 + img_colours_mask = vtk.vtkImageMapToColors()
  677 + img_colours_mask.SetLookupTable(lut_mask)
  678 + img_colours_mask.SetOutputFormatToRGBA()
  679 + img_colours_mask.SetInput(imagedata)
  680 + img_colours_mask.Update()
  681 + # self.img_colours_mask = img_colours_mask
  682 +
  683 + return img_colours_mask.GetOutput()
  684 +
  685 + def do_blend(self, imagedata, mask):
  686 + # blend both imagedatas, so it can be inserted into viewer
  687 + print "Blending Spacing", imagedata.GetSpacing(), mask.GetSpacing()
  688 +
  689 + blend_imagedata = vtk.vtkImageBlend()
  690 + blend_imagedata.SetBlendModeToNormal()
  691 + # blend_imagedata.SetOpacity(0, 1.0)
  692 + blend_imagedata.SetOpacity(1, 0.8)
  693 + blend_imagedata.SetInput(imagedata)
  694 + blend_imagedata.AddInput(mask)
  695 + blend_imagedata.Update()
  696 +
  697 + # return colorer.GetOutput()
  698 +
  699 + return blend_imagedata.GetOutput()
  700 +
  701 +
634 def __build_mask(self, imagedata, create=True): 702 def __build_mask(self, imagedata, create=True):
635 # create new mask instance and insert it into project 703 # create new mask instance and insert it into project
636 if create: 704 if create: