Пример #1
0
def create_sphere(size,
                  radius=-1,
                  sigma=0,
                  num_sigma=2,
                  center=None,
                  gpu=False):
    """Create a 3D sphere volume.

    @param size: size of the resulting volume.
    @param radius: radius of the sphere inside the volume.
    @param sigma: sigma of the Gaussian.
    @param center: center of the sphere.

    @return: sphere inside a volume.
    """

    if size.__class__ == float or len(size) == 1:
        size = (size, size, size)
    assert len(size) == 3

    if center is None:
        center = [size[0] // 2, size[1] // 2, size[2] // 2]
    if radius == -1:
        radius = xp.min(size) // 2

    sphere = xp.zeros(size, dtype=xp.float32)
    [x, y, z] = xp.mgrid[0:size[0], 0:size[1], 0:size[2]]
    r = xp.sqrt((x - center[0])**2 + (y - center[1])**2 + (z - center[2])**2)
    sphere[r <= radius] = 1

    if sigma > 0:
        ind = xp.logical_and(r > radius, r < radius + num_sigma * sigma)
        sphere[ind] = xp.exp(-((r[ind] - radius) / sigma)**2 / 2)

    return sphere
Пример #2
0
def add_noise(data, snr=0.1, m=0):
    """Add gaussian noise to the given volume.
    @param data: input volume.
    @param snr: SNR of the added noise.
    @param m: mean of the added noise.

    @return The image with gaussian noise	
    """
    vs = xp.var(data)
    vn = vs / snr
    sd = xp.sqrt(vn)
    s = xp.ndarray(data.shape)
    noise = sd * standard_normal(s.shape) + m
    t = data + noise
    return t
Пример #3
0
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
Пример #4
0
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
Пример #5
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
def norm_inside_mask(inp, mask):
    """
    To normalise a 2D array within a mask

    @param inp: A 2D array to be normalized.
    @type inp: numpy array 2D
    @param mask: A 2D array of the same size as the input to mask of parts of the ixp.
    @type mask: numpy array 2D
    @return: A normalized 2D array.
    @returntype: numpy array 2D

    @requires: the shape of inp to be equal to the shape of the mask
    """
    # assert ixp.shape == mask.shape
    # assert len(ixp.shape) == 2

    mea = xp.divide(xp.sum(xp.multiply(inp, mask)), xp.sum(mask))
    st = xp.sqrt(
        xp.sum((xp.multiply(mask, mea) + xp.multiply(inp, mask) - mea)**2) /
        xp.sum(mask))
    return xp.multiply((inp - mea) / st, mask)
Пример #7
0
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
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 weightedXCF(volume, reference, numberOfBands, wedgeAngle=-1, gpu=False):
    """
    weightedXCF: Determines the weighted correlation function for volume and reference
    @param volume: A volume 
    @param reference: A reference 
    @param numberOfBands:Number of bands
    @param wedgeAngle: A optional wedge angle
    @return: The weighted correlation function 
    @rtype: L{pytom_volume.vol} 
    @author: Thomas Hrabe 
    @todo: does not work yet -> test is disabled
    """

    if gpu:
        import cupy as xp
    else:
        import numpy as xp

    from pytom.tompy.correlation import bandCF
    from pytom.tompy.transforms import fourier_reduced2full
    from math import sqrt
    import pytom_freqweight

    result = xp.zeros_like(volume)

    q = 0

    if wedgeAngle >= 0:
        wedgeFilter = pytom_freqweight.weight(wedgeAngle, 0, volume.sizeX(),
                                              volume.sizeY(), volume.sizeZ())
        wedgeVolume = wedgeFilter.getWeightVolume(True)
    else:
        wedgeVolume = xp.ones_like(volume)

    w = xp.sqrt(1 / float(volume.size))

    numberVoxels = 0

    for i in range(numberOfBands):
        """
        notation according Steward/Grigorieff paper
        """
        band = [0, 0]
        band[0] = i * volume.shape[0] / numberOfBands
        band[1] = (i + 1) * volume.shape[0] / numberOfBands

        r = bandCF(volume, reference, band, gpu=gpu)

        cc = r[0]

        filter = r[1]
        #get bandVolume
        bandVolume = filter.getWeightVolume(True)

        filterVolumeReduced = bandVolume * wedgeVolume
        filterVolume = fourier_reduced2full(filterVolumeReduced)
        #determine number of voxels != 0
        N = filterVolume[abs(filterVolume) < 1].sum()

        #add to number of total voxels
        numberVoxels = numberVoxels + N

        cc2 = r[0].copy()

        cc2 = cc2**2

        cc = shiftscale(cc, w, 1)
        ccdiv = cc2 / (cc)

        ccdiv = ccdiv**3

        #abs(ccdiv); as suggested by grigorief
        ccdiv = shiftscale(ccdiv, 0, N)

        result = result + ccdiv

    result = shiftscale(result, 0, 1 / float(numberVoxels))

    return result
Пример #10
0
def weightedXCC(volume, reference, numberOfBands, wedgeAngle=-1, gpu=False):
    """
    weightedXCC: Determines the band weighted correlation coefficient for a volume and reference. Notation according Steward/Grigorieff paper
    @param volume: A volume
    @type volume: L{pytom_volume.vol}
    @param reference: A reference of same size as volume
    @type reference: L{pytom_volume.vol}
    @param numberOfBands: Number of bands
    @param wedgeAngle: A optional wedge angle
    @return: The weighted correlation coefficient
    @rtype: float
    @author: Thomas Hrabe
    """

    if gpu:
        import cupy as xp
    else:
        import numpy as xp

    from pytom.tompy.transform import fft, fourier_reduced2full
    from pytom.basic.structures import WedgeInfo

    result = 0
    numberVoxels = 0

    #volume.write('vol.em');
    #reference.write('ref.em');

    wedge = WedgeInfo(wedgeAngle)
    wedgeVolume = wedge.returnWedgeVolume(volume.shape[0], volume.shape[1],
                                          volume.shape[2])

    increment = int(volume.shape[0] / 2 * 1 / numberOfBands)
    band = [0, 100]
    for i in range(0, volume.shape[0] / 2, increment):

        band[0] = i
        band[1] = i + increment

        r = bandCC(volume, reference, band, gpu=gpu)
        cc = r[0]

        #print cc;
        filter = r[1]

        #get bandVolume
        bandVolume = filter.getWeightVolume(True)

        filterVolumeReduced = bandVolume * wedgeVolume
        filterVolume = fourier_reduced2full(filterVolumeReduced)

        #determine number of voxels != 0
        N = (filterVolume != 0).sum()

        w = xp.sqrt(1 / float(N))

        #add to number of total voxels
        numberVoxels = numberVoxels + N
        #print 'w',w;
        #print 'cc',cc;
        #print 'N',N;

        cc2 = cc * cc
        #print 'cc2',cc2;
        if cc <= 0.0:
            cc = cc2
        else:
            cc = cc2 / (cc + w)

        #print 'cc',cc;
        cc = cc * cc * cc
        #no abs
        #print 'cc',cc;

        #add up result
        result = result + cc * N

    return result * (1 / float(numberVoxels))
Пример #11
0
def bandCC(volume, reference, band, verbose=False, shared=None, index=None):
    """
    bandCC: Determines the normalised correlation coefficient within a band
    @param volume: The volume
    @type volume: L{pytom_volume.vol}
    @param reference: The reference
    @type reference: L{pytom_volume.vol}
    @param band: [a,b] - specify the lower and upper end of band.
    @return: First parameter - The correlation of the two volumes in the specified band. 
             Second parameter - The bandpass filter used.
    @rtype: List - [float,L{pytom_freqweight.weight}]
    @author: Thomas Hrabe    
    """

    if not index is None: print(index)

    from pytom.tompy.filter import bandpass
    from pytom.tompy.correlation import xcf
    #from pytom.tompy.filter import vol_comp

    if verbose:
        print('lowest freq : ', band[0], ' highest freq', band[1])

    vf, m = bandpass(volume,
                     band[0],
                     band[1],
                     returnMask=True,
                     fourierOnly=True)
    rf = bandpass(reference, band[0], band[1], mask=m,
                  fourierOnly=True)  #,vf[1])
    #ccVolume = vol_comp(rf[0].shape[0],rf[0].shape[1],rf[0].shape[2])
    #ccVolume.copyVolume(rf[0])

    vf = vf.astype(xp.complex128)
    ccVolume = rf.astype(vf.dtype)

    ccVolume = ccVolume * xp.conj(vf)
    #pytom_volume.conj_mult(ccVolume,vf[0])

    cc = ccVolume.sum()

    cc = cc.real
    v = vf
    r = rf

    absV = xp.abs(v)
    absR = xp.abs(r)

    sumV = xp.sum(absV**2)
    sumR = xp.sum(absR**2)

    sumV = xp.abs(sumV)
    sumR = xp.abs(sumR)

    if sumV == 0:
        sumV = 1

    if sumR == 0:
        sumR = 1

    cc = cc / (xp.sqrt(sumV * sumR))

    #numerical errors will be punished with nan
    if abs(cc) > 1.1:
        cc = float('nan')

    return float(cc)
Пример #12
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