Commit 8594ab8dc7129fe1411173e4568b48779e5f2bdd

Authored by Thiago Franco de Moraes
1 parent 932566e7
Exists in fill_holes_auto

Returning true when a hole were filled

invesalius/data/floodfill.pyx
... ... @@ -6,6 +6,7 @@ from collections import deque
6 6  
7 7 from cython.parallel import prange
8 8 from libc.math cimport floor, ceil
  9 +from libcpp cimport bool
9 10 from libcpp.deque cimport deque as cdeque
10 11 from libcpp.vector cimport vector
11 12  
... ... @@ -237,22 +238,37 @@ def floodfill_auto_threshold(np.ndarray[image_t, ndim=3] data, list seeds, float
237 238 @cython.wraparound(False)
238 239 @cython.nonecheck(False)
239 240 def fill_holes_automatically(np.ndarray[mask_t, ndim=3] mask, np.ndarray[np.uint16_t, ndim=3] labels, unsigned int nlabels, unsigned int max_size):
240   - cdef np.ndarray[np.uint32_t, ndim=1] sizes = np.zeros(shape=(nlabels + 1), dtype=np.uint32)
241   - cdef int x, y, z
242   - cdef int dx, dy, dz
  241 + """
  242 + Fill mask holes automatically. The hole must <= max_size. Return True if any hole were filled.
  243 + """
  244 + cdef np.ndarray[np.uint32_t, ndim=1] sizes = np.zeros(shape=(nlabels + 1), dtype=np.uint32)
  245 + cdef int x, y, z
  246 + cdef int dx, dy, dz
  247 + cdef int i
  248 +
  249 + cdef bool modified = False
  250 +
  251 + dz = mask.shape[0]
  252 + dy = mask.shape[1]
  253 + dx = mask.shape[2]
  254 +
  255 + for z in xrange(dz):
  256 + for y in xrange(dy):
  257 + for x in xrange(dx):
  258 + sizes[labels[z, y, x]] += 1
243 259  
244   - dz = mask.shape[0]
245   - dy = mask.shape[1]
246   - dx = mask.shape[2]
  260 + #Checking if any hole will be filled
  261 + for i in xrange(nlabels + 1):
  262 + if sizes[i] <= max_size:
  263 + modified = True
247 264  
248   - for z in xrange(dz):
249   - for y in xrange(dy):
250   - for x in xrange(dx):
251   - sizes[labels[z, y, x]] += 1
  265 + if not modified:
  266 + return 0
252 267  
  268 + for z in prange(dz, nogil=True):
  269 + for y in xrange(dy):
  270 + for x in xrange(dx):
  271 + if sizes[labels[z, y, x]] <= max_size:
  272 + mask[z, y, x] = 254
253 273  
254   - for z in prange(dz, nogil=True):
255   - for y in xrange(dy):
256   - for x in xrange(dx):
257   - if sizes[labels[z, y, x]] <= max_size:
258   - mask[z, y, x] = 254
  274 + return modified
... ...
invesalius/data/mask.py
... ... @@ -353,9 +353,13 @@ class Mask():
353 353  
354 354 imask = (~(matrix > 127))
355 355 labels, nlabels = ndimage.label(imask, bstruct, output=np.uint16)
356   - print ">>>>", nlabels
357   - floodfill.fill_holes_automatically(matrix, labels, nlabels, size)
358   - self.save_history(index, orientation, self.matrix.copy(), cp_mask)
  356 +
  357 + if nlabels == 0:
  358 + return
  359 +
  360 + ret = floodfill.fill_holes_automatically(matrix, labels, nlabels, size)
  361 + if ret:
  362 + self.save_history(index, orientation, self.matrix.copy(), cp_mask)
359 363 else:
360 364 bstruct = ndimage.generate_binary_structure(2, CON2D[conn])
361 365  
... ... @@ -371,11 +375,15 @@ class Mask():
371 375 imask = (~(matrix > 127))
372 376 labels, nlabels = ndimage.label(imask, bstruct, output=np.uint16)
373 377  
  378 + if nlabels == 0:
  379 + return
  380 +
374 381 labels = labels.reshape(1, labels.shape[0], labels.shape[1])
375 382 matrix = matrix.reshape(1, matrix.shape[0], matrix.shape[1])
376 383  
377   - floodfill.fill_holes_automatically(matrix, labels, nlabels, size)
378   - self.save_history(index, orientation, matrix.copy(), cp_mask)
  384 + ret = floodfill.fill_holes_automatically(matrix, labels, nlabels, size)
  385 + if ret:
  386 + self.save_history(index, orientation, matrix.copy(), cp_mask)
379 387  
380 388 def __del__(self):
381 389 if self.is_shown:
... ...
invesalius/gui/frame.py
... ... @@ -596,7 +596,6 @@ class Frame(wx.Frame):
596 596 Publisher.sendMessage('Enable style', const.SLICE_STATE_MASK_FFILL)
597 597  
598 598 def OnFillHolesAutomatically(self):
599   - # Publisher.sendMessage('Fill holes automatically')
600 599 fdlg = dlg.FillHolesAutoDialog(_(u"Fill holes automatically"))
601 600 fdlg.Show()
602 601  
... ... @@ -752,20 +751,23 @@ class MenuBar(wx.MenuBar):
752 751 self.clean_mask_menu.Enable(False)
753 752  
754 753 mask_menu.AppendSeparator()
  754 +
755 755 self.fill_hole_mask_menu = mask_menu.Append(const.ID_FLOODFILL_MASK, _(u"Fill holes manually"))
756 756 self.fill_hole_mask_menu.Enable(False)
757 757  
758 758 self.fill_hole_auto_menu = mask_menu.Append(const.ID_FILL_HOLE_AUTO, _(u"Fill holes automatically"))
759 759 self.fill_hole_mask_menu.Enable(False)
760 760  
  761 + mask_menu.AppendSeparator()
  762 +
761 763 self.remove_mask_part_menu = mask_menu.Append(const.ID_REMOVE_MASK_PART, _(u"Remove parts"))
762 764 self.remove_mask_part_menu.Enable(False)
763 765  
764 766 self.select_mask_part_menu = mask_menu.Append(const.ID_SELECT_MASK_PART, _(u"Select parts"))
765 767 self.select_mask_part_menu.Enable(False)
766   -
  768 +
767 769 mask_menu.AppendSeparator()
768   -
  770 +
769 771 self.crop_mask_menu = mask_menu.Append(const.ID_CROP_MASK, _("Crop"))
770 772 self.crop_mask_menu.Enable(False)
771 773  
... ...