コード例 #1
0
def find_center_by_gaussian_fit(IM, verbose=False, round_output=False,
                                **kwargs):
    """Deprecated function. Use :func:`find_origin_by_gaussian_fit` instead."""
    _deprecate('abel.tools.center.find_center_by_gaussian_fit() '
               'is deprecated, use '
               'abel.tools.center.find_origin_by_gaussian_fit() instead.')
    return find_origin_by_gaussian_fit(IM, verbose, round_output, **kwargs)
コード例 #2
0
def find_image_center_by_slice(IM, slice_width=10, radial_range=(0, -1),
                               axis=(0, 1), **kwargs):
    """Deprecated function. Use :func:`find_origin_by_slice` instead."""
    _deprecate('abel.tools.center.find_image_center_by_slice() '
               'is deprecated, use '
               'abel.tools.center.find_origin_by_slice() instead.')
    return find_origin_by_slice(IM, slice_width, radial_range, axis, **kwargs)
コード例 #3
0
def find_center_by_center_of_image(data, verbose=False, **kwargs):
    """Deprecated function. Use :func:`find_origin_by_center_of_image`
    instead."""
    _deprecate('abel.tools.center.find_center_by_center_of_image() '
               'is deprecated, use '
               'abel.tools.center.find_origin_by_center_of_image() instead.')
    return find_origin_by_center_of_image(data, verbose, **kwargs)
コード例 #4
0
def find_center(IM, center='image_center', square=False, verbose=False,
                **kwargs):
    """Deprecated function. Use :func:`find_origin` instead."""
    _deprecate('abel.tools.center.find_center() '
               'is deprecated, use abel.tools.center.find_origin() instead.')
    if square:
        _deprecate('Argument "square" has no effect and is deprecated.')
    return find_origin(IM, center, verbose, **kwargs)
コード例 #5
0
    def __init__(self,
                 IM,
                 direction='inverse',
                 method='three_point',
                 origin='none',
                 symmetry_axis=None,
                 use_quadrants=(True, True, True, True),
                 symmetrize_method='average',
                 angular_integration=False,
                 transform_options=dict(),
                 center_options=dict(),
                 angular_integration_options=dict(),
                 recast_as_float64=True,
                 verbose=False,
                 center=_deprecated):
        """
        The one-stop transform function.
        """
        if center is not _deprecated:
            _deprecate(
                'abel.transform.Transform() '
                'argument "center" is deprecated, use "origin" instead.')
            origin = center

        # public class variables
        self.IM = IM  # (optionally) centered, odd-width image
        self.method = method
        self.direction = direction

        # private internal variables
        self._origin = origin
        self._symmetry_axis = symmetry_axis
        self._symmetrize_method = symmetrize_method
        self._use_quadrants = use_quadrants
        self._transform_options = transform_options
        self._recast_as_float64 = recast_as_float64
        _verbose = verbose

        # image processing
        self._verify_some_inputs()

        self._center_image(origin, **center_options)

        self._abel_transform_image(**transform_options)

        self._integration(angular_integration, transform_options,
                          **angular_integration_options)
コード例 #6
0
ファイル: analytical.py プロジェクト: MikhailRyazanov/PyAbel
 def image(self):
     """Deprecated. Use :attr:`func` instead."""
     _deprecate('SampleImage attribute ".image" is deprecated, '
                'use ".func" instead.')
     return self.func
コード例 #7
0
def radial_integration(IM, origin=None, radial_ranges=None):
    r""" Intensity variation in the angular coordinate.

    This function is the :math:`\theta`-coordinate complement to
    :func:`abel.tools.vmi.angular_integration`.

    Evaluates intensity vs angle for defined radial ranges.
    Determines the anisotropy parameter for each radial range.

    See :doc:`examples/example_O2_PES_PAD.py <example_O2_PES_PAD>`.

    Parameters
    ----------
    IM : 2D numpy.array
        the image data

    origin : tuple or None
        image origin in the (row, column) format. If ``None``, the geometric
        center of the image (``rows // 2, cols // 2``) is used.

    radial_ranges : list of tuple ranges or int step
        tuple
            integration ranges
            ``[(r0, r1), (r2, r3), ...]``
            evaluates the intensity vs angle
            for the radial ranges ``r0_r1``, ``r2_r3``, etc.

        int
            the whole radial range ``(0, step), (step, 2*step), ..``

    Returns
    -------
    Beta : array of tuples
        (beta0, error_beta_fit0), (beta1, error_beta_fit1), ...
        corresponding to the radial ranges

    Amplitude : array of tuples
        (amp0, error_amp_fit0), (amp1, error_amp_fit1), ...
        corresponding to the radial ranges

    Rmidpt : numpy float 1D array
        radial mid-point of each radial range

    Intensity_vs_theta: 2D numpy.array
        intensity vs angle distribution for each selected radial range

    theta: 1D numpy.array
        angle coordinates, referenced to vertical direction
    """
    if origin is not None and not isinstance(origin, tuple):
        _deprecate('radial_integration() has 2nd argument "origin", '
                   'use keyword argument "radial_ranges" or insert "None".')
        radial_ranges = origin
        origin = None

    polarIM, r_grid, theta_grid = reproject_image_into_polar(IM, origin)

    theta = theta_grid[0, :]  # theta coordinates
    r = r_grid[:, 0]  # radial coordinates

    if radial_ranges is None:
        radial_ranges = 1
    if isinstance(radial_ranges, int):
        rr = np.arange(0, r[-1], radial_ranges)
        # @DanHickstein clever code to map ranges
        radial_ranges = list(zip(rr[:-1], rr[1:]))

    Intensity_vs_theta = []
    radial_midpt = []
    Beta = []
    Amp = []
    for rr in radial_ranges:
        subr = np.logical_and(r >= rr[0], r <= rr[1])

        # sum intensity across radius of spectral feature
        intensity_vs_theta_at_R = np.sum(polarIM[subr], axis=0)
        Intensity_vs_theta.append(intensity_vs_theta_at_R)
        radial_midpt.append(np.mean(rr))

        beta, amp = anisotropy_parameter(theta, intensity_vs_theta_at_R)
        Beta.append(beta)
        Amp.append(amp)

    return Beta, Amp, radial_midpt, Intensity_vs_theta, theta
コード例 #8
0
ファイル: circularize.py プロジェクト: MikhailRyazanov/PyAbel
def circularize_image(IM,
                      method="lsq",
                      origin=None,
                      radial_range=None,
                      dr=0.5,
                      dt=0.5,
                      smooth=_deprecated,
                      ref_angle=None,
                      inverse=False,
                      return_correction=False,
                      tol=0,
                      center=_deprecated):
    r"""
    Corrects image distortion on the basis that the structure should be
    circular.

    This is a simplified radial scaling version of the algorithm described in
    J. R. Gascooke, S. T. Gibson, W. D. Lawrance,
    "A 'circularisation' method to repair deformations and determine the centre
    of velocity map images",
    `J. Chem. Phys. 147, 013924 (2017)
    <https://dx.doi.org/10.1063/1.4981024>`_.

    This function is especially useful for correcting the image obtained with
    a velocity-map-imaging spectrometer, in the case where there is distortion
    of the Newton sphere (ring) structure due to an imperfect electrostatic
    lens or stray electromagnetic fields. The correction allows the
    highest-resolution 1D photoelectron distribution to be extracted.

    The algorithm splits the image into "slices" at many different angles
    (set by **dt**) and compares the radial intensity profile of adjacent slices.
    A scaling factor is found which aligns each slice profile with the previous
    slice. The image is then corrected using a spline function that smoothly
    connects the discrete scaling factors as a continuous function of angle.

    This circularization algorithm should only be applied to a well-centered
    image, otherwise use the **origin** keyword (described below) to
    center it.


    Parameters
    ----------
    IM : numpy 2D array
        Image to be circularized.

    method : str
        Method used to determine the radial correction factor to align slice
        profiles:

        ``argmax``
            compare intensity-profile.argmax() of each radial slice.
            This method is quick and reliable, but it assumes that
            the radial intensity profile has an obvious maximum.
            The positioning is limited to the nearest pixel.

        ``lsq``
            minimize the difference between a slice intensity-profile
            with its adjacent slice.
            This method is slower and may fail to converge, but it
            may be applied to images with any (circular) structure.
            It aligns the slices with sub-pixel precision.

    origin : float tuple, str or None
        Pre-center image using :func:`abel.tools.center.center_image`.
        May be an explicit (row, column) tuple or a method name: ``'com'``,
        ``'convolution'``, ``'gaussian;``, ``'image_center'``, ``'slice'``.
        ``None`` (default) assumes that the image is already centered.

    radial_range : tuple or None
        Limit slice comparison to the radial range tuple (rmin, rmax), in
        pixels, from the image origin. Use to determine the distortion
        correction associated with particular peaks. It is recommended to
        select a region of your image where the signal-to-noise ratio is
        highest, with sharp persistent (in angle) features.

    dr : float
        Radial grid size for the polar coordinate image, default = 0.5 pixel.
        This is passed to :func:`abel.tools.polar.reproject_image_into_polar`.

        Small values may improve the distortion correction, which is often of
        sub-pixel dimensions, at the cost of reduced signal to noise for the
        slice intensity profile. As a general rule, `dr` should be
        significantly smaller than the radial "feature size" in the image.

    dt : float
        Angular grid size. This sets the number of radial slices, given by
        :math:`2\pi/dt`. Default = 0.1, ~ 63 slices. More slices, using
        smaller `dt`, may provide a more detailed angular variation of the
        correction, at the cost of greater signal to noise in the correction
        function.

        Also passed to :func:`abel.tools.polar.reproject_image_into_polar`.

    smooth : float
        Deprecated, use **tol** instead. The relationship is
        **smooth** = `N`\ :sub:`angles` × **tol**\ :sup:`2`,
        where `N`\ :sub:`angles` is the number of slices (see **dt**).

    ref_angle : None or float
        Reference angle for which radial coordinate is unchanged.
        Angle varies between :math:`-\pi` and :math:`\pi`, with zero angle
        vertical.

        ``None`` uses :func:`numpy.mean` of the radial correction function,
        which attempts to maintain the same average radial scaling. This
        approximation is likely valid, unless you know for certain that a
        specific angle of your image corresponds to an undistorted image.

    inverse : bool
        Apply an inverse Abel transform to the `polar`-coordinate image, to
        remove the background intensity. This may improve the signal-to-noise
        ratio, allowing the weaker intensity featured to be followed in angle.

        Note that this step is only for the purposes of allowing the algorithm
        to better follow peaks in the image. It does not affect the final
        image that is returned, except for (hopefully) slightly improving the
        precision of the distortion correction.

    return_correction : bool
        Additional outputs, as describe below.

    tol : float
        Root-mean-square (RMS) fitting tolerance for the spline function. At
        the default zero value, the spline interpolates between the discrete
        scaling factors. At larger values, a smoother spline is found such that
        its RMS deviation from the discrete scaling factors does not exceed
        this number. For example, ``tol=0.01`` means 1% RMS tolerance for the
        radial scaling correction. At very large tolerances, the spline
        degenerates to a constant, the average of the discrete scaling factors.

        Typically, **tol** may remain zero (use interpolation), but noisy data
        may require some smoothing, since the found discrete scaling factors
        can have noticeable errors. To examine the relative scaling factors and
        how well they are represented by the spline function, use the option
        ``return_correction=True``.

    Returns
    -------
    IMcirc : numpy 2D array
        Circularized version of the input image, same size as input.

    The following values are returned if ``return_correction=True``:

    angles : numpy 1D array
        Mid-point angle (radians) of each image slice.

    radial_correction : numpy 1D array
        Radial correction scale factor at each angular slice.

    radial_correction_function : function(numpy 1D array)
        Function that may be used to evaluate the radial correction at any
        angle.

    """
    if center is not _deprecated:
        _deprecate('abel.tools.circularize.circularize_image() '
                   'argument "center" is deprecated, use "origin" instead.')
        origin = center

    if origin is not None:
        # convenience function for the case image is not centered
        IM = abel.tools.center.center_image(IM, method=origin)

    # map image into polar coordinates - much easier to slice
    # cartesian (Y, X) -> polar (Radius, Theta)
    polarIM, radial_coord, angle_coord = \
        abel.tools.polar.reproject_image_into_polar(IM, dr=dr, dt=dt)

    if inverse:
        # pseudo inverse Abel transform of the polar image, removes background
        # to enhance transition peaks
        polarIM = abel.dasch.two_point_transform(polarIM.T).T

    # more convenient 1-D coordinate arrays
    angles = angle_coord[0]  # angle coordinate
    radial = radial_coord[:, 0]  # radial coordinate

    # limit radial range of polar image, if selected
    if radial_range is not None:
        subr = np.logical_and(radial > radial_range[0],
                              radial < radial_range[1])
        polarIM = polarIM[subr]
        radial = radial[subr]

    # evaluate radial correction factor that aligns each angular slice
    radcorr = correction(polarIM.T, angles, radial, method=method)

    if smooth is not _deprecated:
        _deprecate('abel.tools.circularize.circularize_image() '
                   'argument "smooth" is deprecated, use "tol" instead.')
    else:
        smooth = len(angles) * tol**2

    # periodic spline radial correction vs angle
    spl = splrep(np.append(angles, angles[0] + 2 * np.pi),
                 np.append(radcorr, radcorr[0]),
                 s=smooth,
                 per=True)

    def radial_correction_function(angle):
        return splev(angle, spl)

    # apply the correction
    IMcirc = circularize(IM, radial_correction_function, ref_angle=ref_angle)

    if return_correction:
        return IMcirc, angles, radcorr, radial_correction_function
    else:
        return IMcirc
コード例 #9
0
def find_center_by_convolution(IM, **kwargs):
    """Deprecated function. Use :func:`find_origin_by_convolution` instead."""
    _deprecate('abel.tools.center.find_center_by_convolution() '
               'is deprecated, use '
               'abel.tools.center.find_origin_by_convolution() instead.')
    return find_origin_by_convolution(IM, **kwargs)
コード例 #10
0
def center_image(IM, method='com', odd_size=True, square=False, axes=(0, 1),
                 crop='maintain_size', order=3, verbose=False,
                 center=_deprecated, **kwargs):
    """
    Center image with the custom value or by several methods provided in
    :func:`find_origin()` function.

    Parameters
    ----------
    IM : 2D np.array
        The image data.

    method : str or tuple of float
        either a tuple (float, float), the coordinate of the origin of the
        image in the (row, column) format, or a string to specify an automatic
        centering method:

        ``image_center``
            the center of the image is used as the origin. The trivial result.
        ``com``
            the origin is found as the center of mass.
        ``convolution``
            the origin is found as the maximum of autoconvolution of the image
            projections along each axis.
        ``gaussian``
            the origin is extracted from a fit to a Gaussian function.
            This is probably only appropriate if the data resembles a
            gaussian.
        ``slice``
            the image is broken into slices, and these slices compared for
            symmetry.

    odd_size : boolean
        if ``True``, the returned image will contain an odd number of columns.
        Most of the transform methods require this, so it's best to set this
        to ``True`` if the image will subsequently be Abel-transformed.

    square : bool
        if ``True``, the returned image will have a square shape.

    crop : str
        determines how the image should be cropped. The options are:

        ``maintain_size``
            return image of the same size. Some regions of the original image
            may be lost, and some regions may be filled with zeros.
        ``valid_region``
            return the largest image that can be created without padding.
            All of the returned image will correspond to the original image.
            However, portions of the original image will be lost.
            If you can tolerate clipping the edges of the image, this is
            probably the method to choose.
        ``maintain_data``
            the image will be padded with zeros such that none of the original
            image will be cropped.

        See :func:`set_center` for examples.

    axes : int or tuple of int
        center image with respect to axis ``0`` (vertical), ``1`` (horizontal),
        or both axes ``(0, 1)`` (default). When specifying an explicit origin
        in **method**, unused coordinates can also be passed as ``None``, for
        example, ``method=(row, None)`` or ``method=(None, col)``.

    order : int
        interpolation order, see :func:`set_center` for details.

    Returns
    -------
    out : 2D np.array
        centered image
    """
    if center is not _deprecated:
        _deprecate('abel.tools.center.center_image() '
                   'argument "center" is deprecated, use "method" instead.')
        method = center

    rows, cols = IM.shape

    if odd_size and cols % 2 == 0:
        # drop rightside column
        IM = IM[:, :-1]
        rows, cols = IM.shape

    if square and rows != cols:
        # make rows == cols, but maintain approx. center
        if rows > cols:
            diff = rows - cols
            trim = diff // 2
            if trim > 0:
                IM = IM[trim: -trim]  # remove even number of rows off each end
            if diff % 2:
                IM = IM[: -1]  # remove one additional row

        else:
            # make rows == cols, check row oddness
            if odd_size and rows % 2 == 0:
                IM = IM[:-1, :]
                rows -= 1
            xs = (cols - rows) // 2
            IM = IM[:, xs:-xs]

        rows, cols = IM.shape

    # origin is in (row, column) format!
    if isinstance(method, string_types):
        origin = find_origin(IM, method=method, axes=axes, verbose=verbose,
                             **kwargs)
    else:
        origin = method

    centered_data = set_center(IM, origin=origin, crop=crop, axes=axes,
                               order=order, verbose=verbose)
    return centered_data
コード例 #11
0
def find_origin_by_slice(IM, axes=(0, 1), slice_width=10, radial_range=(0, -1),
                         axis=_deprecated, **kwargs):
    """
    Find the image origin by comparing opposite sides.

    Parameters
    ----------
    IM : 2D np.array
        the image data

    slice_width : integer
        Sum together this number of rows (cols) to improve signal, default 10.

    radial_range: tuple
        (rmin, rmax): radial range ``[rmin:rmax]`` for slice profile
        comparison.

    axes : int or tuple
        find origin coordinates: ``0`` (vertical), or ``1`` (horizontal), or
        ``(0, 1)`` (both vertical and horizontal).

    Returns
    -------
    origin : (float, float)
        (row, column)

    """
    if axis is not _deprecated:
        _deprecate('abel.tools.center.find_origin_by_slice() '
                   'argument "axis" is deprecated, use "axes" instead.')
        axes = axis

    def _align(offset, sliceA, sliceB):
        """
        Intensity difference between an axial slice and its shifted opposite.
        """
        # always shift to the left (towards center)
        if offset < 0:
            diff = shift(sliceA, offset) - sliceB
        else:
            diff = sliceA - shift(sliceB, -offset)
        fvec = (diff**2).sum()
        return fvec

    if isinstance(axes, int):
        axes = [axes]

    rows, cols = IM.shape

    r2 = (rows - 1) / 2
    c2 = (cols - 1) / 2
    top, bottom, left, right = axis_slices(IM, radial_range, slice_width)

    xyoffset = [0.0, 0.0]
    # determine shift to align both slices
    # limit shift to +- 20 pixels
    initial_shift = [0.1, ]

    # vertical axis
    if 0 in axes:
        fit = minimize(_align, initial_shift, args=(top, bottom),
                       bounds=((-50, 50), ), tol=0.1)
        if fit["success"]:
            xyoffset[0] = -float(fit['x']) / 2  # x1/2 for image shift
        else:
            raise RuntimeError("fit failure: axis 0, zero shift set", fit)

    # horizontal axis
    if 1 in axes:
        fit = minimize(_align, initial_shift, args=(left, right),
                       bounds=((-50, 50), ), tol=0.1)
        if fit["success"]:
            xyoffset[1] = -float(fit['x']) / 2  # x1/2 for image shift
        else:
            raise RuntimeError("fit failure: axis 1, zero shift set", fit)

    # this is the (row, col) shift to align the slice profiles
    return r2 - xyoffset[0], c2 - xyoffset[1]
コード例 #12
0
def set_center(data, origin, crop='maintain_size', axes=(0, 1), order=3,
               verbose=False, center=_deprecated):
    """
    Move image origin to mid-point of image (``rows // 2, cols // 2``).

    Parameters
    ----------
    data : 2D np.array
        the image data

    origin : tuple of float
        (row, column) coordinates of the image origin.
        Coordinates set to ``None`` are ignored.

    crop : str
        determines how the image should be cropped. The options are:

        ``maintain_size`` (default)
            return image of the same size. Some regions of the original image
            may be lost and some regions may be filled with zeros.
        ``valid_region``
            return the largest image that can be created without padding.
            All of the returned image will correspond to the original image.
            However, portions of the original image will be lost.
            If you can tolerate clipping the edges of the image, this is
            probably the method to choose.
        ``maintain_data``
            the image will be padded with zeros such that none of the original
            image will be cropped.

        Examples:

        .. plot:: tools/crop_options.py

    axes : int or tuple of int
        center image with respect to axis ``0`` (vertical), ``1`` (horizontal),
        or both axes ``(0, 1)`` (default).

    order : int
        interpolation order (0–5, default is 3) for centering with fractional
        **origin**. Lower orders work faster; **order** = 0 (also implied for
        integer **origin**) means a whole-pixel shift without interpolation and
        is much faster.

    verbose : bool
        print some information for debugging

    Returns
    -------
    out : 2D np.array
        centered image
    """
    if center is not _deprecated:
        _deprecate('abel.tools.center.set_center() '
                   'argument "center" is deprecated, use "origin" instead.')
        origin = center

    def center_of(a):
        """ Indices of array center """
        return np.array(a.shape) // 2

    shape = data.shape
    if verbose:
        print('Original shape', shape, 'and origin', tuple(origin))
    center = center_of(data)

    # remove axes with "None" coordinates, preprocess origin
    if isinstance(axes, int):
        axes = [axes]
    axes = set(axes)
    origin = np.array(origin, dtype=object)  # (for None, int or float)
    subpixel = np.zeros(2)
    origin_ = [None, None]
    for a in [0, 1]:
        if origin[a] is None:
            axes.discard(a)
        else:
            # to absolute coordinates
            if origin[a] < 0:
                origin[a] += shape[a]
            if order:
                # split integer and fractional parts
                i = int(origin[a])
                origin[a], subpixel[a] = i, origin[a] - i
            else:
                # round to whole pixels
                origin[a] = int(round(origin[a]))
            # complement (from the other edge)
            origin_[a] = shape[a] - 1 - origin[a]
    # don't interpolate for whole-pixels shifts
    if np.all(subpixel == 0):
        order = 0
    if verbose:
        print('Centering axes', tuple(axes), 'using order', order)

    # Note: current scipy.ndimage.shift() implementation erases fractional edge
    # pixels, so we wrap it with padding and cropping. Once this behavior is
    # corrected, our code can be cleaned up.

    if crop == 'maintain_size':
        delta = [0, 0]
        if order:  # fractional shift
            for a in axes:
                if origin[a] is not None:
                    delta[a] = center[a] - (origin[a] + subpixel[a])
            out = shift(np.pad(data, 1, 'constant'),
                        delta, order=order)[1:-1, 1:-1]  # (see note above)
        else:  # whole-pixel shift
            src = [slice(None), slice(None)]  # for the source region
            dst = [slice(None), slice(None)]  # for the destination region
            for a in axes:
                delta[a] = center[a] - origin[a]
                # gaps for positive and negative shifts wrt edges
                dpos = max(0, delta[a])
                dneg = max(0, -delta[a])
                # corresponding regions
                src[a] = slice(dneg, shape[a] - dpos)
                dst[a] = slice(dpos, shape[a] - dneg)
            out = np.zeros_like(data)
            out[tuple(dst)] = data[tuple(src)]
        if verbose:
            print('Shifted by', tuple(delta))
            print('Output shape', out.shape,
                  'centered at', tuple(center_of(out)))
        return out
    # for other crop options, first do subpixel shift
    # size will change to add/remove the shifted fractional pixel parts
    if order:
        if verbose:
            print('Subpixel shift by', tuple(-subpixel))
        # (see the note above about padding on both sides and cropping)
        data = shift(np.pad(data, 1, 'constant'),
                     -subpixel, order=order)[:-1, :-1]
        # shift origin or cut unused pixels
        cut = [slice(None), slice(None)]
        for a in [0, 1]:
            if subpixel[a]:
                if crop == 'valid_region':
                    cut[a] = slice(1, -1)  # cut both fractional ends
                    origin_[a] -= 1
                else:
                    origin[a] += 1
                # (shape is not used below, thus not updated here)
            else:
                cut[a] = slice(1, None)  # cut empty (not shifted) pixel
        data = data[tuple(cut)]
    if crop == 'valid_region':
        src = [slice(None), slice(None)]
        for a in axes:
            # distance to the closest edge
            d = min(origin[a], origin_[a])
            # crop symmetrically around the origin
            src[a] = slice(origin[a] - d, origin[a] + d + 1)
        out = data[tuple(src)].copy()  # (independent data, as in other cases)
        if verbose:
            print('Output cropped to', out.shape,
                  'centered at', tuple(center_of(out)))
        return out
    elif crop == 'maintain_data':
        pad = [(0, 0), (0, 0)]
        for a in axes:
            # distance to the farthest edge
            d = max(origin[a], origin_[a])
            # pad to symmetrize around the origin
            pad[a] = (d - origin[a], d - origin_[a])
        out = np.pad(data, pad, 'constant')
        if verbose:
            print('Output padded to', out.shape,
                  'centered at', tuple(center_of(out)))
        return out
    else:
        raise ValueError('Invalid crop option "{}".'.format(crop))
コード例 #13
0
ファイル: center.py プロジェクト: Mobbybobby/PyAbel-1
def set_center(data,
               origin,
               crop='maintain_size',
               axes=(0, 1),
               verbose=False,
               center=_deprecated):
    """
    Move image origin to mid-point of image.

    Parameters
    ----------
    data : 2D np.array
        the image data

    origin : tuple
        (row, column) coordinates of the image origin

    crop : str
        determines how the image should be cropped. The options are:

        ``maintain_size``
            return image of the same size. Some regions of the original image
            may be lost and some regions may be filled with zeros.
        ``valid_region``
            return the largest image that can be created without padding.
            All of the returned image will correspond to the original image.
            However, portions of the original image will be lost.
            If you can tolerate clipping the edges of the image, this is
            probably the method to choose.
        ``maintain_data``
            the image will be padded with zeros such that none of the original
            image will be cropped.

    axes : int or tuple
        center image with respect to axis ``0`` (vertical), ``1`` (horizontal),
        or both axes ``(0, 1)`` (default).

    verbose : bool
        ``True``: print diagnostics
    """
    if center is not _deprecated:
        _deprecate('abel.tools.center.set_center() '
                   'argument "center" is deprecated, use "origin" instead.')
        origin = center

    old_shape = data.shape
    old_center = data.shape[0] // 2, data.shape[1] // 2

    origin = list(origin)
    if origin[0] < 0:
        origin[0] += data.shape[0]
    if origin[1] < 0:
        origin[1] += data.shape[1]

    delta0 = old_center[0] - origin[0]
    delta1 = old_center[1] - origin[1]

    if crop == 'maintain_data':
        # pad the image so that the origin can be moved without losing any of
        # the original data

        # we need to pad the image with zeros before using the shift() function
        shift0, shift1 = (None, None)
        if delta0 != 0:
            shift0 = 1 + int(np.abs(delta0))
        if delta1 != 0:
            shift1 = 1 + int(np.abs(delta1))

        container = np.zeros((data.shape[0] + shift0, data.shape[1] + shift1),
                             dtype=data.dtype)

        area = container[:, :]
        if shift0:
            if delta0 > 0:
                area = area[:-shift0, :]
            else:
                area = area[shift0:, :]
        if shift1:
            if delta1 > 0:
                area = area[:, :-shift1]
            else:
                area = area[:, shift1:]
        area[:, :] = data[:, :]
        data = container
        delta0 += np.sign(delta0) * shift0 / 2.0
        delta1 += np.sign(delta1) * shift1 / 2.0
    if verbose:
        print("delta = ({0}, {1})".format(delta0, delta1))

    if isinstance(axes, int):
        if axes == 0:
            centered_data = shift(data, (delta0, 0))
        elif axes == 1:
            centered_data = shift(data, (0, delta1))
        else:
            raise ValueError("axes value not 0, or 1")
    else:
        centered_data = shift(data, (delta0, delta1))

    if crop == 'maintain_data':
        # pad the image so that the origin can be moved
        # without losing any of the original data
        return centered_data
    elif crop == 'maintain_size':
        return centered_data
    elif crop == 'valid_region':
        # crop to region containing data
        shift0, shift1 = (None, None)
        if isinstance(axes, int):
            if axes == 0 and delta0 != 0:
                shift0 = 1 + int(np.abs(delta0))
                return centered_data[shift0:-shift0, :]
            elif axes == 1 and delta1 != 0:
                shift1 = 1 + int(np.abs(delta1))
                return centered_data[:, shift1:-shift1]
            else:
                raise ValueError("axes value not 0, or 1")
        else:
            if delta0 != 0:
                shift0 = 1 + int(np.abs(delta0))
            if delta1 != 0:
                shift1 = 1 + int(np.abs(delta1))
            return centered_data[shift0:-shift0, shift1:-shift1]
    else:
        raise ValueError("Invalid crop method!!")