From 1b30c68d285ba89fd6ccfea292fdc7b6eff6986a Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 7 Jun 2015 20:20:53 -0500 Subject: [PATCH 01/17] # This is a combination of 10 commits. # The first commit's message is: Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports # This is the 2nd commit message: Style fixes # This is the 3rd commit message: Add a deprecation warning and add to api_changes.txt # This is the 4th commit message: Update TODO and switch to 0.13 deprecation # This is the 5th commit message: Preserve the current API as much as possible and defer to 0.14 # This is the 6th commit message: Move the new kwarg to the very end # This is the 7th commit message: Clarify deprecation warning # This is the 8th commit message: Update to use row/col in clahe # This is the 9th commit message: Update docstring # This is the 10th commit message: Use optimal_step to set up view_as_windows --- TODO.txt | 6 + doc/source/api_changes.txt | 2 + skimage/exposure/_adapthist.py | 165 +++++++++++------------- skimage/exposure/tests/test_exposure.py | 18 ++- 4 files changed, 97 insertions(+), 94 deletions(-) diff --git a/TODO.txt b/TODO.txt index 98e8653b..a9a06a6c 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,5 +1,10 @@ Remember to list any API changes below in `doc/source/api_changes.txt`. +Version 0.14 +------------ +* Remove deprecated ``ntiles_*` kwargs in ``equalize_adapthist``. + + Version 0.13 ------------ * Remove deprecated `None` defaults for `skimage.exposure.rescale_intensity` @@ -12,6 +17,7 @@ Version 0.13 `hprewitt`, `vprewitt`, `roberts_positive_diagonal`, `roberts_negative_diagonal` in `skimage/filters/edges.py` + Version 0.12 ------------ * Change `label` to mark background as 0, not -1, which is consistent with diff --git a/doc/source/api_changes.txt b/doc/source/api_changes.txt index a8edfc3d..e87445b3 100644 --- a/doc/source/api_changes.txt +++ b/doc/source/api_changes.txt @@ -1,5 +1,7 @@ Version 0.12 ------------ +- ``equalize_adapthist`` now takes a ``kernel_size`` keyword argument, replacing + the ``ntiles_*`` arguments. - The functions ``blob_dog``, ``blob_log`` and ``blob_doh`` now return float arrays instead of integer arrays. diff --git a/skimage/exposure/_adapthist.py b/skimage/exposure/_adapthist.py index b71916f5..7d79dc5e 100644 --- a/skimage/exposure/_adapthist.py +++ b/skimage/exposure/_adapthist.py @@ -13,21 +13,22 @@ Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes with no guarantee. """ +from __future__ import division +import numbers import numpy as np from .. import img_as_float, img_as_uint from ..color.adapt_rgb import adapt_rgb, hsv_value from ..exposure import rescale_intensity -from ..util import view_as_blocks, pad +from ..util import view_as_windows +from .._shared.utils import skimage_deprecation, warnings -MAX_REG_X = 16 # max. # contextual regions in x-direction */ -MAX_REG_Y = 16 # max. # contextual regions in y-direction */ NR_OF_GREY = 2 ** 14 # number of grayscale levels to use in CLAHE algorithm @adapt_rgb(hsv_value) def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01, - nbins=256): + nbins=256, kernel_size=None): """Contrast Limited Adaptive Histogram Equalization (CLAHE). An algorithm for local contrast enhancement, that uses histograms computed @@ -38,10 +39,14 @@ def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01, ---------- image : array-like Input image. - ntiles_x : int, optional - Number of tile regions in the X direction. Ranges between 1 and 16. - ntiles_y : int, optional - Number of tile regions in the Y direction. Ranges between 1 and 16. + kernel_size: integer or 2-tuple + Defines the shape of contextual regions used in the algorithm. + If an integer is given, the shape will be a square of + sidelength given by this value. + ntiles_x : int, optional (deprecated in favor of ``kernel_size``) + Number of tile regions in the X direction (horizontal). + ntiles_y : int, optional (deprecated if favor of ``kernel_size``) + Number of tile regions in the Y direction (vertical). clip_limit : float: optional Clipping limit, normalized between 0 and 1 (higher values give more contrast). @@ -64,10 +69,6 @@ def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01, - The CLAHE algorithm is run on the V (Value) channel - The image is converted back to RGB space and returned * For RGBA images, the original alpha channel is removed. - * The CLAHE algorithm relies on image blocks of equal size. This may - result in extra border pixels that would not be handled. In that case, - we pad the image with a repeat of the border pixels, apply the - algorithm, and then trim the image to original size. References ---------- @@ -76,23 +77,34 @@ def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01, """ image = img_as_uint(image) image = rescale_intensity(image, out_range=(0, NR_OF_GREY - 1)) - out = _clahe(image, ntiles_x, ntiles_y, clip_limit * nbins, nbins) - image[:out.shape[0], :out.shape[1]] = out + if kernel_size is None: + warnings.warn('`ntiles_*` have been deprecated in favor of ' + '`kernel_size`. The `ntiles_*` keyword arguments ' + 'will be removed in v0.14', skimage_deprecation) + ntiles_x = ntiles_x or 8 + ntiles_y = ntiles_y or 8 + kernel_size = (np.round(image.shape[0] / ntiles_y), + np.round(image.shape[1] / ntiles_x)) + + if isinstance(kernel_size, numbers.Number): + kernel_size = (kernel_size, kernel_size) + + kernel_size = [int(k) for k in kernel_size] + + image = _clahe(image, kernel_size, clip_limit * nbins, nbins) image = img_as_float(image) return rescale_intensity(image) -def _clahe(image, ntiles_x, ntiles_y, clip_limit, nbins=128): +def _clahe(image, kernel_size, clip_limit, nbins=128): """Contrast Limited Adaptive Histogram Equalization. Parameters ---------- image : array-like Input image. - ntiles_x : int, optional - Number of tile regions in the X direction. Ranges between 2 and 16. - ntiles_y : int, optional - Number of tile regions in the Y direction. Ranges between 2 and 16. + kernel_size: 2-tuple + Defines the shape of contextual regions used in the algorithm. clip_limit : float, optional Normalized clipping limit (higher values give more contrast). nbins : int, optional @@ -109,40 +121,21 @@ def _clahe(image, ntiles_x, ntiles_y, clip_limit, nbins=128): minimum and maximum value as the input image. A clip limit smaller than 1 results in standard (non-contrast limited) AHE. """ - ntiles_x = min(ntiles_x, MAX_REG_X) - ntiles_y = min(ntiles_y, MAX_REG_Y) if clip_limit == 1.0: return image # is OK, immediately returns original image. - h_inner = image.shape[0] - image.shape[0] % ntiles_y - w_inner = image.shape[1] - image.shape[1] % ntiles_x - - # make the tile size divisible by 2 - h_inner -= h_inner % (2 * ntiles_y) - w_inner -= w_inner % (2 * ntiles_x) - - orig_shape = image.shape - width = w_inner // ntiles_x # Actual size of contextual regions - height = h_inner // ntiles_y - - if h_inner != image.shape[0]: - ntiles_y += 1 - if w_inner != image.shape[1]: - ntiles_x += 1 - if h_inner != image.shape[1] or w_inner != image.shape[0]: - h_pad = height * ntiles_y - image.shape[0] - w_pad = width * ntiles_x - image.shape[1] - image = pad(image, ((0, h_pad), (0, w_pad)), mode='reflect') - h_inner, w_inner = image.shape - bin_size = 1 + NR_OF_GREY // nbins lut = np.arange(NR_OF_GREY) lut //= bin_size - img_blocks = view_as_blocks(image, (height, width)) - map_array = np.zeros((ntiles_y, ntiles_x, nbins), dtype=int) - n_pixels = width * height + img_view = view_as_windows(image, kernel_size, optimal_step=True) + nr, nc = img_view.shape[:2] + height = int(image.shape[0] / nr) + width = int(image.shape[1] / nc) + + map_array = np.zeros((nr, nc, nbins), dtype=int) + n_pixels = height * width if clip_limit > 0.0: # Calculate actual cliplimit clip_limit = int(clip_limit * (width * height) / nbins) @@ -152,63 +145,61 @@ def _clahe(image, ntiles_x, ntiles_y, clip_limit, nbins=128): clip_limit = NR_OF_GREY # Large value, do not clip (AHE) # Calculate greylevel mappings for each contextual region - for y in range(ntiles_y): - for x in range(ntiles_x): - sub_img = img_blocks[y, x] + for r in range(nr): + for c in range(nc): + sub_img = img_view[r, c] hist = lut[sub_img.ravel()] hist = np.bincount(hist) hist = np.append(hist, np.zeros(nbins - hist.size, dtype=int)) hist = clip_histogram(hist, clip_limit) hist = map_histogram(hist, 0, NR_OF_GREY - 1, n_pixels) - map_array[y, x] = hist + map_array[r, c] = hist # Interpolate greylevel mappings to get CLAHE image - ystart = 0 - for y in range(ntiles_y + 1): - xstart = 0 - if y == 0: # special case: top row - ystep = height / 2.0 - yU = 0 - yB = 0 - elif y == ntiles_y: # special case: bottom row - ystep = height / 2.0 - yU = ntiles_y - 1 - yB = yU + rstart = 0 + for r in range(nr + 1): + cstart = 0 + if r == 0: # special case: top row + rstep = height / 2.0 + rU = 0 + rB = 0 + elif r == nr: # special case: bottom row + rstep = height / 2.0 + rU = nr - 1 + rB = rU else: # default values - ystep = height - yU = y - 1 - yB = yB + 1 + rstep = height + rU = r - 1 + rB = rB + 1 - for x in range(ntiles_x + 1): - if x == 0: # special case: left column - xstep = width / 2.0 - xL = 0 - xR = 0 - elif x == ntiles_x: # special case: right column - xstep = width / 2.0 - xL = ntiles_x - 1 - xR = xL + for c in range(nc + 1): + if c == 0: # special case: left column + cstep = width / 2.0 + cL = 0 + cR = 0 + elif c == nc: # special case: right column + cstep = width / 2.0 + cL = nc - 1 + cR = cL else: # default values - xstep = width - xL = x - 1 - xR = xL + 1 + cstep = width + cL = c - 1 + cR = cL + 1 - mapLU = map_array[yU, xL] - mapRU = map_array[yU, xR] - mapLB = map_array[yB, xL] - mapRB = map_array[yB, xR] + mapLU = map_array[rU, cL] + mapRU = map_array[rU, cR] + mapLB = map_array[rB, cL] + mapRB = map_array[rB, cR] - xslice = np.arange(xstart, xstart + xstep) - yslice = np.arange(ystart, ystart + ystep) - interpolate(image, xslice, yslice, + cslice = np.arange(cstart, cstart + cstep) + rslice = np.arange(rstart, rstart + rstep) + + interpolate(image, cslice, rslice, mapLU, mapRU, mapLB, mapRB, lut) - xstart += xstep # set pointer on next matrix */ + cstart += cstep # set pointer on next matrix */ - ystart += ystep - - if image.shape != orig_shape: - image = image[:orig_shape[0], :orig_shape[1]] + rstart += rstep return image diff --git a/skimage/exposure/tests/test_exposure.py b/skimage/exposure/tests/test_exposure.py index 265ce246..6b2d0a2e 100644 --- a/skimage/exposure/tests/test_exposure.py +++ b/skimage/exposure/tests/test_exposure.py @@ -192,7 +192,7 @@ def test_adapthist_scalar(): """Test a scalar uint8 image """ img = skimage.img_as_ubyte(data.moon()) - adapted = exposure.equalize_adapthist(img, clip_limit=0.02) + adapted = exposure.equalize_adapthist(img, kernel_size=64, clip_limit=0.02) assert adapted.min() == 0.0 assert adapted.max() == 1.0 assert img.shape == adapted.shape @@ -211,13 +211,17 @@ def test_adapthist_grayscale(): img = skimage.img_as_float(data.astronaut()) img = rgb2gray(img) img = np.dstack((img, img, img)) - with expected_warnings(['precision loss|non-contiguous input']): - adapted = exposure.equalize_adapthist(img, 10, 9, clip_limit=0.01, + with expected_warnings(['precision loss|non-contiguous input', 'deprecated']): + adapted_old = exposure.equalize_adapthist(img, 10, 9, clip_limit=0.01, nbins=128) + adapted = exposure.equalize_adapthist(img, kernel_size=(57, 51), clip_limit=0.01, + nbins=128) + np.testing.assert_allclose(adapted, adapted_old) assert_almost_equal = np.testing.assert_almost_equal assert img.shape == adapted.shape - assert_almost_equal(peak_snr(img, adapted), 97.6876, 3) - assert_almost_equal(norm_brightness_err(img, adapted), 0.0591, 3) + assert_almost_equal(peak_snr(img, adapted), 90.669, 3) + assert_almost_equal(norm_brightness_err(img, adapted), 0.084, 3) + return data, adapted @@ -229,7 +233,7 @@ def test_adapthist_color(): warnings.simplefilter('always') hist, bin_centers = exposure.histogram(img) assert len(w) > 0 - with expected_warnings(['precision loss']): + with expected_warnings(['precision loss', 'deprecated']): adapted = exposure.equalize_adapthist(img, clip_limit=0.01) assert_almost_equal = np.testing.assert_almost_equal @@ -248,7 +252,7 @@ def test_adapthist_alpha(): img = skimage.img_as_float(data.astronaut()) alpha = np.ones((img.shape[0], img.shape[1]), dtype=float) img = np.dstack((img, alpha)) - with expected_warnings(['precision loss']): + with expected_warnings(['precision loss', 'deprecated']): adapted = exposure.equalize_adapthist(img) assert adapted.shape != img.shape img = img[:, :, :3] From 998be36c2d916c77080ad20cb2fd6005e9702964 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 15 Jun 2015 21:35:30 -0500 Subject: [PATCH 02/17] Update equalize_adapthist to use new view_as_windows Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports Style fixes Add a deprecation warning and add to api_changes.txt Update TODO and switch to 0.13 deprecation Preserve the current API as much as possible and defer to 0.14 Move the new kwarg to the very end Clarify deprecation warning Update to use row/col in clahe Update docstring Use optimal_step to set up view_as_windows Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports --- skimage/exposure/_adapthist.py | 23 +++++++++++++++++++++++ skimage/exposure/tests/test_exposure.py | 9 +++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/skimage/exposure/_adapthist.py b/skimage/exposure/_adapthist.py index 7d79dc5e..9f7cadf9 100644 --- a/skimage/exposure/_adapthist.py +++ b/skimage/exposure/_adapthist.py @@ -20,15 +20,23 @@ from .. import img_as_float, img_as_uint from ..color.adapt_rgb import adapt_rgb, hsv_value from ..exposure import rescale_intensity from ..util import view_as_windows +<<<<<<< HEAD from .._shared.utils import skimage_deprecation, warnings +======= +>>>>>>> 3bcbbc0... Update equalize_adapthist to use new view_as_windows NR_OF_GREY = 2 ** 14 # number of grayscale levels to use in CLAHE algorithm @adapt_rgb(hsv_value) +<<<<<<< HEAD def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01, nbins=256, kernel_size=None): +======= +def equalize_adapthist(image, kernel_size=64, ntiles_x=None, ntiles_y=None, + clip_limit=0.01, nbins=256): +>>>>>>> 3bcbbc0... Update equalize_adapthist to use new view_as_windows """Contrast Limited Adaptive Histogram Equalization (CLAHE). An algorithm for local contrast enhancement, that uses histograms computed @@ -42,11 +50,19 @@ def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01, kernel_size: integer or 2-tuple Defines the shape of contextual regions used in the algorithm. If an integer is given, the shape will be a square of +<<<<<<< HEAD sidelength given by this value. ntiles_x : int, optional (deprecated in favor of ``kernel_size``) Number of tile regions in the X direction (horizontal). ntiles_y : int, optional (deprecated if favor of ``kernel_size``) Number of tile regions in the Y direction (vertical). +======= + sidelength given by its value. + ntiles_x : int, optional + Number of tile regions in the X direction. + ntiles_y : int, optional + Number of tile regions in the Y direction. +>>>>>>> 3bcbbc0... Update equalize_adapthist to use new view_as_windows clip_limit : float: optional Clipping limit, normalized between 0 and 1 (higher values give more contrast). @@ -77,6 +93,7 @@ def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01, """ image = img_as_uint(image) image = rescale_intensity(image, out_range=(0, NR_OF_GREY - 1)) +<<<<<<< HEAD if kernel_size is None: warnings.warn('`ntiles_*` have been deprecated in favor of ' '`kernel_size`. The `ntiles_*` keyword arguments ' @@ -85,6 +102,12 @@ def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01, ntiles_y = ntiles_y or 8 kernel_size = (np.round(image.shape[0] / ntiles_y), np.round(image.shape[1] / ntiles_x)) +======= + if ntiles_x or ntiles_y: + ntiles_x = ntiles_x or 8 + ntiles_y = ntiles_y or 8 + kernel_size = (image.shape[0] / ntiles_y, image.shape[1] / ntiles_x) +>>>>>>> 3bcbbc0... Update equalize_adapthist to use new view_as_windows if isinstance(kernel_size, numbers.Number): kernel_size = (kernel_size, kernel_size) diff --git a/skimage/exposure/tests/test_exposure.py b/skimage/exposure/tests/test_exposure.py index 6b2d0a2e..3d684445 100644 --- a/skimage/exposure/tests/test_exposure.py +++ b/skimage/exposure/tests/test_exposure.py @@ -211,17 +211,14 @@ def test_adapthist_grayscale(): img = skimage.img_as_float(data.astronaut()) img = rgb2gray(img) img = np.dstack((img, img, img)) - with expected_warnings(['precision loss|non-contiguous input', 'deprecated']): + with expected_warnings(['precision loss|non-contiguous input', + 'deprecated']): adapted_old = exposure.equalize_adapthist(img, 10, 9, clip_limit=0.01, - nbins=128) - adapted = exposure.equalize_adapthist(img, kernel_size=(57, 51), clip_limit=0.01, - nbins=128) - np.testing.assert_allclose(adapted, adapted_old) + adapted = exposure.equalize_adapthist(img, kernel_size=(57, 51), clip_limit=0.01, nbins=128) assert_almost_equal = np.testing.assert_almost_equal assert img.shape == adapted.shape assert_almost_equal(peak_snr(img, adapted), 90.669, 3) assert_almost_equal(norm_brightness_err(img, adapted), 0.084, 3) - return data, adapted From 6017e38e670768a282fb3b7a3f6a9e1c3f067d5c Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 15 Jun 2015 21:36:21 -0500 Subject: [PATCH 03/17] Style fixes Update equalize_adapthist to use new view_as_windows Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports Style fixes Add a deprecation warning and add to api_changes.txt Update TODO and switch to 0.13 deprecation Preserve the current API as much as possible and defer to 0.14 Move the new kwarg to the very end Clarify deprecation warning Update to use row/col in clahe Update docstring Use optimal_step to set up view_as_windows Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports Style fixes --- skimage/exposure/_adapthist.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/skimage/exposure/_adapthist.py b/skimage/exposure/_adapthist.py index 9f7cadf9..094dd4b8 100644 --- a/skimage/exposure/_adapthist.py +++ b/skimage/exposure/_adapthist.py @@ -35,8 +35,12 @@ def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01, nbins=256, kernel_size=None): ======= def equalize_adapthist(image, kernel_size=64, ntiles_x=None, ntiles_y=None, +<<<<<<< HEAD clip_limit=0.01, nbins=256): >>>>>>> 3bcbbc0... Update equalize_adapthist to use new view_as_windows +======= + clip_limit=0.01, nbins=256): +>>>>>>> 172fb0d... Style fixes """Contrast Limited Adaptive Histogram Equalization (CLAHE). An algorithm for local contrast enhancement, that uses histograms computed @@ -50,6 +54,7 @@ def equalize_adapthist(image, kernel_size=64, ntiles_x=None, ntiles_y=None, kernel_size: integer or 2-tuple Defines the shape of contextual regions used in the algorithm. If an integer is given, the shape will be a square of +<<<<<<< HEAD <<<<<<< HEAD sidelength given by this value. ntiles_x : int, optional (deprecated in favor of ``kernel_size``) @@ -58,6 +63,9 @@ def equalize_adapthist(image, kernel_size=64, ntiles_x=None, ntiles_y=None, Number of tile regions in the Y direction (vertical). ======= sidelength given by its value. +======= + sidelength given by this value. +>>>>>>> 172fb0d... Style fixes ntiles_x : int, optional Number of tile regions in the X direction. ntiles_y : int, optional @@ -93,7 +101,7 @@ def equalize_adapthist(image, kernel_size=64, ntiles_x=None, ntiles_y=None, """ image = img_as_uint(image) image = rescale_intensity(image, out_range=(0, NR_OF_GREY - 1)) -<<<<<<< HEAD + if kernel_size is None: warnings.warn('`ntiles_*` have been deprecated in favor of ' '`kernel_size`. The `ntiles_*` keyword arguments ' @@ -102,12 +110,6 @@ def equalize_adapthist(image, kernel_size=64, ntiles_x=None, ntiles_y=None, ntiles_y = ntiles_y or 8 kernel_size = (np.round(image.shape[0] / ntiles_y), np.round(image.shape[1] / ntiles_x)) -======= - if ntiles_x or ntiles_y: - ntiles_x = ntiles_x or 8 - ntiles_y = ntiles_y or 8 - kernel_size = (image.shape[0] / ntiles_y, image.shape[1] / ntiles_x) ->>>>>>> 3bcbbc0... Update equalize_adapthist to use new view_as_windows if isinstance(kernel_size, numbers.Number): kernel_size = (kernel_size, kernel_size) From e42cb6fadf5f472dff7717981e1619de01f0add3 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 15 Jun 2015 21:37:01 -0500 Subject: [PATCH 04/17] Update docstring Style fixes Update equalize_adapthist to use new view_as_windows Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports Style fixes Add a deprecation warning and add to api_changes.txt Update TODO and switch to 0.13 deprecation Preserve the current API as much as possible and defer to 0.14 Move the new kwarg to the very end Clarify deprecation warning Update to use row/col in clahe Update docstring Use optimal_step to set up view_as_windows Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports Style fixes Add a deprecation warning and add to api_changes.txt --- skimage/exposure/_adapthist.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/skimage/exposure/_adapthist.py b/skimage/exposure/_adapthist.py index 094dd4b8..85120b35 100644 --- a/skimage/exposure/_adapthist.py +++ b/skimage/exposure/_adapthist.py @@ -21,9 +21,13 @@ from ..color.adapt_rgb import adapt_rgb, hsv_value from ..exposure import rescale_intensity from ..util import view_as_windows <<<<<<< HEAD +<<<<<<< HEAD from .._shared.utils import skimage_deprecation, warnings ======= >>>>>>> 3bcbbc0... Update equalize_adapthist to use new view_as_windows +======= +from .._shared.utils import skimage_deprecation +>>>>>>> 446f383... Add a deprecation warning and add to api_changes.txt NR_OF_GREY = 2 ** 14 # number of grayscale levels to use in CLAHE algorithm From 733b62890a75777e13eb92ad510ac10386c393e1 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 15 Jun 2015 21:37:33 -0500 Subject: [PATCH 05/17] Docstring and TODO Update docstring Style fixes Update equalize_adapthist to use new view_as_windows Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports Style fixes Add a deprecation warning and add to api_changes.txt Update TODO and switch to 0.13 deprecation Preserve the current API as much as possible and defer to 0.14 Move the new kwarg to the very end Clarify deprecation warning Update to use row/col in clahe Update docstring Use optimal_step to set up view_as_windows Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports Style fixes Add a deprecation warning and add to api_changes.txt Update TODO and switch to 0.13 deprecation --- TODO.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO.txt b/TODO.txt index a9a06a6c..e6557ff4 100644 --- a/TODO.txt +++ b/TODO.txt @@ -16,6 +16,7 @@ Version 0.13 * Remove deprecated edge filters `hsobel`, `vsobel`, `hscharr`, `vscharr`, `hprewitt`, `vprewitt`, `roberts_positive_diagonal`, `roberts_negative_diagonal` in `skimage/filters/edges.py` +* Remove deprecated ``ntiles_*` kwargs in ``equalize_adapthist``. Version 0.12 From 5ba3cad178cd05c14e36cbe6d01e5054e62a893e Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 15 Jun 2015 21:39:19 -0500 Subject: [PATCH 06/17] Update tests Docstring and TODO Update docstring Style fixes Update equalize_adapthist to use new view_as_windows Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports Style fixes Add a deprecation warning and add to api_changes.txt Update TODO and switch to 0.13 deprecation Preserve the current API as much as possible and defer to 0.14 Move the new kwarg to the very end Clarify deprecation warning Update to use row/col in clahe Update docstring Use optimal_step to set up view_as_windows Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports Style fixes Add a deprecation warning and add to api_changes.txt Update TODO and switch to 0.13 deprecation Preserve the current API as much as possible and defer to 0.14 --- TODO.txt | 2 +- skimage/exposure/_adapthist.py | 22 +++++++++------------- skimage/exposure/tests/test_exposure.py | 3 +-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/TODO.txt b/TODO.txt index e6557ff4..a96b3731 100644 --- a/TODO.txt +++ b/TODO.txt @@ -16,7 +16,7 @@ Version 0.13 * Remove deprecated edge filters `hsobel`, `vsobel`, `hscharr`, `vscharr`, `hprewitt`, `vprewitt`, `roberts_positive_diagonal`, `roberts_negative_diagonal` in `skimage/filters/edges.py` -* Remove deprecated ``ntiles_*` kwargs in ``equalize_adapthist``. + Version 0.12 diff --git a/skimage/exposure/_adapthist.py b/skimage/exposure/_adapthist.py index 85120b35..b0ed63d7 100644 --- a/skimage/exposure/_adapthist.py +++ b/skimage/exposure/_adapthist.py @@ -22,12 +22,16 @@ from ..exposure import rescale_intensity from ..util import view_as_windows <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD from .._shared.utils import skimage_deprecation, warnings ======= >>>>>>> 3bcbbc0... Update equalize_adapthist to use new view_as_windows ======= from .._shared.utils import skimage_deprecation >>>>>>> 446f383... Add a deprecation warning and add to api_changes.txt +======= +from .._shared.utils import skimage_deprecation, warnings +>>>>>>> 204208a... Preserve the current API as much as possible and defer to 0.14 NR_OF_GREY = 2 ** 14 # number of grayscale levels to use in CLAHE algorithm @@ -35,6 +39,7 @@ NR_OF_GREY = 2 ** 14 # number of grayscale levels to use in CLAHE algorithm @adapt_rgb(hsv_value) <<<<<<< HEAD +<<<<<<< HEAD def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01, nbins=256, kernel_size=None): ======= @@ -43,6 +48,9 @@ def equalize_adapthist(image, kernel_size=64, ntiles_x=None, ntiles_y=None, clip_limit=0.01, nbins=256): >>>>>>> 3bcbbc0... Update equalize_adapthist to use new view_as_windows ======= +======= +def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, kernel_size=None, +>>>>>>> 204208a... Preserve the current API as much as possible and defer to 0.14 clip_limit=0.01, nbins=256): >>>>>>> 172fb0d... Style fixes """Contrast Limited Adaptive Histogram Equalization (CLAHE). @@ -58,23 +66,11 @@ def equalize_adapthist(image, kernel_size=64, ntiles_x=None, ntiles_y=None, kernel_size: integer or 2-tuple Defines the shape of contextual regions used in the algorithm. If an integer is given, the shape will be a square of -<<<<<<< HEAD -<<<<<<< HEAD sidelength given by this value. ntiles_x : int, optional (deprecated in favor of ``kernel_size``) Number of tile regions in the X direction (horizontal). ntiles_y : int, optional (deprecated if favor of ``kernel_size``) Number of tile regions in the Y direction (vertical). -======= - sidelength given by its value. -======= - sidelength given by this value. ->>>>>>> 172fb0d... Style fixes - ntiles_x : int, optional - Number of tile regions in the X direction. - ntiles_y : int, optional - Number of tile regions in the Y direction. ->>>>>>> 3bcbbc0... Update equalize_adapthist to use new view_as_windows clip_limit : float: optional Clipping limit, normalized between 0 and 1 (higher values give more contrast). @@ -113,7 +109,7 @@ def equalize_adapthist(image, kernel_size=64, ntiles_x=None, ntiles_y=None, ntiles_x = ntiles_x or 8 ntiles_y = ntiles_y or 8 kernel_size = (np.round(image.shape[0] / ntiles_y), - np.round(image.shape[1] / ntiles_x)) + np.round(image.shape[1] / ntiles_x))0.14 if isinstance(kernel_size, numbers.Number): kernel_size = (kernel_size, kernel_size) diff --git a/skimage/exposure/tests/test_exposure.py b/skimage/exposure/tests/test_exposure.py index 3d684445..bde77cdb 100644 --- a/skimage/exposure/tests/test_exposure.py +++ b/skimage/exposure/tests/test_exposure.py @@ -214,8 +214,7 @@ def test_adapthist_grayscale(): with expected_warnings(['precision loss|non-contiguous input', 'deprecated']): adapted_old = exposure.equalize_adapthist(img, 10, 9, clip_limit=0.01, - adapted = exposure.equalize_adapthist(img, kernel_size=(57, 51), clip_limit=0.01, nbins=128) - assert_almost_equal = np.testing.assert_almost_equal + adapted = exposure.equalize_adapthist(img, kernel_size=(57, 51), clip_limit=0.01, nbins=128)most_equal assert img.shape == adapted.shape assert_almost_equal(peak_snr(img, adapted), 90.669, 3) assert_almost_equal(norm_brightness_err(img, adapted), 0.084, 3) From 944e7204b7c4bfeeb16f74fd372f6df1e81d7b4a Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 15 Jun 2015 21:40:23 -0500 Subject: [PATCH 07/17] wip wip Update tests Docstring and TODO Update docstring Style fixes Update equalize_adapthist to use new view_as_windows Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports Style fixes Add a deprecation warning and add to api_changes.txt Update TODO and switch to 0.13 deprecation Preserve the current API as much as possible and defer to 0.14 Move the new kwarg to the very end Clarify deprecation warning Update to use row/col in clahe Update docstring Use optimal_step to set up view_as_windows Update equalize_adapthist to use new view_as_windows Try rbase again Update equalize_adapthist to use new view_as_windows Fix relative imports Style fixes Add a deprecation warning and add to api_changes.txt Update TODO and switch to 0.13 deprecation Preserve the current API as much as possible and defer to 0.14 Move the new kwarg to the very end Clarify deprecation warning Update docstring --- skimage/exposure/_adapthist.py | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/skimage/exposure/_adapthist.py b/skimage/exposure/_adapthist.py index b0ed63d7..fc13072b 100644 --- a/skimage/exposure/_adapthist.py +++ b/skimage/exposure/_adapthist.py @@ -20,39 +20,14 @@ from .. import img_as_float, img_as_uint from ..color.adapt_rgb import adapt_rgb, hsv_value from ..exposure import rescale_intensity from ..util import view_as_windows -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD from .._shared.utils import skimage_deprecation, warnings -======= ->>>>>>> 3bcbbc0... Update equalize_adapthist to use new view_as_windows -======= -from .._shared.utils import skimage_deprecation ->>>>>>> 446f383... Add a deprecation warning and add to api_changes.txt -======= -from .._shared.utils import skimage_deprecation, warnings ->>>>>>> 204208a... Preserve the current API as much as possible and defer to 0.14 - NR_OF_GREY = 2 ** 14 # number of grayscale levels to use in CLAHE algorithm @adapt_rgb(hsv_value) -<<<<<<< HEAD -<<<<<<< HEAD def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01, nbins=256, kernel_size=None): -======= -def equalize_adapthist(image, kernel_size=64, ntiles_x=None, ntiles_y=None, -<<<<<<< HEAD - clip_limit=0.01, nbins=256): ->>>>>>> 3bcbbc0... Update equalize_adapthist to use new view_as_windows -======= -======= -def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, kernel_size=None, ->>>>>>> 204208a... Preserve the current API as much as possible and defer to 0.14 - clip_limit=0.01, nbins=256): ->>>>>>> 172fb0d... Style fixes """Contrast Limited Adaptive Histogram Equalization (CLAHE). An algorithm for local contrast enhancement, that uses histograms computed @@ -109,7 +84,7 @@ def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, kernel_size=None, ntiles_x = ntiles_x or 8 ntiles_y = ntiles_y or 8 kernel_size = (np.round(image.shape[0] / ntiles_y), - np.round(image.shape[1] / ntiles_x))0.14 + np.round(image.shape[1] / ntiles_x)) if isinstance(kernel_size, numbers.Number): kernel_size = (kernel_size, kernel_size) From 489ae2ec1a423004e2ab14402629d451ec63de26 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 15 Jun 2015 21:42:59 -0500 Subject: [PATCH 08/17] Fix rebase error --- skimage/exposure/tests/test_exposure.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/skimage/exposure/tests/test_exposure.py b/skimage/exposure/tests/test_exposure.py index bde77cdb..f074151b 100644 --- a/skimage/exposure/tests/test_exposure.py +++ b/skimage/exposure/tests/test_exposure.py @@ -214,7 +214,8 @@ def test_adapthist_grayscale(): with expected_warnings(['precision loss|non-contiguous input', 'deprecated']): adapted_old = exposure.equalize_adapthist(img, 10, 9, clip_limit=0.01, - adapted = exposure.equalize_adapthist(img, kernel_size=(57, 51), clip_limit=0.01, nbins=128)most_equal + nbins=128) + adapted = exposure.equalize_adapthist(img, kernel_size=(57, 51), clip_limit=0.01, nbins=128) assert img.shape == adapted.shape assert_almost_equal(peak_snr(img, adapted), 90.669, 3) assert_almost_equal(norm_brightness_err(img, adapted), 0.084, 3) From 3aafbb78dd2718b2b3bab6d5b4e1043121cb1b21 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 15 Jun 2015 21:50:54 -0500 Subject: [PATCH 09/17] Rename optimal_step and add comments --- skimage/exposure/_adapthist.py | 2 +- skimage/util/shape.py | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/skimage/exposure/_adapthist.py b/skimage/exposure/_adapthist.py index fc13072b..6a200371 100644 --- a/skimage/exposure/_adapthist.py +++ b/skimage/exposure/_adapthist.py @@ -129,7 +129,7 @@ def _clahe(image, kernel_size, clip_limit, nbins=128): lut = np.arange(NR_OF_GREY) lut //= bin_size - img_view = view_as_windows(image, kernel_size, optimal_step=True) + img_view = view_as_windows(image, kernel_size, min_overlap=True) nr, nc = img_view.shape[:2] height = int(image.shape[0] / nr) width = int(image.shape[1] / nc) diff --git a/skimage/util/shape.py b/skimage/util/shape.py index 48e9a5ef..b8ceec02 100644 --- a/skimage/util/shape.py +++ b/skimage/util/shape.py @@ -104,7 +104,7 @@ def view_as_blocks(arr_in, block_shape): return arr_out -def view_as_windows(arr_in, window_shape, step=1, optimal_step=False): +def view_as_windows(arr_in, window_shape, step=1, min_overlap=False): """Rolling window view of the input n-dimensional array. Windows are overlapping views of the input array, with adjacent windows @@ -122,7 +122,7 @@ def view_as_windows(arr_in, window_shape, step=1, optimal_step=False): step : integer or tuple of length arr_in.ndim Indicates step size at which extraction shall be performed. If integer is given, then the step is uniform in all dimensions. - optimal_step: bool, optional + min_overlap: bool, optional When True, selects a ``step`` that will give full coverage of ``arr_in`` with minimal overlap. @@ -229,13 +229,16 @@ def view_as_windows(arr_in, window_shape, step=1, optimal_step=False): if not (len(window_shape) == ndim): raise ValueError("`window_shape` is incompatible with `arr_in.shape`") - if optimal_step: - rem = np.array(arr_in.shape) - np.array(window_shape) + if min_overlap: + # start with no overlap step = list(window_shape) - + # subtract the initial window shape from the overall shape + remainder = np.array(arr_in.shape) - np.array(window_shape) + # shrink the step size in each direction as needed + # to get full coverage for (ind, size) in enumerate(window_shape): - ns = int(np.ceil(arr_in.shape[ind] / size)) - while step[ind] * (ns - 1) > rem[ind]: + num_steps = int(np.ceil(arr_in.shape[ind] / size)) + while step[ind] * (num_steps - 1) > remainder[ind]: step[ind] -= 1 if isinstance(step, numbers.Number): From c948f9fe970c2c827419267758d0449b3c693a0a Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 15 Jun 2015 22:02:17 -0500 Subject: [PATCH 10/17] Fix view as windows test --- skimage/util/tests/test_shape.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/skimage/util/tests/test_shape.py b/skimage/util/tests/test_shape.py index 5c59edb0..e6dfbc87 100644 --- a/skimage/util/tests/test_shape.py +++ b/skimage/util/tests/test_shape.py @@ -176,18 +176,18 @@ def test_view_as_windows_step_tuple(): [22, 23]]]]) -def test_view_as_windows_optimal_step(): +def test_view_as_windows_min_overlap(): A = np.arange(24).reshape((6, 4)) - B = view_as_windows(A, (3, 2), optimal_step=True) + B = view_as_windows(A, (3, 2), min_overlap=True) assert B.shape == (2, 2, 3, 2) assert B.size == A.size A = np.arange(512 * 512).reshape((512, 512)) - B = view_as_windows(A, (10, 10), optimal_step=True) + B = view_as_windows(A, (10, 10), min_overlap=True) assert B.shape == (56, 56, 10, 10) assert B.size >= A.size - C = view_as_windows(A, (11, 9), optimal_step=True) + C = view_as_windows(A, (11, 9), min_overlap=True) assert C.shape == (51, 63, 11, 9) assert C.size >= A.size From 1f56de9595d7db2aa7107e9ec5211d971a1420c6 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 16 Jun 2015 06:42:23 -0500 Subject: [PATCH 11/17] Remove min_overlap kwarg --- skimage/util/shape.py | 17 +---------------- skimage/util/tests/test_shape.py | 16 ---------------- 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/skimage/util/shape.py b/skimage/util/shape.py index b8ceec02..b786ec1c 100644 --- a/skimage/util/shape.py +++ b/skimage/util/shape.py @@ -104,7 +104,7 @@ def view_as_blocks(arr_in, block_shape): return arr_out -def view_as_windows(arr_in, window_shape, step=1, min_overlap=False): +def view_as_windows(arr_in, window_shape, step=1): """Rolling window view of the input n-dimensional array. Windows are overlapping views of the input array, with adjacent windows @@ -122,9 +122,6 @@ def view_as_windows(arr_in, window_shape, step=1, min_overlap=False): step : integer or tuple of length arr_in.ndim Indicates step size at which extraction shall be performed. If integer is given, then the step is uniform in all dimensions. - min_overlap: bool, optional - When True, selects a ``step`` that will give full coverage of - ``arr_in`` with minimal overlap. Returns ------- @@ -229,18 +226,6 @@ def view_as_windows(arr_in, window_shape, step=1, min_overlap=False): if not (len(window_shape) == ndim): raise ValueError("`window_shape` is incompatible with `arr_in.shape`") - if min_overlap: - # start with no overlap - step = list(window_shape) - # subtract the initial window shape from the overall shape - remainder = np.array(arr_in.shape) - np.array(window_shape) - # shrink the step size in each direction as needed - # to get full coverage - for (ind, size) in enumerate(window_shape): - num_steps = int(np.ceil(arr_in.shape[ind] / size)) - while step[ind] * (num_steps - 1) > remainder[ind]: - step[ind] -= 1 - if isinstance(step, numbers.Number): if step < 1: raise ValueError("`step` must be >= 1") diff --git a/skimage/util/tests/test_shape.py b/skimage/util/tests/test_shape.py index e6dfbc87..7a6a785d 100644 --- a/skimage/util/tests/test_shape.py +++ b/skimage/util/tests/test_shape.py @@ -176,21 +176,5 @@ def test_view_as_windows_step_tuple(): [22, 23]]]]) -def test_view_as_windows_min_overlap(): - A = np.arange(24).reshape((6, 4)) - B = view_as_windows(A, (3, 2), min_overlap=True) - assert B.shape == (2, 2, 3, 2) - assert B.size == A.size - - A = np.arange(512 * 512).reshape((512, 512)) - B = view_as_windows(A, (10, 10), min_overlap=True) - assert B.shape == (56, 56, 10, 10) - assert B.size >= A.size - - C = view_as_windows(A, (11, 9), min_overlap=True) - assert C.shape == (51, 63, 11, 9) - assert C.size >= A.size - - if __name__ == '__main__': np.testing.run_module_suite() From acc9a8a74838ada804b3dc4ffb71369ded1db85e Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 16 Jun 2015 06:42:37 -0500 Subject: [PATCH 12/17] Use smarter indexing --- skimage/exposure/_adapthist.py | 52 ++++++++++++++----------- skimage/exposure/tests/test_exposure.py | 4 +- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/skimage/exposure/_adapthist.py b/skimage/exposure/_adapthist.py index 6a200371..56d34967 100644 --- a/skimage/exposure/_adapthist.py +++ b/skimage/exposure/_adapthist.py @@ -125,34 +125,42 @@ def _clahe(image, kernel_size, clip_limit, nbins=128): if clip_limit == 1.0: return image # is OK, immediately returns original image. + nr = int(np.ceil(image.shape[0] / kernel_size[0])) + nc = int(np.ceil(image.shape[1] / kernel_size[1])) + + row_step = int(np.floor(image.shape[0] / nr)) + col_step = int(np.floor(image.shape[1] / nc)) + + img_view = view_as_windows(image, kernel_size, (row_step, col_step)) + print(img_view.shape, nc, nr) + bin_size = 1 + NR_OF_GREY // nbins lut = np.arange(NR_OF_GREY) lut //= bin_size - img_view = view_as_windows(image, kernel_size, min_overlap=True) - nr, nc = img_view.shape[:2] - height = int(image.shape[0] / nr) - width = int(image.shape[1] / nc) - map_array = np.zeros((nr, nc, nbins), dtype=int) - n_pixels = height * width - - if clip_limit > 0.0: # Calculate actual cliplimit - clip_limit = int(clip_limit * (width * height) / nbins) - if clip_limit < 1: - clip_limit = 1 - else: - clip_limit = NR_OF_GREY # Large value, do not clip (AHE) # Calculate greylevel mappings for each contextual region for r in range(nr): for c in range(nc): - sub_img = img_view[r, c] + if r < (nr - 1) and c < (nc - 1): + sub_img = img_view[r, c] + else: + sub_img = image[r * row_step: (r + 1) * row_step, + c * col_step: (c + 1) * col_step] + + if clip_limit > 0.0: # Calculate actual cliplimit + cl = int(clip_limit * sub_img.size / nbins) + if cl < 1: + cl = 1 + else: + cl = NR_OF_GREY # Large value, do not clip (AHE) + hist = lut[sub_img.ravel()] hist = np.bincount(hist) hist = np.append(hist, np.zeros(nbins - hist.size, dtype=int)) - hist = clip_histogram(hist, clip_limit) - hist = map_histogram(hist, 0, NR_OF_GREY - 1, n_pixels) + hist = clip_histogram(hist, cl) + hist = map_histogram(hist, 0, NR_OF_GREY - 1, sub_img.size) map_array[r, c] = hist # Interpolate greylevel mappings to get CLAHE image @@ -160,29 +168,29 @@ def _clahe(image, kernel_size, clip_limit, nbins=128): for r in range(nr + 1): cstart = 0 if r == 0: # special case: top row - rstep = height / 2.0 + rstep = row_step / 2.0 rU = 0 rB = 0 elif r == nr: # special case: bottom row - rstep = height / 2.0 + rstep = row_step / 2.0 rU = nr - 1 rB = rU else: # default values - rstep = height + rstep = row_step rU = r - 1 rB = rB + 1 for c in range(nc + 1): if c == 0: # special case: left column - cstep = width / 2.0 + cstep = col_step / 2.0 cL = 0 cR = 0 elif c == nc: # special case: right column - cstep = width / 2.0 + cstep = col_step / 2.0 cL = nc - 1 cR = cL else: # default values - cstep = width + cstep = col_step cL = c - 1 cR = cL + 1 diff --git a/skimage/exposure/tests/test_exposure.py b/skimage/exposure/tests/test_exposure.py index f074151b..708ea753 100644 --- a/skimage/exposure/tests/test_exposure.py +++ b/skimage/exposure/tests/test_exposure.py @@ -217,8 +217,8 @@ def test_adapthist_grayscale(): nbins=128) adapted = exposure.equalize_adapthist(img, kernel_size=(57, 51), clip_limit=0.01, nbins=128) assert img.shape == adapted.shape - assert_almost_equal(peak_snr(img, adapted), 90.669, 3) - assert_almost_equal(norm_brightness_err(img, adapted), 0.084, 3) + assert_almost_equal(peak_snr(img, adapted), 98.961, 3) + assert_almost_equal(norm_brightness_err(img, adapted), 0.0577, 3) return data, adapted From d755decf15701a834f64311664c7324088bedfcf Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 16 Jun 2015 06:43:56 -0500 Subject: [PATCH 13/17] Remove debug print --- skimage/exposure/_adapthist.py | 1 - 1 file changed, 1 deletion(-) diff --git a/skimage/exposure/_adapthist.py b/skimage/exposure/_adapthist.py index 56d34967..7ede3c68 100644 --- a/skimage/exposure/_adapthist.py +++ b/skimage/exposure/_adapthist.py @@ -132,7 +132,6 @@ def _clahe(image, kernel_size, clip_limit, nbins=128): col_step = int(np.floor(image.shape[1] / nc)) img_view = view_as_windows(image, kernel_size, (row_step, col_step)) - print(img_view.shape, nc, nr) bin_size = 1 + NR_OF_GREY // nbins lut = np.arange(NR_OF_GREY) From 323a2791bb811d448e7241922b2278f2d5cca5f2 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 16 Jun 2015 06:47:22 -0500 Subject: [PATCH 14/17] Rename variable for clarity --- skimage/exposure/_adapthist.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/skimage/exposure/_adapthist.py b/skimage/exposure/_adapthist.py index 7ede3c68..970f9b5d 100644 --- a/skimage/exposure/_adapthist.py +++ b/skimage/exposure/_adapthist.py @@ -149,16 +149,16 @@ def _clahe(image, kernel_size, clip_limit, nbins=128): c * col_step: (c + 1) * col_step] if clip_limit > 0.0: # Calculate actual cliplimit - cl = int(clip_limit * sub_img.size / nbins) - if cl < 1: - cl = 1 + clim = int(clip_limit * sub_img.size / nbins) + if clim < 1: + clim = 1 else: - cl = NR_OF_GREY # Large value, do not clip (AHE) + clim = NR_OF_GREY # Large value, do not clip (AHE) hist = lut[sub_img.ravel()] hist = np.bincount(hist) hist = np.append(hist, np.zeros(nbins - hist.size, dtype=int)) - hist = clip_histogram(hist, cl) + hist = clip_histogram(hist, clim) hist = map_histogram(hist, 0, NR_OF_GREY - 1, sub_img.size) map_array[r, c] = hist From 603844431ae4f28ad68010cce54cd7d31bb5d447 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 16 Jun 2015 06:49:14 -0500 Subject: [PATCH 15/17] More variable renaming --- skimage/exposure/_adapthist.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/skimage/exposure/_adapthist.py b/skimage/exposure/_adapthist.py index 970f9b5d..3b021ce5 100644 --- a/skimage/exposure/_adapthist.py +++ b/skimage/exposure/_adapthist.py @@ -167,29 +167,29 @@ def _clahe(image, kernel_size, clip_limit, nbins=128): for r in range(nr + 1): cstart = 0 if r == 0: # special case: top row - rstep = row_step / 2.0 + r_offset = row_step / 2.0 rU = 0 rB = 0 elif r == nr: # special case: bottom row - rstep = row_step / 2.0 + r_offset = row_step / 2.0 rU = nr - 1 rB = rU else: # default values - rstep = row_step + r_offset = row_step rU = r - 1 rB = rB + 1 for c in range(nc + 1): if c == 0: # special case: left column - cstep = col_step / 2.0 + c_offset = col_step / 2.0 cL = 0 cR = 0 elif c == nc: # special case: right column - cstep = col_step / 2.0 + c_offset = col_step / 2.0 cL = nc - 1 cR = cL else: # default values - cstep = col_step + c_offset = col_step cL = c - 1 cR = cL + 1 @@ -198,15 +198,15 @@ def _clahe(image, kernel_size, clip_limit, nbins=128): mapLB = map_array[rB, cL] mapRB = map_array[rB, cR] - cslice = np.arange(cstart, cstart + cstep) - rslice = np.arange(rstart, rstart + rstep) + cslice = np.arange(cstart, cstart + c_offset) + rslice = np.arange(rstart, rstart + r_offset) interpolate(image, cslice, rslice, mapLU, mapRU, mapLB, mapRB, lut) - cstart += cstep # set pointer on next matrix */ + cstart += c_offset # set pointer on next matrix */ - rstart += rstep + rstart += r_offset return image From 085be65e83148a09b98ae5d0df3fb0bb1099d5da Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 13 Jul 2015 17:00:13 -0500 Subject: [PATCH 16/17] Remove use of view_as_window and fix docstring --- skimage/exposure/_adapthist.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/skimage/exposure/_adapthist.py b/skimage/exposure/_adapthist.py index 3b021ce5..343f71b3 100644 --- a/skimage/exposure/_adapthist.py +++ b/skimage/exposure/_adapthist.py @@ -19,7 +19,6 @@ import numpy as np from .. import img_as_float, img_as_uint from ..color.adapt_rgb import adapt_rgb, hsv_value from ..exposure import rescale_intensity -from ..util import view_as_windows from .._shared.utils import skimage_deprecation, warnings NR_OF_GREY = 2 ** 14 # number of grayscale levels to use in CLAHE algorithm @@ -44,7 +43,7 @@ def equalize_adapthist(image, ntiles_x=8, ntiles_y=8, clip_limit=0.01, sidelength given by this value. ntiles_x : int, optional (deprecated in favor of ``kernel_size``) Number of tile regions in the X direction (horizontal). - ntiles_y : int, optional (deprecated if favor of ``kernel_size``) + ntiles_y : int, optional (deprecated in favor of ``kernel_size``) Number of tile regions in the Y direction (vertical). clip_limit : float: optional Clipping limit, normalized between 0 and 1 (higher values give more @@ -131,8 +130,6 @@ def _clahe(image, kernel_size, clip_limit, nbins=128): row_step = int(np.floor(image.shape[0] / nr)) col_step = int(np.floor(image.shape[1] / nc)) - img_view = view_as_windows(image, kernel_size, (row_step, col_step)) - bin_size = 1 + NR_OF_GREY // nbins lut = np.arange(NR_OF_GREY) lut //= bin_size @@ -142,11 +139,8 @@ def _clahe(image, kernel_size, clip_limit, nbins=128): # Calculate greylevel mappings for each contextual region for r in range(nr): for c in range(nc): - if r < (nr - 1) and c < (nc - 1): - sub_img = img_view[r, c] - else: - sub_img = image[r * row_step: (r + 1) * row_step, - c * col_step: (c + 1) * col_step] + sub_img = image[r * row_step: (r + 1) * row_step, + c * col_step: (c + 1) * col_step] if clip_limit > 0.0: # Calculate actual cliplimit clim = int(clip_limit * sub_img.size / nbins) From 80fe225fc8b694737021ff54d0d052e8ea72a818 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 13 Jul 2015 17:46:30 -0500 Subject: [PATCH 17/17] Fix failing test --- skimage/exposure/tests/test_exposure.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skimage/exposure/tests/test_exposure.py b/skimage/exposure/tests/test_exposure.py index 708ea753..8fb6d621 100644 --- a/skimage/exposure/tests/test_exposure.py +++ b/skimage/exposure/tests/test_exposure.py @@ -217,8 +217,8 @@ def test_adapthist_grayscale(): nbins=128) adapted = exposure.equalize_adapthist(img, kernel_size=(57, 51), clip_limit=0.01, nbins=128) assert img.shape == adapted.shape - assert_almost_equal(peak_snr(img, adapted), 98.961, 3) - assert_almost_equal(norm_brightness_err(img, adapted), 0.0577, 3) + assert_almost_equal(peak_snr(img, adapted), 101.750, 3) + assert_almost_equal(norm_brightness_err(img, adapted), 0.0540, 3) return data, adapted