133 lines
4.4 KiB
Python
133 lines
4.4 KiB
Python
import functools
|
|
import warnings
|
|
from itertools import product
|
|
|
|
import numpy as np
|
|
|
|
from .dtype import img_as_float
|
|
|
|
|
|
def _rename_image_params(func):
|
|
wm_images = (
|
|
"Since version 0.24, the two input images are named `image0` and "
|
|
"`image1` (instead of `image1` and `image2`, respectively). Please use "
|
|
"`image0, image1` to avoid this warning for now, and avoid an error "
|
|
"from version 0.26 onwards."
|
|
)
|
|
|
|
wm_method = (
|
|
"Starting in version 0.24, all arguments following `image0, image1` "
|
|
"(including `method`) will be keyword-only. Please pass `method=` "
|
|
"in the function call to avoid this warning for now, and avoid an error "
|
|
"from version 0.26 onwards."
|
|
)
|
|
|
|
@functools.wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
# Turn all args into kwargs
|
|
for i, (value, param) in enumerate(
|
|
zip(args, ["image0", "image1", "method", "n_tiles"])
|
|
):
|
|
if i >= 2:
|
|
warnings.warn(wm_method, category=FutureWarning, stacklevel=2)
|
|
if param in kwargs:
|
|
raise ValueError(
|
|
f"{param} passed both as positional and keyword argument."
|
|
)
|
|
else:
|
|
kwargs[param] = value
|
|
args = tuple()
|
|
|
|
# Account for `image2` if given
|
|
if "image2" in kwargs.keys():
|
|
warnings.warn(wm_images, category=FutureWarning, stacklevel=2)
|
|
|
|
# Safely move `image2` to `image1` if that's empty
|
|
if "image1" in kwargs.keys():
|
|
# Safely move `image1` to `image0`
|
|
if "image0" in kwargs.keys():
|
|
raise ValueError(
|
|
"Three input images given; please use only `image0` "
|
|
"and `image1`."
|
|
)
|
|
kwargs["image0"] = kwargs.pop("image1")
|
|
kwargs["image1"] = kwargs.pop("image2")
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
@_rename_image_params
|
|
def compare_images(image0, image1, *, method='diff', n_tiles=(8, 8)):
|
|
"""
|
|
Return an image showing the differences between two images.
|
|
|
|
.. versionadded:: 0.16
|
|
|
|
Parameters
|
|
----------
|
|
image0, image1 : ndarray, shape (M, N)
|
|
Images to process, must be of the same shape.
|
|
|
|
.. versionchanged:: 0.24
|
|
`image1` and `image2` were renamed into `image0` and `image1`
|
|
respectively.
|
|
method : string, optional
|
|
Method used for the comparison.
|
|
Valid values are {'diff', 'blend', 'checkerboard'}.
|
|
Details are provided in the note section.
|
|
|
|
.. versionchanged:: 0.24
|
|
This parameter and following ones are keyword-only.
|
|
n_tiles : tuple, optional
|
|
Used only for the `checkerboard` method. Specifies the number
|
|
of tiles (row, column) to divide the image.
|
|
|
|
Returns
|
|
-------
|
|
comparison : ndarray, shape (M, N)
|
|
Image showing the differences.
|
|
|
|
Notes
|
|
-----
|
|
``'diff'`` computes the absolute difference between the two images.
|
|
``'blend'`` computes the mean value.
|
|
``'checkerboard'`` makes tiles of dimension `n_tiles` that display
|
|
alternatively the first and the second image. Note that images must be
|
|
2-dimensional to be compared with the checkerboard method.
|
|
"""
|
|
|
|
if image1.shape != image0.shape:
|
|
raise ValueError('Images must have the same shape.')
|
|
|
|
img1 = img_as_float(image0)
|
|
img2 = img_as_float(image1)
|
|
|
|
if method == 'diff':
|
|
comparison = np.abs(img2 - img1)
|
|
elif method == 'blend':
|
|
comparison = 0.5 * (img2 + img1)
|
|
elif method == 'checkerboard':
|
|
if img1.ndim != 2:
|
|
raise ValueError(
|
|
'Images must be 2-dimensional to be compared with the '
|
|
'checkerboard method.'
|
|
)
|
|
shapex, shapey = img1.shape
|
|
mask = np.full((shapex, shapey), False)
|
|
stepx = int(shapex / n_tiles[0])
|
|
stepy = int(shapey / n_tiles[1])
|
|
for i, j in product(range(n_tiles[0]), range(n_tiles[1])):
|
|
if (i + j) % 2 == 0:
|
|
mask[i * stepx : (i + 1) * stepx, j * stepy : (j + 1) * stepy] = True
|
|
comparison = np.zeros_like(img1)
|
|
comparison[mask] = img1[mask]
|
|
comparison[~mask] = img2[~mask]
|
|
else:
|
|
raise ValueError(
|
|
'Wrong value for `method`. '
|
|
'Must be either "diff", "blend" or "checkerboard".'
|
|
)
|
|
return comparison
|