"Fossies" - the Fresh Open Source Software Archive

Member "scikit-image-0.19.3/skimage/exposure/tests/test_exposure.py" (12 Jun 2022, 29371 Bytes) of package /linux/misc/scikit-image-0.19.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_exposure.py": 0.19.2_vs_0.19.3.

    1 import warnings
    2 
    3 import numpy as np
    4 import pytest
    5 from numpy.testing import (assert_allclose,
    6                            assert_almost_equal,
    7                            assert_array_almost_equal,
    8                            assert_array_equal,
    9                            assert_equal)
   10 
   11 from skimage import data
   12 from skimage import exposure
   13 from skimage import util
   14 from skimage.color import rgb2gray
   15 from skimage.exposure.exposure import intensity_range
   16 from skimage.util.dtype import dtype_range
   17 from skimage._shared._warnings import expected_warnings
   18 from skimage._shared.utils import _supported_float_type
   19 
   20 
   21 # Test integer histograms
   22 # =======================
   23 
   24 def test_wrong_source_range():
   25     im = np.array([-1, 100], dtype=np.int8)
   26     with pytest.raises(ValueError):
   27         frequencies, bin_centers = exposure.histogram(im,
   28                                                       source_range='foobar')
   29 
   30 
   31 def test_negative_overflow():
   32     im = np.array([-1, 100], dtype=np.int8)
   33     frequencies, bin_centers = exposure.histogram(im)
   34     assert_array_equal(bin_centers, np.arange(-1, 101))
   35     assert frequencies[0] == 1
   36     assert frequencies[-1] == 1
   37     assert_array_equal(frequencies[1:-1], 0)
   38 
   39 
   40 def test_all_negative_image():
   41     im = np.array([-100, -1], dtype=np.int8)
   42     frequencies, bin_centers = exposure.histogram(im)
   43     assert_array_equal(bin_centers, np.arange(-100, 0))
   44     assert frequencies[0] == 1
   45     assert frequencies[-1] == 1
   46     assert_array_equal(frequencies[1:-1], 0)
   47 
   48 
   49 def test_int_range_image():
   50     im = np.array([10, 100], dtype=np.int8)
   51     frequencies, bin_centers = exposure.histogram(im)
   52     assert_equal(len(bin_centers), len(frequencies))
   53     assert_equal(bin_centers[0], 10)
   54     assert_equal(bin_centers[-1], 100)
   55 
   56 
   57 def test_multichannel_int_range_image():
   58     im = np.array([[10, 5], [100, 102]], dtype=np.int8)
   59     frequencies, bin_centers = exposure.histogram(im, channel_axis=-1)
   60     for ch in range(im.shape[-1]):
   61         assert_equal(len(frequencies[ch]), len(bin_centers))
   62     assert_equal(bin_centers[0], 5)
   63     assert_equal(bin_centers[-1], 102)
   64 
   65 
   66 def test_peak_uint_range_dtype():
   67     im = np.array([10, 100], dtype=np.uint8)
   68     frequencies, bin_centers = exposure.histogram(im, source_range='dtype')
   69     assert_array_equal(bin_centers, np.arange(0, 256))
   70     assert_equal(frequencies[10], 1)
   71     assert_equal(frequencies[100], 1)
   72     assert_equal(frequencies[101], 0)
   73     assert_equal(frequencies.shape, (256,))
   74 
   75 
   76 def test_peak_int_range_dtype():
   77     im = np.array([10, 100], dtype=np.int8)
   78     frequencies, bin_centers = exposure.histogram(im, source_range='dtype')
   79     assert_array_equal(bin_centers, np.arange(-128, 128))
   80     assert_equal(frequencies[128+10], 1)
   81     assert_equal(frequencies[128+100], 1)
   82     assert_equal(frequencies[128+101], 0)
   83     assert_equal(frequencies.shape, (256,))
   84 
   85 
   86 def test_flat_uint_range_dtype():
   87     im = np.linspace(0, 255, 256, dtype=np.uint8)
   88     frequencies, bin_centers = exposure.histogram(im, source_range='dtype')
   89     assert_array_equal(bin_centers, np.arange(0, 256))
   90     assert_equal(frequencies.shape, (256,))
   91 
   92 
   93 def test_flat_int_range_dtype():
   94     im = np.linspace(-128, 128, 256, dtype=np.int8)
   95     frequencies, bin_centers = exposure.histogram(im, source_range='dtype')
   96     assert_array_equal(bin_centers, np.arange(-128, 128))
   97     assert_equal(frequencies.shape, (256,))
   98 
   99 
  100 @pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
  101 def test_peak_float_out_of_range_image(dtype):
  102     im = np.array([10, 100], dtype=dtype)
  103     frequencies, bin_centers = exposure.histogram(im, nbins=90)
  104     assert bin_centers.dtype == dtype
  105     # offset values by 0.5 for float...
  106     assert_array_equal(bin_centers, np.arange(10, 100) + 0.5)
  107 
  108 
  109 @pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
  110 def test_peak_float_out_of_range_dtype(dtype):
  111     im = np.array([10, 100], dtype=dtype)
  112     nbins = 10
  113     frequencies, bin_centers = exposure.histogram(im, nbins=nbins,
  114                                                   source_range='dtype')
  115     assert bin_centers.dtype == dtype
  116     assert_almost_equal(np.min(bin_centers), -0.9, 3)
  117     assert_almost_equal(np.max(bin_centers), 0.9, 3)
  118     assert_equal(len(bin_centers), 10)
  119 
  120 
  121 def test_normalize():
  122     im = np.array([0, 255, 255], dtype=np.uint8)
  123     frequencies, bin_centers = exposure.histogram(im, source_range='dtype',
  124                                                   normalize=False)
  125     expected = np.zeros(256)
  126     expected[0] = 1
  127     expected[-1] = 2
  128     assert_equal(frequencies, expected)
  129     frequencies, bin_centers = exposure.histogram(im, source_range='dtype',
  130                                                   normalize=True)
  131     expected /= 3.
  132     assert_equal(frequencies, expected)
  133 
  134 
  135 # Test multichannel histograms
  136 # ============================
  137 
  138 @pytest.mark.parametrize('source_range', ['dtype', 'image'])
  139 @pytest.mark.parametrize('dtype', [np.uint8, np.int16, np.float64])
  140 @pytest.mark.parametrize('channel_axis', [0, 1, -1])
  141 def test_multichannel_hist_common_bins_uint8(dtype, source_range,
  142                                              channel_axis):
  143     """Check that all channels use the same binning."""
  144     # Construct multichannel image with uniform values within each channel,
  145     # but the full range of values across channels.
  146     shape = (5, 5)
  147     channel_size = shape[0] * shape[1]
  148     imin, imax = dtype_range[dtype]
  149     im = np.stack(
  150         (
  151             np.full(shape, imin, dtype=dtype),
  152             np.full(shape, imax, dtype=dtype),
  153         ),
  154         axis=channel_axis
  155     )
  156     frequencies, bin_centers = exposure.histogram(
  157         im, source_range=source_range, channel_axis=channel_axis
  158     )
  159     if np.issubdtype(dtype, np.integer):
  160         assert_array_equal(bin_centers, np.arange(imin, imax + 1))
  161     assert frequencies[0][0] == channel_size
  162     assert frequencies[0][-1] == 0
  163     assert frequencies[1][0] == 0
  164     assert frequencies[1][-1] == channel_size
  165 
  166 
  167 # Test histogram equalization
  168 # ===========================
  169 
  170 np.random.seed(0)
  171 
  172 test_img_int = data.camera()
  173 # squeeze image intensities to lower image contrast
  174 test_img = util.img_as_float(test_img_int)
  175 test_img = exposure.rescale_intensity(test_img / 5. + 100)
  176 
  177 
  178 def test_equalize_uint8_approx():
  179     """Check integer bins used for uint8 images."""
  180     img_eq0 = exposure.equalize_hist(test_img_int)
  181     img_eq1 = exposure.equalize_hist(test_img_int, nbins=3)
  182     assert_allclose(img_eq0, img_eq1)
  183 
  184 
  185 def test_equalize_ubyte():
  186     img = util.img_as_ubyte(test_img)
  187     img_eq = exposure.equalize_hist(img)
  188 
  189     cdf, bin_edges = exposure.cumulative_distribution(img_eq)
  190     check_cdf_slope(cdf)
  191 
  192 
  193 @pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
  194 def test_equalize_float(dtype):
  195     img = util.img_as_float(test_img).astype(dtype, copy=False)
  196     img_eq = exposure.equalize_hist(img)
  197     assert img_eq.dtype == _supported_float_type(dtype)
  198 
  199     cdf, bin_edges = exposure.cumulative_distribution(img_eq)
  200     check_cdf_slope(cdf)
  201     assert bin_edges.dtype == _supported_float_type(dtype)
  202 
  203 
  204 def test_equalize_masked():
  205     img = util.img_as_float(test_img)
  206     mask = np.zeros(test_img.shape)
  207     mask[100:400, 100:400] = 1
  208     img_mask_eq = exposure.equalize_hist(img, mask=mask)
  209     img_eq = exposure.equalize_hist(img)
  210 
  211     cdf, bin_edges = exposure.cumulative_distribution(img_mask_eq)
  212     check_cdf_slope(cdf)
  213 
  214     assert not (img_eq == img_mask_eq).all()
  215 
  216 
  217 def check_cdf_slope(cdf):
  218     """Slope of cdf which should equal 1 for an equalized histogram."""
  219     norm_intensity = np.linspace(0, 1, len(cdf))
  220     slope, intercept = np.polyfit(norm_intensity, cdf, 1)
  221     assert 0.9 < slope < 1.1
  222 
  223 
  224 # Test intensity range
  225 # ====================
  226 
  227 
  228 @pytest.mark.parametrize("test_input,expected", [
  229     ('image', [0, 1]),
  230     ('dtype', [0, 255]),
  231     ((10, 20), [10, 20])
  232 ])
  233 def test_intensity_range_uint8(test_input, expected):
  234     image = np.array([0, 1], dtype=np.uint8)
  235     out = intensity_range(image, range_values=test_input)
  236     assert_array_equal(out, expected)
  237 
  238 
  239 @pytest.mark.parametrize("test_input,expected", [
  240     ('image', [0.1, 0.2]),
  241     ('dtype', [-1, 1]),
  242     ((0.3, 0.4), [0.3, 0.4])
  243 ])
  244 def test_intensity_range_float(test_input, expected):
  245     image = np.array([0.1, 0.2], dtype=np.float64)
  246     out = intensity_range(image, range_values=test_input)
  247     assert_array_equal(out, expected)
  248 
  249 
  250 def test_intensity_range_clipped_float():
  251     image = np.array([0.1, 0.2], dtype=np.float64)
  252     out = intensity_range(image, range_values='dtype', clip_negative=True)
  253     assert_array_equal(out, (0, 1))
  254 
  255 
  256 # Test rescale intensity
  257 # ======================
  258 
  259 uint10_max = 2**10 - 1
  260 uint12_max = 2**12 - 1
  261 uint14_max = 2**14 - 1
  262 uint16_max = 2**16 - 1
  263 
  264 
  265 def test_rescale_stretch():
  266     image = np.array([51, 102, 153], dtype=np.uint8)
  267     out = exposure.rescale_intensity(image)
  268     assert out.dtype == np.uint8
  269     assert_array_almost_equal(out, [0, 127, 255])
  270 
  271 
  272 def test_rescale_shrink():
  273     image = np.array([51., 102., 153.])
  274     out = exposure.rescale_intensity(image)
  275     assert_array_almost_equal(out, [0, 0.5, 1])
  276 
  277 
  278 @pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
  279 def test_rescale_in_range(dtype):
  280     image = np.array([51., 102., 153.], dtype=dtype)
  281     out = exposure.rescale_intensity(image, in_range=(0, 255))
  282     assert_array_almost_equal(out, [0.2, 0.4, 0.6], decimal=4)
  283     # with out_range='dtype', the output has the same dtype
  284     assert out.dtype == image.dtype
  285 
  286 
  287 def test_rescale_in_range_clip():
  288     image = np.array([51., 102., 153.])
  289     out = exposure.rescale_intensity(image, in_range=(0, 102))
  290     assert_array_almost_equal(out, [0.5, 1, 1])
  291 
  292 
  293 @pytest.mark.parametrize('dtype', [np.int8, np.int32, np.float16, np.float32,
  294                                    np.float64])
  295 def test_rescale_out_range(dtype):
  296     """Check that output range is correct.
  297 
  298     .. versionchanged:: 0.17
  299         This function used to return dtype matching the input dtype. It now
  300         matches the output.
  301 
  302     .. versionchanged:: 0.19
  303         float16 and float32 inputs now result in float32 output. Formerly they
  304         would give float64 outputs.
  305     """
  306     image = np.array([-10, 0, 10], dtype=dtype)
  307     out = exposure.rescale_intensity(image, out_range=(0, 127))
  308     assert out.dtype == _supported_float_type(image.dtype)
  309     assert_array_almost_equal(out, [0, 63.5, 127])
  310 
  311 
  312 def test_rescale_named_in_range():
  313     image = np.array([0, uint10_max, uint10_max + 100], dtype=np.uint16)
  314     out = exposure.rescale_intensity(image, in_range='uint10')
  315     assert_array_almost_equal(out, [0, uint16_max, uint16_max])
  316 
  317 
  318 def test_rescale_named_out_range():
  319     image = np.array([0, uint16_max], dtype=np.uint16)
  320     out = exposure.rescale_intensity(image, out_range='uint10')
  321     assert_array_almost_equal(out, [0, uint10_max])
  322 
  323 
  324 def test_rescale_uint12_limits():
  325     image = np.array([0, uint16_max], dtype=np.uint16)
  326     out = exposure.rescale_intensity(image, out_range='uint12')
  327     assert_array_almost_equal(out, [0, uint12_max])
  328 
  329 
  330 def test_rescale_uint14_limits():
  331     image = np.array([0, uint16_max], dtype=np.uint16)
  332     out = exposure.rescale_intensity(image, out_range='uint14')
  333     assert_array_almost_equal(out, [0, uint14_max])
  334 
  335 
  336 def test_rescale_all_zeros():
  337     image = np.zeros((2, 2), dtype=np.uint8)
  338     out = exposure.rescale_intensity(image)
  339     assert ~np.isnan(out).all()
  340     assert_array_almost_equal(out, image)
  341 
  342 
  343 def test_rescale_constant():
  344     image = np.array([130, 130], dtype=np.uint16)
  345     out = exposure.rescale_intensity(image, out_range=(0, 127))
  346     assert_array_almost_equal(out, [127, 127])
  347 
  348 
  349 def test_rescale_same_values():
  350     image = np.ones((2, 2))
  351     out = exposure.rescale_intensity(image)
  352     assert ~np.isnan(out).all()
  353     assert_array_almost_equal(out, image)
  354 
  355 
  356 @pytest.mark.parametrize(
  357     "in_range,out_range", [("image", "dtype"),
  358                            ("dtype", "image")]
  359 )
  360 def test_rescale_nan_warning(in_range, out_range):
  361     image = np.arange(12, dtype=float).reshape(3, 4)
  362     image[1, 1] = np.nan
  363 
  364     msg = (
  365         r"One or more intensity levels are NaN\."
  366         r" Rescaling will broadcast NaN to the full image\."
  367     )
  368 
  369     # 2019/11/10 Passing NaN to np.clip raises a DeprecationWarning for
  370     # versions above 1.17
  371     # TODO: Remove once NumPy removes this DeprecationWarning
  372     numpy_warning_1_17_plus = (
  373         "Passing `np.nan` to mean no clipping in np.clip"
  374     )
  375 
  376     if in_range == "image":
  377         exp_warn = [msg, numpy_warning_1_17_plus]
  378     else:
  379         exp_warn = [msg]
  380 
  381     with expected_warnings(exp_warn):
  382         exposure.rescale_intensity(image, in_range, out_range)
  383 
  384 
  385 @pytest.mark.parametrize(
  386     "out_range, out_dtype", [
  387         ('uint8', np.uint8),
  388         ('uint10', np.uint16),
  389         ('uint12', np.uint16),
  390         ('uint16', np.uint16),
  391         ('float', float),
  392     ]
  393 )
  394 def test_rescale_output_dtype(out_range, out_dtype):
  395     image = np.array([-128, 0, 127], dtype=np.int8)
  396     output_image = exposure.rescale_intensity(image, out_range=out_range)
  397     assert output_image.dtype == out_dtype
  398 
  399 
  400 def test_rescale_no_overflow():
  401     image = np.array([-128, 0, 127], dtype=np.int8)
  402     output_image = exposure.rescale_intensity(image, out_range=np.uint8)
  403     assert_array_equal(output_image, [0, 128, 255])
  404     assert output_image.dtype == np.uint8
  405 
  406 
  407 def test_rescale_float_output():
  408     image = np.array([-128, 0, 127], dtype=np.int8)
  409     output_image = exposure.rescale_intensity(image, out_range=(0, 255))
  410     assert_array_equal(output_image, [0, 128, 255])
  411     assert output_image.dtype == float
  412 
  413 
  414 def test_rescale_raises_on_incorrect_out_range():
  415     image = np.array([-128, 0, 127], dtype=np.int8)
  416     with pytest.raises(ValueError):
  417         _ = exposure.rescale_intensity(image, out_range='flat')
  418 
  419 
  420 # Test adaptive histogram equalization
  421 # ====================================
  422 
  423 @pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
  424 def test_adapthist_grayscale(dtype):
  425     """Test a grayscale float image
  426     """
  427     img = util.img_as_float(data.astronaut()).astype(dtype, copy=False)
  428     img = rgb2gray(img)
  429     img = np.dstack((img, img, img))
  430     adapted = exposure.equalize_adapthist(img, kernel_size=(57, 51),
  431                                           clip_limit=0.01, nbins=128)
  432     assert img.shape == adapted.shape
  433     assert adapted.dtype == _supported_float_type(dtype)
  434     snr_decimal = 3 if dtype != np.float16 else 2
  435     assert_almost_equal(peak_snr(img, adapted), 100.140, snr_decimal)
  436     assert_almost_equal(norm_brightness_err(img, adapted), 0.0529, 3)
  437 
  438 
  439 def test_adapthist_color():
  440     """Test an RGB color uint16 image
  441     """
  442     img = util.img_as_uint(data.astronaut())
  443     with warnings.catch_warnings(record=True) as w:
  444         warnings.simplefilter('always')
  445         hist, bin_centers = exposure.histogram(img)
  446         assert len(w) > 0
  447     adapted = exposure.equalize_adapthist(img, clip_limit=0.01)
  448 
  449     assert adapted.min() == 0
  450     assert adapted.max() == 1.0
  451     assert img.shape == adapted.shape
  452     full_scale = exposure.rescale_intensity(img)
  453     assert_almost_equal(peak_snr(full_scale, adapted), 109.393, 1)
  454     assert_almost_equal(norm_brightness_err(full_scale, adapted), 0.02, 2)
  455     return data, adapted
  456 
  457 
  458 def test_adapthist_alpha():
  459     """Test an RGBA color image
  460     """
  461     img = util.img_as_float(data.astronaut())
  462     alpha = np.ones((img.shape[0], img.shape[1]), dtype=float)
  463     img = np.dstack((img, alpha))
  464     adapted = exposure.equalize_adapthist(img)
  465     assert adapted.shape != img.shape
  466     img = img[:, :, :3]
  467     full_scale = exposure.rescale_intensity(img)
  468     assert img.shape == adapted.shape
  469     assert_almost_equal(peak_snr(full_scale, adapted), 109.393, 2)
  470     assert_almost_equal(norm_brightness_err(full_scale, adapted), 0.0248, 3)
  471 
  472 
  473 def test_adapthist_grayscale_Nd():
  474     """
  475     Test for n-dimensional consistency with float images
  476     Note: Currently if img.ndim == 3, img.shape[2] > 4 must hold for the image
  477     not to be interpreted as a color image by @adapt_rgb
  478     """
  479     # take 2d image, subsample and stack it
  480     img = util.img_as_float(data.astronaut())
  481     img = rgb2gray(img)
  482     a = 15
  483     img2d = util.img_as_float(img[0:-1:a, 0:-1:a])
  484     img3d = np.array([img2d] * (img.shape[0] // a))
  485 
  486     # apply CLAHE
  487     adapted2d = exposure.equalize_adapthist(img2d,
  488                                             kernel_size=5,
  489                                             clip_limit=0.05)
  490     adapted3d = exposure.equalize_adapthist(img3d,
  491                                             kernel_size=5,
  492                                             clip_limit=0.05)
  493 
  494     # check that dimensions of input and output match
  495     assert img2d.shape == adapted2d.shape
  496     assert img3d.shape == adapted3d.shape
  497 
  498     # check that the result from the stack of 2d images is similar
  499     # to the underlying 2d image
  500     assert np.mean(np.abs(adapted2d
  501                           - adapted3d[adapted3d.shape[0] // 2])) < 0.02
  502 
  503 
  504 def test_adapthist_constant():
  505     """Test constant image, float and uint
  506     """
  507     img = np.zeros((8, 8))
  508     img += 2
  509     img = img.astype(np.uint16)
  510     adapted = exposure.equalize_adapthist(img, 3)
  511     assert np.min(adapted) == np.max(adapted)
  512 
  513     img = np.zeros((8, 8))
  514     img += 0.1
  515     img = img.astype(np.float64)
  516     adapted = exposure.equalize_adapthist(img, 3)
  517     assert np.min(adapted) == np.max(adapted)
  518 
  519 
  520 def test_adapthist_borders():
  521     """Test border processing
  522     """
  523     img = rgb2gray(util.img_as_float(data.astronaut()))
  524 
  525     # maximize difference between orig and processed img
  526     img /= 100.
  527     img[img.shape[0] // 2, img.shape[1] // 2] = 1.
  528 
  529     # check borders are processed for different kernel sizes
  530     border_index = -1
  531     for kernel_size in range(51, 71, 2):
  532         adapted = exposure.equalize_adapthist(img, kernel_size, clip_limit=0.5)
  533         # Check last columns are processed
  534         assert norm_brightness_err(adapted[:, border_index],
  535                                    img[:, border_index]) > 0.1
  536         # Check last rows are processed
  537         assert norm_brightness_err(adapted[border_index, :],
  538                                    img[border_index, :]) > 0.1
  539 
  540 
  541 def test_adapthist_clip_limit():
  542     img_u = data.moon()
  543     img_f = util.img_as_float(img_u)
  544 
  545     # uint8 input
  546     img_clahe0 = exposure.equalize_adapthist(img_u, clip_limit=0)
  547     img_clahe1 = exposure.equalize_adapthist(img_u, clip_limit=1)
  548     assert_array_equal(img_clahe0, img_clahe1)
  549 
  550     # float64 input
  551     img_clahe0 = exposure.equalize_adapthist(img_f, clip_limit=0)
  552     img_clahe1 = exposure.equalize_adapthist(img_f, clip_limit=1)
  553     assert_array_equal(img_clahe0, img_clahe1)
  554 
  555 
  556 def peak_snr(img1, img2):
  557     """Peak signal to noise ratio of two images
  558 
  559     Parameters
  560     ----------
  561     img1 : array-like
  562     img2 : array-like
  563 
  564     Returns
  565     -------
  566     peak_snr : float
  567         Peak signal to noise ratio
  568     """
  569     if img1.ndim == 3:
  570         img1, img2 = rgb2gray(img1.copy()), rgb2gray(img2.copy())
  571     img1 = util.img_as_float(img1)
  572     img2 = util.img_as_float(img2)
  573     mse = 1. / img1.size * np.square(img1 - img2).sum()
  574     _, max_ = dtype_range[img1.dtype.type]
  575     return 20 * np.log(max_ / mse)
  576 
  577 
  578 def norm_brightness_err(img1, img2):
  579     """Normalized Absolute Mean Brightness Error between two images
  580 
  581     Parameters
  582     ----------
  583     img1 : array-like
  584     img2 : array-like
  585 
  586     Returns
  587     -------
  588     norm_brightness_error : float
  589         Normalized absolute mean brightness error
  590     """
  591     if img1.ndim == 3:
  592         img1, img2 = rgb2gray(img1), rgb2gray(img2)
  593     ambe = np.abs(img1.mean() - img2.mean())
  594     nbe = ambe / dtype_range[img1.dtype.type][1]
  595     return nbe
  596 
  597 
  598 # Test Gamma Correction
  599 # =====================
  600 
  601 def test_adjust_gamma_1x1_shape():
  602     """Check that the shape is maintained"""
  603     img = np.ones([1, 1])
  604     result = exposure.adjust_gamma(img, 1.5)
  605     assert img.shape == result.shape
  606 
  607 
  608 def test_adjust_gamma_one():
  609     """Same image should be returned for gamma equal to one"""
  610     image = np.random.uniform(0, 255, (8, 8))
  611     result = exposure.adjust_gamma(image, 1)
  612     assert_array_equal(result, image)
  613 
  614 
  615 @pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
  616 def test_adjust_gamma_zero(dtype):
  617     """White image should be returned for gamma equal to zero"""
  618     image = np.random.uniform(0, 255, (8, 8)).astype(dtype, copy=False)
  619     result = exposure.adjust_gamma(image, 0)
  620     dtype = image.dtype.type
  621     assert_array_equal(result, dtype_range[dtype][1])
  622     assert result.dtype == image.dtype
  623 
  624 
  625 def test_adjust_gamma_less_one():
  626     """Verifying the output with expected results for gamma
  627     correction with gamma equal to half"""
  628     image = np.arange(0, 255, 4, np.uint8).reshape((8, 8))
  629     expected = np.array([
  630         [  0,  31,  45,  55,  63,  71,  78,  84],
  631         [ 90,  95, 100, 105, 110, 115, 119, 123],
  632         [127, 131, 135, 139, 142, 146, 149, 153],
  633         [156, 159, 162, 165, 168, 171, 174, 177],
  634         [180, 183, 186, 188, 191, 194, 196, 199],
  635         [201, 204, 206, 209, 211, 214, 216, 218],
  636         [221, 223, 225, 228, 230, 232, 234, 236],
  637         [238, 241, 243, 245, 247, 249, 251, 253]], dtype=np.uint8)
  638 
  639     result = exposure.adjust_gamma(image, 0.5)
  640     assert_array_equal(result, expected)
  641 
  642 
  643 def test_adjust_gamma_greater_one():
  644     """Verifying the output with expected results for gamma
  645     correction with gamma equal to two"""
  646     image = np.arange(0, 255, 4, np.uint8).reshape((8, 8))
  647     expected = np.array([
  648         [  0,   0,   0,   0,   1,   1,   2,   3],
  649         [  4,   5,   6,   7,   9,  10,  12,  14],
  650         [ 16,  18,  20,  22,  25,  27,  30,  33],
  651         [ 36,  39,  42,  45,  49,  52,  56,  60],
  652         [ 64,  68,  72,  76,  81,  85,  90,  95],
  653         [100, 105, 110, 116, 121, 127, 132, 138],
  654         [144, 150, 156, 163, 169, 176, 182, 189],
  655         [196, 203, 211, 218, 225, 233, 241, 249]], dtype=np.uint8)
  656 
  657     result = exposure.adjust_gamma(image, 2)
  658     assert_array_equal(result, expected)
  659 
  660 
  661 def test_adjust_gamma_negative():
  662     image = np.arange(0, 255, 4, np.uint8).reshape((8, 8))
  663     with pytest.raises(ValueError):
  664         exposure.adjust_gamma(image, -1)
  665 
  666 
  667 def test_adjust_gamma_u8_overflow():
  668     img = 255 * np.ones((2, 2), dtype=np.uint8)
  669 
  670     assert np.all(exposure.adjust_gamma(img, gamma=1, gain=1.1) == 255)
  671 
  672 
  673 # Test Logarithmic Correction
  674 # ===========================
  675 
  676 @pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
  677 def test_adjust_log_1x1_shape(dtype):
  678     """Check that the shape is maintained"""
  679     img = np.ones([1, 1], dtype=dtype)
  680     result = exposure.adjust_log(img, 1)
  681     assert img.shape == result.shape
  682     assert result.dtype == dtype
  683 
  684 
  685 def test_adjust_log():
  686     """Verifying the output with expected results for logarithmic
  687     correction with multiplier constant multiplier equal to unity"""
  688     image = np.arange(0, 255, 4, np.uint8).reshape((8, 8))
  689     expected = np.array([
  690         [  0,   5,  11,  16,  22,  27,  33,  38],
  691         [ 43,  48,  53,  58,  63,  68,  73,  77],
  692         [ 82,  86,  91,  95, 100, 104, 109, 113],
  693         [117, 121, 125, 129, 133, 137, 141, 145],
  694         [149, 153, 157, 160, 164, 168, 172, 175],
  695         [179, 182, 186, 189, 193, 196, 199, 203],
  696         [206, 209, 213, 216, 219, 222, 225, 228],
  697         [231, 234, 238, 241, 244, 246, 249, 252]], dtype=np.uint8)
  698 
  699     result = exposure.adjust_log(image, 1)
  700     assert_array_equal(result, expected)
  701 
  702 
  703 def test_adjust_inv_log():
  704     """Verifying the output with expected results for inverse logarithmic
  705     correction with multiplier constant multiplier equal to unity"""
  706     image = np.arange(0, 255, 4, np.uint8).reshape((8, 8))
  707     expected = np.array([
  708         [  0,   2,   5,   8,  11,  14,  17,  20],
  709         [ 23,  26,  29,  32,  35,  38,  41,  45],
  710         [ 48,  51,  55,  58,  61,  65,  68,  72],
  711         [ 76,  79,  83,  87,  90,  94,  98, 102],
  712         [106, 110, 114, 118, 122, 126, 130, 134],
  713         [138, 143, 147, 151, 156, 160, 165, 170],
  714         [174, 179, 184, 188, 193, 198, 203, 208],
  715         [213, 218, 224, 229, 234, 239, 245, 250]], dtype=np.uint8)
  716 
  717     result = exposure.adjust_log(image, 1, True)
  718     assert_array_equal(result, expected)
  719 
  720 
  721 # Test Sigmoid Correction
  722 # =======================
  723 
  724 @pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
  725 def test_adjust_sigmoid_1x1_shape(dtype):
  726     """Check that the shape is maintained"""
  727     img = np.ones([1, 1], dtype=dtype)
  728     result = exposure.adjust_sigmoid(img, 1, 5)
  729     assert img.shape == result.shape
  730     assert result.dtype == dtype
  731 
  732 
  733 def test_adjust_sigmoid_cutoff_one():
  734     """Verifying the output with expected results for sigmoid correction
  735     with cutoff equal to one and gain of 5"""
  736     image = np.arange(0, 255, 4, np.uint8).reshape((8, 8))
  737     expected = np.array([
  738         [  1,   1,   1,   2,   2,   2,   2,   2],
  739         [  3,   3,   3,   4,   4,   4,   5,   5],
  740         [  5,   6,   6,   7,   7,   8,   9,  10],
  741         [ 10,  11,  12,  13,  14,  15,  16,  18],
  742         [ 19,  20,  22,  24,  25,  27,  29,  32],
  743         [ 34,  36,  39,  41,  44,  47,  50,  54],
  744         [ 57,  61,  64,  68,  72,  76,  80,  85],
  745         [ 89,  94,  99, 104, 108, 113, 118, 123]], dtype=np.uint8)
  746 
  747     result = exposure.adjust_sigmoid(image, 1, 5)
  748     assert_array_equal(result, expected)
  749 
  750 
  751 def test_adjust_sigmoid_cutoff_zero():
  752     """Verifying the output with expected results for sigmoid correction
  753     with cutoff equal to zero and gain of 10"""
  754     image = np.arange(0, 255, 4, np.uint8).reshape((8, 8))
  755     expected = np.array([
  756         [127, 137, 147, 156, 166, 175, 183, 191],
  757         [198, 205, 211, 216, 221, 225, 229, 232],
  758         [235, 238, 240, 242, 244, 245, 247, 248],
  759         [249, 250, 250, 251, 251, 252, 252, 253],
  760         [253, 253, 253, 253, 254, 254, 254, 254],
  761         [254, 254, 254, 254, 254, 254, 254, 254],
  762         [254, 254, 254, 254, 254, 254, 254, 254],
  763         [254, 254, 254, 254, 254, 254, 254, 254]], dtype=np.uint8)
  764 
  765     result = exposure.adjust_sigmoid(image, 0, 10)
  766     assert_array_equal(result, expected)
  767 
  768 
  769 def test_adjust_sigmoid_cutoff_half():
  770     """Verifying the output with expected results for sigmoid correction
  771     with cutoff equal to half and gain of 10"""
  772     image = np.arange(0, 255, 4, np.uint8).reshape((8, 8))
  773     expected = np.array([
  774         [  1,   1,   2,   2,   3,   3,   4,   5],
  775         [  5,   6,   7,   9,  10,  12,  14,  16],
  776         [ 19,  22,  25,  29,  34,  39,  44,  50],
  777         [ 57,  64,  72,  80,  89,  99, 108, 118],
  778         [128, 138, 148, 158, 167, 176, 184, 192],
  779         [199, 205, 211, 217, 221, 226, 229, 233],
  780         [236, 238, 240, 242, 244, 246, 247, 248],
  781         [249, 250, 250, 251, 251, 252, 252, 253]], dtype=np.uint8)
  782 
  783     result = exposure.adjust_sigmoid(image, 0.5, 10)
  784     assert_array_equal(result, expected)
  785 
  786 
  787 def test_adjust_inv_sigmoid_cutoff_half():
  788     """Verifying the output with expected results for inverse sigmoid
  789     correction with cutoff equal to half and gain of 10"""
  790     image = np.arange(0, 255, 4, np.uint8).reshape((8, 8))
  791     expected = np.array([
  792         [253, 253, 252, 252, 251, 251, 250, 249],
  793         [249, 248, 247, 245, 244, 242, 240, 238],
  794         [235, 232, 229, 225, 220, 215, 210, 204],
  795         [197, 190, 182, 174, 165, 155, 146, 136],
  796         [126, 116, 106,  96,  87,  78,  70,  62],
  797         [ 55,  49,  43,  37,  33,  28,  25,  21],
  798         [ 18,  16,  14,  12,  10,   8,   7,   6],
  799         [  5,   4,   4,   3,   3,   2,   2,   1]], dtype=np.uint8)
  800 
  801     result = exposure.adjust_sigmoid(image, 0.5, 10, True)
  802     assert_array_equal(result, expected)
  803 
  804 
  805 def test_is_low_contrast():
  806     image = np.linspace(0, 0.04, 100)
  807     assert exposure.is_low_contrast(image)
  808     image[-1] = 1
  809     assert exposure.is_low_contrast(image)
  810     assert not exposure.is_low_contrast(image, upper_percentile=100)
  811 
  812     image = (image * 255).astype(np.uint8)
  813     assert exposure.is_low_contrast(image)
  814     assert not exposure.is_low_contrast(image, upper_percentile=100)
  815 
  816     image = (image.astype(np.uint16)) * 2**8
  817     assert exposure.is_low_contrast(image)
  818     assert not exposure.is_low_contrast(image, upper_percentile=100)
  819 
  820 
  821 def test_is_low_contrast_boolean():
  822     image = np.zeros((8, 8), dtype=bool)
  823     assert exposure.is_low_contrast(image)
  824 
  825     image[:5] = 1
  826     assert not exposure.is_low_contrast(image)
  827 
  828 
  829 # Test negative input
  830 #####################
  831 
  832 @pytest.mark.parametrize("exposure_func", [exposure.adjust_gamma,
  833                                            exposure.adjust_log,
  834                                            exposure.adjust_sigmoid])
  835 def test_negative_input(exposure_func):
  836     image = np.arange(-10, 245, 4).reshape((8, 8)).astype(np.double)
  837     with pytest.raises(ValueError):
  838         exposure_func(image)
  839 
  840 
  841 # Test Dask Compatibility
  842 # =======================
  843 
  844 def test_dask_histogram():
  845     pytest.importorskip('dask', reason="dask python library is not installed")
  846     import dask.array as da
  847     dask_array = da.from_array(np.array([[0, 1], [1, 2]]), chunks=(1, 2))
  848     output_hist, output_bins = exposure.histogram(dask_array)
  849     expected_bins = [0, 1, 2]
  850     expected_hist = [1, 2, 1]
  851     assert np.allclose(expected_bins, output_bins)
  852     assert np.allclose(expected_hist, output_hist)