Skip to content

Commit

Permalink
Merge pull request #403 from jakirkham/branch-22.10-merge-22.08
Browse files Browse the repository at this point in the history
Forward-merge branch-22.08 to branch-22.10 [skip gpuci]
  • Loading branch information
ajschmidt8 authored Sep 2, 2022
2 parents 36e7f3b + cd5deb8 commit 90fc72a
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 42 deletions.
48 changes: 46 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,53 @@

Please see https://github.com/rapidsai/cucim/releases/tag/v22.10.00a for the latest changes to this development branch.

# cuCIM 22.08.00 (Date TBD)
# cuCIM 22.08.00 (17 Aug 2022)

Please see https://github.com/rapidsai/cucim/releases/tag/v22.08.00a for the latest changes to this development branch.
## 🚨 Breaking Changes

- Stain extraction: use a less strict condition across channels when thresholding ([#316](https://github.com/rapidsai/cucim/pull/316)) [@grlee77](https://github.com/grlee77)

## 🐛 Bug Fixes

- create SimilarityTransform using CuPy 9.x-compatible indexing ([#365](https://github.com/rapidsai/cucim/pull/365)) [@grlee77](https://github.com/grlee77)
- Add `__init__.py` in `cucim.core` ([#359](https://github.com/rapidsai/cucim/pull/359)) [@jakirkham](https://github.com/jakirkham)
- Stain extraction: use a less strict condition across channels when thresholding ([#316](https://github.com/rapidsai/cucim/pull/316)) [@grlee77](https://github.com/grlee77)
- Incorporate bug fixes from skimage 0.19.3 ([#312](https://github.com/rapidsai/cucim/pull/312)) [@grlee77](https://github.com/grlee77)
- fix RawKernel bug for canny filter when quantiles are used ([#310](https://github.com/rapidsai/cucim/pull/310)) [@grlee77](https://github.com/grlee77)

## 📖 Documentation

- Defer loading of `custom.js` ([#383](https://github.com/rapidsai/cucim/pull/383)) [@galipremsagar](https://github.com/galipremsagar)
- add cucim.core.morphology to API docs + other docstring fixes ([#367](https://github.com/rapidsai/cucim/pull/367)) [@grlee77](https://github.com/grlee77)
- Update README.md ([#361](https://github.com/rapidsai/cucim/pull/361)) [@HesAnEasyCoder](https://github.com/HesAnEasyCoder)
- remove unimplemented functions from See Also and fix version numbers in deprecation warnings ([#356](https://github.com/rapidsai/cucim/pull/356)) [@grlee77](https://github.com/grlee77)
- Forward-merge branch-22.06 to branch-22.08 ([#344](https://github.com/rapidsai/cucim/pull/344)) [@grlee77](https://github.com/grlee77)
- Update README.md ([#315](https://github.com/rapidsai/cucim/pull/315)) [@HesAnEasyCoder](https://github.com/HesAnEasyCoder)
- Update index.rst ([#314](https://github.com/rapidsai/cucim/pull/314)) [@HesAnEasyCoder](https://github.com/HesAnEasyCoder)
- Update PyPI package documentation for v22.06.00 ([#311](https://github.com/rapidsai/cucim/pull/311)) [@gigony](https://github.com/gigony)

## 🚀 New Features

- Add segmentation with the Chan-Vese active contours method ([#343](https://github.com/rapidsai/cucim/pull/343)) [@grlee77](https://github.com/grlee77)
- Add cucim.skimage.morphology.medial_axis ([#342](https://github.com/rapidsai/cucim/pull/342)) [@grlee77](https://github.com/grlee77)
- Add cucim.skimage.segmentation.expand_labels ([#341](https://github.com/rapidsai/cucim/pull/341)) [@grlee77](https://github.com/grlee77)
- Add Euclidean distance transform for images/volumes ([#318](https://github.com/rapidsai/cucim/pull/318)) [@grlee77](https://github.com/grlee77)

## 🛠️ Improvements

- Revert "Allow CuPy 11" ([#362](https://github.com/rapidsai/cucim/pull/362)) [@galipremsagar](https://github.com/galipremsagar)
- Fix issues with day & night modes in python docs ([#360](https://github.com/rapidsai/cucim/pull/360)) [@galipremsagar](https://github.com/galipremsagar)
- Allow CuPy 11 ([#357](https://github.com/rapidsai/cucim/pull/357)) [@jakirkham](https://github.com/jakirkham)
- more efficient separable convolution ([#355](https://github.com/rapidsai/cucim/pull/355)) [@grlee77](https://github.com/grlee77)
- Support resolution and spacing metadata ([#349](https://github.com/rapidsai/cucim/pull/349)) [@gigony](https://github.com/gigony)
- Performance optimizations to morphological segmentation functions ([#340](https://github.com/rapidsai/cucim/pull/340)) [@grlee77](https://github.com/grlee77)
- benchmarks: avoid use of deprecated pandas API ([#339](https://github.com/rapidsai/cucim/pull/339)) [@grlee77](https://github.com/grlee77)
- Reduce memory overhead and improve performance of normalize_colors_pca ([#328](https://github.com/rapidsai/cucim/pull/328)) [@grlee77](https://github.com/grlee77)
- Protect against obscure divide by zero error in edge case of `normalize_colors_pca` ([#327](https://github.com/rapidsai/cucim/pull/327)) [@grlee77](https://github.com/grlee77)
- complete parametrization of cucim.skimage benchmarks ([#324](https://github.com/rapidsai/cucim/pull/324)) [@grlee77](https://github.com/grlee77)
- parameterization of `filters` and `features` benchmarks (v2) ([#322](https://github.com/rapidsai/cucim/pull/322)) [@grlee77](https://github.com/grlee77)
- Add a fast histogram-based median filter ([#317](https://github.com/rapidsai/cucim/pull/317)) [@grlee77](https://github.com/grlee77)
- Remove custom compiler environment variables ([#307](https://github.com/rapidsai/cucim/pull/307)) [@ajschmidt8](https://github.com/ajschmidt8)

# cuCIM 22.06.00 (7 Jun 2022)

Expand Down
60 changes: 52 additions & 8 deletions python/cucim/src/cucim/core/operations/morphology/_pba_2d.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,40 @@
import functools
import math
import numbers
import os


import cupy

try:
# math.lcm was introduced in Python 3.9
from math import lcm
except ImportError:

"""Fallback implementation of least common multiple (lcm)
TODO: remove once minimum Python requirement is >= 3.9
"""

def _lcm(a, b):
return abs(b * (a // math.gcd(a, b)))

@functools.lru_cache()
def lcm(*args):
nargs = len(args)
if not all(isinstance(a, numbers.Integral) for a in args):
raise TypeError("all arguments must be integers")
if nargs == 0:
return 1
res = int(args[0])
if nargs == 1:
return abs(res)
for i in range(1, nargs):
x = int(args[i])
res = _lcm(res, x)
return res


pba2d_defines_template = """
// MARKER is used to mark blank pixels in the texture.
Expand Down Expand Up @@ -119,27 +151,39 @@ def _pba_2d(arr, sampling=None, return_distances=True, return_indices=False,
# if len(sampling) != 2:
# raise ValueError("sampling must be a sequence of two values.")

padded_size = math.ceil(max(arr.shape) / block_size) * block_size
if block_params is None:
# should be <= size / 64. sy must be a multiple of m1
m1 = max(1, min(padded_size // block_size, 32))
padded_size = math.ceil(max(arr.shape) / block_size) * block_size

# should be <= size / block_size. sy must be a multiple of m1
m1 = padded_size // block_size
# size must be a multiple of m2
m2 = max(1, min(padded_size // block_size, 32))
m2 = max(1, min(padded_size // block_size, block_size))
# m2 must also be a power of two
m2 = 2**math.floor(math.log2(m2))
if padded_size % m2 != 0:
raise RuntimeError("error in setting default m2")

# should be <= 64. texture size must be a multiple of m3
m3 = min(min(m1, m2), 2)
else:
if any(p < 1 for p in block_params):
raise ValueError("(m1, m2, m3) in blockparams must be >= 1")
m1, m2, m3 = block_params
if math.log2(m2) % 1 > 1e-5:
raise ValueError("m2 must be a power of 2")
multiple = lcm(block_size, m1, m2, m3)
padded_size = math.ceil(max(arr.shape) / multiple) * multiple

if m1 > padded_size // block_size:
raise ValueError("m1 too large. must be <= arr.shape[0] // 32")
raise ValueError(
f"m1 too large. must be <= padded arr.shape[0] // {block_size}"
)
if m2 > padded_size // block_size:
raise ValueError("m2 too large. must be <= arr.shape[1] // 32")
raise ValueError(
f"m2 too large. must be <= padded arr.shape[1] // {block_size}"
)
if m3 > padded_size // block_size:
raise ValueError(
f"m3 too large. must be <= padded arr.shape[1] // {block_size}"
)
for m in (m1, m2, m3):
if padded_size % m != 0:
raise ValueError(
Expand Down
32 changes: 1 addition & 31 deletions python/cucim/src/cucim/core/operations/morphology/_pba_3d.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,10 @@
import functools
import math
import numbers
import os

import cupy
import numpy as np

from ._pba_2d import _get_block_size

try:
# math.lcm was introduced in Python 3.9
from math import lcm
except ImportError:

"""Fallback implementation of least common multiple (lcm)
TODO: remove once minimum Python requirement is >= 3.9
"""

def _lcm(a, b):
return abs(b * (a // math.gcd(a, b)))

@functools.lru_cache()
def lcm(*args):
nargs = len(args)
if not all(isinstance(a, numbers.Integral) for a in args):
raise TypeError("all arguments must be integers")
if nargs == 0:
return 1
res = int(args[0])
if nargs == 1:
return abs(res)
for i in range(1, nargs):
x = int(args[i])
res = _lcm(res, x)
return res
from ._pba_2d import _get_block_size, lcm


pba3d_defines_template = """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def assert_percentile_equal(arr1, arr2, pct=95):
((384, 256), (1.5, 1.5)),
((14, 32, 50), None),
((50, 32, 24), (2, 2, 2)),
]
],
)
@pytest.mark.parametrize('density', [5, 50, 95])
@pytest.mark.parametrize('block_params', [None, (1, 1, 1)])
Expand Down Expand Up @@ -65,6 +65,60 @@ def test_distance_transform_edt(
assert_percentile_equal(out, expected, pct=95)


@pytest.mark.parametrize(
'shape',
(
[(s,) * 2 for s in range(512, 512 + 32)]
+ [(s,) * 2 for s in range(1024, 1024 + 16)]
+ [(s,) * 2 for s in range(2050, 2050)]
+ [(s,) * 2 for s in range(4100, 4100)]
),
)
@pytest.mark.parametrize('density', [2, 98])
def test_distance_transform_edt_additional_shapes(shape, density):

kwargs_scipy = dict(return_distances=True, return_indices=False)
kwargs_cucim = copy(kwargs_scipy)
img = binary_image(shape, pct_true=density)
distances = distance_transform_edt(img, **kwargs_cucim)
expected = ndi_cpu.distance_transform_edt(cp.asnumpy(img), **kwargs_scipy)
cp.testing.assert_allclose(distances, expected)


@pytest.mark.parametrize(
'shape',
[(s,) * 2 for s in range(1024, 1024 + 4)],
)
@pytest.mark.parametrize(
'block_params',
[(1, 1, 1), (5, 4, 2), (3, 8, 4), (7, 16, 1), (11, 32, 3), (1, 1, 16)]
)
def test_distance_transform_edt_block_params(shape, block_params):

kwargs_scipy = dict(return_distances=True, return_indices=False)
kwargs_cucim = copy(kwargs_scipy)
kwargs_cucim['block_params'] = block_params
img = binary_image(shape, pct_true=4)
distances = distance_transform_edt(img, **kwargs_cucim)
expected = ndi_cpu.distance_transform_edt(cp.asnumpy(img), **kwargs_scipy)
cp.testing.assert_allclose(distances, expected)


@pytest.mark.parametrize(
'block_params', [
(0, 1, 1), (1, 0, 1), (1, 1, 0), # no elements can be < 1
(1, 3, 1), (1, 5, 1), (1, 7, 1), # 2nd element must be a power of 2
(128, 1, 1), # m1 too large for the array size
(1, 128, 1), # m2 too large for the array size
(1, 1, 128), # m3 too large for the array size
]
)
def test_distance_transform_edt_block_params_invalid(block_params):
img = binary_image((512, 512), pct_true=4)
with pytest.raises(ValueError):
distance_transform_edt(img, block_params=block_params)


@pytest.mark.parametrize('return_indices', [False, True])
@pytest.mark.parametrize('return_distances', [False, True])
@pytest.mark.parametrize(
Expand Down

0 comments on commit 90fc72a

Please sign in to comment.