From 0344e51d405a5ddc6816f77deb543570449ead11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Wed, 5 Sep 2012 15:03:14 +0200 Subject: [PATCH 01/25] Add function to build gaussian and laplacian pyramids --- skimage/transform/__init__.py | 5 +- skimage/transform/pyramid.py | 292 ++++++++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 skimage/transform/pyramid.py diff --git a/skimage/transform/__init__.py b/skimage/transform/__init__.py index a25ce969..abf31517 100644 --- a/skimage/transform/__init__.py +++ b/skimage/transform/__init__.py @@ -4,7 +4,8 @@ from .finite_radon_transform import * from .integral import * from ._geometric import (warp, warp_coords, estimate_transform, SimilarityTransform, AffineTransform, - ProjectiveTransform, PolynomialTransform, + ProjectiveTransform, PolynomialTransform, PiecewiseAffineTransform) from ._warps import swirl, homography, resize, rotate - +from .pyramid import (pyramid_reduce, pyramid_expand, + build_gaussian_pyramid, build_laplacian_pyramid) diff --git a/skimage/transform/pyramid.py b/skimage/transform/pyramid.py new file mode 100644 index 00000000..1a011fb6 --- /dev/null +++ b/skimage/transform/pyramid.py @@ -0,0 +1,292 @@ +import math +import numpy as np +from scipy import ndimage +from skimage.transform import resize +from skimage.util import img_as_float + + +def _smooth(image, sigma, mode, cval): + + # allocate output array + smoothed = np.empty(image.shape, dtype=np.double) + + if image.ndim == 3: # apply gaussian filter to all dimensions independently + for dim in range(image.shape[2]): + ndimage.gaussian_filter(image[..., dim], sigma, + output=smoothed[..., dim], + mode=mode, cval=cval) + else: + ndimage.gaussian_filter(image, sigma, output=smoothed, + mode=mode, cval=cval) + + return smoothed + + +def _check_factor(factor): + if factor <= 1: + raise ValueError('scale factor must be greater than 1') + + +def pyramid_reduce(image, factor=2, sigma=None, order=1, + mode='reflect', cval=0): + """Smooth and then downsample image. + + Parameters + ---------- + image : array + Input image. + factor : float, optional + Downscale factor. Default is 2. + sigma : float, optional + Sigma for gaussian filter. Default is `2 * factor / 6.0` which + corresponds to a filter mask twice the size of the scale factor that + covers more than 99% of the gaussian distribution. + order : int, optional + Order of splines used in interpolation of downsampling. See + `scipy.ndimage.map_coordinates` for detail. Default is 1. + mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional + The mode parameter determines how the array borders are handled, where + cval is the value when mode is equal to 'constant'. + Default is 'reflect'. + cval : float, optional + Value to fill past edges of input if mode is 'constant'. Default is 0. + + Returns + ------- + out : array + Smoothed and downsampled image. + + References + ---------- + ..[1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf + + """ + + _check_factor(factor) + + image = img_as_float(image) + + rows = image.shape[0] + cols = image.shape[1] + out_rows = math.ceil(rows / float(factor)) + out_cols = math.ceil(cols / float(factor)) + + if sigma is None: + # automatically determine sigma which covers > 99% of distribution + sigma = 2 * factor / 6.0 + + smoothed = _smooth(image, sigma, mode, cval) + out = resize(smoothed, (out_rows, out_cols), order=order, + mode=mode, cval=cval) + + return out + + +def pyramid_expand(image, factor=2, sigma=None, order=1, + mode='reflect', cval=0): + """Upsample and then smooth image. + + Parameters + ---------- + image : array + Input image. + factor : float, optional + Upscale factor. Default is 2. + sigma : float, optional + Sigma for gaussian filter. Default is `2 * factor / 6.0` which + corresponds to a filter mask twice the size of the scale factor that + covers more than 99% of the gaussian distribution. + order : int, optional + Order of splines used in interpolation of downsampling. See + `scipy.ndimage.map_coordinates` for detail. Default is 1. + mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional + The mode parameter determines how the array borders are handled, where + cval is the value when mode is equal to 'constant'. + Default is 'reflect'. + cval : float, optional + Value to fill past edges of input if mode is 'constant'. Default is 0. + + Returns + ------- + out : array + Upsampled and smoothed image. + + References + ---------- + ..[1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf + + """ + + _check_factor(factor) + + rows = image.shape[0] + cols = image.shape[1] + out_rows = 2 * rows + out_cols = 2 * cols + + if sigma is None: + # automatically determine sigma which covers > 99% of distribution + sigma = 2 * factor / 6.0 + + resized = resize(image, (out_rows, out_cols), order=order, + mode=mode, cval=cval) + out = _smooth(resized, sigma, mode, cval) + + return out + + +def build_gaussian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, + mode='reflect', cval=0): + """Build gaussian pyramid. + + Recursively applies the `pyramid_reduce` function to the image. + + Parameters + ---------- + image : array + Input image. + max_layer : int + Number of layers for the pyramid. 0th layer is the original image. + Default is -1 which builds all possible layers. + factor : float, optional + Downscale factor. Default is 2. + sigma : float, optional + Sigma for gaussian filter. Default is `2 * factor / 6.0` which + corresponds to a filter mask twice the size of the scale factor that + covers more than 99% of the gaussian distribution. + order : int, optional + Order of splines used in interpolation of downsampling. See + `scipy.ndimage.map_coordinates` for detail. Default is 1. + mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional + The mode parameter determines how the array borders are handled, where + cval is the value when mode is equal to 'constant'. + Default is 'reflect'. + cval : float, optional + Value to fill past edges of input if mode is 'constant'. Default is 0. + + Returns + ------- + pyramid : list of arrays + + """ + + _check_factor(factor) + + pyramid = [] + pyramid.append(image) + + layer = 0 + rows = image.shape[0] + cols = image.shape[1] + + # build downsampled images until max_layer is reached or downsampled image + # has size of 1 in one direction + while True: + layer += 1 + + layer_image = pyramid_reduce(pyramid[-1], factor, sigma, order, + mode, cval) + + # image degraded to 1px + if layer_image.ndim == 1: + break + + prev_rows = rows + prev_cols = cols + rows = layer_image.shape[0] + cols = layer_image.shape[1] + + # no change to previous pyramid layer + if prev_rows == rows and prev_cols == cols: + break + + pyramid.append(layer_image) + + if layer == max_layer: + break + + return pyramid + + +def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, + mode='reflect', cval=0): + """Build laplacian pyramid. + + Each layer contains the difference between the downsampled and the + downsampled plus smoothed image. + + Parameters + ---------- + image : array + Input image. + max_layer : int + Number of layers for the pyramid. 0th layer is the original image. + Default is -1 which builds all possible layers. + factor : float, optional + Downscale factor. Default is 2. + sigma : float, optional + Sigma for gaussian filter. Default is `2 * factor / 6.0` which + corresponds to a filter mask twice the size of the scale factor that + covers more than 99% of the gaussian distribution. + order : int, optional + Order of splines used in interpolation of downsampling. See + `scipy.ndimage.map_coordinates` for detail. Default is 1. + mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional + The mode parameter determines how the array borders are handled, where + cval is the value when mode is equal to 'constant'. + Default is 'reflect'. + cval : float, optional + Value to fill past edges of input if mode is 'constant'. Default is 0. + + Returns + ------- + pyramid : list of arrays + + """ + + _check_factor(factor) + + if sigma is None: + # automatically determine sigma which covers > 99% of distribution + sigma = 2 * factor / 6.0 + + pyramid = [] + pyramid.append(image - _smooth(image, sigma, mode, cval)) + + layer = 0 + rows = image.shape[0] + cols = image.shape[1] + + # build downsampled images until max_layer is reached or downsampled image + # has size of 1 in one direction + while True: + layer += 1 + + rows = pyramid[-1].shape[0] + cols = pyramid[-1].shape[1] + out_rows = math.ceil(rows / float(factor)) + out_cols = math.ceil(cols / float(factor)) + + resized = resize(pyramid[-1], (out_rows, out_cols), order=order, + mode=mode, cval=cval) + layer_image = _smooth(resized, sigma, mode, cval) + + # image degraded to 1px + if layer_image.ndim == 1: + break + + prev_rows = rows + prev_cols = cols + rows = layer_image.shape[0] + cols = layer_image.shape[1] + + # no change to previous pyramid layer + if prev_rows == rows and prev_cols == cols: + break + + pyramid.append(layer_image) + + if layer == max_layer: + break + + return pyramid From b7ac633a5e470f9164b496d53d9f110581ac4814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Wed, 5 Sep 2012 15:06:24 +0200 Subject: [PATCH 02/25] Add missing references --- skimage/transform/pyramid.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/skimage/transform/pyramid.py b/skimage/transform/pyramid.py index 1a011fb6..5c0a7905 100644 --- a/skimage/transform/pyramid.py +++ b/skimage/transform/pyramid.py @@ -168,6 +168,10 @@ def build_gaussian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, ------- pyramid : list of arrays + References + ---------- + ..[1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf + """ _check_factor(factor) @@ -242,6 +246,10 @@ def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, ------- pyramid : list of arrays + References + ---------- + ..[1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf + """ _check_factor(factor) From c57085520967fa92ad97f67ab85fe3f370c3ff84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Wed, 5 Sep 2012 15:07:46 +0200 Subject: [PATCH 03/25] Rename file of pyramid functions --- skimage/transform/__init__.py | 4 ++-- skimage/transform/{pyramid.py => pyramids.py} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename skimage/transform/{pyramid.py => pyramids.py} (100%) diff --git a/skimage/transform/__init__.py b/skimage/transform/__init__.py index abf31517..fc2b12ef 100644 --- a/skimage/transform/__init__.py +++ b/skimage/transform/__init__.py @@ -7,5 +7,5 @@ from ._geometric import (warp, warp_coords, estimate_transform, ProjectiveTransform, PolynomialTransform, PiecewiseAffineTransform) from ._warps import swirl, homography, resize, rotate -from .pyramid import (pyramid_reduce, pyramid_expand, - build_gaussian_pyramid, build_laplacian_pyramid) +from .pyramids import (pyramid_reduce, pyramid_expand, + build_gaussian_pyramid, build_laplacian_pyramid) diff --git a/skimage/transform/pyramid.py b/skimage/transform/pyramids.py similarity index 100% rename from skimage/transform/pyramid.py rename to skimage/transform/pyramids.py From eaed3dff1e478ee0ba9e1564ab22fc9ec059f166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Wed, 5 Sep 2012 15:18:08 +0200 Subject: [PATCH 04/25] Add tests for pyramid functions --- skimage/transform/tests/test_pyramids.py | 41 ++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 skimage/transform/tests/test_pyramids.py diff --git a/skimage/transform/tests/test_pyramids.py b/skimage/transform/tests/test_pyramids.py new file mode 100644 index 00000000..e10d317e --- /dev/null +++ b/skimage/transform/tests/test_pyramids.py @@ -0,0 +1,41 @@ +from numpy.testing import assert_array_equal, run_module_suite +from skimage import data +from skimage.transform import (pyramid_reduce, pyramid_expand, + build_gaussian_pyramid, build_laplacian_pyramid) + + +image = data.lena() + + +def test_pyramid_reduce(): + rows, cols, dim = image.shape + out = pyramid_reduce(image, factor=2) + assert_array_equal(out.shape, (rows / 2, cols / 2, dim)) + + +def test_pyramid_expand(): + rows, cols, dim = image.shape + out = pyramid_expand(image, factor=2) + assert_array_equal(out.shape, (rows * 2, cols * 2, dim)) + + +def test_build_gaussian_pyramid(): + rows, cols, dim = image.shape + pyramid = build_gaussian_pyramid(image, factor=2) + + for layer, out in enumerate(pyramid): + layer_shape = (rows / 2 ** layer, cols / 2 ** layer, dim) + assert_array_equal(out.shape, layer_shape) + + +def test_build_laplacian_pyramid(): + rows, cols, dim = image.shape + pyramid = build_laplacian_pyramid(image, factor=2) + + for layer, out in enumerate(pyramid): + layer_shape = (rows / 2 ** layer, cols / 2 ** layer, dim) + assert_array_equal(out.shape, layer_shape) + + +if __name__ == "__main__": + run_module_suite() From c42b3d656dc31f86338d3066c49be276730d06ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 7 Sep 2012 18:11:48 +0200 Subject: [PATCH 05/25] Fix wrong factor in pyramid_expand --- skimage/transform/pyramids.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index 5c0a7905..e5507460 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -121,8 +121,8 @@ def pyramid_expand(image, factor=2, sigma=None, order=1, rows = image.shape[0] cols = image.shape[1] - out_rows = 2 * rows - out_cols = 2 * cols + out_rows = math.ceil(factor * rows) + out_cols = math.ceil(factor * cols) if sigma is None: # automatically determine sigma which covers > 99% of distribution From b7e965eec0a60fff314c488f750a37b808e219ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 7 Sep 2012 18:26:57 +0200 Subject: [PATCH 06/25] Fix singleton dimension for 1 pixel image --- skimage/transform/_geometric.py | 6 ++++-- skimage/transform/pyramids.py | 18 ++---------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/skimage/transform/_geometric.py b/skimage/transform/_geometric.py index f81e6e22..c3f21db9 100644 --- a/skimage/transform/_geometric.py +++ b/skimage/transform/_geometric.py @@ -1016,5 +1016,7 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1, if mode == 'constant' and not (0 <= cval <= 1): clipped[out == cval] = cval - # Remove singleton dim introduced by atleast_3d - return clipped.squeeze() + if clipped.shape[0] == 1 or clipped.shape[1] == 1: + return clipped + else: # remove singleton dim introduced by atleast_3d + return clipped.squeeze() diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index e5507460..0fdef92e 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -185,16 +185,12 @@ def build_gaussian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, # build downsampled images until max_layer is reached or downsampled image # has size of 1 in one direction - while True: + while layer != max_layer: layer += 1 layer_image = pyramid_reduce(pyramid[-1], factor, sigma, order, mode, cval) - # image degraded to 1px - if layer_image.ndim == 1: - break - prev_rows = rows prev_cols = cols rows = layer_image.shape[0] @@ -206,9 +202,6 @@ def build_gaussian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, pyramid.append(layer_image) - if layer == max_layer: - break - return pyramid @@ -267,7 +260,7 @@ def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, # build downsampled images until max_layer is reached or downsampled image # has size of 1 in one direction - while True: + while layer != max_layer: layer += 1 rows = pyramid[-1].shape[0] @@ -279,10 +272,6 @@ def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, mode=mode, cval=cval) layer_image = _smooth(resized, sigma, mode, cval) - # image degraded to 1px - if layer_image.ndim == 1: - break - prev_rows = rows prev_cols = cols rows = layer_image.shape[0] @@ -294,7 +283,4 @@ def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, pyramid.append(layer_image) - if layer == max_layer: - break - return pyramid From 2780ae63e2591c64b50a5e8de982000d5fb55147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 7 Sep 2012 18:33:43 +0200 Subject: [PATCH 07/25] Make pyramid functions generators --- skimage/transform/pyramids.py | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index 0fdef92e..babdea58 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -176,23 +176,24 @@ def build_gaussian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, _check_factor(factor) - pyramid = [] - pyramid.append(image) - layer = 0 rows = image.shape[0] cols = image.shape[1] + prev_layer_image = image + yield prev_layer_image + # build downsampled images until max_layer is reached or downsampled image # has size of 1 in one direction while layer != max_layer: layer += 1 - layer_image = pyramid_reduce(pyramid[-1], factor, sigma, order, + layer_image = pyramid_reduce(prev_layer_image, factor, sigma, order, mode, cval) prev_rows = rows prev_cols = cols + prev_layer_image = layer_image rows = layer_image.shape[0] cols = layer_image.shape[1] @@ -200,9 +201,7 @@ def build_gaussian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, if prev_rows == rows and prev_cols == cols: break - pyramid.append(layer_image) - - return pyramid + yield layer_image def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, @@ -251,29 +250,30 @@ def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, # automatically determine sigma which covers > 99% of distribution sigma = 2 * factor / 6.0 - pyramid = [] - pyramid.append(image - _smooth(image, sigma, mode, cval)) - layer = 0 rows = image.shape[0] cols = image.shape[1] + prev_layer_image = image - _smooth(image, sigma, mode, cval) + yield prev_layer_image + # build downsampled images until max_layer is reached or downsampled image # has size of 1 in one direction while layer != max_layer: layer += 1 - rows = pyramid[-1].shape[0] - cols = pyramid[-1].shape[1] + rows = prev_layer_image.shape[0] + cols = prev_layer_image.shape[1] out_rows = math.ceil(rows / float(factor)) out_cols = math.ceil(cols / float(factor)) - resized = resize(pyramid[-1], (out_rows, out_cols), order=order, + resized = resize(prev_layer_image, (out_rows, out_cols), order=order, mode=mode, cval=cval) layer_image = _smooth(resized, sigma, mode, cval) prev_rows = rows prev_cols = cols + prev_layer_image = layer_image rows = layer_image.shape[0] cols = layer_image.shape[1] @@ -281,6 +281,4 @@ def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, if prev_rows == rows and prev_cols == cols: break - pyramid.append(layer_image) - - return pyramid + yield layer_image From bccbc36b91afcd3baede742a41707bc96bb25b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 7 Sep 2012 18:47:50 +0200 Subject: [PATCH 08/25] Use consistent dtype for all levels of pyramid --- skimage/transform/pyramids.py | 10 ++++++++-- skimage/transform/tests/test_pyramids.py | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index babdea58..bccc5f51 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -119,6 +119,8 @@ def pyramid_expand(image, factor=2, sigma=None, order=1, _check_factor(factor) + image = img_as_float(image) + rows = image.shape[0] cols = image.shape[1] out_rows = math.ceil(factor * rows) @@ -176,12 +178,15 @@ def build_gaussian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, _check_factor(factor) + image = img_as_float(image) + layer = 0 rows = image.shape[0] cols = image.shape[1] + # cast to float for consistent data type in pyramid prev_layer_image = image - yield prev_layer_image + yield image # build downsampled images until max_layer is reached or downsampled image # has size of 1 in one direction @@ -246,6 +251,8 @@ def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, _check_factor(factor) + image = img_as_float(image) + if sigma is None: # automatically determine sigma which covers > 99% of distribution sigma = 2 * factor / 6.0 @@ -255,7 +262,6 @@ def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, cols = image.shape[1] prev_layer_image = image - _smooth(image, sigma, mode, cval) - yield prev_layer_image # build downsampled images until max_layer is reached or downsampled image # has size of 1 in one direction diff --git a/skimage/transform/tests/test_pyramids.py b/skimage/transform/tests/test_pyramids.py index e10d317e..981b93fe 100644 --- a/skimage/transform/tests/test_pyramids.py +++ b/skimage/transform/tests/test_pyramids.py @@ -33,6 +33,7 @@ def test_build_laplacian_pyramid(): pyramid = build_laplacian_pyramid(image, factor=2) for layer, out in enumerate(pyramid): + layer += 1 layer_shape = (rows / 2 ** layer, cols / 2 ** layer, dim) assert_array_equal(out.shape, layer_shape) From f078854197cae61691d86b043b92f0b613409fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 7 Sep 2012 18:57:36 +0200 Subject: [PATCH 09/25] Rename factor parameters for better comprehensibility --- skimage/transform/pyramids.py | 56 ++++++++++++------------ skimage/transform/tests/test_pyramids.py | 8 ++-- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index bccc5f51..470218a5 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -27,7 +27,7 @@ def _check_factor(factor): raise ValueError('scale factor must be greater than 1') -def pyramid_reduce(image, factor=2, sigma=None, order=1, +def pyramid_reduce(image, downscale=2, sigma=None, order=1, mode='reflect', cval=0): """Smooth and then downsample image. @@ -35,10 +35,10 @@ def pyramid_reduce(image, factor=2, sigma=None, order=1, ---------- image : array Input image. - factor : float, optional + downscale : float, optional Downscale factor. Default is 2. sigma : float, optional - Sigma for gaussian filter. Default is `2 * factor / 6.0` which + Sigma for gaussian filter. Default is `2 * downscale / 6.0` which corresponds to a filter mask twice the size of the scale factor that covers more than 99% of the gaussian distribution. order : int, optional @@ -62,18 +62,18 @@ def pyramid_reduce(image, factor=2, sigma=None, order=1, """ - _check_factor(factor) + _check_factor(downscale) image = img_as_float(image) rows = image.shape[0] cols = image.shape[1] - out_rows = math.ceil(rows / float(factor)) - out_cols = math.ceil(cols / float(factor)) + out_rows = math.ceil(rows / float(downscale)) + out_cols = math.ceil(cols / float(downscale)) if sigma is None: # automatically determine sigma which covers > 99% of distribution - sigma = 2 * factor / 6.0 + sigma = 2 * downscale / 6.0 smoothed = _smooth(image, sigma, mode, cval) out = resize(smoothed, (out_rows, out_cols), order=order, @@ -82,7 +82,7 @@ def pyramid_reduce(image, factor=2, sigma=None, order=1, return out -def pyramid_expand(image, factor=2, sigma=None, order=1, +def pyramid_expand(image, upscale=2, sigma=None, order=1, mode='reflect', cval=0): """Upsample and then smooth image. @@ -90,10 +90,10 @@ def pyramid_expand(image, factor=2, sigma=None, order=1, ---------- image : array Input image. - factor : float, optional + upscale : float, optional Upscale factor. Default is 2. sigma : float, optional - Sigma for gaussian filter. Default is `2 * factor / 6.0` which + Sigma for gaussian filter. Default is `2 * upscale / 6.0` which corresponds to a filter mask twice the size of the scale factor that covers more than 99% of the gaussian distribution. order : int, optional @@ -117,18 +117,18 @@ def pyramid_expand(image, factor=2, sigma=None, order=1, """ - _check_factor(factor) + _check_factor(upscale) image = img_as_float(image) rows = image.shape[0] cols = image.shape[1] - out_rows = math.ceil(factor * rows) - out_cols = math.ceil(factor * cols) + out_rows = math.ceil(upscale * rows) + out_cols = math.ceil(upscale * cols) if sigma is None: # automatically determine sigma which covers > 99% of distribution - sigma = 2 * factor / 6.0 + sigma = 2 * upscale / 6.0 resized = resize(image, (out_rows, out_cols), order=order, mode=mode, cval=cval) @@ -137,8 +137,8 @@ def pyramid_expand(image, factor=2, sigma=None, order=1, return out -def build_gaussian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, - mode='reflect', cval=0): +def build_gaussian_pyramid(image, max_layer=-1, downscale=2, sigma=None, + order=1, mode='reflect', cval=0): """Build gaussian pyramid. Recursively applies the `pyramid_reduce` function to the image. @@ -150,10 +150,10 @@ def build_gaussian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, max_layer : int Number of layers for the pyramid. 0th layer is the original image. Default is -1 which builds all possible layers. - factor : float, optional + downscale : float, optional Downscale factor. Default is 2. sigma : float, optional - Sigma for gaussian filter. Default is `2 * factor / 6.0` which + Sigma for gaussian filter. Default is `2 * downscale / 6.0` which corresponds to a filter mask twice the size of the scale factor that covers more than 99% of the gaussian distribution. order : int, optional @@ -176,7 +176,7 @@ def build_gaussian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, """ - _check_factor(factor) + _check_factor(downscale) image = img_as_float(image) @@ -193,7 +193,7 @@ def build_gaussian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, while layer != max_layer: layer += 1 - layer_image = pyramid_reduce(prev_layer_image, factor, sigma, order, + layer_image = pyramid_reduce(prev_layer_image, downscale, sigma, order, mode, cval) prev_rows = rows @@ -209,8 +209,8 @@ def build_gaussian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, yield layer_image -def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, - mode='reflect', cval=0): +def build_laplacian_pyramid(image, max_layer=-1, downscale=2, sigma=None, + order=1, mode='reflect', cval=0): """Build laplacian pyramid. Each layer contains the difference between the downsampled and the @@ -223,10 +223,10 @@ def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, max_layer : int Number of layers for the pyramid. 0th layer is the original image. Default is -1 which builds all possible layers. - factor : float, optional + downscale : float, optional Downscale factor. Default is 2. sigma : float, optional - Sigma for gaussian filter. Default is `2 * factor / 6.0` which + Sigma for gaussian filter. Default is `2 * downscale / 6.0` which corresponds to a filter mask twice the size of the scale factor that covers more than 99% of the gaussian distribution. order : int, optional @@ -249,13 +249,13 @@ def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, """ - _check_factor(factor) + _check_factor(downscale) image = img_as_float(image) if sigma is None: # automatically determine sigma which covers > 99% of distribution - sigma = 2 * factor / 6.0 + sigma = 2 * downscale / 6.0 layer = 0 rows = image.shape[0] @@ -270,8 +270,8 @@ def build_laplacian_pyramid(image, max_layer=-1, factor=2, sigma=None, order=1, rows = prev_layer_image.shape[0] cols = prev_layer_image.shape[1] - out_rows = math.ceil(rows / float(factor)) - out_cols = math.ceil(cols / float(factor)) + out_rows = math.ceil(rows / float(downscale)) + out_cols = math.ceil(cols / float(downscale)) resized = resize(prev_layer_image, (out_rows, out_cols), order=order, mode=mode, cval=cval) diff --git a/skimage/transform/tests/test_pyramids.py b/skimage/transform/tests/test_pyramids.py index 981b93fe..d9e6c599 100644 --- a/skimage/transform/tests/test_pyramids.py +++ b/skimage/transform/tests/test_pyramids.py @@ -9,19 +9,19 @@ image = data.lena() def test_pyramid_reduce(): rows, cols, dim = image.shape - out = pyramid_reduce(image, factor=2) + out = pyramid_reduce(image, downscale=2) assert_array_equal(out.shape, (rows / 2, cols / 2, dim)) def test_pyramid_expand(): rows, cols, dim = image.shape - out = pyramid_expand(image, factor=2) + out = pyramid_expand(image, upscale=2) assert_array_equal(out.shape, (rows * 2, cols * 2, dim)) def test_build_gaussian_pyramid(): rows, cols, dim = image.shape - pyramid = build_gaussian_pyramid(image, factor=2) + pyramid = build_gaussian_pyramid(image, downscale=2) for layer, out in enumerate(pyramid): layer_shape = (rows / 2 ** layer, cols / 2 ** layer, dim) @@ -30,7 +30,7 @@ def test_build_gaussian_pyramid(): def test_build_laplacian_pyramid(): rows, cols, dim = image.shape - pyramid = build_laplacian_pyramid(image, factor=2) + pyramid = build_laplacian_pyramid(image, downscale=2) for layer, out in enumerate(pyramid): layer += 1 From e6675dcda6721acb6ad70adc68f1e33ce8190fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 7 Sep 2012 19:07:58 +0200 Subject: [PATCH 10/25] Add example script for image pyramids --- doc/examples/plot_pyramid.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 doc/examples/plot_pyramid.py diff --git a/doc/examples/plot_pyramid.py b/doc/examples/plot_pyramid.py new file mode 100644 index 00000000..cacf0689 --- /dev/null +++ b/doc/examples/plot_pyramid.py @@ -0,0 +1,32 @@ +""" +==================== +Build image pyramids +==================== + +This example shows how to build image pyramids. +""" + +import numpy as np +import matplotlib.pyplot as plt + +from skimage import data +from skimage import img_as_float +from skimage.transform import build_gaussian_pyramid + + +image = data.lena() +rows, cols, dim = image.shape +pyramid = tuple(build_gaussian_pyramid(image, downscale=2)) + +display = np.zeros((rows, cols + cols / 2, 3), dtype=np.double) + +display[:rows, :cols, :] = pyramid[0] + +i_row = 0 +for p in pyramid[1:]: + n_rows, n_cols = p.shape[:2] + display[i_row:i_row + n_rows, cols:cols + n_cols] = p + i_row += n_rows + +plt.imshow(display) +plt.show() From 8e14f5f073dc054933f744978699b440213e3b7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sat, 8 Sep 2012 15:24:14 +0200 Subject: [PATCH 11/25] Add missing 0th layer of laplacian pyramid --- skimage/transform/pyramids.py | 1 + skimage/transform/tests/test_pyramids.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index 470218a5..4dd6f7b1 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -262,6 +262,7 @@ def build_laplacian_pyramid(image, max_layer=-1, downscale=2, sigma=None, cols = image.shape[1] prev_layer_image = image - _smooth(image, sigma, mode, cval) + yield prev_layer_image # build downsampled images until max_layer is reached or downsampled image # has size of 1 in one direction diff --git a/skimage/transform/tests/test_pyramids.py b/skimage/transform/tests/test_pyramids.py index d9e6c599..9aa236ff 100644 --- a/skimage/transform/tests/test_pyramids.py +++ b/skimage/transform/tests/test_pyramids.py @@ -33,7 +33,6 @@ def test_build_laplacian_pyramid(): pyramid = build_laplacian_pyramid(image, downscale=2) for layer, out in enumerate(pyramid): - layer += 1 layer_shape = (rows / 2 ** layer, cols / 2 ** layer, dim) assert_array_equal(out.shape, layer_shape) From 6142df6531d294c530bf12464e15f6d50ff33962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sat, 8 Sep 2012 17:24:11 +0200 Subject: [PATCH 12/25] Update doc string return type of image pyramids --- skimage/transform/pyramids.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index 4dd6f7b1..7a8e8228 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -168,7 +168,8 @@ def build_gaussian_pyramid(image, max_layer=-1, downscale=2, sigma=None, Returns ------- - pyramid : list of arrays + pyramid : generator + Generator yielding pyramid layers. References ---------- @@ -241,7 +242,8 @@ def build_laplacian_pyramid(image, max_layer=-1, downscale=2, sigma=None, Returns ------- - pyramid : list of arrays + pyramid : generator + Generator yielding pyramid layers. References ---------- From 2206681a89346970b71ca8d0ed1ff60a861b2ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 19:40:28 +0200 Subject: [PATCH 13/25] Update pyramid example with longer description --- doc/examples/plot_pyramid.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/examples/plot_pyramid.py b/doc/examples/plot_pyramid.py index cacf0689..218e86b1 100644 --- a/doc/examples/plot_pyramid.py +++ b/doc/examples/plot_pyramid.py @@ -3,7 +3,10 @@ Build image pyramids ==================== -This example shows how to build image pyramids. +The `build_gauassian_pyramid` function takes an image and yields successive +images shrunk by a constant scale factor. Image pyramids are often used, e.g., +to implement algorithms for denoising, texture discrimination, and scale- +invariant detection. """ import numpy as np From bab2f715dda1427bf9f17f8b3f009157fce89376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 19:41:06 +0200 Subject: [PATCH 14/25] Use more readable variable name for image --- doc/examples/plot_pyramid.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/examples/plot_pyramid.py b/doc/examples/plot_pyramid.py index 218e86b1..999435d5 100644 --- a/doc/examples/plot_pyramid.py +++ b/doc/examples/plot_pyramid.py @@ -21,15 +21,15 @@ image = data.lena() rows, cols, dim = image.shape pyramid = tuple(build_gaussian_pyramid(image, downscale=2)) -display = np.zeros((rows, cols + cols / 2, 3), dtype=np.double) +composite_image = np.zeros((rows, cols + cols / 2, 3), dtype=np.double) -display[:rows, :cols, :] = pyramid[0] +composite_image[:rows, :cols, :] = pyramid[0] i_row = 0 for p in pyramid[1:]: n_rows, n_cols = p.shape[:2] - display[i_row:i_row + n_rows, cols:cols + n_cols] = p + composite_image[i_row:i_row + n_rows, cols:cols + n_cols] = p i_row += n_rows -plt.imshow(display) +plt.imshow(composite_image) plt.show() From c9fd1f3dd044af88d2e62ed6ca41b6a29f321ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 19:44:13 +0200 Subject: [PATCH 15/25] Add doc string to helper function _smooth --- skimage/transform/pyramids.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index 7a8e8228..458b8c20 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -6,8 +6,8 @@ from skimage.util import img_as_float def _smooth(image, sigma, mode, cval): + """Return image with each channel smoothed by the gaussian filter.""" - # allocate output array smoothed = np.empty(image.shape, dtype=np.double) if image.ndim == 3: # apply gaussian filter to all dimensions independently From b812faf3698d2720a2a9e43aaf360a60b13c833e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 19:49:04 +0200 Subject: [PATCH 16/25] Remove default parameter values from doc string --- skimage/transform/pyramids.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index 458b8c20..53ec614c 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -36,20 +36,19 @@ def pyramid_reduce(image, downscale=2, sigma=None, order=1, image : array Input image. downscale : float, optional - Downscale factor. Default is 2. + Downscale factor. sigma : float, optional Sigma for gaussian filter. Default is `2 * downscale / 6.0` which corresponds to a filter mask twice the size of the scale factor that covers more than 99% of the gaussian distribution. order : int, optional Order of splines used in interpolation of downsampling. See - `scipy.ndimage.map_coordinates` for detail. Default is 1. + `scipy.ndimage.map_coordinates` for detail. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The mode parameter determines how the array borders are handled, where cval is the value when mode is equal to 'constant'. - Default is 'reflect'. cval : float, optional - Value to fill past edges of input if mode is 'constant'. Default is 0. + Value to fill past edges of input if mode is 'constant'. Returns ------- @@ -91,20 +90,19 @@ def pyramid_expand(image, upscale=2, sigma=None, order=1, image : array Input image. upscale : float, optional - Upscale factor. Default is 2. + Upscale factor. sigma : float, optional Sigma for gaussian filter. Default is `2 * upscale / 6.0` which corresponds to a filter mask twice the size of the scale factor that covers more than 99% of the gaussian distribution. order : int, optional Order of splines used in interpolation of downsampling. See - `scipy.ndimage.map_coordinates` for detail. Default is 1. + `scipy.ndimage.map_coordinates` for detail. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The mode parameter determines how the array borders are handled, where cval is the value when mode is equal to 'constant'. - Default is 'reflect'. cval : float, optional - Value to fill past edges of input if mode is 'constant'. Default is 0. + Value to fill past edges of input if mode is 'constant'. Returns ------- @@ -151,20 +149,19 @@ def build_gaussian_pyramid(image, max_layer=-1, downscale=2, sigma=None, Number of layers for the pyramid. 0th layer is the original image. Default is -1 which builds all possible layers. downscale : float, optional - Downscale factor. Default is 2. + Downscale factor. sigma : float, optional Sigma for gaussian filter. Default is `2 * downscale / 6.0` which corresponds to a filter mask twice the size of the scale factor that covers more than 99% of the gaussian distribution. order : int, optional Order of splines used in interpolation of downsampling. See - `scipy.ndimage.map_coordinates` for detail. Default is 1. + `scipy.ndimage.map_coordinates` for detail. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The mode parameter determines how the array borders are handled, where cval is the value when mode is equal to 'constant'. - Default is 'reflect'. cval : float, optional - Value to fill past edges of input if mode is 'constant'. Default is 0. + Value to fill past edges of input if mode is 'constant'. Returns ------- @@ -225,20 +222,19 @@ def build_laplacian_pyramid(image, max_layer=-1, downscale=2, sigma=None, Number of layers for the pyramid. 0th layer is the original image. Default is -1 which builds all possible layers. downscale : float, optional - Downscale factor. Default is 2. + Downscale factor. sigma : float, optional Sigma for gaussian filter. Default is `2 * downscale / 6.0` which corresponds to a filter mask twice the size of the scale factor that covers more than 99% of the gaussian distribution. order : int, optional Order of splines used in interpolation of downsampling. See - `scipy.ndimage.map_coordinates` for detail. Default is 1. + `scipy.ndimage.map_coordinates` for detail. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The mode parameter determines how the array borders are handled, where cval is the value when mode is equal to 'constant'. - Default is 'reflect'. cval : float, optional - Value to fill past edges of input if mode is 'constant'. Default is 0. + Value to fill past edges of input if mode is 'constant'. Returns ------- From f011a816e58ed2c0b0ce2b6c15f793ed692c4547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 19:50:59 +0200 Subject: [PATCH 17/25] Update short description of pyramid functions --- skimage/transform/pyramids.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index 53ec614c..dc35db7b 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -96,7 +96,7 @@ def pyramid_expand(image, upscale=2, sigma=None, order=1, corresponds to a filter mask twice the size of the scale factor that covers more than 99% of the gaussian distribution. order : int, optional - Order of splines used in interpolation of downsampling. See + Order of splines used in interpolation of upsampling. See `scipy.ndimage.map_coordinates` for detail. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The mode parameter determines how the array borders are handled, where @@ -137,7 +137,7 @@ def pyramid_expand(image, upscale=2, sigma=None, order=1, def build_gaussian_pyramid(image, max_layer=-1, downscale=2, sigma=None, order=1, mode='reflect', cval=0): - """Build gaussian pyramid. + """Yield images of the gaussian pyramid formed by the input image. Recursively applies the `pyramid_reduce` function to the image. @@ -209,7 +209,7 @@ def build_gaussian_pyramid(image, max_layer=-1, downscale=2, sigma=None, def build_laplacian_pyramid(image, max_layer=-1, downscale=2, sigma=None, order=1, mode='reflect', cval=0): - """Build laplacian pyramid. + """Yield images of the laplacian pyramid formed by the input image. Each layer contains the difference between the downsampled and the downsampled plus smoothed image. From c86d9196d8a631a388c39d0ab2a2e7197990106a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 19:55:46 +0200 Subject: [PATCH 18/25] Add information about return dtype --- skimage/transform/pyramids.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index dc35db7b..b6442bc6 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -53,7 +53,7 @@ def pyramid_reduce(image, downscale=2, sigma=None, order=1, Returns ------- out : array - Smoothed and downsampled image. + Smoothed and downsampled float image. References ---------- @@ -107,7 +107,7 @@ def pyramid_expand(image, upscale=2, sigma=None, order=1, Returns ------- out : array - Upsampled and smoothed image. + Upsampled and smoothed float image. References ---------- @@ -139,7 +139,9 @@ def build_gaussian_pyramid(image, max_layer=-1, downscale=2, sigma=None, order=1, mode='reflect', cval=0): """Yield images of the gaussian pyramid formed by the input image. - Recursively applies the `pyramid_reduce` function to the image. + Recursively applies the `pyramid_reduce` function to the image, and yields + the downscaled images. Note that the first image of the pyramid will be the + original, unscaled image. Parameters ---------- @@ -166,7 +168,7 @@ def build_gaussian_pyramid(image, max_layer=-1, downscale=2, sigma=None, Returns ------- pyramid : generator - Generator yielding pyramid layers. + Generator yielding pyramid layers as float images. References ---------- @@ -239,7 +241,7 @@ def build_laplacian_pyramid(image, max_layer=-1, downscale=2, sigma=None, Returns ------- pyramid : generator - Generator yielding pyramid layers. + Generator yielding pyramid layers as float images. References ---------- From 43afda1fa0ae2d0011d6b87b5c05e3eb1fe13a21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 20:02:25 +0200 Subject: [PATCH 19/25] Use gaussian pyramid function for collection viewer example --- viewer_examples/viewers/collection_viewer.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/viewer_examples/viewers/collection_viewer.py b/viewer_examples/viewers/collection_viewer.py index b36ddf82..32c0b836 100644 --- a/viewer_examples/viewers/collection_viewer.py +++ b/viewer_examples/viewers/collection_viewer.py @@ -21,9 +21,11 @@ home/end keys import numpy as np from skimage import data from skimage.viewer import CollectionViewer +from skimage.transform import build_gaussian_pyramid + img = data.lena() -img_collection = [np.uint8(img * 0.9**i) for i in range(20)] +img_collection = tuple(build_gaussian_pyramid(img)) view = CollectionViewer(img_collection) view.show() From 8a75cc4626bd38faeec102aea894d4e7ac08646c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 21:01:11 +0200 Subject: [PATCH 20/25] Update description of collection viewer example --- viewer_examples/viewers/collection_viewer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/viewer_examples/viewers/collection_viewer.py b/viewer_examples/viewers/collection_viewer.py index 32c0b836..24c97ab0 100644 --- a/viewer_examples/viewers/collection_viewer.py +++ b/viewer_examples/viewers/collection_viewer.py @@ -4,7 +4,7 @@ CollectionViewer demo ===================== Demo of CollectionViewer for viewing collections of images. This demo uses -successively darker versions of the same image to fake an image collection. +the different layers of the gaussian pyramid as image collection. You can scroll through images with the slider, or you can interact with the viewer using your keyboard: From 0f175a86b2d3b957adae12c15d1cf8157e5eaaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 21:34:42 +0200 Subject: [PATCH 21/25] Fix bug in laplacian pyramid caused by renamed variables --- skimage/transform/pyramids.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index b6442bc6..bcd52352 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -261,31 +261,29 @@ def build_laplacian_pyramid(image, max_layer=-1, downscale=2, sigma=None, rows = image.shape[0] cols = image.shape[1] - prev_layer_image = image - _smooth(image, sigma, mode, cval) - yield prev_layer_image + smoothed_image = _smooth(image, sigma, mode, cval) + yield image - smoothed_image # build downsampled images until max_layer is reached or downsampled image # has size of 1 in one direction while layer != max_layer: layer += 1 - rows = prev_layer_image.shape[0] - cols = prev_layer_image.shape[1] + out_rows = math.ceil(rows / float(downscale)) out_cols = math.ceil(cols / float(downscale)) - resized = resize(prev_layer_image, (out_rows, out_cols), order=order, - mode=mode, cval=cval) - layer_image = _smooth(resized, sigma, mode, cval) + resized_image = resize(smoothed_image, (out_rows, out_cols), + order=order, mode=mode, cval=cval) + smoothed_image = _smooth(resized_image, sigma, mode, cval) prev_rows = rows prev_cols = cols - prev_layer_image = layer_image - rows = layer_image.shape[0] - cols = layer_image.shape[1] + rows = resized_image.shape[0] + cols = resized_image.shape[1] # no change to previous pyramid layer if prev_rows == rows and prev_cols == cols: break - yield layer_image + yield resized_image - smoothed_image From 35ef2706065eb80258648c06ff2d4c6476002f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 21:36:21 +0200 Subject: [PATCH 22/25] Update legacy comment --- skimage/transform/pyramids.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index bcd52352..5028c034 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -188,8 +188,8 @@ def build_gaussian_pyramid(image, max_layer=-1, downscale=2, sigma=None, prev_layer_image = image yield image - # build downsampled images until max_layer is reached or downsampled image - # has size of 1 in one direction + # build downsampled images until max_layer is reached or downscale process + # does not change image size while layer != max_layer: layer += 1 @@ -264,12 +264,11 @@ def build_laplacian_pyramid(image, max_layer=-1, downscale=2, sigma=None, smoothed_image = _smooth(image, sigma, mode, cval) yield image - smoothed_image - # build downsampled images until max_layer is reached or downsampled image - # has size of 1 in one direction + # build downsampled images until max_layer is reached or downscale process + # does not change image size while layer != max_layer: layer += 1 - out_rows = math.ceil(rows / float(downscale)) out_cols = math.ceil(cols / float(downscale)) From d922c962e370b7b65dfbe84ccbcf452ce8c3f044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 21:36:56 +0200 Subject: [PATCH 23/25] Add another reference to laplacian pyramid --- skimage/transform/pyramids.py | 1 + 1 file changed, 1 insertion(+) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index 5028c034..79e00466 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -246,6 +246,7 @@ def build_laplacian_pyramid(image, max_layer=-1, downscale=2, sigma=None, References ---------- ..[1] http://web.mit.edu/persci/people/adelson/pub_pdfs/pyramid83.pdf + ..[2] http://sepwww.stanford.edu/~morgan/texturematch/paper_html/node3.html """ From a080624c7d1ca07fd2ddd6125fd24e8aba2e0a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 22:14:42 +0200 Subject: [PATCH 24/25] Move comment to correct code --- skimage/transform/pyramids.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index 79e00466..f07fb1c5 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -178,13 +178,13 @@ def build_gaussian_pyramid(image, max_layer=-1, downscale=2, sigma=None, _check_factor(downscale) + # cast to float for consistent data type in pyramid image = img_as_float(image) layer = 0 rows = image.shape[0] cols = image.shape[1] - # cast to float for consistent data type in pyramid prev_layer_image = image yield image @@ -252,6 +252,7 @@ def build_laplacian_pyramid(image, max_layer=-1, downscale=2, sigma=None, _check_factor(downscale) + # cast to float for consistent data type in pyramid image = img_as_float(image) if sigma is None: From 7766838d78288885f2b2e9a3ea86f1860afcafde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 9 Sep 2012 22:15:15 +0200 Subject: [PATCH 25/25] Remove unused import --- doc/examples/plot_pyramid.py | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/examples/plot_pyramid.py b/doc/examples/plot_pyramid.py index 999435d5..60067549 100644 --- a/doc/examples/plot_pyramid.py +++ b/doc/examples/plot_pyramid.py @@ -13,7 +13,6 @@ import numpy as np import matplotlib.pyplot as plt from skimage import data -from skimage import img_as_float from skimage.transform import build_gaussian_pyramid