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,4 +87,5 @@ class Mask():
87 def create_mask(self, shape): 87 def create_mask(self, shape):
88 print "Creating a mask" 88 print "Creating a mask"
89 self.temp_file = tempfile.mktemp() 89 self.temp_file = tempfile.mktemp()
  90 + shape = shape[0] + 1, shape[1] + 1, shape[2] + 1
90 self.matrix = numpy.memmap(self.temp_file, mode='w+', dtype='uint8', shape=shape) 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,6 +41,10 @@ class Slice(object):
41 self.blend_filter = None 41 self.blend_filter = None
42 self.matrix = None 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 self.num_gradient = 0 48 self.num_gradient = 0
45 self.interaction_style = st.StyleStateManager() 49 self.interaction_style = st.StyleStateManager()
46 50
@@ -59,6 +63,8 @@ class Slice(object): @@ -59,6 +63,8 @@ class Slice(object):
59 'Set edition threshold values') 63 'Set edition threshold values')
60 ps.Publisher().subscribe(self.__set_current_mask_threshold, 64 ps.Publisher().subscribe(self.__set_current_mask_threshold,
61 'Set threshold values') 65 'Set threshold values')
  66 + ps.Publisher().subscribe(self.__set_current_mask_threshold_actual_slice,
  67 + 'Changing threshold values')
62 ps.Publisher().subscribe(self.__set_current_mask_colour, 68 ps.Publisher().subscribe(self.__set_current_mask_colour,
63 'Change mask colour') 69 'Change mask colour')
64 ps.Publisher().subscribe(self.__set_mask_name, 'Change mask name') 70 ps.Publisher().subscribe(self.__set_mask_name, 'Change mask name')
@@ -192,11 +198,27 @@ class Slice(object): @@ -192,11 +198,27 @@ class Slice(object):
192 def __set_current_mask_threshold(self, evt_pubsub): 198 def __set_current_mask_threshold(self, evt_pubsub):
193 threshold_range = evt_pubsub.data 199 threshold_range = evt_pubsub.data
194 index = self.current_mask.index 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 #Clear edited points 216 #Clear edited points
197 self.current_mask.edited_points = {} 217 self.current_mask.edited_points = {}
198 self.num_gradient += 1 218 self.num_gradient += 1
199 219
  220 + ps.Publisher().sendMessage('Reload actual slice')
  221 +
200 def __set_current_mask_colour(self, pubsub_evt): 222 def __set_current_mask_colour(self, pubsub_evt):
201 # "if" is necessary because wx events are calling this before any mask 223 # "if" is necessary because wx events are calling this before any mask
202 # has been created 224 # has been created
@@ -237,29 +259,66 @@ class Slice(object): @@ -237,29 +259,66 @@ class Slice(object):
237 #--------------------------------------------------------------------------- 259 #---------------------------------------------------------------------------
238 260
239 def GetSlices(self, orientation, slice_number): 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 if orientation == 'AXIAL': 288 if orientation == 'AXIAL':
241 - n_array = numpy.array(self.matrix[slice_number]) 289 + n_image = numpy.array(self.matrix[slice_number])
242 elif orientation == 'CORONAL': 290 elif orientation == 'CORONAL':
243 - n_array = numpy.array(self.matrix[..., slice_number, ...]) 291 + n_image = numpy.array(self.matrix[..., slice_number, ...])
244 elif orientation == 'SAGITAL': 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 if orientation == 'AXIAL': 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 n_mask = numpy.array(self.current_mask.matrix[slice_number]) 304 n_mask = numpy.array(self.current_mask.matrix[slice_number])
  305 +
257 elif orientation == 'CORONAL': 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 n_mask = numpy.array(self.current_mask.matrix[..., slice_number, ...]) 312 n_mask = numpy.array(self.current_mask.matrix[..., slice_number, ...])
  313 +
259 elif orientation == 'SAGITAL': 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 n_mask = numpy.array(self.current_mask.matrix[..., ..., slice_number]) 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 def GetNumberOfSlices(self, orientation): 323 def GetNumberOfSlices(self, orientation):
265 if orientation == 'AXIAL': 324 if orientation == 'AXIAL':
@@ -304,10 +363,14 @@ class Slice(object): @@ -304,10 +363,14 @@ class Slice(object):
304 proj = Project() 363 proj = Project()
305 proj.mask_dict[index].edition_threshold_range = threshold_range 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 Set a mask threshold range given its index and tuple of min and max 369 Set a mask threshold range given its index and tuple of min and max
310 threshold values. 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 thresh_min, thresh_max = threshold_range 375 thresh_min, thresh_max = threshold_range
313 376
@@ -327,12 +390,20 @@ class Slice(object): @@ -327,12 +390,20 @@ class Slice(object):
327 #self.img_colours_mask.SetInput(self.current_mask.imagedata) 390 #self.img_colours_mask.SetInput(self.current_mask.imagedata)
328 391
329 # TODO: find out a better way to do threshold 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 # Update viewer 408 # Update viewer
338 #ps.Publisher().sendMessage('Update slice viewer') 409 #ps.Publisher().sendMessage('Update slice viewer')
@@ -653,6 +724,16 @@ class Slice(object): @@ -653,6 +724,16 @@ class Slice(object):
653 724
654 return colorer.GetOutput() 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 def do_colour_mask(self, imagedata): 737 def do_colour_mask(self, imagedata):
657 scalar_range = int(imagedata.GetScalarRange()[1]) 738 scalar_range = int(imagedata.GetScalarRange()[1])
658 r, g, b = self.current_mask.colour 739 r, g, b = self.current_mask.colour
@@ -772,7 +853,3 @@ class Slice(object): @@ -772,7 +853,3 @@ class Slice(object):
772 filename, filetype = pubsub_evt.data 853 filename, filetype = pubsub_evt.data
773 if (filetype == const.FILETYPE_IMAGEDATA): 854 if (filetype == const.FILETYPE_IMAGEDATA):
774 iu.Export(imagedata, filename) 855 iu.Export(imagedata, filename)
775 -  
776 -  
777 -  
778 -  
invesalius/data/viewer_slice.py
@@ -886,6 +886,8 @@ class Viewer(wx.Panel): @@ -886,6 +886,8 @@ class Viewer(wx.Panel):
886 ps.Publisher().subscribe(self.AddActors, ('Add actors', ORIENTATIONS[self.orientation])) 886 ps.Publisher().subscribe(self.AddActors, ('Add actors', ORIENTATIONS[self.orientation]))
887 ps.Publisher().subscribe(self.RemoveActors, ('Remove actors', ORIENTATIONS[self.orientation])) 887 ps.Publisher().subscribe(self.RemoveActors, ('Remove actors', ORIENTATIONS[self.orientation]))
888 888
  889 + ps.Publisher().subscribe(self.ReloadActualSlice, 'Reload actual slice')
  890 +
889 def SetDefaultCursor(self, pusub_evt): 891 def SetDefaultCursor(self, pusub_evt):
890 self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) 892 self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
891 893
@@ -1381,11 +1383,7 @@ class Viewer(wx.Panel): @@ -1381,11 +1383,7 @@ class Viewer(wx.Panel):
1381 image = self.slice_.GetSlices(self.orientation, index) 1383 image = self.slice_.GetSlices(self.orientation, index)
1382 self.actor.SetInput(image) 1384 self.actor.SetInput(image)
1383 self.__update_display_extent(image) 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 def ChangeSliceNumber(self, pubsub_evt): 1388 def ChangeSliceNumber(self, pubsub_evt):
1391 index = pubsub_evt.data 1389 index = pubsub_evt.data
@@ -1445,6 +1443,9 @@ class Viewer(wx.Panel): @@ -1445,6 +1443,9 @@ class Viewer(wx.Panel):
1445 slice_number)) 1443 slice_number))
1446 self.interactor.Render() 1444 self.interactor.Render()
1447 1445
  1446 + def ReloadActualSlice(self, pubsub_evt):
  1447 + self.OnScrollBar()
  1448 +
1448 def AddActors(self, pubsub_evt): 1449 def AddActors(self, pubsub_evt):
1449 "Inserting actors" 1450 "Inserting actors"
1450 actors, n = pubsub_evt.data 1451 actors, n = pubsub_evt.data
invesalius/gui/dialogs.py
@@ -521,7 +521,7 @@ class NewMask(wx.Dialog): @@ -521,7 +521,7 @@ class NewMask(wx.Dialog):
521 self.SetSizer(sizer) 521 self.SetSizer(sizer)
522 sizer.Fit(self) 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 self.combo_thresh.Bind(wx.EVT_COMBOBOX, self.OnComboThresh) 525 self.combo_thresh.Bind(wx.EVT_COMBOBOX, self.OnComboThresh)
526 526
527 527