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
invesalius/data/slice_.py
| ... | ... | @@ -244,9 +244,23 @@ class Slice(object): |
| 244 | 244 | elif orientation == 'SAGITAL': |
| 245 | 245 | n_array = numpy.array(self.matrix[..., ..., slice_number]) |
| 246 | 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 | 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 | 264 | def GetNumberOfSlices(self, orientation): |
| 251 | 265 | if orientation == 'AXIAL': |
| 252 | 266 | return self.matrix.shape[0] |
| ... | ... | @@ -298,22 +312,30 @@ class Slice(object): |
| 298 | 312 | thresh_min, thresh_max = threshold_range |
| 299 | 313 | |
| 300 | 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 | 337 | # Update viewer |
| 316 | - ps.Publisher().sendMessage('Update slice viewer') | |
| 338 | + #ps.Publisher().sendMessage('Update slice viewer') | |
| 317 | 339 | |
| 318 | 340 | # Update data notebook (GUI) |
| 319 | 341 | ps.Publisher().sendMessage('Set mask threshold in notebook', |
| ... | ... | @@ -541,8 +563,6 @@ class Slice(object): |
| 541 | 563 | future_mask = Mask() |
| 542 | 564 | future_mask.create_mask(self.matrix.shape) |
| 543 | 565 | |
| 544 | - | |
| 545 | - future_mask = Mask() | |
| 546 | 566 | if colour: |
| 547 | 567 | future_mask.colour = colour |
| 548 | 568 | if opacity: |
| ... | ... | @@ -594,6 +614,8 @@ class Slice(object): |
| 594 | 614 | |
| 595 | 615 | self.current_mask = future_mask |
| 596 | 616 | |
| 617 | + print self.current_mask.matrix | |
| 618 | + | |
| 597 | 619 | ps.Publisher().sendMessage('Change mask selected', future_mask.index) |
| 598 | 620 | ps.Publisher().sendMessage('Update slice viewer') |
| 599 | 621 | |
| ... | ... | @@ -631,6 +653,52 @@ class Slice(object): |
| 631 | 653 | |
| 632 | 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 | 702 | def __build_mask(self, imagedata, create=True): |
| 635 | 703 | # create new mask instance and insert it into project |
| 636 | 704 | if create: | ... | ... |