Commit 3e8484532f5a3e62106871eb97be11e6d970950e
1 parent
ba729de6
Exists in
ff_mask
Using an iter to traverse the voxel neighbourhood
Showing
2 changed files
with
56 additions
and
25 deletions
Show diff stats
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 | 81 | @cython.boundscheck(False) # turn of bounds-checking for entire function |
| 82 | 82 | @cython.wraparound(False) |
| 83 | 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 | 86 | cdef int to_return = 0 |
| 87 | 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 | 89 | to_return = 1 |
| 90 | 90 | |
| 91 | 91 | cdef int x, y, z |
| 92 | + cdef int xd, yd, zd | |
| 92 | 93 | cdef int w, h, d |
| 93 | 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 | 107 | while stack: |
| 107 | 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 | 143 | if to_return: |
| 138 | 144 | return out | ... | ... |
invesalius/data/styles.py
| ... | ... | @@ -1769,7 +1769,6 @@ class FlooFillMaskInteractorStyle(DefaultInteractorStyle): |
| 1769 | 1769 | if (self.viewer.slice_.buffer_slices[self.orientation].mask is None): |
| 1770 | 1770 | return |
| 1771 | 1771 | |
| 1772 | - | |
| 1773 | 1772 | viewer = self.viewer |
| 1774 | 1773 | iren = viewer.interactor |
| 1775 | 1774 | |
| ... | ... | @@ -1793,9 +1792,35 @@ class FlooFillMaskInteractorStyle(DefaultInteractorStyle): |
| 1793 | 1792 | |
| 1794 | 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 | 1825 | def get_coordinate_cursor(self): |
| 1801 | 1826 | # Find position | ... | ... |