Source code for magni.imaging.domains

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

Module providing a multi domain image class.

Routine listings
----------------
MultiDomainImage(object)
    Provide access to an image in the domains of a compressed sensing context.

"""

from __future__ import division

from magni.utils.matrices import Matrix as _Matrix
from magni.utils.matrices import MatrixCollection as _MatrixC
from magni.utils.validation import decorate_validation as _decorate_validation
from magni.utils.validation import validate_numeric as _numeric


[docs]class MultiDomainImage(object): """ Provide access to an image in the domains of a compressed sensing context. Given a measurement matrix and a dictionary, an image can be supplied in either the measurement domain, the image domain, or the coefficient domain. This class then provides access to the image in all three domains. Parameters ---------- Phi : magni.utils.matrices.Matrix, magni.utils.matrices.MatrixCollection, or numpy.ndarray The measurement matrix. Psi : magni.utils.matrices.Matrix, magni.utils.matrices.MatrixCollection, or numpy.ndarray The dictionary. Notes ----- The image is only converted to other domains than the supplied when the the image is requested in another domain. The image is, however, stored in up to three versions internally in order to reduce computation overhead. This may introduce a memory overhead. Examples -------- Define a measurement matrix which skips every other sample: >>> import numpy as np, magni >>> func = lambda vec: vec[::2] >>> func_T = lambda vec: np.float64([vec[0], 0, vec[1]]).reshape(3, 1) >>> Phi = magni.utils.matrices.Matrix(func, func_T, (), (2, 3)) Define a dictionary which is simply a rotated identity matrix: >>> v = np.sqrt(0.5) >>> Psi = np.float64([[ v, -v, 0], ... [ v, v, 0], ... [ 0, 0, 1]]) Instantiate the current class to handle domains: >>> from magni.imaging.domains import MultiDomainImage >>> domains = MultiDomainImage(Phi, Psi) An image can the be supplied in any domain and likewise retrieved in any domain. For example, setting the measurements and getting the coefficients: >>> domains.measurements = np.ones(2).reshape(-1, 1) >>> np.set_printoptions(suppress=True) >>> print(domains.coefficients) [[ 0.70710678] [-0.70710678] [ 1. ]] Or setting the coefficients and getting the image: >>> domains.coefficients = np.ones(3).reshape(-1, 1) >>> print(domains.image) [[ 0. ] [ 1.41421356] [ 1. ]] Or setting the image and getting the measurements: >>> domains.image = np.ones(3).reshape(-1, 1) >>> print(domains.measurements) [[ 1.] [ 1.]] """ def __init__(self, Phi, Psi): @_decorate_validation def validate_input(): _numeric('Phi', ('integer', 'floating', 'complex'), shape=(-1, -1)) _numeric('Psi', ('integer', 'floating', 'complex'), shape=(Phi.shape[1], -1)) validate_input() self._Phi = Phi self._Psi = Psi self._has_data = False self._measurements = None self._image = None self._coefficients = None @property def coefficients(self): """ Get the image in the coefficient domain. Returns ------- coefficients : numpy.ndarray The dictionary coefficients of the image. """ if self._has_data: if self._coefficients is None: if self._image is None: self._image = self._Phi.T.dot(self._measurements) self._coefficients = self._Psi.T.dot(self._image) return self._coefficients @coefficients.setter def coefficients(self, value): """ Set the image in the coefficient domain. Parameters ---------- coefficients : numpy.ndarray The dictionary coefficients of the image. """ @_decorate_validation def validate_input(): _numeric('value', ('integer', 'floating', 'complex'), shape=(self._Psi.shape[1], 1)) validate_input() self._has_data = True self._measurements = None self._image = None self._coefficients = value @property def image(self): """ Get the image in the image domain. Returns ------- image : numpy.ndarray The image. """ if self._has_data: if self._image is None: if self._measurements is not None: self._image = self._Phi.T.dot(self._measurements) elif self._coefficients is not None: self._image = self._Psi.dot(self._coefficients) return self._image @image.setter def image(self, value): """ Set the image in the image domain. Parameters ---------- image : numpy.ndarray The image. """ @_decorate_validation def validate_input(): _numeric('value', ('integer', 'floating', 'complex'), shape=(self._Phi.shape[1], 1)) validate_input() self._has_data = True self._measurements = None self._image = value self._coefficients = None @property def measurements(self): """ Get the image in the measurement domain. Returns ------- measurements : numpy.ndarray The measurements of the image. """ if self._has_data: if self._measurements is None: if self._image is None: self._image = self._Psi.dot(self._coefficients) self._measurements = self._Phi.dot(self._image) return self._measurements @measurements.setter def measurements(self, value): """ Set the image in the measurement domain. Parameters ---------- measurements : numpy.ndarray The measurements of the image. """ @_decorate_validation def validate_input(): _numeric('value', ('integer', 'floating', 'complex'), shape=(self._Phi.shape[0], 1)) validate_input() self._has_data = True self._measurements = value self._image = None self._coefficients = None