Skip to content

Commit

Permalink
fix unit tests, skimage convolve and skeletonize(_3d), fast_get globa…
Browse files Browse the repository at this point in the history
…l value reference and np.float_.
  • Loading branch information
tgandor committed Jan 23, 2025
1 parent 4a462a2 commit 1d3bbed
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 31 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ language: python
python:
- "3.8"
- "3.9"
- "3.10"
install:
- pip install .[all]
script: pytest
2 changes: 1 addition & 1 deletion chunky3d/_version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version_info = (0, 1, 14)
version_info = (0, 1, 15)
__version__ = ".".join(map(str, version_info))
47 changes: 29 additions & 18 deletions chunky3d/chunky.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,19 @@
from .helpers import slice_normalize, slice_shape, check_start_end
from .multiprocesses import ProcessPool

EMPTY_GRID_VALUE: np.uint32 = 0xFFFFFFFF


@njit
def fast_get(
ijk, dense_data, grid_mask, chunks, envelope=0, fill_value=0.0, error_value=0.0
ijk,
dense_data,
grid_mask,
chunks,
envelope=0,
fill_value=0.0,
error_value=0.0,
# empty_idx_value=EMPTY_GRID_VALUE,
):
if ijk[0] < 0 or ijk[1] < 0 or ijk[2] < 0:
return error_value
Expand All @@ -32,7 +41,7 @@ def fast_get(

idx = grid_mask[bi, bj, bk]

if idx != Sparse.EMPTY_GRID_VALUE:
if idx != EMPTY_GRID_VALUE:
return dense_data[
envelope + idx * (chunks[0] + 2 * envelope) + li,
envelope + lj,
Expand Down Expand Up @@ -212,7 +221,7 @@ class Sparse:
get_k3d_voxels_group_dict: get chunks as list of dict for use in K3D voxels group
"""

EMPTY_GRID_VALUE = 0xFFFFFFFF
EMPTY_GRID_VALUE = EMPTY_GRID_VALUE

def __init__(
self,
Expand Down Expand Up @@ -350,7 +359,7 @@ def _chunk_to_global_coord(self, chunk_id, coord):

@property
def dtype(self):
""" The NumPy data type. """
"""The NumPy data type."""
return self._dtype

@dtype.setter
Expand Down Expand Up @@ -380,15 +389,15 @@ def shape(self, val):

@property
def size(self):
return np.product(self._shape)
return np.prod(self._shape)

@property
def itemsize(self):
return self._dtype.itemsize

@property
def chunks(self):
""" A tuple of integers describing the length of each dimension of a chunk of the array. """
"""A tuple of integers describing the length of each dimension of a chunk of the array."""
return self._chunk_shape

@chunks.setter
Expand All @@ -412,12 +421,12 @@ def chunks(self, val):

@property
def cdata_shape(self):
""" A tuple of integers describing the number of chunks along each dimension of the array. """
"""A tuple of integers describing the number of chunks along each dimension of the array."""
return self._block_shape

@property
def fill_value(self):
""" A value used for uninitialized (empty) portions of the array. """
"""A value used for uninitialized (empty) portions of the array."""
return self._default_value

@fill_value.setter
Expand All @@ -426,22 +435,22 @@ def fill_value(self, fill_value):

@property
def nchunks(self):
""" Total number of chunks. """
"""Total number of chunks."""
return np.prod(self.cdata_shape)

@property
def nchunks_initialized(self):
""" The number of chunks that have been initialized with some data. """
"""The number of chunks that have been initialized with some data."""
return len(self._grid)

@property
def kchunks_initialized(self):
""" List of keys of chunks that have been initialized with some data. """
"""List of keys of chunks that have been initialized with some data."""
return set(self._grid.keys())

@property
def chunks_initialized(self):
""" List of copies of chunks that have been initialized with some data. """
"""List of copies of chunks that have been initialized with some data."""
return [
Chunk(
self._grid[k],
Expand All @@ -453,7 +462,7 @@ def chunks_initialized(self):

@property
def origin(self):
""" A tuple of floats describing the position in world coordinates (x,y,z) of the voxel (0,0,0). """
"""A tuple of floats describing the position in world coordinates (x,y,z) of the voxel (0,0,0)."""
return self._origin

@origin.setter
Expand All @@ -469,7 +478,7 @@ def origin(self, val):

@property
def spacing(self):
""" A tuple of floats describing the (width,height,length) of the cubical cells that compose the data set. """
"""A tuple of floats describing the (width,height,length) of the cubical cells that compose the data set."""
return self._spacing

@spacing.setter
Expand Down Expand Up @@ -720,7 +729,7 @@ def _run(self, *args, **kwargs):
return to_update, prev

def _get_keys_for_run(self, envelope, skip_neighbours):
""" Helper method to determine keys which Sparse will be iterated over during `run` method """
"""Helper method to determine keys which Sparse will be iterated over during `run` method"""
if envelope == (0, 0, 0):
keys = set(self._grid.keys())
else:
Expand All @@ -730,7 +739,7 @@ def _get_keys_for_run(self, envelope, skip_neighbours):
conv_size = np.array([2, 2, 2]) + np.ceil(
np.array(envelope) / np.array(self.chunks)
).astype(np.uint16)
neighbours = scipy.ndimage.filters.convolve(
neighbours = scipy.ndimage.convolve(
self.grid_mask.astype(np.uint16) != 0xFFFF,
np.ones(conv_size),
mode="constant",
Expand Down Expand Up @@ -1090,7 +1099,7 @@ def __setitem__(self, key, val):
key = slice_normalize(key, self.shape)
shape = slice_shape(key, self.shape)

if np.product(shape) == 0:
if np.prod(shape) == 0:
return

if np.shape(val) != shape:
Expand Down Expand Up @@ -1362,6 +1371,8 @@ def copy(self):
return s

def astype(self, dtype):
new_sparse = Sparse.empty_like(self, fill_value=dtype(self.fill_value), dtype=dtype)
new_sparse = Sparse.empty_like(
self, fill_value=dtype(self.fill_value), dtype=dtype
)
new_sparse.copy_from(self)
return new_sparse
8 changes: 4 additions & 4 deletions chunky3d/sparse_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from collections import Counter

import numpy as np
from skimage.morphology import skeletonize_3d
from skimage.morphology import skeletonize

from .helpers import slice_normalize, min_dtype, max_dtype
from .chunky import Sparse
Expand Down Expand Up @@ -54,7 +54,7 @@ def _try_import_itk_thickness(import_error=True):
except ImportError:
_have_itk = False
_have_itk_thickness = False

if not import_error:
return

Expand Down Expand Up @@ -293,7 +293,7 @@ def mul(sparse_a: Sparse, sparse_b: Sparse):

def add(sparse_a, sparse_b):
sparse_a.run_multivariate(lambda a, b: a + b[0], [sparse_b])
sparse_a.fill_value = sparse_a.fill_value + sparse_b.fill_value
sparse_a.fill_value = sparse_a.fill_value + sparse_b.fill_value


def subtract(sparse_a, sparse_b):
Expand Down Expand Up @@ -418,7 +418,7 @@ def thinning(sparse, envelope, multiprocesses=1):
"""1 pixel-thin wire skeletonization"""
sparse.run(
lambda data, prev: (
(skeletonize_3d(data) > 0).astype(data.dtype),
(skeletonize(data) > 0).astype(data.dtype),
prev,
),
envelope=envelope,
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ dill
msgpack
msgpack_numpy
numba
numpy
psutil
scipy
scikit-image
scikit-image
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,9 @@ def version(*parts):
'Topic :: Multimedia :: Graphics :: 3D Modeling',
'Topic :: Scientific/Engineering :: Medical Science Apps.',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
]
, project_urls={
'Source': 'https://github.com/K3D-tools/chunky3d',
Expand Down
10 changes: 5 additions & 5 deletions test/test_sparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def test_set_get(self):
def test_getitem(self):
shp = (234, 231, 128)
mga = np.random.rand(shp[0], shp[1], shp[2])
s = Sparse(shp, dtype=np.float_, chunks=(16, 32, 8), fill_value=0)
s = Sparse(shp, dtype=np.float64, chunks=(16, 32, 8), fill_value=0)
s.set((0, 0, 0), mga)

w2 = s[-138:-10:2, -223:-39:5, 120:128:1]
Expand All @@ -63,7 +63,7 @@ def test_getitem(self):
def test_getitem_simple_vs_slice(self):
shp = (234, 231, 128)
mga = np.random.rand(*shp)
s = Sparse(shp, dtype=np.float_, chunks=(16, 32, 8), fill_value=0)
s = Sparse(shp, dtype=np.float64, chunks=(16, 32, 8), fill_value=0)
s.set((0, 0, 0), mga)

for _ in range(10):
Expand All @@ -74,8 +74,8 @@ def test_getitem_simple_vs_slice(self):

def test_setitem_simple_vs_slice(self):
shp = (23, 12, 128)
s_point = Sparse(shp, dtype=np.float_, chunks=(16, 32, 8), fill_value=0)
s_slice = Sparse(shp, dtype=np.float_, chunks=(16, 32, 8), fill_value=0)
s_point = Sparse(shp, dtype=np.float64, chunks=(16, 32, 8), fill_value=0)
s_slice = Sparse(shp, dtype=np.float64, chunks=(16, 32, 8), fill_value=0)

s_point[0, 1, 2] = 3
s_slice[0:1, 1:2, 2:3] = 3
Expand Down Expand Up @@ -156,7 +156,7 @@ def test_memory_usage(self):
mask_size = np.zeros(s._block_shape, dtype=np.int32).__sizeof__()
after_grid_mask = s.__sizeof__()
self.assertEqual(after_grid_mask, defragmented + mask_size - None.__sizeof__())

def test_astype(self):
grid_shape = (4, 4, 4)
chunk_shape = 4
Expand Down

0 comments on commit 1d3bbed

Please sign in to comment.