Source code for magni.imaging._util

"""
..
    Copyright (c) 2014-2017, Magni developers.
    All rights reserved.
    See LICENSE.rst for further information.

Module providing the public functions of the magni.imaging subpackage.

"""

from __future__ import division

import numpy as np

from magni.utils.validation import decorate_validation as _decorate_validation
from magni.utils.validation import validate_numeric as _numeric


[docs]def double_mirror(img, fftstyle=False): """ Mirror image in both the vertical and horisontal axes. The image is mirrored around its upper left corner first in the horizontal axis and then in the vertical axis such that an image of four times the size of the original is returned. If `fftstyle` is True, the image is constructed such it would represent a fftshifted version of the mirrored `img` such that entry (0, 0) is the DC component. Parameters ---------- img : ndarray The image to mirror. fftstyle : bool The flag that indicates if the fftstyle mirrored image is returned. Returns ------- mirrored_img : ndarray The mirrored image. Examples -------- For example, mirror a very simple 2-by-3 pixel image. >>> import numpy as np >>> from magni.imaging._util import double_mirror >>> img = np.arange(6).reshape(2, 3) >>> img array([[0, 1, 2], [3, 4, 5]]) >>> double_mirror(img) array([[5, 4, 3, 3, 4, 5], [2, 1, 0, 0, 1, 2], [2, 1, 0, 0, 1, 2], [5, 4, 3, 3, 4, 5]]) >>> double_mirror(img, fftstyle=True) array([[0, 0, 0, 0, 0, 0], [0, 5, 4, 3, 4, 5], [0, 2, 1, 0, 1, 2], [0, 5, 4, 3, 4, 5]]) """ @_decorate_validation def validate_input(): _numeric('img', ('boolean', 'integer', 'floating', 'complex'), shape=(-1, -1)) _numeric('fftstyle', 'boolean') validate_input() if fftstyle: mirrored_img = np.zeros((img.shape[0] * 2, img.shape[1] * 2), dtype=img.dtype) tmp = np.pad(img, ((img.shape[0] - 1, 0), (img.shape[1] - 1, 0)), mode='reflect') mirrored_img[1:, 1:] = tmp else: mirrored_img = np.pad(img, ((img.shape[0], 0), (img.shape[1], 0)), mode='symmetric') return mirrored_img
[docs]def get_inscribed_masks(img, as_vec=False): """ Return a set of inscribed masks covering the image. Two masks are returned. One is the disc with radius equal to that of the inscribed circle for `img`. The other is the inscribed square of the first mask. If `as_vec` is True, the `img` must be a vector representation of the (matrix) image. In this case, the masks are also returned in vector representation. Parameters ---------- img : ndarray The square image of even height/width which the masks should cover. as_vec : bool The indicator of whether or not to treat `img` as a vector instead of an image (the default is False, which implies that `img` is treated as a matrix. Returns ------- cicle_mask : ndarray The inscribed cicle mask. square_mask : ndarray The inscribed square mask. Examples -------- For example, get the inscribed masks of an 8-by-8 image: >>> import numpy as np >>> from magni.imaging._util import get_inscribed_masks, mat2vec >>> img = np.arange(64).reshape(8, 8) >>> circle_mask, square_mask = get_inscribed_masks(img) >>> np_printoptions = np.get_printoptions() >>> np.set_printoptions(formatter={'bool': lambda x: str(int(x))}) >>> circle_mask array([[0, 1, 1, 1, 1, 1, 1, 0], [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], [0, 1, 1, 1, 1, 1, 1, 0]], dtype=bool) >>> square_mask array([[0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0]], dtype=bool) Or get the same masks based on a vector: >>> img_vec = mat2vec(img) >>> c_vec_mask, s_vec_mask = get_inscribed_masks(img_vec, as_vec=True) >>> c_vec_mask array([[0], [1], [1], [1], [1], [1], [1], [0], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [1], [1], [1], [1], [1], [0]], dtype=bool) >>> np.set_printoptions(**np_printoptions) """ @_decorate_validation def validate_input(): _numeric('as_vec', 'boolean') if not as_vec: _numeric('img', ('boolean', 'integer', 'floating', 'complex'), shape=(-1, -1)) if img.shape[0] != img.shape[1]: raise ValueError('The input image must be square') if np.mod(img.shape[0], 2) != 0: raise ValueError('The image height/width must be an even' + ' number of pixels') else: _numeric('img', ('boolean', 'integer', 'floating', 'complex'), shape=(-1, 1)) if not np.allclose(np.mod(np.sqrt(img.size), 1), 0): raise ValueError('The input image must be square') if np.mod(np.sqrt(img.shape[0]), 2) != 0: raise ValueError('The image height/width must be an even' + ' number of pixels') validate_input() if as_vec: r = np.sqrt(img.shape[0]) / 2 else: r = img.shape[0] / 2 x, y = np.meshgrid(*map(np.arange, (r, r))) circle_mask = double_mirror(x**2 + y**2 <= r**2) square_mask = double_mirror(np.maximum(x, y) <= r / np.sqrt(2)) if as_vec: return mat2vec(circle_mask), mat2vec(square_mask) else: return circle_mask, square_mask
[docs]def mat2vec(x): """ Reshape `x` from matrix to vector by stacking columns. Parameters ---------- x : ndarray Matrix that should be reshaped to vector. Returns ------- ndarray Column vector formed by stacking the columns of the matrix `x`. See Also -------- vec2mat : The inverse operation Notes ----- The returned column vector is C contiguous. Examples -------- For example, >>> import numpy as np >>> from magni.imaging._util import mat2vec >>> x = np.arange(4).reshape(2, 2) >>> x array([[0, 1], [2, 3]]) >>> mat2vec(x) array([[0], [2], [1], [3]]) """ @_decorate_validation def validate_input(): _numeric('x', ('boolean', 'integer', 'floating', 'complex'), shape=(-1, -1)) validate_input() return x.T.reshape(-1, 1)
[docs]def vec2mat(x, mn_tuple): """ Reshape `x` from column vector to matrix. Parameters ---------- x : ndarray Matrix that should be reshaped to vector. mn_tuple : tuple A tuple (m, n) containing the parameters m, n as listed below. m : int Number of rows in the resulting matrix. n : int Number of columns in the resulting matrix. Returns ------- ndarray Matrix formed by taking `n` columns of lenght `m` from the column vector `x`. See Also -------- mat2vec : The inverse operation Notes ----- The returned matrix is C contiguous. Examples -------- For example, >>> import numpy as np >>> from magni.imaging._util import vec2mat >>> x = np.arange(4).reshape(4, 1) >>> x array([[0], [1], [2], [3]]) >>> vec2mat(x, (2, 2)) array([[0, 2], [1, 3]]) """ m, n = mn_tuple @_decorate_validation def validate_input(): _numeric('m', 'integer', range_='[1;inf)') _numeric('n', 'integer', range_='[1;inf)') _numeric('x', ('boolean', 'integer', 'floating', 'complex'), shape=(m * n, 1)) validate_input() return x.reshape(n, m).T