scikit-image
132 строки · 4.4 Кб
1import functools
2import warnings
3from itertools import product
4
5import numpy as np
6
7from .dtype import img_as_float
8
9
10def _rename_image_params(func):
11wm_images = (
12"Since version 0.24, the two input images are named `image0` and "
13"`image1` (instead of `image1` and `image2`, respectively). Please use "
14"`image0, image1` to avoid this warning for now, and avoid an error "
15"from version 0.26 onwards."
16)
17
18wm_method = (
19"Starting in version 0.24, all arguments following `image0, image1` "
20"(including `method`) will be keyword-only. Please pass `method=` "
21"in the function call to avoid this warning for now, and avoid an error "
22"from version 0.26 onwards."
23)
24
25@functools.wraps(func)
26def wrapper(*args, **kwargs):
27# Turn all args into kwargs
28for i, (value, param) in enumerate(
29zip(args, ["image0", "image1", "method", "n_tiles"])
30):
31if i >= 2:
32warnings.warn(wm_method, category=FutureWarning, stacklevel=2)
33if param in kwargs:
34raise ValueError(
35f"{param} passed both as positional and keyword argument."
36)
37else:
38kwargs[param] = value
39args = tuple()
40
41# Account for `image2` if given
42if "image2" in kwargs.keys():
43warnings.warn(wm_images, category=FutureWarning, stacklevel=2)
44
45# Safely move `image2` to `image1` if that's empty
46if "image1" in kwargs.keys():
47# Safely move `image1` to `image0`
48if "image0" in kwargs.keys():
49raise ValueError(
50"Three input images given; please use only `image0` "
51"and `image1`."
52)
53kwargs["image0"] = kwargs.pop("image1")
54kwargs["image1"] = kwargs.pop("image2")
55
56return func(*args, **kwargs)
57
58return wrapper
59
60
61@_rename_image_params
62def compare_images(image0, image1, *, method='diff', n_tiles=(8, 8)):
63"""
64Return an image showing the differences between two images.
65
66.. versionadded:: 0.16
67
68Parameters
69----------
70image0, image1 : ndarray, shape (M, N)
71Images to process, must be of the same shape.
72
73.. versionchanged:: 0.24
74`image1` and `image2` were renamed into `image0` and `image1`
75respectively.
76method : string, optional
77Method used for the comparison.
78Valid values are {'diff', 'blend', 'checkerboard'}.
79Details are provided in the note section.
80
81.. versionchanged:: 0.24
82This parameter and following ones are keyword-only.
83n_tiles : tuple, optional
84Used only for the `checkerboard` method. Specifies the number
85of tiles (row, column) to divide the image.
86
87Returns
88-------
89comparison : ndarray, shape (M, N)
90Image showing the differences.
91
92Notes
93-----
94``'diff'`` computes the absolute difference between the two images.
95``'blend'`` computes the mean value.
96``'checkerboard'`` makes tiles of dimension `n_tiles` that display
97alternatively the first and the second image. Note that images must be
982-dimensional to be compared with the checkerboard method.
99"""
100
101if image1.shape != image0.shape:
102raise ValueError('Images must have the same shape.')
103
104img1 = img_as_float(image0)
105img2 = img_as_float(image1)
106
107if method == 'diff':
108comparison = np.abs(img2 - img1)
109elif method == 'blend':
110comparison = 0.5 * (img2 + img1)
111elif method == 'checkerboard':
112if img1.ndim != 2:
113raise ValueError(
114'Images must be 2-dimensional to be compared with the '
115'checkerboard method.'
116)
117shapex, shapey = img1.shape
118mask = np.full((shapex, shapey), False)
119stepx = int(shapex / n_tiles[0])
120stepy = int(shapey / n_tiles[1])
121for i, j in product(range(n_tiles[0]), range(n_tiles[1])):
122if (i + j) % 2 == 0:
123mask[i * stepx : (i + 1) * stepx, j * stepy : (j + 1) * stepy] = True
124comparison = np.zeros_like(img1)
125comparison[mask] = img1[mask]
126comparison[~mask] = img2[~mask]
127else:
128raise ValueError(
129'Wrong value for `method`. '
130'Must be either "diff", "blend" or "checkerboard".'
131)
132return comparison
133