| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- import numpy as np
- import scipy.ndimage as ndi
- from ..color import rgb2gray
- from ..util import img_as_float
- # TODO: when minimum numpy dependency is 1.25 use:
- # np..exceptions.AxisError instead of AxisError
- # and remove this try-except
- try:
- from numpy import AxisError
- except ImportError:
- from numpy.exceptions import AxisError
- __all__ = ['blur_effect']
- _EPSILON = np.spacing(np.float64(1))
- def blur_effect(image, h_size=11, channel_axis=None, reduce_func=np.max):
- """Compute a metric that indicates the strength of blur in an image
- (0 for no blur, 1 for maximal blur).
- Parameters
- ----------
- image : ndarray
- RGB or grayscale nD image. The input image is converted to grayscale
- before computing the blur metric.
- h_size : int, optional
- Size of the re-blurring filter.
- channel_axis : int or None, optional
- If None, the image is assumed to be grayscale (single-channel).
- Otherwise, this parameter indicates which axis of the array
- corresponds to color channels.
- reduce_func : callable, optional
- Function used to calculate the aggregation of blur metrics along all
- axes. If set to None, the entire list is returned, where the i-th
- element is the blur metric along the i-th axis.
- Returns
- -------
- blur : float (0 to 1) or list of floats
- Blur metric: by default, the maximum of blur metrics along all axes.
- Notes
- -----
- `h_size` must keep the same value in order to compare results between
- images. Most of the time, the default size (11) is enough. This means that
- the metric can clearly discriminate blur up to an average 11x11 filter; if
- blur is higher, the metric still gives good results but its values tend
- towards an asymptote.
- References
- ----------
- .. [1] Frederique Crete, Thierry Dolmiere, Patricia Ladret, and Marina
- Nicolas "The blur effect: perception and estimation with a new
- no-reference perceptual blur metric" Proc. SPIE 6492, Human Vision and
- Electronic Imaging XII, 64920I (2007)
- https://hal.archives-ouvertes.fr/hal-00232709
- :DOI:`10.1117/12.702790`
- """
- if channel_axis is not None:
- try:
- # ensure color channels are in the final dimension
- image = np.moveaxis(image, channel_axis, -1)
- except AxisError:
- print('channel_axis must be one of the image array dimensions')
- raise
- except TypeError:
- print('channel_axis must be an integer')
- raise
- image = rgb2gray(image)
- n_axes = image.ndim
- image = img_as_float(image)
- shape = image.shape
- B = []
- from ..filters import sobel
- slices = tuple([slice(2, s - 1) for s in shape])
- for ax in range(n_axes):
- filt_im = ndi.uniform_filter1d(image, h_size, axis=ax)
- im_sharp = np.abs(sobel(image, axis=ax))
- im_blur = np.abs(sobel(filt_im, axis=ax))
- # avoid numerical instabilities
- im_sharp = np.maximum(_EPSILON, im_sharp)
- im_blur = np.maximum(_EPSILON, im_blur)
- T = np.maximum(0, im_sharp - im_blur)
- M1 = np.sum(im_sharp[slices])
- M2 = np.sum(T[slices])
- B.append(np.abs(M1 - M2) / M1)
- return B if reduce_func is None else reduce_func(B)
|