Commit 3e8484532f5a3e62106871eb97be11e6d970950e

Authored by Thiago Franco de Moraes
1 parent ba729de6
Exists in ff_mask

Using an iter to traverse the voxel neighbourhood

invesalius/data/floodfill.pyx
@@ -81,7 +81,7 @@ def floodfill(np.ndarray[image_t, ndim=3] data, int i, int j, int k, int v, int @@ -81,7 +81,7 @@ def floodfill(np.ndarray[image_t, ndim=3] data, int i, int j, int k, int v, int
81 @cython.boundscheck(False) # turn of bounds-checking for entire function 81 @cython.boundscheck(False) # turn of bounds-checking for entire function
82 @cython.wraparound(False) 82 @cython.wraparound(False)
83 @cython.nonecheck(False) 83 @cython.nonecheck(False)
84 -def floodfill_threshold(np.ndarray[image_t, ndim=3] data, list seeds, int t0, int t1, int fill, np.ndarray[mask_t, ndim=3] out): 84 +def floodfill_threshold(np.ndarray[image_t, ndim=3] data, list seeds, int t0, int t1, int fill, tuple neighbor_iter, np.ndarray[mask_t, ndim=3] out):
85 85
86 cdef int to_return = 0 86 cdef int to_return = 0
87 if out is None: 87 if out is None:
@@ -89,6 +89,7 @@ def floodfill_threshold(np.ndarray[image_t, ndim=3] data, list seeds, int t0, in @@ -89,6 +89,7 @@ def floodfill_threshold(np.ndarray[image_t, ndim=3] data, list seeds, int t0, in
89 to_return = 1 89 to_return = 1
90 90
91 cdef int x, y, z 91 cdef int x, y, z
  92 + cdef int xd, yd, zd
92 cdef int w, h, d 93 cdef int w, h, d
93 cdef int xo, yo, zo 94 cdef int xo, yo, zo
94 95
@@ -106,33 +107,38 @@ def floodfill_threshold(np.ndarray[image_t, ndim=3] data, list seeds, int t0, in @@ -106,33 +107,38 @@ def floodfill_threshold(np.ndarray[image_t, ndim=3] data, list seeds, int t0, in
106 while stack: 107 while stack:
107 x, y, z = stack.pop() 108 x, y, z = stack.pop()
108 109
109 - xo = x  
110 - yo = y  
111 - zo = z  
112 110
113 - if z + 1 < d and data[z + 1, y, x] >= t0 and data[z + 1, y, x] <= t1 and out[zo + 1, yo, xo] != fill:  
114 - out[zo + 1, yo, xo] = fill  
115 - stack.append((x, y, z + 1)) 111 + for xd, yd, zd in neighbor_iter:
  112 + xo = x + xd
  113 + yo = y + yd
  114 + zo = z + zd
  115 + if 0 <= (x + xd) < w and 0 <= (y + yd) < h and 0 <= (z + zd) < d and out[zo, yo, xo] != fill and t0 <= data[zo, yo, xo] <= t1:
  116 + out[zo, yo, xo] = fill
  117 + stack.append((xo, yo, zo))
116 118
117 - if z - 1 >= 0 and data[z - 1, y, x] >= t0 and data[z - 1, y, x] <= t1 and out[zo - 1, yo, xo] != fill:  
118 - out[zo - 1, yo, xo] = fill  
119 - stack.append((x, y, z - 1)) 119 + # if z + 1 < d and data[z + 1, y, x] >= t0 and data[z + 1, y, x] <= t1 and out[zo + 1, yo, xo] != fill:
  120 + # out[zo + 1, yo, xo] = fill
  121 + # stack.append((x, y, z + 1))
120 122
121 - if y + 1 < h and data[z, y + 1, x] >= t0 and data[z, y + 1, x] <= t1 and out[zo, yo + 1, xo] != fill:  
122 - out[zo, yo + 1, xo] = fill  
123 - stack.append((x, y + 1, z)) 123 + # if z - 1 >= 0 and data[z - 1, y, x] >= t0 and data[z - 1, y, x] <= t1 and out[zo - 1, yo, xo] != fill:
  124 + # out[zo - 1, yo, xo] = fill
  125 + # stack.append((x, y, z - 1))
124 126
125 - if y - 1 >= 0 and data[z, y - 1, x] >= t0 and data[z, y - 1, x] <= t1 and out[zo, yo - 1, xo] != fill:  
126 - out[zo, yo - 1, xo] = fill  
127 - stack.append((x, y - 1, z)) 127 + # if y + 1 < h and data[z, y + 1, x] >= t0 and data[z, y + 1, x] <= t1 and out[zo, yo + 1, xo] != fill:
  128 + # out[zo, yo + 1, xo] = fill
  129 + # stack.append((x, y + 1, z))
128 130
129 - if x + 1 < w and data[z, y, x + 1] >= t0 and data[z, y, x + 1] <= t1 and out[zo, yo, xo + 1] != fill:  
130 - out[zo, yo, xo + 1] = fill  
131 - stack.append((x + 1, y, z)) 131 + # if y - 1 >= 0 and data[z, y - 1, x] >= t0 and data[z, y - 1, x] <= t1 and out[zo, yo - 1, xo] != fill:
  132 + # out[zo, yo - 1, xo] = fill
  133 + # stack.append((x, y - 1, z))
132 134
133 - if x - 1 >= 0 and data[z, y, x - 1] >= t0 and data[z, y, x - 1] <= t1 and out[zo, yo, xo - 1] != fill:  
134 - out[zo, yo, xo - 1] = fill  
135 - stack.append((x - 1, y, z)) 135 + # if x + 1 < w and data[z, y, x + 1] >= t0 and data[z, y, x + 1] <= t1 and out[zo, yo, xo + 1] != fill:
  136 + # out[zo, yo, xo + 1] = fill
  137 + # stack.append((x + 1, y, z))
  138 +
  139 + # if x - 1 >= 0 and data[z, y, x - 1] >= t0 and data[z, y, x - 1] <= t1 and out[zo, yo, xo - 1] != fill:
  140 + # out[zo, yo, xo - 1] = fill
  141 + # stack.append((x - 1, y, z))
136 142
137 if to_return: 143 if to_return:
138 return out 144 return out
invesalius/data/styles.py
@@ -1769,7 +1769,6 @@ class FlooFillMaskInteractorStyle(DefaultInteractorStyle): @@ -1769,7 +1769,6 @@ class FlooFillMaskInteractorStyle(DefaultInteractorStyle):
1769 if (self.viewer.slice_.buffer_slices[self.orientation].mask is None): 1769 if (self.viewer.slice_.buffer_slices[self.orientation].mask is None):
1770 return 1770 return
1771 1771
1772 -  
1773 viewer = self.viewer 1772 viewer = self.viewer
1774 iren = viewer.interactor 1773 iren = viewer.interactor
1775 1774
@@ -1793,9 +1792,35 @@ class FlooFillMaskInteractorStyle(DefaultInteractorStyle): @@ -1793,9 +1792,35 @@ class FlooFillMaskInteractorStyle(DefaultInteractorStyle):
1793 1792
1794 cp_mask = mask.copy() 1793 cp_mask = mask.copy()
1795 1794
1796 - floodfill.floodfill_threshold(cp_mask, [[x, y, z]], 0, 1, 254, mask) 1795 + from_3d = True
  1796 + if from_3d:
  1797 + neighbor_iter = ((-1, 0, 0),
  1798 + (1, 0, 0),
  1799 + (0, -1, 0),
  1800 + (0, 1, 0),
  1801 + (0, 0, -1),
  1802 + (0, 0, 1))
  1803 + else:
  1804 + neighbor_iter = ((-1, 0, 0),
  1805 + (1, 0, 0),
  1806 + (0, -1, 0),
  1807 + (0, 1, 0))
1797 1808
1798 - viewer.OnScrollBar() 1809 + if iren.GetControlKey():
  1810 + floodfill.floodfill_threshold(cp_mask, [[x, y, z]], 254, 255, 1, neighbor_iter, mask)
  1811 + else:
  1812 + floodfill.floodfill_threshold(cp_mask, [[x, y, z]], 0, 1, 254, neighbor_iter, mask)
  1813 +
  1814 + self.viewer.slice_.buffer_slices['AXIAL'].discard_mask()
  1815 + self.viewer.slice_.buffer_slices['CORONAL'].discard_mask()
  1816 + self.viewer.slice_.buffer_slices['SAGITAL'].discard_mask()
  1817 +
  1818 + self.viewer.slice_.buffer_slices['AXIAL'].discard_vtk_mask()
  1819 + self.viewer.slice_.buffer_slices['CORONAL'].discard_vtk_mask()
  1820 + self.viewer.slice_.buffer_slices['SAGITAL'].discard_vtk_mask()
  1821 +
  1822 + self.viewer.slice_.current_mask.was_edited = True
  1823 + Publisher.sendMessage('Reload actual slice')
1799 1824
1800 def get_coordinate_cursor(self): 1825 def get_coordinate_cursor(self):
1801 # Find position 1826 # Find position