Esempio n. 1
0
def nfold(im, mod, center=None, mask=None, fill_value=0.0):
    """ 
    Returns an images averaged according to n-fold rotational symmetry. This can be used to
    boost the signal-to-noise ratio on an image with known symmetry, e.g. a diffraction pattern.

    Parameters
    ----------
    im : array_like, ndim 2
        Image to be azimuthally-symmetrized.
    center : array_like, shape (2,) or None, optional
        Coordinates of the center (in pixels). If ``center=None``, the image is rotated around
        its center, i.e. ``center=(rows / 2 - 0.5, cols / 2 - 0.5)``.
    mod : int
        Fold symmetry number. Valid numbers must be a divisor of 360.
    mask : `~numpy.ndarray` or None, optional
        Mask of `image`. The mask should evaluate to `True` (or 1) on invalid pixels. 
        If None (default), no mask is used.
    fill_value : float, optional
        In the case of a mask that overlaps with itself when rotationally averaged,
        the overlapping regions will be filled with this value.

    Returns
    -------
    out : `~numpy.ndarray`, dtype float
        Symmetrized image.

    Raises
    ------
    ValueError : If `mod` is not a divisor of 360 deg.
    """
    if (360 % mod):
        raise ValueError(
            '{}-fold rotational symmetry is not valid (not a divisor of 360).'.
            format(mod))
    angles = range(0, 360, int(360 / mod))

    # Data-type must be float because of use of NaN
    im = np.array(im, dtype=np.float, copy=True)

    if mask is not None:
        im[mask] = np.nan

    kwargs = {
        'center': center,
        'mode': 'constant',
        'cval': 0,
        'preserve_range': True
    }

    # Use weights because edges of the pictures, which might be cropped by the rotation
    # should not count in the average
    wt = np.ones_like(im, dtype=np.uint8)
    weights = (rotate(wt, angle, **kwargs) for angle in angles)
    rotated = (rotate(im, angle, **kwargs) for angle in angles)

    avg = average(rotated, weights=weights, ignore_nan=True)
    return nan_to_num(avg, fill_value, copy=False)
Esempio n. 2
0
    def test_ufunc(self):
        stack = nan_to_num(self.stack, fill_value=ufunc.identity)

        def sufunc(arrays, ignore_nan=False):  # s for stream
            return last(ireduce_ufunc(arrays, ufunc, axis=1, ignore_nan=True))

        from_numpy = ufunc.reduce(stack, axis=1)
        from_sufunc = sufunc(self.source)
        self.assertSequenceEqual(from_numpy.shape, from_sufunc.shape)
        self.assertTrue(np.allclose(from_numpy, from_sufunc))
Esempio n. 3
0
def reflection(im, angle, center=None, mask=None, fill_value=0.0):
    """
    Symmetrize an image according to a reflection plane.

    Parameters
    ----------
    im : array_like, ndim 2
        Image to be symmetrized.
    angle : float
        Angle (in degrees) of the line that defines the reflection plane. This angle
        increases counter-clockwise from the positive x-axis. Angles
        larger that 360 are mapped back to [0, 360). Note that ``angle`` and ``angle + 180``
        are equivalent.
    center : array_like, shape (2,) or None, optional
        Coordinates of the center (in pixels). If ``center=None``, the image is rotated around
        its center, i.e. ``center=(rows / 2 - 0.5, cols / 2 - 0.5)``.
    mask : `~numpy.ndarray` or None, optional
        Mask of `image`. The mask should evaluate to `True` (or 1) on valid pixels. 
        If None (default), no mask is used.
    fill_value : float, optional
        In the case of a mask that overlaps with itself when rotationally averaged,
        the overlapping regions will be filled with this value.

    Returns
    -------
    out : `~numpy.ndarray`, dtype float
        Symmetrized image.
    """
    angle = float(angle) % 360

    # Data-type must be float because of use of NaN
    im = np.array(im, dtype=np.float, copy=True)
    reflected = np.array(im, copy=True)  # reflected image

    if mask is not None:
        invalid_pixels = np.logical_not(mask)
        im[invalid_pixels] = np.nan
        reflected[invalid_pixels] = np.nan

    kwargs = {
        "center": center,
        "mode": "constant",
        "cval": 0,
        "preserve_range": True
    }

    # Rotate the 'reflected' image so that the reflection line is the x-axis
    # Flip the image along the y-axis
    # Rotate back to original orientation
    # FIXME: this will not work properly for images that are offcenter
    reflected = rotate(reflected, -angle, **kwargs)
    reflected = mirror(reflected, axes=0)
    reflected = rotate(reflected, angle, **kwargs)

    return nan_to_num(average([im, reflected]), fill_value, copy=False)
Esempio n. 4
0
 def test_generic(self):
     """ Test that NaNs are replaced with a fill value """
     with np.errstate(divide="ignore", invalid="ignore"):
         vals = nan_to_num(np.array([0]) / 0.0, fill_value=14)
     self.assertEqual(vals[0], 14)
Esempio n. 5
0
 def test_complex_good(self):
     """ Test nan_to_num on complex input """
     vals = nan_to_num(1 + 1j)
     self.assertEqual(vals, 1 + 1j)
Esempio n. 6
0
 def test_integer(self):
     """ Test that nan_to_num on integers does nothing """
     vals = nan_to_num(1)
     self.assertEqual(vals, 1)
     vals = nan_to_num([1])
     self.assertTrue(np.allclose(vals, np.array([1])))
Esempio n. 7
0
def nfold(im, mod, center=None, mask=None, fill_value=0.0):
    """
    Returns an images averaged according to n-fold rotational symmetry. This can be used to
    boost the signal-to-noise ratio on an image with known symmetry, e.g. a diffraction pattern.

    Parameters
    ----------
    im : array_like, ndim 2
        Image to be azimuthally-symmetrized.
    center : array_like, shape (2,) or None, optional
        Coordinates of the center (in pixels) in the format ``center=[col, row]``. If ``center=None``,
        the image is rotated around the center of the array, i.e. ``center=(cols / 2 - 0.5, rows / 2 - 0.5)``.
    mod : int
        Fold symmetry number. Valid numbers must be a divisor of 360.
    mask : `~numpy.ndarray` or None, optional
        Mask of `image`. The mask should evaluate to `True` (or 1) on valid pixels.
        If None (default), no mask is used.
    fill_value : float, optional
        In the case of a mask that overlaps with itself when rotationally averaged,
        the overlapping regions will be filled with this value.

    Returns
    -------
    out : `~numpy.ndarray`, dtype float
        Symmetrized image.

    Raises
    ------
    ValueError : If `mod` is not a divisor of 360 deg.
    """
    if 360 % mod:
        raise ValueError(
            f"{mod}-fold rotational symmetry is not valid (not a divisor of 360)."
        )
    angles = range(0, 360, int(360 / mod))

    im = np.array(im, copy=True)

    kwargs = {
        "center": center,
        "mode": "constant",
        "cval": 0,
        "preserve_range": True
    }

    if mask is None:
        return ns.average(rotate(im, angle, **kwargs) for angle in angles)

    # Use weights because edges of the pictures, which might be cropped by the rotation
    # should not count in the average
    wt = np.ones_like(mask, dtype=im.dtype)
    wt[np.logical_not(mask)] = 0

    weights = (rotate(wt, angle, **kwargs) for angle in angles)
    imgs = (rotate(im, angle, **kwargs) for angle in angles)

    avg = ns.average(imgs, weights=weights)

    # Mask may overlap with itself during symmetrization. At those points, the average
    # will be zero (because the weights are 0 there)
    # However, because users may want to change that value to `fill_value != 0`, we need
    # to know where is the overlap
    if fill_value != 0.0:
        invalid_pixels = np.logical_not(mask)
        masks = (rotate(invalid_pixels, angle, **kwargs) for angle in angles)
        overlap = ns.prod(masks).astype(bool)  # equivalent to logical_and
        avg[overlap] = fill_value

    return ns.nan_to_num(avg, fill_value=fill_value)