コード例 #1
0
    def test_eq_3(self):
        a = ChunkGrid(1, bool, False)
        b = ChunkGrid(1, bool, False)

        x = a == b
        self.assertEqual(0, len(x.chunks))
        self.assertTrue(x.fill_value)
コード例 #2
0
    def _compute_fill_task(
        self, task: FloodFillTask
    ) -> Optional[Tuple[Chunk[b8], List[FloodFillTask]]]:
        """
        Create a fill mask for a chunk with a source mask
        :param task: fill task
        :return: A tuple of the resulting fill mask for this chunk and tasks for the neighboring chunks to fill
        """

        # Do nothing when out of bounds
        if self.is_out_of_bounds(task.index):
            return None

        # Get mask
        mask_chunk: Chunk[b8] = self.mask.ensure_chunk_at_index(task.index,
                                                                insert=False)

        # Method cache (prevent lookup in loop)
        __face_flip = ChunkFace.flip
        __face_slice = ChunkFace.slice

        if mask_chunk.is_filled():
            if mask_chunk.value:
                return (Chunk(task.index, mask_chunk.size, b8,
                              b8_False).set_fill(b8_True), [
                                  FloodFillTask(i, face=__face_flip(f))
                                  for f, i in ChunkGrid.iter_neighbors_indices(
                                      mask_chunk.index) if f != task.face
                              ])
            else:
                return Chunk(task.index, mask_chunk.size, b8, b8_False), []

        task_image: np.ndarray = task.image(mask_chunk.array_shape)
        assert task_image.shape == mask_chunk.array_shape
        if not task_image.any():
            # return Chunk(task.index, chunk.size, dtype=np_bool8).set_fill(False), []
            return None
        else:
            mask = mask_chunk.to_array()
            # Enforce that only "free" fields in mask are filled
            img = task_image & mask
            result = ndimage.binary_propagation(img, mask=mask).astype(b8)

            # Create tasks where propagation is possible
            tasks = []
            for f, i in ChunkGrid.iter_neighbors_indices(mask_chunk.index):
                face_slice = result[__face_slice(f)]
                if face_slice.all():
                    if f != task.face:
                        tasks.append(FloodFillTask(i, face=__face_flip(f)))
                elif face_slice.any():
                    tmp = np.full(mask_chunk.shape, b8_False, dtype=b8)
                    tmp[__face_slice(__face_flip(f))] = face_slice
                    tasks.append(FloodFillTask(i, image=tmp))
            return Chunk(task.index, mask_chunk.size, b8,
                         b8_False).set_array(result).cleanup(), tasks
コード例 #3
0
    def test__getitem_empty(self):
        a = ChunkGrid(2, int, -1)
        a.set_or_fill((0, 0, 0), 1)

        res = a[-1:1, -1:1, -1:1]

        expected = np.full((2, 2, 2), -1)
        expected[1, 1, 1] = 1

        self.assertEqual(str(expected), str(res))
コード例 #4
0
    def test_reflected(self):
        grid = ChunkGrid(2, float, -1.0)
        grid.set_value((0, 0, 0), 0.5)
        grid.set_value((0, 0, 1), 1.0)

        result = (0 < grid) & (grid < 1.0)
        actual = result.to_dense()

        expected = np.zeros((2, 2, 2), dtype=bool)
        expected[0, 0, 0] = True

        self.assertEqual(str(expected), str(actual))
コード例 #5
0
    def test_eq_1(self):
        a = ChunkGrid(2, bool, False)
        b = ChunkGrid(2, bool, False)
        a.set_value((0, 0, 0), True)
        result = (a == b).to_dense()
        self.assertIsInstance((a == b), ChunkGrid)

        expected = np.ones((2, 2, 2), dtype=bool)
        expected[0, 0, 0] = False

        assert result.shape == expected.shape
        self.assertEqual(str(expected), str(result))
コード例 #6
0
 def grid_segments(self) -> Tuple[ChunkGrid[np.bool8], ChunkGrid[np.bool8]]:
     to_voxel = MinCut.to_voxel
     segments = self.segments()
     if self._grid_segment0 is None:
         self._grid_segment0 = ChunkGrid(self.crust.chunk_size, np.bool8, False)
         self._grid_segment0[[p for node, s in zip(self.nodes, segments) if s == False
                              for p in to_voxel(node)]] = True
     if self._grid_segment1 is None:
         self._grid_segment1 = ChunkGrid(self.crust.chunk_size, np.bool8, False)
         self._grid_segment1[[p for node, s in zip(self.nodes, segments) if s == True
                              for p in to_voxel(node)]] = True
     return self._grid_segment0, self._grid_segment1
コード例 #7
0
 def _test_inplace_modified(self, op, a: ChunkGrid, a0: ChunkGrid, b: ChunkGrid, b0: ChunkGrid, inplace: bool):
     # Test if inplace (or not) is working intended
     ad = a.to_dense()
     a0d = a0.to_dense()
     bd = b.to_dense()
     b0d = b0.to_dense()
     if inplace:  # Inplace modification - change
         opa = ad == op(ad, bd)
         opb = bd == b0d
     else:  # Not inplace modification - no change
         opa = ad == a0d
         opb = bd == b0d
     self.assertTrue(np.all(opa), f"Failure-Inplace-{inplace} {op}! \n{ad}\n-------\n{a0d}")
     self.assertTrue(np.all(opb), f"Failure-Inplace-{inplace} {op}! \n{bd}\n-------\n{b0d}")
コード例 #8
0
    def test_set_pos(self):
        a = ChunkGrid(2, bool, False)
        a.set_value((0, 0, 0), True)
        a.set_value((2, 2, 2), True)

        self.assertFalse(a.chunks[0, 0, 0].is_filled())

        result = a.to_dense()

        expected = np.zeros((4, 4, 4), dtype=bool)
        expected[0, 0, 0] = True
        expected[2, 2, 2] = True

        assert result.shape == expected.shape
        self.assertEqual(str(expected), str(result))
コード例 #9
0
    def test_special_dtype(self):

        t = np.dtype((np.int, (3,)))
        a = ChunkGrid(2, dtype=t, fill_value=np.zeros(3))

        a.set_value((0, 0, 0), np.ones(3))
        a.set_value((2, 2, 2), np.ones(3))
        dense = a.to_dense()

        expected = np.zeros((4, 4, 4), dtype=t)
        expected[0, 0, 0] = 1
        expected[2, 2, 2] = 1

        self.assertEqual(expected.shape, dense.shape)
        self.assertEqual(str(expected), str(dense))
コード例 #10
0
    def test_single_negative(self):
        a = ChunkGrid(2, bool, False)
        a.set_value((0, 0, 0), True)

        res = dilate(a, steps=1)
        self.assertEqual(4, len(res.chunks))
        c0 = res.chunks.get((0, 0, 0))
        self.assertIsNotNone(c0)
        self.assertFalse(c0.is_filled())

        expected = np.zeros((4, 4, 4), dtype=bool)
        expected[2, 2, 1:4] = True
        expected[2, 1:4, 2] = True
        expected[1:4, 2, 2] = True

        self.assertEqual(str(expected), str(res.to_dense()))
コード例 #11
0
    def test_filled(self):
        a = ChunkGrid(2, bool, False)
        a.ensure_chunk_at_index((0, 0, 0)).set_fill(True)

        res = dilate(a, steps=1)
        self.assertEqual(7, len(res.chunks))
        c0 = res.chunks.get((0, 0, 0))
        self.assertIsNotNone(c0)
        self.assertTrue(c0.is_filled())
        self.assertTrue(c0.value)

        expected = np.zeros((6, 6, 6), dtype=bool)
        expected[2:-2, 2:-2, 1:-1] = True
        expected[2:-2, 1:-1, 2:-2] = True
        expected[1:-1, 2:-2, 2:-2] = True
        self.assertEqual(str(expected), str(res.to_dense()))
コード例 #12
0
def flood_fill_at(position: Vec3i,
                  mask: ChunkGrid,
                  max_steps: Optional[int] = None,
                  verbose=False,
                  **kwargs) -> ChunkGrid[b8]:
    image = ChunkGrid(mask.chunk_size, b8, False)
    image[position] = True
    return flood_fill(image, mask, max_steps, verbose=verbose, **kwargs)
コード例 #13
0
 def __init__(self, mask: ChunkGrid, verbose=False):
     self.mask: ChunkGrid[b8] = mask.copy(dtype=b8)
     self.mask.cleanup(remove=True).pad_chunks(1)
     self.verbose = verbose
     self.__mask_chunks_get = self.mask.chunks.get
     self.min, self.max = self.mask.chunks.minmax(True)
     self.min -= 1
     self.max += 1
コード例 #14
0
def grid_normals(surface: ChunkGrid[np.bool8], outer: ChunkGrid[np.bool8], normal_kernel: Optional[np.ndarray] = None) \
        -> ChunkGrid[Vec3f]:
    normal_pos, normal_val = detect_normals(surface, outer, normal_kernel)
    normals: ChunkGrid[np.float32] = ChunkGrid(surface.chunk_size,
                                               np.dtype((np.float32, (3, ))),
                                               0.0)
    normals[normal_pos] = normal_val
    return normals
コード例 #15
0
    def test_padding_1(self):
        a = ChunkGrid(2, int, 0)
        expected = np.zeros((6, 6, 6), dtype=int)
        for n, i in enumerate(np.ndindex(6, 6, 6)):
            pos = np.array(i, dtype=int) - 2
            a.set_value(pos, n + 1)
            expected[i] = n + 1

        data = a.padding_at((0, 0, 0), 2)
        self.assertEqual(expected.shape, data.shape)
        self.assertEqual(str(expected), str(data))

        expected2 = expected[1:-1, 1:-1, 1:-1]
        data2 = a.padding_at((0, 0, 0), 1)
        self.assertEqual(expected2.shape, data2.shape)
        self.assertEqual(str(expected2), str(data2))

        expected3_tmp = np.zeros((6, 6, 6), dtype=int)
        for n, i in enumerate(np.ndindex(6, 6, 6)):
            expected3_tmp[i] = n + 1
        expected3 = np.zeros((8, 8, 8), dtype=int)
        expected3[1:-1, 1:-1, 1:-1] = expected3_tmp
        data3 = a.padding_at((0, 0, 0), 3)
        self.assertEqual(expected3.shape, data3.shape)
        self.assertEqual(str(expected3), str(data3))
コード例 #16
0
    def test_padding_vec3_4(self):
        dtype = np.dtype((int, (3,)))
        a = ChunkGrid(2, dtype, np.zeros(3))
        expected = np.zeros((6, 6, 6, 3), dtype=int)

        for n, i in enumerate(np.ndindex(6, 6, 6)):
            pos = np.array(i, dtype=int) - 2
            value = np.array([1, 2, 3]) + (n + 1) * 3
            a.set_value(pos, value)
            s = np.sum(pos < 0) + np.sum(2 <= pos)
            if s >= 2:
                continue
            expected[i] = value

        data = a.padding_at((0, 0, 0), 2, corners=False, edges=False)
        self.assertEqual(expected.shape, data.shape)
        self.assertEqual(str(expected), str(data))

        expected2 = expected[1:-1, 1:-1, 1:-1]
        data2 = a.padding_at((0, 0, 0), 1, corners=False, edges=False)
        self.assertEqual(expected2.shape, data2.shape)
        self.assertEqual(str(expected2), str(data2))

        expected3_tmp = np.zeros((6, 6, 6, 3), dtype=int)
        for n, i in enumerate(np.ndindex(6, 6, 6)):
            value = np.array([1, 2, 3]) + (n + 1) * 3
            expected3_tmp[i] = value
        expected3 = np.zeros((8, 8, 8, 3), dtype=int)
        expected3[1:-1, 1:-1, 1:-1] = expected3_tmp
        data3 = a.padding_at((0, 0, 0), 3, corners=False, edges=False)
        self.assertEqual(expected3.shape, data3.shape)
        self.assertEqual(str(expected3), str(data3))
コード例 #17
0
    def test_padding_2(self):
        a = ChunkGrid(2, int, 0)
        expected = np.zeros((6, 6, 6), dtype=int)
        for n, i in enumerate(np.ndindex(6, 6, 6)):
            pos = np.array(i, dtype=int) - 2
            a.set_value(pos, n + 1)
            s = np.sum(pos < 0) + np.sum(2 <= pos)
            if s >= 2:
                continue
            expected[i] = n + 1

        data = a.padding_at((0, 0, 0), 2, corners=False, edges=False)
        self.assertEqual(expected.shape, data.shape)
        self.assertEqual(str(expected), str(data))

        expected2 = expected[1:-1, 1:-1, 1:-1]
        data2 = a.padding_at((0, 0, 0), 1, corners=False, edges=False)
        self.assertEqual(expected2.shape, data2.shape)
        self.assertEqual(str(expected2), str(data2))

        expected3_tmp = np.zeros((6, 6, 6), dtype=int)
        for n, i in enumerate(np.ndindex(6, 6, 6)):
            expected3_tmp[i] = n + 1
        expected3 = np.zeros((8, 8, 8), dtype=int)
        expected3[1:-1, 1:-1, 1:-1] = expected3_tmp
        data3 = a.padding_at((0, 0, 0), 3, corners=False, edges=False)
        self.assertEqual(expected3.shape, data3.shape)
        self.assertEqual(str(expected3), str(data3))
コード例 #18
0
    def test_eq_2(self):
        a = ChunkGrid(2, bool, False)
        b = ChunkGrid(2, bool, False)

        a.set_value((0, 0, 0), True)
        a.set_value((2, 2, 2), True)

        comp = a == b
        self.assertIsInstance(comp, ChunkGrid)
        self.assertIs(comp.dtype.type, np.bool8)

        expected = np.ones((4, 4, 4), dtype=bool)
        expected[0, 0, 0] = False
        expected[2, 2, 2] = False

        result = comp.to_dense()
        assert result.shape == expected.shape
        self.assertEqual(str(expected), str(result))
コード例 #19
0
    def test_getitem(self):
        CS = 2
        shape = (CS * 3, CS * 3, CS * 3)
        soll = np.arange(shape[0] * shape[1] * shape[2]).reshape(shape)

        a = ChunkGrid(CS, int, -1)
        for u in range(shape[0] // CS):
            for v in range(shape[1] // CS):
                for w in range(shape[2] // CS):
                    x, y, z = u * CS, v * CS, w * CS
                    index = (u, v, w)
                    a.ensure_chunk_at_index(index).set_array(soll[x:x + CS, y:y + CS, z:z + CS])

        dense = a.to_dense()
        self.assertEqual(soll.shape, dense.shape)
        self.assertEqual(str(soll), str(dense))

        self.assertEqual(str(soll[1: shape[0] - 1, 1: shape[1] - 1, 1: shape[2] - 1]),
                         str(a[1: shape[0] - 1, 1: shape[1] - 1, 1: shape[2] - 1]))
コード例 #20
0
    def make_value_scatter(self, grid: ChunkGrid, mask: ChunkGrid[bool],
                           **kwargs):

        items = list(grid.items(mask=mask))
        points, values = zip(*items)  # type: Sequence[Vec3i], Sequence
        pts = np.array(points, dtype=np.float32) + 0.5
        values = np.array(values)

        merge_default(kwargs, marker=dict(color=values))
        return self.make_scatter(pts, **kwargs)
コード例 #21
0
    def test_padding(self):
        grid = ChunkGrid(2, int, -1)
        grid.ensure_chunk_at_index((0, 0, 0)).set_fill(1)
        grid.ensure_chunk_at_index((0, 0, 1)).set_fill(2)
        grid.ensure_chunk_at_index((0, 1, 0)).set_fill(3)
        grid.ensure_chunk_at_index((0, 1, 1)).set_fill(4)

        t = grid.chunks[(0, 0, 1)]
        t.set_array(np.array([
            [(111, 112), (121, 122)],
            [(211, 212), (221, 222)]
        ]))
        expected1 = t.to_array()[:, :, 0]

        c = grid.chunks.get((0, 0, 0))
        pad = c.padding(grid, 1)
        actual = pad

        expected = np.ones((4, 4, 4), int) * -1
        expected[1:3, 1:3, 1:3] = 1
        expected[1:-1, 1:-1, -1] = expected1
        expected[1:-1, -1, 1:-1] = 3

        self.assertEqual(expected.shape, actual.shape)
        # self.assertTrue(np.all(actual == expected), f"Failure! \n{actual}\n-------\n{expected}")
        self.assertEqual(str(expected), str(actual))
コード例 #22
0
 def fill_at_pos(self,
                 position: Vec3i,
                 max_steps: Optional[int] = None) -> ChunkGrid[bool]:
     """
     Start the flood fill at a position
     :param position: the starting point
     :param max_steps: maximum propagation steps between chunks
     :return:
     """
     image: ChunkGrid[b8] = ChunkGrid(self.mask.chunk_size,
                                      dtype=b8,
                                      fill_value=b8(False))
     image.set_value(position, True)
     return self.fill(image, max_steps=max_steps)
コード例 #23
0
def dilate_no_mask(image: ChunkGrid[bool_t], steps=1, structure: Optional[np.ndarray] = None) -> ChunkGrid[bool_t]:
    if structure is not None:
        assert structure.ndim == 2 and structure.shape == (3, 3)

    __pad_slice = slice(1, -1)

    result = image.astype(np.bool8)
    for step in range(steps):
        # Temporary result between each step
        tmp = result.copy(empty=True)
        # Dilate inner chunk
        # result.pad_chunks(1)

        for index, r in result.chunks.items():
            if r.is_filled() and r.value:
                tmp.ensure_chunk_at_index(index).set_fill(r.value)
                for f, ni in ChunkGrid.iter_neighbors_indices(r.index):
                    ch = tmp.ensure_chunk_at_index(ni)
                    if not (ch.is_filled() and ch.value):
                        arr = ch.to_array()
                        arr[f.flip().slice()] = True
                        ch.set_array(arr)
                        ch.cleanup()
                continue

            padded = result.padding_at(index, 1, corners=False, edges=False)
            if (not np.any(padded)):  # Skip, nothing to do
                continue

            # Do dilation
            dilated = ndimage.binary_dilation(padded, structure=structure)

            # Copy result to tmp
            ch = tmp.ensure_chunk_at_index(index)
            ch.set_array(dilated[1:-1, 1:-1, 1:-1])
            ch.cleanup()

            # Propagate to the next chunks
            for f in ChunkFace:  # type: ChunkFace
                s = dilated[f.slice(other=__pad_slice)]
                if np.any(s):
                    ch: Chunk = tmp.ensure_chunk_at_index(f.direction() + index)
                    arr = ch.to_array()
                    arr[f.flip().slice()] |= s
                    ch.set_array(arr)

        # Set result
        result = tmp
    result.cleanup(remove=True)
    return result
コード例 #24
0
    def test_getitem_offset(self):
        CS = 2
        shape = (CS * 3, CS * 3, CS * 3)
        soll = np.arange(shape[0] * shape[1] * shape[2]).reshape(shape)
        offset_chunk = (-1, 0, 1)

        a = ChunkGrid(CS, int, -1)
        for u in range(shape[0] // CS):
            for v in range(shape[1] // CS):
                for w in range(shape[2] // CS):
                    index = np.add((u, v, w), offset_chunk)
                    x, y, z = np.multiply((u, v, w), CS)
                    a.ensure_chunk_at_index(index).set_array(soll[x:x + CS, y:y + CS, z:z + CS])

        offset_voxel = np.multiply(offset_chunk, CS)
        dense, off = a.to_dense(return_offset=True)
        self.assertEqual(soll.shape, dense.shape)
        self.assertEqual(str(soll), str(dense))
        self.assertEqual(list(offset_voxel), list(off))

        ox, oy, oz = off
        self.assertEqual(str(soll[1: shape[0] - 1, 1: shape[1] - 1, 1: shape[2] - 1]),
                         str(a[1 + ox: shape[0] - 1 + ox, 1 + oy: shape[1] - 1 + oy, 1 + oz: shape[2] - 1 + oz]))
コード例 #25
0
    def _test_operator1_int(self, op):
        a = ChunkGrid(2, int, -1)

        a.set_value((0, 0, 0), 0)
        a.set_value((0, 0, 1), 2)
        a.set_value((0, 1, 0), -2)

        expected = op(a.to_dense())
        res = op(a)
        self.assertIsInstance(res, ChunkGrid)
        result = res.to_dense()
        assert result.shape == expected.shape
        self.assertTrue(np.all(result == expected), f"Failure {op}! \n{result}\n-------\n{expected}")
コード例 #26
0
    def test_split(self):
        a = ChunkGrid(2, int, 0)
        a[0, 0, 0] = 1
        a[0, 0, 1] = 2
        a[0, 1, 0] = 3
        self.assertEqual(1, len(a.chunks))

        pos = np.array([
            (0, 0, 0),
            (0, 0, 1),
            (0, 1, 0),
            (0, 1, 1),
            (1, 0, 0),
            (1, 0, 1),
            (1, 1, 0),
            (1, 1, 1),
        ])

        b = a.split(2)
        self.assertEqual(8, len(b.chunks))

        offset = (0, 0, 0)
        for p in pos:
            self.assertEqual(1, b.get_value(p + offset))

        offset = (0, 0, 2)
        for p in pos:
            self.assertEqual(2, b.get_value(p + offset))

        offset = (0, 2, 0)
        for p in pos:
            self.assertEqual(3, b.get_value(p + offset))

        offset = (2, 0, 0)
        for p in pos:
            self.assertEqual(0, b.get_value(p + offset))
コード例 #27
0
    def test_get_block_1(self):
        a = ChunkGrid(2, int, 0)
        expected = np.zeros((6, 6, 6), dtype=int)
        for n, i in enumerate(np.ndindex(6, 6, 6)):
            pos = np.array(i, dtype=int) - 2
            a.set_value(pos, n + 1)
            expected[i] = n + 1

        block = a.get_block_at((0, 0, 0), (3, 3, 3), corners=True, edges=True)
        self.assertEqual(str(expected), str(a.block_to_array(block)))
コード例 #28
0
    def test_mask_1(self):
        a = ChunkGrid(2, int, 0)

        mask = ChunkGrid(2, bool, False)
        mask[1:3, 1:3, 1:3] = True
        self.assertEqual((4, 4, 4), mask.to_dense().shape)
        a[mask] = 3

        expected = np.zeros((4, 4, 4), dtype=int)
        expected[1:3, 1:3, 1:3] = 3

        self.assertEqual(str(expected), str(a.to_dense()))

        tmp = a == 3
        self.assertEqual(str(mask.to_dense()), str(tmp.to_dense()))
def diffuse(model: ChunkGrid[bool], repeat=1):
    """
    Diffuse the voxels in model to their neighboring voxels
    :param model: the model to diffuse
    :param repeat: number of diffusion steps
    :return: diffused model
    """
    kernel = np.zeros((3, 3, 3), dtype=float)
    kernel[1] = 1
    kernel[:, 1] = 1
    kernel[:, :, 1] = 1
    kernel /= np.sum(kernel)

    result = ChunkGrid(model.chunk_size, dtype=float, fill_value=1.0)
    result[model] = 0.0
    result.pad_chunks(repeat // result.chunk_size + 1)

    for r in range(repeat):
        tmp = result.copy(empty=True)
        for chunk in result.chunks:
            padded = chunk.padding(result, 1)
            ndimage.convolve(padded,
                             kernel,
                             output=padded,
                             mode='constant',
                             cval=1.0)
            conv = padded[1:-1, 1:-1, 1:-1]
            m = model.ensure_chunk_at_index(chunk.index, insert=False)
            if m.is_filled():
                if m.value:
                    tmp.ensure_chunk_at_index(chunk.index).set_fill(0.0)
                    continue
            else:
                conv[m.to_array()] = 0.0
            tmp.ensure_chunk_at_index(chunk.index).set_array(conv)
            # Expand chunks
            for f, i in ChunkGrid.iter_neighbors_indices(chunk.index):
                tmp.ensure_chunk_at_index(i)

        result = tmp

    result.cleanup(remove=True)
    return result
コード例 #30
0
    def test_get_block_2(self):
        a = ChunkGrid(2, int, 0)
        expected = np.zeros((6, 6, 6), dtype=int)
        for n, i in enumerate(np.ndindex(6, 6, 6)):
            pos = np.array(i, dtype=int) - 2
            a.set_value(pos, n + 1)
            s = np.sum(pos < 0) + np.sum(2 <= pos)
            if s >= 2:
                continue
            expected[i] = n + 1

        block = a.get_block_at((0, 0, 0), (3, 3, 3), corners=False, edges=False)
        self.assertEqual(str(expected), str(a.block_to_array(block)))