Commit b702ed1b3a1542226c903c8241cc39f8f7b94d7c
1 parent
2f2deade
Exists in
master
and in
67 other branches
ENH: Starting to work with masks.
* Added a threshold function * starting without masks, need to create one in the starting
Showing
2 changed files
with
86 additions
and
17 deletions
Show diff stats
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: |