Пример #1
0
def bandCF(volume, reference, band=[0, 100]):
    """
    bandCF:
    @param volume: The volume
    @param reference: The reference
    @param band: [a,b] - specify the lower and upper end of band. [0,1] if not set.
    @return: First parameter - The correlation of the two volumes in the specified ring. 
             Second parameter - The bandpass filter used.
    @rtype: List - [L{pytom_volume.vol},L{pytom_freqweight.weight}]
    @author: Thomas Hrabe   
    @todo: does not work yet -> test is disabled
    """

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

    import pytom_volume
    from math import sqrt
    from pytom.basic import fourier
    from pytom.basic.filter import bandpassFilter
    from pytom.basic.correlation import nXcf

    vf = bandpassFilter(volume, band[0], band[1], fourierOnly=True)
    rf = bandpassFilter(reference, band[0], band[1], vf[1], fourierOnly=True)

    v = pytom_volume.reducedToFull(vf[0])
    r = pytom_volume.reducedToFull(rf[0])

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

    pytom_volume.power(absV, 2)
    pytom_volume.power(absR, 2)

    sumV = abs(pytom_volume.sum(absV))
    sumR = abs(pytom_volume.sum(absR))

    if sumV == 0:
        sumV = 1

    if sumR == 0:
        sumR = 1

    pytom_volume.conjugate(rf[0])

    fresult = vf[0] * rf[0]

    #transform back to real space
    result = fourier.ifft(fresult)

    fourier.iftshift(result)

    result.shiftscale(0, 1 / float(sqrt(sumV * sumR)))

    return [result, vf[1]]
Пример #2
0
def frm_correlate(vf,
                  wf,
                  vg,
                  wg,
                  b,
                  max_freq,
                  weights=None,
                  ps=False,
                  denominator1=None,
                  denominator2=None,
                  return_score=True):
    """Calculate the correlation of two volumes as a function of Euler angle.

    Parameters
    ----------
    vf: Volume Nr. 1
        pytom_volume.vol

    wf: Mask of vf in Fourier space.
        pytom.basic.structures.Wedge

    vg: Volume Nr. 2 / Reference
        pytom_volume.vol

    wg: Mask of vg in Fourier space.
        pytom.basic.structures.Wedge

    b: Bandwidth range of spherical harmonics.
       None -> [4, 64]
       List -> [b_min, b_max]
       Integer -> [b, b]

    max_freq: Maximal frequency involved in calculation.
              Integer.

    weights: Obsolete.

    ps: Calculation based on only the power spectrum of two volumes or not.
        Boolean. Default is False.

    denominator1: If the denominator1 is provided or not. If yes, do not have to re-calculate it again.
                  This field is used out of computation effeciency consideration.
                  Default is None, not provided.

    denominator2: If the denominator2 is provided or not. If yes, do not have to re-calculate it again.
                  This field is used out of computation effeciency consideration.
                  Default is None, not provided.

    return_score: Return the correlation score or return the intermediate result (numerator, denominator1, denominator2).
                  Boolean, default is True.

    Returns
    -------
    If return_score is set to True, return the correlation function; otherwise return the intermediate result.
    """
    if not weights:  # weights, not used yet
        weights = [1 for i in xrange(max_freq)]

    from pytom.basic.fourier import fft, ifft, ftshift, iftshift
    from pytom_volume import vol, reducedToFull, abs, real, imag, rescale
    from vol2sf import vol2sf
    from math import log, ceil, pow

    # IMPORTANT!!! Should firstly do the IFFTSHIFT on the volume data (NOT FFTSHIFT since for odd-sized data it matters!),
    # and then followed by the FFT.
    vf = ftshift(reducedToFull(fft(iftshift(vf, inplace=False))),
                 inplace=False)
    vg = ftshift(reducedToFull(fft(iftshift(vg, inplace=False))),
                 inplace=False)

    if ps:  # power spectrum only
        ff = abs(vf)
        ff = real(ff)
        gg = abs(vg)
        gg = real(gg)
    else:  # use spline intepolation on the real/imaginary parts. Can be done better, but now it suffices.
        vfr = real(vf)
        vfi = imag(vf)
        vgr = real(vg)
        vgi = imag(vg)

    numerator = None
    if denominator1 is not None and denominator2 is not None:
        to_calculate = 1
    elif denominator1 is None and denominator2 is not None:
        to_calculate = 2
    else:
        to_calculate = 0

    _last_bw = 0
    # might be a better idea to start from 2 due to the bad interpolation around 0 frequency!
    # this can be better solved by NFFT!
    for r in xrange(1, max_freq + 1):
        # calculate the appropriate bw
        bw = get_adaptive_bw(r, b)

        # construct the wedge masks accordingly
        # now this part has been shifted to Pytom
        # if _last_bw != bw:
        #     # mf = create_wedge_sf(wf[0], wf[1], bw)
        #     # mg = create_wedge_sf(wg[0], wg[1], bw)
        #     mf = wf.toSphericalFunc(bw)
        #     mg = wg.toSphericalFunc(bw)
        mf = wf.toSphericalFunc(bw, r)
        mg = wg.toSphericalFunc(bw, r)

        if ps:
            corr1, corr2, corr3 = sph_correlate_ps(vol2sf(ff, r, bw), mf,
                                                   vol2sf(gg, r, bw), mg,
                                                   to_calculate)
        else:
            corr1, corr2, corr3 = sph_correlate_fourier(
                vol2sf(vfr, r, bw), vol2sf(vfi, r, bw), mf, vol2sf(vgr, r, bw),
                vol2sf(vgi, r, bw), mg, to_calculate)

        if _last_bw != bw:  # size is different, have to do enlarge
            if numerator is None:
                numerator = np.zeros((2 * bw, 2 * bw, 2 * bw), dtype='double')
                if to_calculate == 1:
                    pass
                elif to_calculate == 2:
                    denominator1 = np.zeros((2 * bw, 2 * bw, 2 * bw),
                                            dtype='double')
                else:
                    denominator1 = np.zeros((2 * bw, 2 * bw, 2 * bw),
                                            dtype='double')
                    denominator2 = np.zeros((2 * bw, 2 * bw, 2 * bw),
                                            dtype='double')
            else:
                numerator = enlarge2(numerator)
                if to_calculate == 1:
                    pass
                elif to_calculate == 2:
                    denominator1 = enlarge2(denominator1)
                else:
                    denominator1 = enlarge2(denominator1)
                    denominator2 = enlarge2(denominator2)

        numerator += corr1 * (r**2) * weights[r - 1]
        if to_calculate == 1:
            pass
        elif to_calculate == 2:
            denominator1 += corr2 * (r**2) * weights[r - 1]
        else:
            denominator1 += corr2 * (r**2) * weights[r - 1]
            denominator2 += corr3 * (r**2) * weights[r - 1]

        _last_bw = bw

    if return_score:
        res = numerator / (denominator1 * denominator2)**0.5
        return res
    else:
        return (numerator, denominator1, denominator2)
Пример #3
0
def bandCC(volume,reference,band,verbose = False):
    """
    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    
    """
    import pytom_volume
    from pytom.basic.filter import bandpassFilter
    from pytom.basic.correlation import xcf
    from math import sqrt
    
    if verbose:
        print('lowest freq : ', band[0],' highest freq' , band[1])
        
    vf = bandpassFilter(volume,band[0],band[1],fourierOnly=True)
    rf = bandpassFilter(reference,band[0],band[1],vf[1],fourierOnly=True)
    
    ccVolume = pytom_volume.vol_comp(rf[0].sizeX(),rf[0].sizeY(),rf[0].sizeZ())
    ccVolume.copyVolume(rf[0])
    
    pytom_volume.conj_mult(ccVolume,vf[0])
    
    cc = pytom_volume.sum(ccVolume)

    cc = cc.real
    
    v = vf[0]
    r = rf[0]
    
    absV = pytom_volume.abs(v)
    absR = pytom_volume.abs(r)
    
    pytom_volume.power(absV,2)
    pytom_volume.power(absR,2)
    
    sumV = pytom_volume.sum(absV)
    sumR = pytom_volume.sum(absR)
    
    sumV = abs(sumV)
    sumR = abs(sumR)
    
    if sumV == 0:
        sumV =1
        
    if sumR == 0:
        sumR =1
        
    cc = cc / (sqrt(sumV*sumR)) 
    
    #numerical errors will be punished with nan
    if abs(cc) > 1.1 :
        cc = float('nan')
    
    return [cc,vf[1]];
Пример #4
0
def frm_determine_orientation(vf, wf, vg, wg, b, radius=None, weights=None, r_score=False, norm=False):
    """Auxiliary function for xu_align_vol. Find the angle to rotate vg to match vf, using only their power spectrums.

    Parameters
    ----------
    vf: The volume you want to match.
        pytom_volume.vol

    wf: The single tilt wedge information of volume vf.
        [missing_wedge_angle1, missing_wedge_angle2]. Note this is defined different with frm_align im frm.py!

    vg: The reference volume.
        pytom_volume.vol

    wg: The single tilt wedge information of volume vg.
        [missing_wedge_angle1, missing_wedge_angle2]. Note this is defined different with frm_align im frm.py!

    b: The adaptive bandwidth of spherical harmonics.
       List [min_bandwidth, max_bandwidth], min_bandwidth, max_bandwidth in the range [4, 64].
       Or integer, which would then mean to use fixed bandwidth: min_bandwidth = max_bandwidth = integer.

    radius: The maximal radius in the Fourier space, which is equal to say the maximal frequency involved in calculation.
            Integer. By default is half of the volume size.

    weights: Obsolete.

    r_score: Obsolete.

    norm: Obsolete.

    Returns
    -------
    The angle (Euler angle, ZXZ convention [Phi, Psi, Theta]) to rotate vg to match vf.
    """
    if not radius: # set the radius
        radius = vf.sizeX()/2
    if not weights: # set the weights
        weights = [1 for i in range(radius)]
    
    if not b: # set the bandwidth adaptively
        b_min = 4
        b_max = 128
    elif b.__class__ == tuple or b.__class__ == list:
        b_min = b[0]
        b_max = b[1]
    elif isinstance(b, int): # fixed bandwidth
        b_min = b
        b_max = b
    else:
        raise RuntimeError("Argument b is not valid!")
    
    from pytom.basic.fourier import fft, ifft, ftshift, iftshift
    from pytom_volume import vol, reducedToFull, rescale, abs, real
    from .vol2sf import vol2sf
    from pytom_numpy import vol2npy
    from math import log, ceil, pow

    # IMPORTANT!!! Should firstly do the IFFTSHIFT on the volume data (NOT FFTSHIFT since for odd-sized data it matters!),
    # and then followed by the FFT.
    vf = ftshift(reducedToFull(fft(iftshift(vf, inplace=False))), inplace=False)
    vg = ftshift(reducedToFull(fft(iftshift(vg, inplace=False))), inplace=False)

    ff = abs(vf)
    ff = real(ff)
    gg = abs(vg)
    gg = real(gg)
    
    get_bw = lambda x: int(pow(2, int(ceil(log(2*x, 2)))))
    
    numerator = None
    denominator1 = None
    denominator2 = None
    _last_bw = 0
    for r in range(1, radius+1):
        # calculate the appropriate bw
        bw = get_bw(r)
        if bw < b_min:
            bw = b_min
        if bw > b_max:
            bw = b_max
            
        # construct the wedge masks accordingly
        if _last_bw != bw:
            mf = create_wedge_sf(wf[0], wf[1], bw)
            mg = create_wedge_sf(wg[0], wg[1], bw)
        
        corr1, corr2, corr3 = frm_constrained_corr(vol2sf(ff, r, bw), mf, vol2sf(gg, r, bw), mg, norm, return_score=False)
        
        if _last_bw != bw:
            if numerator is None:
                numerator = np.zeros((2*bw, 2*bw, 2*bw), dtype='double')
                denominator1 = np.zeros((2*bw, 2*bw, 2*bw), dtype='double')
                denominator2 = np.zeros((2*bw, 2*bw, 2*bw), dtype='double')
            else:
                numerator = enlarge2(numerator)
                denominator1 = enlarge2(denominator1)
                denominator2 = enlarge2(denominator2)
        
        numerator += corr1*(r**2)*weights[r-1]
        denominator1 += corr2*(r**2)*weights[r-1]
        denominator2 += corr3*(r**2)*weights[r-1]
        
        _last_bw = bw
    
    res = numerator/(denominator1 * denominator2)**0.5

    return frm_find_topn_angles_interp2(res)
Пример #5
0
def bart_align_vol(vf, wf, vg, wg, b, radius=None, peak_offset=None):
    """Implementation of Bartesaghi's approach for alignment. For detail, please check the paper.

    Parameters
    ----------
    vf: The volume you want to match.
        pytom_volume.vol

    wf: The single tilt wedge information of volume vf.
        [missing_wedge_angle1, missing_wedge_angle2]. Note this is defined different with frm_align im frm.py!

    vg: The reference volume.
        pytom_volume.vol

    wg: The single tilt wedge information of volume vg.
        [missing_wedge_angle1, missing_wedge_angle2]. Note this is defined different with frm_align im frm.py!

    b: The bandwidth of spherical harmonics.
       Integer in the range [4, 64]

    radius: The maximal radius in the Fourier space, which is equal to say the maximal frequency involved in calculation.
            Integer. By default is half of the volume size.

    peak_offset: The maximal offset which allows the peak of the score to be.
                 Or simply speaking, the maximal distance allowed to shift vg to match vf.
                 This parameter is needed to prevent shifting the reference volume out of the frame.
                 Integer. By default is half of the volume size.

    Returns
    -------
    The best translation and rotation (Euler angle, ZXZ convention [Phi, Psi, Theta]) to transform vg to match vf.
    (best_translation, best_rotation, correlation_score)
    """
    from pytom_volume import vol, rotateSpline, max, peak
    from pytom.basic.correlation import nXcf
    from pytom.basic.filter import lowpassFilter
    from pytom.basic.structures import WedgeInfo
    from pytom_volume import initSphere

    if not radius: # set the radius
        radius = vf.sizeX()/2

    if peak_offset is None:
        peak_offset = vol(vf.sizeX(), vf.sizeY(), vf.sizeZ())
        initSphere(peak_offset, vf.sizeX()/2, 0,0, vf.sizeX()/2,vf.sizeY()/2,vf.sizeZ()/2)
    elif isinstance(peak_offset, int):
        peak_radius = peak_offset
        peak_offset = vol(vf.sizeX(), vf.sizeY(), vf.sizeZ())
        initSphere(peak_offset, peak_radius, 0,0, vf.sizeX()/2,vf.sizeY()/2,vf.sizeZ()/2)
    elif peak_offset.__class__ == vol:
        pass
    else:
        raise RuntimeError('Peak offset is given wrong!')
    
    from pytom.basic.fourier import fft, ifft, ftshift, iftshift
    from pytom_volume import vol, reducedToFull, rescale, abs, real
    from .vol2sf import vol2sf
    from pytom_numpy import vol2npy
    from math import log, ceil, pow

    # IMPORTANT!!! Should firstly do the IFFTSHIFT on the volume data (NOT FFTSHIFT since for odd-sized data it matters!),
    # and then followed by the FFT.
    ff = abs(ftshift(reducedToFull(fft(iftshift(vf, inplace=False))), inplace=False))
    ff = real(ff)
    gg = abs(ftshift(reducedToFull(fft(iftshift(vg, inplace=False))), inplace=False))
    gg = real(gg)
    
    sf = None
    sg = None
    mf = create_wedge_sf(wf[0], wf[1], b)
    mg = create_wedge_sf(wg[0], wg[1], b)

    for r in range(3, radius+1): # Should start from 3 since the interpolation in the first 2 bands is not accurate.
        if sf is None:
            sf = vol2sf(ff, r, b)
            sg = vol2sf(gg, r, b)
        else:
            sf += vol2sf(ff, r, b)
            sg += vol2sf(gg, r, b)
    
    corr = frm_constrained_corr(sf, mf, sg, mg)
    ang, val = frm_find_best_angle_interp(corr)

    tmp = vol(vg.sizeX(),vg.sizeY(),vg.sizeZ())
    rotateSpline(vg, tmp, ang[0], ang[1], ang[2])
    wedge_f = WedgeInfo(90+wf[0], 90-wf[1])
    wedge_g = WedgeInfo(90+wg[0], 90-wg[1])
    cc = nXcf(lowpassFilter(wedge_g.apply(vf), radius, 0)[0], lowpassFilter(wedge_f.apply(tmp), radius, 0)[0])
    pos = peak(cc, peak_offset)
    pos, score = find_subpixel_peak_position(vol2npy(cc), pos)

    return (pos, ang, score)
Пример #6
0
def frm_determine_orientation_rscore(vf, wf, vg, wg, b, radius=None, weights=None):
    """Obsolete.
    """
    if not radius: # set the radius
        radius = vf.sizeX()/2
    if not weights: # set the weights
        weights = [1 for i in range(radius)]
    
    if not b: # set the bandwidth adaptively
        b_min = 4
        b_max = 128
    elif b.__class__ == tuple or b.__class__ == list:
        b_min = b[0]
        b_max = b[1]
    elif isinstance(b, int): # fixed bandwidth
        b_min = b
        b_max = b
    else:
        raise RuntimeError("Argument b is not valid!")
    
    from pytom.basic.fourier import fft, ifft, ftshift, iftshift
    from pytom_volume import vol, reducedToFull, rescale, abs, real
    from .vol2sf import vol2sf
    from pytom_numpy import vol2npy
    from math import log, ceil, pow

    # IMPORTANT!!! Should firstly do the IFFTSHIFT on the volume data (NOT FFTSHIFT since for odd-sized data it matters!),
    # and then followed by the FFT.
    vf = ftshift(reducedToFull(fft(iftshift(vf, inplace=False))), inplace=False)
    vg = ftshift(reducedToFull(fft(iftshift(vg, inplace=False))), inplace=False)

    ff = abs(vf)
    ff = real(ff)
    gg = abs(vg)
    gg = real(gg)
    
    get_bw = lambda x: int(pow(2, int(ceil(log(2*x, 2)))))
    
    res = None
    _last_bw = 0
    for r in range(1, radius+1):
        # calculate the appropriate bw
        bw = get_bw(r)
        if bw < b_min:
            bw = b_min
        if bw > b_max:
            bw = b_max
            
        # construct the wedge masks accordingly
        if _last_bw != bw:
            mf = create_wedge_sf(wf[0], wf[1], bw)
            mg = create_wedge_sf(wg[0], wg[1], bw)
        
        corr = frm_constrained_corr(vol2sf(ff, r, bw), mf, vol2sf(gg, r, bw), mg, norm=False, return_score=True)
        
        if _last_bw != bw:
            if res is None:
                res = np.zeros((2*bw, 2*bw, 2*bw), dtype='double')
            else:
                res = enlarge2(res)
        
        res += corr*(r**2)*weights[r-1]
        
        _last_bw = bw

    return frm_find_topn_angles_interp(res)