Commit 86398ac2c899ed4f0b11af3a7787c66ffe5811c3

Authored by tfmoraes
1 parent e95a97e6

ENH: Threshold mask is working, but is necessary to create a mask because is not…

… created a mask automatically in the init.
invesalius/data/mask.py
... ... @@ -87,4 +87,5 @@ class Mask():
87 87 def create_mask(self, shape):
88 88 print "Creating a mask"
89 89 self.temp_file = tempfile.mktemp()
  90 + shape = shape[0] + 1, shape[1] + 1, shape[2] + 1
90 91 self.matrix = numpy.memmap(self.temp_file, mode='w+', dtype='uint8', shape=shape)
... ...
invesalius/data/slice_.py
... ... @@ -41,6 +41,10 @@ class Slice(object):
41 41 self.blend_filter = None
42 42 self.matrix = None
43 43  
  44 + self.buffer_slices = {"AXIAL": [-1, None, None],
  45 + "CORONAL": [-1,None, None],
  46 + "SAGITAL": [-1, None, None]}
  47 +
44 48 self.num_gradient = 0
45 49 self.interaction_style = st.StyleStateManager()
46 50  
... ... @@ -59,6 +63,8 @@ class Slice(object):
59 63 'Set edition threshold values')
60 64 ps.Publisher().subscribe(self.__set_current_mask_threshold,
61 65 'Set threshold values')
  66 + ps.Publisher().subscribe(self.__set_current_mask_threshold_actual_slice,
  67 + 'Changing threshold values')
62 68 ps.Publisher().subscribe(self.__set_current_mask_colour,
63 69 'Change mask colour')
64 70 ps.Publisher().subscribe(self.__set_mask_name, 'Change mask name')
... ... @@ -192,11 +198,27 @@ class Slice(object):
192 198 def __set_current_mask_threshold(self, evt_pubsub):
193 199 threshold_range = evt_pubsub.data
194 200 index = self.current_mask.index
195   - self.SetMaskThreshold(index, threshold_range)
  201 + #self.SetMaskThreshold(index, threshold_range)
  202 + #Clear edited points
  203 + self.current_mask.edited_points = {}
  204 + self.num_gradient += 1
  205 + self.current_mask.matrix[0, :, :] = 0
  206 + self.current_mask.matrix[:, 0, :] = 0
  207 + self.current_mask.matrix[:, :, 0] = 0
  208 +
  209 + def __set_current_mask_threshold_actual_slice(self, evt_pubsub):
  210 + threshold_range = evt_pubsub.data
  211 + index = self.current_mask.index
  212 + for orientation in self.buffer_slices:
  213 + self.SetMaskThreshold(index, threshold_range,
  214 + self.buffer_slices[orientation][0],
  215 + orientation)
196 216 #Clear edited points
197 217 self.current_mask.edited_points = {}
198 218 self.num_gradient += 1
199 219  
  220 + ps.Publisher().sendMessage('Reload actual slice')
  221 +
200 222 def __set_current_mask_colour(self, pubsub_evt):
201 223 # "if" is necessary because wx events are calling this before any mask
202 224 # has been created
... ... @@ -237,29 +259,66 @@ class Slice(object):
237 259 #---------------------------------------------------------------------------
238 260  
239 261 def GetSlices(self, orientation, slice_number):
  262 + if self.buffer_slices[orientation][0] == slice_number:
  263 + print "From buffer"
  264 + image = self.buffer_slices[orientation][1]
  265 + n_mask = self.buffer_slices[orientation][2]
  266 + mask = iu.to_vtk(n_mask, self.spacing, slice_number, orientation)
  267 + final_image = self.do_blend(image, self.do_colour_mask(mask))
  268 + else:
  269 + n_image = self.GetImageSlice(orientation, slice_number)
  270 + image = iu.to_vtk(n_image, self.spacing, slice_number, orientation)
  271 + image = self.do_ww_wl(image)
  272 +
  273 + if self.current_mask and self.current_mask.is_shown:
  274 + print "Mask"
  275 + n_mask = self.GetMaskSlice(orientation, slice_number)
  276 + mask = iu.to_vtk(n_mask, self.spacing, slice_number, orientation)
  277 + final_image = self.do_blend(image, self.do_colour_mask(mask))
  278 + else:
  279 + n_mask = None
  280 + final_image = image
  281 +
  282 + self.buffer_slices[orientation] = [slice_number, image, n_mask,
  283 + n_image]
  284 + self.slice_number = slice_number
  285 + return final_image
  286 +
  287 + def GetImageSlice(self, orientation, slice_number):
240 288 if orientation == 'AXIAL':
241   - n_array = numpy.array(self.matrix[slice_number])
  289 + n_image = numpy.array(self.matrix[slice_number])
242 290 elif orientation == 'CORONAL':
243   - n_array = numpy.array(self.matrix[..., slice_number, ...])
  291 + n_image = numpy.array(self.matrix[..., slice_number, ...])
244 292 elif orientation == 'SAGITAL':
245   - n_array = numpy.array(self.matrix[..., ..., slice_number])
246   - image = iu.to_vtk(n_array, self.spacing, slice_number, orientation)
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)
252   - return image
  293 + n_image = numpy.array(self.matrix[..., ..., slice_number])
  294 + return n_image
253 295  
254   - def GetSlicesMask(self, orientation, slice_number):
  296 + def GetMaskSlice(self, orientation, slice_number):
  297 + slice_number += 1
255 298 if orientation == 'AXIAL':
  299 + if self.current_mask.matrix[slice_number, 0, 0] == 0:
  300 + self.current_mask.matrix[slice_number, 1:, 1:] = \
  301 + self.do_threshold_to_a_slice(self.GetImageSlice(orientation,
  302 + slice_number))
  303 + self.current_mask.matrix[slice_number, 0, 0] = 1
256 304 n_mask = numpy.array(self.current_mask.matrix[slice_number])
  305 +
257 306 elif orientation == 'CORONAL':
  307 + if self.current_mask.matrix[0, slice_number, 0] == 0:
  308 + self.current_mask.matrix[1:, slice_number, 1:] = \
  309 + self.do_threshold_to_a_slice(self.GetImageSlice(orientation,
  310 + slice_number))
  311 + self.current_mask.matrix[0, slice_number, 0] = 1
258 312 n_mask = numpy.array(self.current_mask.matrix[..., slice_number, ...])
  313 +
259 314 elif orientation == 'SAGITAL':
  315 + if self.current_mask.matrix[0, 0, slice_number] == 0:
  316 + self.current_mask.matrix[1:, 1:, slice_number] = \
  317 + self.do_threshold_to_a_slice(self.GetImageSlice(orientation,
  318 + slice_number))
  319 + self.current_mask.matrix[0, 0, slice_number] = 1
260 320 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)
  321 + return n_mask
263 322  
264 323 def GetNumberOfSlices(self, orientation):
265 324 if orientation == 'AXIAL':
... ... @@ -304,10 +363,14 @@ class Slice(object):
304 363 proj = Project()
305 364 proj.mask_dict[index].edition_threshold_range = threshold_range
306 365  
307   - def SetMaskThreshold(self, index, threshold_range):
  366 + def SetMaskThreshold(self, index, threshold_range, slice_number=None,
  367 + orientation=None):
308 368 """
309 369 Set a mask threshold range given its index and tuple of min and max
310 370 threshold values.
  371 +
  372 + If slice_number is None then all the threshold is calculated for all
  373 + slices, otherwise only to indicated slice.
311 374 """
312 375 thresh_min, thresh_max = threshold_range
313 376  
... ... @@ -327,12 +390,20 @@ class Slice(object):
327 390 #self.img_colours_mask.SetInput(self.current_mask.imagedata)
328 391  
329 392 # 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
  393 +
  394 + if slice_number is None:
  395 + for n, slice_ in enumerate(self.matrix):
  396 + m = numpy.ones(slice_.shape, self.current_mask.matrix.dtype)
  397 + m[slice_ < thresh_min] = 0
  398 + m[slice_ > thresh_max] = 0
  399 + m[m == 1] = 255
  400 + self.current_mask.matrix[n] = m
  401 + else:
  402 + print "Only one slice"
  403 + slice_ = self.buffer_slices[orientation][3]
  404 + m = numpy.zeros(slice_.shape, self.current_mask.matrix.dtype)
  405 + m[numpy.logical_and(slice_ >= thresh_min,slice_ <= thresh_max)] = 255
  406 + self.buffer_slices[orientation][2] = m
336 407  
337 408 # Update viewer
338 409 #ps.Publisher().sendMessage('Update slice viewer')
... ... @@ -653,6 +724,16 @@ class Slice(object):
653 724  
654 725 return colorer.GetOutput()
655 726  
  727 + def do_threshold_to_a_slice(self, slice_matrix):
  728 + """
  729 + Based on the current threshold bounds generates a threshold mask to
  730 + given slice_matrix.
  731 + """
  732 + thresh_min, thresh_max = self.current_mask.threshold_range
  733 + m = numpy.zeros(slice_matrix.shape, self.current_mask.matrix.dtype)
  734 + m[numpy.logical_and(slice_matrix >= thresh_min, slice_matrix <= thresh_max)] = 255
  735 + return m
  736 +
656 737 def do_colour_mask(self, imagedata):
657 738 scalar_range = int(imagedata.GetScalarRange()[1])
658 739 r, g, b = self.current_mask.colour
... ... @@ -772,7 +853,3 @@ class Slice(object):
772 853 filename, filetype = pubsub_evt.data
773 854 if (filetype == const.FILETYPE_IMAGEDATA):
774 855 iu.Export(imagedata, filename)
775   -
776   -
777   -
778   -
... ...
invesalius/data/viewer_slice.py
... ... @@ -886,6 +886,8 @@ class Viewer(wx.Panel):
886 886 ps.Publisher().subscribe(self.AddActors, ('Add actors', ORIENTATIONS[self.orientation]))
887 887 ps.Publisher().subscribe(self.RemoveActors, ('Remove actors', ORIENTATIONS[self.orientation]))
888 888  
  889 + ps.Publisher().subscribe(self.ReloadActualSlice, 'Reload actual slice')
  890 +
889 891 def SetDefaultCursor(self, pusub_evt):
890 892 self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
891 893  
... ... @@ -1381,11 +1383,7 @@ class Viewer(wx.Panel):
1381 1383 image = self.slice_.GetSlices(self.orientation, index)
1382 1384 self.actor.SetInput(image)
1383 1385 self.__update_display_extent(image)
1384   - print "slice", index
1385   - print "display extent", self.actor.GetDisplayExtent()
1386   - print "whole extent", image.GetWholeExtent()
1387   - print "boundsa", self.actor.GetBounds()
1388   - print "camera", self.cam.GetPosition(), self.cam.GetFocalPoint()
  1386 + self.interactor.Render()
1389 1387  
1390 1388 def ChangeSliceNumber(self, pubsub_evt):
1391 1389 index = pubsub_evt.data
... ... @@ -1445,6 +1443,9 @@ class Viewer(wx.Panel):
1445 1443 slice_number))
1446 1444 self.interactor.Render()
1447 1445  
  1446 + def ReloadActualSlice(self, pubsub_evt):
  1447 + self.OnScrollBar()
  1448 +
1448 1449 def AddActors(self, pubsub_evt):
1449 1450 "Inserting actors"
1450 1451 actors, n = pubsub_evt.data
... ...
invesalius/gui/dialogs.py
... ... @@ -521,7 +521,7 @@ class NewMask(wx.Dialog):
521 521 self.SetSizer(sizer)
522 522 sizer.Fit(self)
523 523  
524   - self.Bind(grad.EVT_THRESHOLD_CHANGE, self.OnSlideChanged, self.gradient)
  524 + self.Bind(grad.EVT_THRESHOLD_CHANGED, self.OnSlideChanged, self.gradient)
525 525 self.combo_thresh.Bind(wx.EVT_COMBOBOX, self.OnComboThresh)
526 526  
527 527  
... ...