From 2a562c118e50ba0279f331ad7fb8bd2794777d4e Mon Sep 17 00:00:00 2001 From: Gregory Lee Date: Thu, 27 Apr 2023 14:09:30 -0400 Subject: [PATCH] Fix `return_error='always'` behavior in phase_cross_correlation (#549) This MR updates behavior of the `return_error` argument to match the final version implemented in scikit-image 0.20. It also fixes a test suite error seen when recent `imageio` causes one of the test images to be loaded as RGB instead of grayscale. Authors: - Gregory Lee (https://github.com/grlee77) Approvers: - https://github.com/jakirkham URL: https://github.com/rapidsai/cucim/pull/549 --- .../registration/_phase_cross_correlation.py | 32 +++++++++++++++---- .../tests/test_phase_cross_correlation.py | 6 ++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/python/cucim/src/cucim/skimage/registration/_phase_cross_correlation.py b/python/cucim/src/cucim/skimage/registration/_phase_cross_correlation.py index 0937125d0..d38126cb8 100644 --- a/python/cucim/src/cucim/skimage/registration/_phase_cross_correlation.py +++ b/python/cucim/src/cucim/skimage/registration/_phase_cross_correlation.py @@ -5,6 +5,7 @@ import itertools import math +import warnings import cupy as cp import cupyx.scipy.ndimage as ndi @@ -220,7 +221,7 @@ def phase_cross_correlation(reference_image, moving_image, *, this parameter is set to ``True``, the *real* space cross-correlation is computed for each possible shift, and the shift with the highest cross-correlation within the overlapping area is returned. - return_error : bool, optional + return_error : bool, {"always"}, optional Returns error and phase difference if "always" is given. If False, or either ``reference_mask`` or ``moving_mask`` are given, only the shift is returned. @@ -253,10 +254,14 @@ def phase_cross_correlation(reference_image, moving_image, *, the axis order of the input array. error : float Translation invariant normalized RMS error between - ``reference_image`` and ``moving_image``. + ``reference_image`` and ``moving_image``. For masked cross-correlation + this error is not available and NaN is returned if ``return_error`` + is "always". phasediff : float Global phase difference between the two images (should be - zero if images are non-negative). + zero if images are non-negative). For masked cross-correlation + this phase difference is not available and NaN is returned if + ``return_error`` is "always". Notes ----- @@ -294,10 +299,25 @@ def phase_cross_correlation(reference_image, moving_image, *, Pattern Recognition, pp. 2918-2925 (2010). :DOI:`10.1109/CVPR.2010.5540032` """ + def warn_return_error(): + warnings.warn( + "In scikit-image 0.22, phase_cross_correlation will start " + "returning a tuple or 3 items (shift, error, phasediff) always. " + "To enable the new return behavior and silence this warning, use " + "return_error='always'.", + category=FutureWarning, + stacklevel=3, + ) + if (reference_mask is not None) or (moving_mask is not None): - return _masked_phase_cross_correlation(reference_image, moving_image, - reference_mask, moving_mask, - overlap_ratio) + shift = _masked_phase_cross_correlation(reference_image, moving_image, + reference_mask, moving_mask, + overlap_ratio) + if return_error == "always": + return shift, np.nan, np.nan + else: + warn_return_error() + return shift # images must be the same shape if reference_image.shape != moving_image.shape: diff --git a/python/cucim/src/cucim/skimage/registration/tests/test_phase_cross_correlation.py b/python/cucim/src/cucim/skimage/registration/tests/test_phase_cross_correlation.py index 5561b66c2..c3a960aff 100644 --- a/python/cucim/src/cucim/skimage/registration/tests/test_phase_cross_correlation.py +++ b/python/cucim/src/cucim/skimage/registration/tests/test_phase_cross_correlation.py @@ -180,6 +180,12 @@ def test_mismatch_offsets_size(): ) def test_disambiguate_2d(shift0, shift1): image = cp.array(eagle()[500:, 900:]) # use a highly textured image region + + # Protect against some versions of scikit-image + imagio loading as + # RGB instead of grayscale. + if image.ndim == 3: + image = image[..., 0] + shift = (shift0, shift1) origin0 = [] for s in shift: