Skip to content

Commit

Permalink
Fix canny and butterworth (recent CuPy and NumPy compatibility) (#574)
Browse files Browse the repository at this point in the history
It is possible in some cases for array scalar `low_threshold` to cause a failure to launch the non-maximum suppression kernel. This MR casts the array scalar to a float to avoid the issue.

I encountered this as a test failure locally with the existing `test_use_quantiles` test case for `canny` . I am unsure what underlying change caused this to suddenly start failing (possibly an underlying change in CuPy's kernel launching behavior).

A second issue with NumPy >= 1.25 compatibility for `butterworth` is also fixed in this MR. The `cupyx.scipy.fft` call raises an error in comparing an array fft_shape to a tuple shape internally. Casting `fft_shape` to a tuple avoids this.

Authors:
  - Gregory Lee (https://github.com/grlee77)

Approvers:
  - https://github.com/jakirkham

URL: #574
  • Loading branch information
grlee77 authored Jun 20, 2023
1 parent 91ad7ef commit 632881c
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 2 deletions.
7 changes: 7 additions & 0 deletions python/cucim/src/cucim/skimage/feature/_canny.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,13 @@ def _nonmaximum_suppression_bilinear(
kernel = _get_nonmax_kernel(large_int=large_int)

out = cp.empty_like(magnitude)

if isinstance(low_threshold, cp.ndarray):
# if array scalar was provided, make sure dtype matches other arrays
if low_threshold.ndim > 0:
raise ValueError("expected scalar low_treshold")
low_threshold = float(low_threshold)

kernel(isobel, jsobel, magnitude, eroded_mask, low_threshold, out)
return out

Expand Down
4 changes: 2 additions & 2 deletions python/cucim/src/cucim/skimage/filters/_fft_based.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ def butterworth(
elif npad > 0:
center_slice = tuple(slice(npad, s + npad) for s in image.shape)
image = pad(image, npad, mode='edge')
fft_shape = (image.shape if channel_axis is None
else np.delete(image.shape, channel_axis))
fft_shape = tuple(image.shape if channel_axis is None
else np.delete(image.shape, channel_axis))
is_real = cp.isrealobj(image)
float_dtype = _supported_float_type(image.dtype, allow_complex=True)
image = image.astype(float_dtype, copy=False)
Expand Down

0 comments on commit 632881c

Please sign in to comment.