コード例 #1
0
ファイル: filter.py プロジェクト: xmzzaa/PyTom
def circle_filter(sizeX, sizeY, radiusCutoff):
    """
    circleFilter: NEEDS Documentation
    @param sizeX: NEEDS Documentation
    @param sizeY: NEEDS Documentation
    @param radiusCutoff: NEEDS Documentation
    """
    X, Y = xp.meshgrid(
        xp.arange(-sizeX // 2 + sizeX % 2, sizeX // 2 + sizeX % 2),
        xp.arange(-sizeY // 2 + sizeY % 2, sizeY // 2 + sizeY % 2))
    R = xp.sqrt(X**2 + Y**2)

    filter = xp.zeros((sizeX, sizeY), dtype=xp.float32)
    filter[R <= radiusCutoff] = 1

    return filter
コード例 #2
0
def taper_edges(image, width):
    """
    taper edges of image (or volume) with cos function

    @param image: input image (or volume)
    @type image: ndarray
    @param width: width of edge
    @type width: int

    @return: image with smoothened edges, taper_mask
    @rtype: array-like

    @author: GvdS
    """

    dims = list(image.shape) + [0]
    val = xp.cos(xp.arange(1, width + 1) * xp.pi / (2. * (width)))
    taperX = xp.ones((dims[0]), dtype=xp.float32)
    taperY = xp.ones((dims[1]))
    taperX[:width] = val[::-1]
    taperX[-width:] = val
    taperY[:width] = val[::-1]
    taperY[-width:] = val
    if dims[2] > 1:
        taperZ = xp.ones((dims[2]))
        taperZ[:width] = val[::-1]
        taperZ[-width:] = val
        Z, X, Y = xp.meshgrid(taperX, taperY, taperZ)
        taper_mask = X * (X < Y) * (X < Z) + Y * (Y <= X) * (Y < Z) + Z * (
            Z <= Y) * (Z <= X)
    else:
        X, Y = xp.meshgrid(taperY, taperX)
        taper_mask = X * (X < Y) + Y * (Y <= X)

    return image * taper_mask, taper_mask
コード例 #3
0
ファイル: filter.py プロジェクト: xmzzaa/PyTom
def ellipse_filter(sizeX, sizeY, radiusCutoffX, radiusCutoffY):
    """
    circleFilter: NEEDS Documentation
    @param sizeX: NEEDS Documentation
    @param sizeY: NEEDS Documentation
    @param radiusCutoff: NEEDS Documentation
    """
    X, Y = xp.meshgrid(
        xp.arange(-sizeY // 2 + sizeY % 2, sizeY // 2 + sizeY % 2),
        xp.arange(-sizeX // 2 + sizeX % 2, sizeX // 2 + sizeX % 2))
    R = xp.sqrt((X / radiusCutoffX)**2 + (Y / radiusCutoffY)**2)

    filter = xp.zeros((sizeX, sizeY), dtype=xp.float32)
    #print(filter.shape, R.shape)
    filter[R <= 1] = 1

    return filter
コード例 #4
0
ファイル: filter.py プロジェクト: xmzzaa/PyTom
def exact_filter(tilt_angles, tiltAngle, sX, sY, sliceWidth=1, arr=[]):
    """
    exactFilter: Generates the exact weighting function required for weighted backprojection - y-axis is tilt axis
    Reference : Optik, Exact filters for general geometry three dimensional reconstuction, vol.73,146,1986.
    @param tilt_angles: list of all the tilt angles in one tilt series
    @param titlAngle: tilt angle for which the exact weighting function is calculated
    @param sizeX: size of weighted image in X
    @param sizeY: size of weighted image in Y

    @return: filter volume

    """
    import numpy as xp

    # Calculate the relative angles in radians.
    diffAngles = (xp.array(tilt_angles) - tiltAngle) * xp.pi / 180.

    # Closest angle to tiltAngle (but not tiltAngle) sets the maximal frequency of overlap (Crowther's frequency).
    # Weights only need to be calculated up to this frequency.
    sampling = xp.min(xp.abs(diffAngles)[xp.abs(diffAngles) > 0.001])

    crowtherFreq = min(sX // 2,
                       xp.int32(xp.ceil(sliceWidth / xp.sin(sampling))))
    arrCrowther = xp.matrix(
        xp.abs(xp.arange(-crowtherFreq, min(sX // 2, crowtherFreq + 1))))

    # Calculate weights
    wfuncCrowther = 1. / (xp.clip(
        1 - xp.array(xp.matrix(xp.abs(xp.sin(diffAngles))).T * arrCrowther)**2,
        0, 2)).sum(axis=0)

    # Create full with weightFunc
    wfunc = xp.ones((sX, sY), dtype=xp.float32)

    # row_stack is not implemented in cupy
    weightingFunc = xp.column_stack(([
        (wfuncCrowther),
    ] * (sY))).T

    wfunc[:, sX // 2 - crowtherFreq:sX // 2 +
          min(sX // 2, crowtherFreq + 1)] = weightingFunc

    return wfunc
コード例 #5
0
ファイル: filter.py プロジェクト: xmzzaa/PyTom
def ramp_filter(sizeX, sizeY, crowtherFreq=None):
    """
    rampFilter: Generates the weighting function required for weighted backprojection - y-axis is tilt axis

    @param sizeX: size of weighted image in X
    @param sizeY: size of weighted image in Y
    @param crowtherFreq: size of weighted image in Y
    @return: filter volume

    """

    if crowtherFreq is None: crowtherFreq = sizeX // 2
    rampLine = xp.abs(xp.arange(-sizeX // 2, sizeX // 2)) / crowtherFreq
    rampLine[rampLine > 1] = 1
    rampfilter = xp.column_stack(([
        (rampLine),
    ] * (sizeY))).T

    return rampfilter
コード例 #6
0
def invert_WedgeSum(invol, r_max=None, lowlimit=0., lowval=0.):
    """
    invert wedge sum - avoid division by zero and boost of high frequencies

    @param invol: input volume
    @type invol: L{pytom_volume.vol} or L{pytom_volume.vol_comp}
    @param r_max: radius
    @type r_max: L{int}
    @param lowlimit: lower limit - all values below this value that lie in the specified radius will be replaced \
                by lowval
    @type lowlimit: L{float}
    @param lowval: replacement value
    @type lowval: L{float}

    @author: FF
    """
    from math import sqrt
    if not r_max:
        r_max = invol.shape[1] // 2 - 1

    dx, dy, dz = invol.shape

    if dz != dx:
        X, Y, Z = xp.meshgrid(xp.arange(-dx // 2, dx // 2 + dx % 2),
                              xp.arange(-dy // 2, dy // 2 + dy % 2),
                              xp.arange(0, dz))
        invol = xp.fft.fftshift(invol, axes=(0, 1))
    else:
        X, Y, Z = xp.meshgrid(xp.arange(-dx // 2, dx // 2 + dx % 2),
                              xp.arange(-dy // 2, dy // 2 + dy % 2),
                              xp.arange(-dz // 2, dz // 2 + dz % 2))

    R = xp.sqrt(X**2 + Y**2 + Z**2).astype(xp.int32)

    invol_out = invol.copy().astype(xp.float32)
    invol_out[invol < lowlimit] = lowval
    invol_out = 1. / invol_out
    invol_out[R >= r_max] = 0

    if dx != dz:
        invol_out = xp.fft.fftshift(invol_out, axes=(0, 1))

    return invol_out
コード例 #7
0
ファイル: filter.py プロジェクト: xmzzaa/PyTom
def profile2FourierVol(profile, dim=None, reduced=False):
    """
    create Volume from 1d radial profile, e.g., to modulate signal with \
    specific function such as CTF or FSC. Simple linear interpolation is used\
    for sampling.

    @param profile: profile
    @type profile: 1-d L{pytom_volume.vol} or 1-d python array
    @param dim: dimension of (cubic) output
    @type dim: L{int}
    @param reduced: If true reduced Fourier representation (N/2+1, N, N) is generated.
    @type reduced: L{bool}

    @return: 3-dim complex volume with spherically symmetrical profile
    @rtype: L{pytom_volume.vol}
    @author: FF
    """

    if dim is None:
        try:
            dim = [
                2 * profile.shape[0],
            ] * 3
        except:
            dim = [
                2 * len(profile),
            ] * 3

    is3D = (len(dim) == 3)

    nx, ny = dim[:2]
    if reduced:
        if is3D:
            nz = int(dim[2] // 2) + 1
        else:
            ny = int(ny // 2) + 1
    else:
        if is3D:
            nz = dim[2]

    try:
        r_max = profile.shape[0] - 1
    except:
        r_max = len(profile) - 1

    if len(dim) == 3:
        if reduced:
            X, Y, Z = xp.meshgrid(xp.arange(-nx // 2, nx // 2 + nx % 2),
                                  xp.arange(-ny // 2, ny // 2 + ny % 2),
                                  xp.arange(0, nz))
        else:
            X, Y, Z = xp.meshgrid(xp.arange(-nx // 2, nx // 2 + nx % 2),
                                  xp.arange(-ny // 2, ny // 2 + ny % 2),
                                  xp.arange(-nz // 2, nz // 2 + nz % 2))
        R = xp.sqrt(X**2 + Y**2 + Z**2)

    else:
        if reduced:
            X, Y = xp.meshgrid(xp.arange(-nx // 2, ny // 2 + ny % 2),
                               xp.arange(0, ny))
        else:
            X, Y = xp.meshgrid(xp.arange(-nx // 2, nx // 2 + nx % 2),
                               xp.arange(-ny // 2, ny // 2 + ny % 2))
        R = xp.sqrt(X**2 + Y**2)

    IR = xp.floor(R).astype(xp.int64)
    valIR_l1 = IR.copy()
    valIR_l2 = valIR_l1 + 1
    val_l1, val_l2 = xp.zeros_like(X, dtype=xp.float64), xp.zeros_like(
        X, dtype=xp.float64)

    l1 = R - IR.astype(xp.float32)
    l2 = 1 - l1

    try:
        profile = xp.array(profile)
    except:
        import numpy
        profile = xp.array(numpy.array(profile))

    for n in xp.arange(r_max):
        val_l1[valIR_l1 == n] = profile[n]
        val_l2[valIR_l2 == n + 1] = profile[n + 1]

    val_l1[IR == r_max] = profile[n + 1]
    val_l2[IR == r_max] = profile[n + 1]

    val_l1[R > r_max] = 0
    val_l2[R > r_max] = 0

    fkernel = l2 * val_l1 + l1 * val_l2

    if reduced:
        fkernel = xp.fft.fftshift(fkernel, axes=(0, 1))
    else:
        fkernel = xp.fft.fftshift(fkernel)

    return fkernel
コード例 #8
0
ファイル: filter.py プロジェクト: xmzzaa/PyTom
def create_asymmetric_wedge(angle1,
                            angle2,
                            cutoffRadius,
                            sizeX,
                            sizeY,
                            sizeZ,
                            smooth,
                            rotation=None):
    '''This function returns an asymmetric wedge object.
    @param angle1: angle of wedge1 in degrees
    @type angle1: int
    @param angle2: angle of wedge2 in degrees
    @type angle2: int
    @param cutOffRadius: radius from center beyond which the wedge is set to zero.
    @type cutOffRadius: int
    @param sizeX: the size of the box in x-direction.
    @type sizeX: int
    @param sizeY: the size of the box in y-direction.
    @type sizeY: int
    @param sizeZ: the size of the box in z-direction.
    @type sizeZ: int
    @param smooth: smoothing parameter that defines the amount of smoothing  at the edge of the wedge.
    @type smooth: float
    @return: 3D array determining the wedge object.
    @rtype: ndarray of xp.float64'''

    range_angle1Smooth = smooth / xp.sin(angle1 * xp.pi / 180.)
    range_angle2Smooth = smooth / xp.sin(angle2 * xp.pi / 180.)
    wedge = xp.zeros((sizeX, sizeY, sizeZ // 2 + 1))

    if rotation is None:
        z, y, x = xp.meshgrid(
            xp.arange(-sizeX // 2 + sizeX % 2, sizeX // 2 + sizeX % 2),
            xp.arange(-sizeY // 2 + sizeY % 2, sizeY // 2 + sizeY % 2),
            xp.arange(0, sizeZ // 2 + 1))

    else:
        cx, cy, cz = [s // 2 for s in (sizeX, sizeY, sizeZ)]
        grid = xp.mgrid[-cx:sizeX - cx, -cy:sizeY - cy, :sizeZ // 2 + 1]

        phi, the, psi = rotation

        phi = -float(phi) * xp.pi / 180.0
        the = -float(the) * xp.pi / 180.0
        psi = -float(psi) * xp.pi / 180.0
        sin_alpha = xp.sin(phi)
        cos_alpha = xp.cos(phi)
        sin_beta = xp.sin(the)
        cos_beta = xp.cos(the)
        sin_gamma = xp.sin(psi)
        cos_gamma = xp.cos(psi)

        # Calculate inverse rotation matrix
        Inv_R = xp.zeros((3, 3), dtype='float32')

        Inv_R[0, 0] = cos_alpha * cos_gamma - cos_beta * sin_alpha \
                      * sin_gamma
        Inv_R[0, 1] = -cos_alpha * sin_gamma - cos_beta * sin_alpha \
                      * cos_gamma
        Inv_R[0, 2] = sin_beta * sin_alpha

        Inv_R[1, 0] = sin_alpha * cos_gamma + cos_beta * cos_alpha \
                      * sin_gamma
        Inv_R[1, 1] = -sin_alpha * sin_gamma + cos_beta * cos_alpha \
                      * cos_gamma
        Inv_R[1, 2] = -sin_beta * cos_alpha

        Inv_R[2, 0] = sin_beta * sin_gamma
        Inv_R[2, 1] = sin_beta * cos_gamma
        Inv_R[2, 2] = cos_beta

        temp = grid.reshape((3, grid.size // 3))
        temp = xp.dot(Inv_R, temp)
        grid = xp.reshape(temp, grid.shape)

        y = grid[0, :, :, :]
        z = grid[1, :, :, :]
        x = grid[2, :, :, :]

    r = xp.sqrt(x**2 + y**2 + z**2)

    wedge[xp.tan(angle1 * xp.pi / 180) < y / x] = 1
    wedge[xp.tan(-angle2 * xp.pi / 180) > y / x] = 1
    wedge[sizeX // 2, :, 0] = 1

    if smooth:
        area = xp.abs(x -
                      (y / xp.tan(angle1 * xp.pi / 180))) <= range_angle1Smooth
        strip = 1 - (xp.abs(x - (y / xp.tan(angle1 * xp.pi / 180.))) *
                     xp.sin(angle1 * xp.pi / 180.) / smooth)
        wedge += (strip * area * (1 - wedge) * (y > 0))

        area2 = xp.abs(x +
                       (y /
                        xp.tan(angle2 * xp.pi / 180))) <= range_angle2Smooth
        strip2 = 1 - (xp.abs(x + (y / xp.tan(angle2 * xp.pi / 180.))) *
                      xp.sin(angle2 * xp.pi / 180.) / smooth)
        wedge += (strip2 * area2 * (1 - wedge) * (y <= 0))

    wedge[r > cutoffRadius] = 0

    return xp.fft.fftshift(wedge, axes=(0, 1))
コード例 #9
0
def randomizePhaseBeyondFreq(volume, frequency):
    '''This function randomizes the phases beyond a given frequency, while preserving the Friedel symmetry.
    @param volume: target volume
    @type volume: 3d ndarray
    @param frequency: frequency in pixel beyond which phases are randomized.
    @type frequency: int

    @return: 3d volume.
    @rtype: 3d ndarray
    @author: GvdS'''

    from numpy.fft import ifftn, fftshift, fftn, rfftn, irfftn
    from numpy import angle, abs, exp, meshgrid, arange, sqrt, pi, rot90

    threeD = len(volume.shape) == 3
    twoD = len(volume.shape) == 2

    if not twoD and not threeD:
        raise Exception(
            'Invalid volume dimensions: either supply 3D or 2D ndarray')

    if twoD:
        dx, dy = volume.shape
    else:
        dx, dy, dz = volume.shape

    ft = xp.fft.rfftn(volume)
    phase = xp.angle(ft)

    amplitude = xp.abs(ft)
    rnda = generate_random_phases_3d(
        amplitude.shape,
        reduced_complex=True)  # (ranf((dx,dy,dz//2+1)) * pi * 2) - pi

    if twoD:
        X, Y = xp.meshgrid(xp.arange(-dx // 2, dx // 2 + dx % 2),
                           xp.arange(-dy // 2, dy // 2 + dy % 2))
        RF = xp.sqrt(X**2 + Y**2).astype(int)
        R = xp.fft.fftshift(RF)[:, :dy // 2 + 1]
    else:
        X, Y, Z = xp.meshgrid(xp.arange(-dx // 2, dx // 2),
                              xp.arange(-dy // 2, dy // 2),
                              xp.arange(-dz // 2, dz // 2))
        RF = xp.sqrt(X**2 + Y**2 + Z**2)  # .astype(int)
        R = xp.fft.fftshift(RF)[:, :, :dz // 2 + 1]
        # centralslice = fftshift(rnda[:,:,0])
        # cc = dx//2
        # ccc= (dx-1)//2
        # centralslice[cc, cc-ccc:cc] = centralslice[cc,-ccc:][::-1]*-1
        # centralslice[cc-ccc:cc,cc-ccc:] = rot90(centralslice[-ccc:,cc-ccc:],2)*-1
        # rnda[:,:,0] = fftshift(centralslice)

    rnda[R <= frequency] = 0
    phase[R > frequency] = 0
    phase += rnda
    image = xp.fft.irfftn((amplitude * xp.exp(1j * phase)), s=volume.shape)

    if xp.abs(image.imag).sum() > 1E-8:
        raise Exception(
            'Imaginary part is non-zero. Failed to centro-summetrize the phases.'
        )

    return image.real