Пример #1
0
 def showRotations(self,volume,directory,mask=None):
     """
     showRotations: Will store x,y,z slice through volume after each rotation was applied 
     """
     from pytom.tools.toImage import volumeToPNG
     from pytom.tools.files import dump2TextFile
     from pytom_volume import vol,rotateSpline
     from pytom.tools.files import getPytomPath,readStringFile
     from pytom.frontend.htmlDefines import headResponse200,copyright
 
     pytomPath = getPytomPath()
     cssDefines = readStringFile(pytomPath + '/frontend/htmlDefines/CSS.css')
 
     html = '<html>' + cssDefines
     html = html + '\n<title>PyTom Alignment</title>\n'
     html = html + '<body><center><h1 type="Main">List of Rotations</h1></center>\n'
     html = html + '</br></br></br></br></br></br></br></br><center>\n'
     html = html + '<table>\n'
     html = html + '<tr><td>Z1 (Phi) Z2 (Psi) X(Theta)</td><td>x-Slice</td><td>y-Slice</td><td>z-Slice</td></tr>'
     
     rotated = vol(volume.sizeX(),volume.sizeY(),volume.sizeZ())
     
     if not mask:
         mask = vol(volume.sizeX(),volume.sizeY(),volume.sizeZ())
         mask.setAll(1)
         
     volume = volume * mask    
     
     self.reset()
     
     rotation = self.nextRotation()
     rotationCounter = 0
     
     while not rotation == [None,None,None]:
     
         rotateSpline(volume,rotated,rotation[0],rotation[1],rotation[2])
         html = html + '<tr><td>' + str(rotation[0]) + ' ' + str(rotation[1]) + ' ' + str(rotation[2]) +'</td>/n'
         volumeToPNG(rotated,directory + str(rotationCounter) + '-x.png',rotated.sizeX()/2,'x')
         html = html + '<td><img src="' + directory + str(rotationCounter) + '-x.png"/></td>'
         volumeToPNG(rotated,directory + str(rotationCounter) + '-y.png',rotated.sizeY()/2,'y')
         html = html + '<td><img src="' + directory + str(rotationCounter) + '-y.png"/></td>'
         volumeToPNG(rotated,directory + str(rotationCounter) + '-z.png',rotated.sizeZ()/2,'z')
         html = html + '<td><img src="' + directory + str(rotationCounter) + '-z.png"/></td>'
         
         rotation = self.nextRotation()
         rotationCounter = rotationCounter + 1 
     
     html = html + '</body></html>'
     
     dump2TextFile(directory + 'rotations.html',html)
def sag_fine_grained_alignment(vf,
                               wf,
                               vg,
                               wg,
                               max_freq,
                               ang=[0, 0, 0],
                               loc=[0, 0, 0],
                               mask=None,
                               B,
                               alpha,
                               maxIter,
                               lambda1):
    """SAG-based fine-grained alignment between experimental data and reference data.
    Parameters
    vf: Experimental data
        pytom_volume.vol

    wf: Mask of vf in Fourier space.
        pytom.basic.structures.Wedge. If none, no missing wedge.

    vg: Reference data 
        pytom_volume.vol

    wg: Mask of vg in Fourier space.
        pytom.basic.structures.Wedge. If none, no missing wedge.

    max_freq: Maximal frequency involved in calculation.
              Integer.

    ang: Initial rotation angle

    loc: Initial translation value
    
    mask: Mask volume in real space.
          pytom_volume.vol

    B: Batch number 

    alpha: Step size

    maxIter: The max iteration number

    lambda1: Regularization parameter

    Returns
    -------
    (Optimal rotation angle and translation value.
    (best_translation, best_rotation, correlation_score)
    """
    from pytom_volume import vol, rotateSpline, peak, sum, power
    from pytom.basic.transformations import shift
    from pytom.basic.filter import lowpassFilter
    from pytom.basic.structures import Mask, SingleTiltWedge, Rotation
    from pytom_volume import initSphere
    from pytom_numpy import vol2npy

    import math
    import random

    if vf.sizeX() != vg.sizeX() or vf.sizeY() != vg.sizeY() or vf.sizeZ(
    ) != vg.sizeZ():
        raise RuntimeError('Two volumes must have the same size!')

    if wf is None:
        wf = SingleTiltWedge(0)
    else:
        vf = wf.apply(vf)
    if wg is None:
        wg = SingleTiltWedge(0)
    else:
        vg = wg.apply(vg)

    if mask is None:
        m = vol(vf.sizeX(), vf.sizeY(), vf.sizeZ())
        initSphere(m,
                   vf.sizeX() / 2, 0, 0,
                   vf.sizeX() / 2,
                   vf.sizeY() / 2,
                   vf.sizeZ() / 2)
        mask = m

    old_value = -1
    max_pos = [-1, -1, -1]
    max_ang = None
    max_value = -1.0

    ang_epsilon = np.ones(3) * (math.pi * (1.0 / 180))
    loc_epsilon = np.ones(3) * 1.0

    n = vf.sizeX()
    vf0_n = vol2npy(vf)

    if maxIter is None:
        maxIter = n / 2
    iVals = np.int32(np.ceil((n - B) * np.random.random(maxIter)))

    if lambda1 is None:
        lambda1 = 1 / n
    eps = np.finfo(np.float32).eps
    Lmax = 0.25 * np.max(np.sum(vf0_n**2)) + lambda1
    if alpha is None:
        alpha = 1 / Lmax

    d = np.zeros(6)
    g = np.zeros([n, 6])
    covered = np.int32(np.zeros(n))
    nCovered = 0
    grad = np.zeros(6)
    deri = np.zeros(6)
    vg2 = vol(vf.sizeX(), vf.sizeY(), vf.sizeZ())
    mask2 = vol(mask.sizeX(), mask.sizeY(), mask.sizeZ())

    for i in range(n):
        if (covered[i] != 0):
            nCovered += 1

    for k in range(maxIter):
        i = iVals[k] - 1
        if k == 0:
            rotateSpline(vg, vg2, ang[0], ang[1], ang[2])
            rotateSpline(mask, mask2, ang[0], ang[1], ang[2])

            vg2 = wf.apply(vg2)
            vg2 = lowpassFilter(vg2, max_freq, max_freq / 10.)[0]
            vg2_s = transform_single_vol(vg2, mask2)

            vf2 = shift(vf,
                        -loc[0] + vf.sizeX() / 2,
                        -loc[1] + vf.sizeY() / 2,
                        -loc[2] + vf.sizeZ() / 2,
                        imethod='spline')
            vf2 = lowpassFilter(vf2, max_freq, max_freq / 10.)[0]
            vf2 = wg.apply(vf2, Rotation(ang))
            vf2_s = transform_single_vol(vf2, mask2)

            i = 0
            ri = np.sum(
                vol2npy(vf2_s)[i:i + B, :, :] - vol2npy(vg2_s)[i:i + B, :, :])

        vg2_p = vol(n, n, n)
        vg2_m = vol(n, n, n)
        mask2_p = vol(n, n, n)
        mask2_m = vol(n, n, n)
        for dim_i in range(3):
            if abs(ang_epsilon[dim_i]) > eps:
                ang_epsilon_t = np.zeros(3)
                ang_epsilon_t[dim_i] = ang_epsilon[dim_i]

                angle = ang + ang_epsilon_t
                rotateSpline(vg, vg2_p, angle[0], angle[1], angle[2])
                rotateSpline(mask, mask2_p, angle[0], angle[1], angle[2])
                vg2_p = wf.apply(vg2_p)
                vg2_p = lowpassFilter(vg2_p, max_freq, max_freq / 10.)[0]
                vg2_pf = transform_single_vol(vg2_p, mask2_p)

                angle = ang - ang_epsilon_t
                rotateSpline(vg, vg2_m, angle[0], angle[1], angle[2])
                rotateSpline(mask, mask2_m, angle[0], angle[1], angle[2])
                vg2_m = wf.apply(vg2_m)
                vg2_m = lowpassFilter(vg2_m, max_freq, max_freq / 10.)[0]
                vg2_mf = transform_single_vol(vg2_m, mask2_m)

                vg2_ang_deri = (vg2_pf - vg2_mf) / (2 * ang_epsilon[dim_i])
                vg2_ang_deri_n = vol2npy(vg2_ang_deri)
                deri[dim_i] = np.sum(vg2_ang_deri_n[i:i + B, :, :])

                del vg2_pf, vg2_mf, vg2_ang_deri, vg2_ang_deri_n, angle
        del vg2_p, vg2_m, mask2_p, mask2_m

        vf1_ps = vol(n, n, n)
        vf1_ms = vol(n, n, n)
        ang_f = [ang[0], ang[1], ang[2]]
        for dim_i in range(3):
            if abs(loc_epsilon[dim_i]) > eps:
                loc_epsilon_t = np.zeros(3)
                loc_epsilon_t[dim_i] = ang_epsilon[dim_i]

                vf1_ps.copyVolume(vf)
                vf1_ms.copyVolume(vf)

                loc_r = loc + loc_epsilon_t
                vf1_tp = shift(vf1_ps, -loc_r[0] + vf1_ps.sizeX() / 2,
                               -loc_r[1] + vf1_ps.sizeY() / 2,
                               -loc_r[2] + vf1_ps.sizeZ() / 2, 'spline')
                vf1_tp = lowpassFilter(vf1_tp, max_freq, max_freq / 10.)[0]
                vf1_tp = wg.apply(vf1_tp, Rotation(ang_f))

                loc_r = loc - loc_epsilon_t
                vf1_tm = shift(vf1_ms, -loc_r[0] + vf1_ms.sizeX() / 2,
                               -loc_r[1] + vf1_ms.sizeY() / 2,
                               -loc_r[2] + vf1_ms.sizeZ() / 2, 'spline')
                vf1_tm = lowpassFilter(vf1_tm, max_freq, max_freq / 10.)[0]
                vf1_tm = wg.apply(vf1_tm, Rotation(ang_f))

                vf1_tpf = transform_single_vol(vf1_tp, mask2)
                vf1_tmf = transform_single_vol(vf1_tm, mask2)
                vf1_loc_deri = (vf1_tpf - vf1_tmf) / (2 * ang_epsilon[dim_i])
                vf1_loc_deri_n = vol2npy(vf1_loc_deri)
                deri[dim_i + 3] = np.sum(vf1_loc_deri_n[i:i + B, :, :])

                del vf1_tp, vf1_tm, vf1_tpf, vf1_tmf, vf1_loc_deri, vf1_loc_deri_n
        del vf1_ps, vf1_ms, ang_f

        for dim_i in range(6):
            grad[dim_i] = ri * deri[dim_i] / B

        for dim_i in range(6):
            d[dim_i] += grad[dim_i] - np.sum(g[i:i + B, dim_i])

        for dim_i in range(6):
            g[i:i + B, dim_i] = grad[dim_i]

        for j0 in range(i, i + B + 1):
            if (covered[j0] == 0):
                covered[j0] = 1
                nCovered += 1

        for dim_i in range(6):
            opt_beta[dim_i] -= alpha * d[dim_i] / nCovered
        ang = opt_beta[:3]
        loc = opt_beta[3:]

        rotateSpline(vg, vg2, ang[0], ang[1], ang[2])
        rotateSpline(mask, mask2, ang[0], ang[1], ang[2])

        vg2 = wf.apply(vg2)
        vg2 = lowpassFilter(vg2, max_freq, max_freq / 10.)[0]
        vg2_s = transform_single_vol(vg2, mask2)

        vf2 = shift(vf,
                    -loc[0] + vf.sizeX() / 2,
                    -loc[1] + vf.sizeY() / 2,
                    -loc[2] + vf.sizeZ() / 2,
                    imethod='spline')
        vf2 = lowpassFilter(vf2, max_freq, max_freq / 10.)[0]
        vf2 = wg.apply(vf2, Rotation(ang))
        vf2_s = transform_single_vol(vf2, mask2)
        ri = np.sum(
            vol2npy(vf2_s)[i:i + B, :, :] - vol2npy(vg2_s)[i:i + B, :, :])
        from pytom.basic.correlation import nxcc
        val = nxcc(vf2_s, vg2_s, mask)

        if val > max_value:
            max_pos = loc
            max_ang = ang
            max_value = val
        if abs(max_value - old_value) <= eps:
            break
        else:
            old_value = max_value
        del vg2_s, vf2, vf2_s

    del d, g, grad, deri

    return max_pos, max_ang, max_value
Пример #3
0
def frm_constrained_align(vf,
                          wf,
                          vg,
                          wg,
                          b,
                          max_freq,
                          peak_offset=None,
                          mask=None,
                          constraint=None,
                          weights=None,
                          position=None,
                          num_seeds=5,
                          pytom_volume=None):
    """Find the best alignment (translation & rotation) of volume vg (reference) to match vf.
    For details, please check the paper.

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

    wf: Mask of vf in Fourier space.
        pytom.basic.structures.Wedge. If none, no missing wedge.

    vg: Volume Nr. 2 / Reference
        pytom_volume.vol

    wg: Mask of vg in Fourier space.
        pytom.basic.structures.Wedge. If none, no missing 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.

    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.
                 pytom_volume.vol / Integer. By default is half of the volume radius.

    mask: Mask volume for vg in real space.
          pytom_volume.vol

    constraint: Angular constraint
                sh_alignment.constrained_frm.AngularConstraint

    weights: Obsolete.

    position: If the translation is already known or not. If provided, no translational search will be conducted.
              List: [x,y,z], default None.

    num_seeds: Number of threads for the expectation maximization procedure. The more the better, yet slower.
               Integer, default is 5.

    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, peak
    from pytom.basic.transformations import shift
    from pytom.basic.correlation import FLCF
    from pytom.basic.filter import lowpassFilter
    from pytom.basic.structures import Mask, SingleTiltWedge
    from pytom_volume import initSphere
    from pytom_numpy import vol2npy

    if vf.sizeX() != vg.sizeX() or vf.sizeY() != vg.sizeY() or vf.sizeZ(
    ) != vg.sizeZ():
        raise RuntimeError('Two volumes must have the same size!')

    if wf is None:
        wf = SingleTiltWedge(0)
    if wg is None:
        wg = SingleTiltWedge(0)

    if peak_offset is None:
        peak_offset = vol(vf.sizeX(), vf.sizeY(), vf.sizeZ())
        initSphere(peak_offset,
                   vf.sizeX() / 4, 0, 0,
                   vf.sizeX() / 2,
                   vf.sizeY() / 2,
                   vf.sizeZ() / 2)
    elif peak_offset.__class__ == 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!')

    # cut out the outer part which normally contains nonsense
    m = vol(vf.sizeX(), vf.sizeY(), vf.sizeZ())
    initSphere(m,
               vf.sizeX() / 2, 0, 0,
               vf.sizeX() / 2,
               vf.sizeY() / 2,
               vf.sizeZ() / 2)
    vf = vf * m
    vg = vg * m
    if mask is None:
        mask = m
    else:
        vg = vg * mask

    if position is None:  # if position is not given, we have to find it ourself
        # first roughtly determine the orientation (only according to the energy info)
        # get multiple candidate orientations
        numerator, denominator1, denominator2 = frm_correlate(
            vf, wf, vg, wg, b, max_freq, weights, True, None, None, False)
        score = numerator / (denominator1 * denominator2)**0.5
        res = frm_find_topn_constrained_angles_interp(
            score, num_seeds,
            get_adaptive_bw(max_freq, b) / 16., constraint)
    else:
        # the position is given by the user
        vf2 = shift(vf, -position[0] + vf.sizeX() / 2,
                    -position[1] + vf.sizeY() / 2,
                    -position[2] + vf.sizeZ() / 2, 'fourier')
        score = frm_correlate(vf2, wf, vg, wg, b, max_freq, weights, ps=False)
        orientation, max_value = frm_find_best_constrained_angle_interp(
            score, constraint=constraint)

        return position, orientation, max_value

    # iteratively refine the position & orientation
    from pytom.tools.maths import euclidianDistance
    max_iter = 10  # maximal number of iterations
    mask2 = vol(mask.sizeX(), mask.sizeY(),
                mask.sizeZ())  # store the rotated mask
    vg2 = vol(vg.sizeX(), vg.sizeY(), vg.sizeZ())
    lowpass_vf = lowpassFilter(vf, max_freq, max_freq / 10.)[0]

    max_position = None
    max_orientation = None
    max_value = -1.0
    for i in xrange(num_seeds):
        old_pos = [-1, -1, -1]
        lm_pos = [-1, -1, -1]
        lm_ang = None
        lm_value = -1.0
        orientation = res[i][0]  # initial orientation
        for j in xrange(max_iter):
            rotateSpline(vg, vg2, orientation[0], orientation[1],
                         orientation[2])  # first rotate
            rotateSpline(mask, mask2, orientation[0], orientation[1],
                         orientation[2])  # rotate the mask as well
            vg2 = wf.apply(vg2)  # then apply the wedge
            vg2 = lowpassFilter(vg2, max_freq, max_freq / 10.)[0]
            score = FLCF(lowpass_vf, vg2, mask2)  # find the position
            pos = peak(score, peak_offset)
            pos, val = find_subpixel_peak_position(vol2npy(score), pos)
            if val > lm_value:
                lm_pos = pos
                lm_ang = orientation
                lm_value = val

            if euclidianDistance(lm_pos, old_pos) <= 1.0:
                # terminate this thread
                if lm_value > max_value:
                    max_position = lm_pos
                    max_orientation = lm_ang
                    max_value = lm_value

                break
            else:
                old_pos = lm_pos

            # here we shift the target, not the reference
            # if you dont want the shift to change the energy landscape, use fourier shift
            vf2 = shift(vf, -lm_pos[0] + vf.sizeX() / 2,
                        -lm_pos[1] + vf.sizeY() / 2,
                        -lm_pos[2] + vf.sizeZ() / 2, 'fourier')
            score = frm_correlate(vf2, wf, vg, wg, b, max_freq, weights, False,
                                  denominator1, denominator2, True)
            orientation, val = frm_find_best_constrained_angle_interp(
                score, constraint=constraint)

        else:  # no converge after the specified iteration, still get the best result as we can
            if lm_value > max_value:
                max_position = lm_pos
                max_orientation = lm_ang
                max_value = lm_value

        # print max_value # for show the convergence of the algorithm

    return max_position, max_orientation, max_value
Пример #4
0
def xu_align_vol(vf, wf, vg, wg, b, radius=None, mask=None, peak_offset=None):
    """Implementation of Xu'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 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.

    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, peak
    from pytom.basic.transformations import shift
    from pytom.basic.correlation import nXcf
    from pytom.basic.filter import lowpassFilter
    from pytom.basic.structures import Mask
    from pytom_volume import initSphere
    from pytom_numpy import vol2npy

    if vf.sizeX()!=vg.sizeX() or vf.sizeY()!=vg.sizeY() or vf.sizeZ()!=vg.sizeZ():
        raise RuntimeError('Two volumes must have the same size!')

    if mask is None:
        mask = vol(vf.sizeX(), vf.sizeY(), vf.sizeZ())
        initSphere(mask, vf.sizeX()/2, 0,0, vf.sizeX()/2,vf.sizeY()/2,vf.sizeZ()/2)
    elif mask.__class__ == vol:
        pass
    elif mask.__class__ == Mask:
        mask = mask.getVolume()
    elif isinstance(mask, int):
        mask_radius = mask
        mask = vol(vf.sizeX(), vf.sizeY(), vf.sizeZ())
        initSphere(mask, mask_radius, 0,0, vf.sizeX()/2,vf.sizeY()/2,vf.sizeZ()/2)
    else:
        raise RuntimeError('Given mask has wrong type!')

    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!')

    # cut out the outer part which normally contains nonsense
    vf = vf*mask

    position = None
    if position is None: # if position is not given, we have to find it ourself
        # first roughtly determine the orientation (only according to the energy info)
        # get multiple candidate orientations
        orientations = frm_determine_orientation(vf, wf, vg, wg, b, radius, None, None, False)
    else:
        # the position is given by the user
        vf2 = shift(vf, -position[0]+vf.sizeX()/2, -position[1]+vf.sizeY()/2, -position[2]+vf.sizeZ()/2, 'spline')
        res = frm_fourier_adaptive_wedge_vol(vf2, wf, vg, wg, b, radius, None, None, False)
        orientation, max_value = frm_find_best_angle_interp(res)

        return position, orientation, max_value

    
    from pytom.basic.structures import WedgeInfo
    from pytom.tools.maths import euclidianDistance
    max_iter = 1 # maximal number of iterations
    wedge = WedgeInfo([90+wf[0], 90-wf[1]])
    old_pos = [-1, -1, -1]
    vg2 = vol(vg.sizeX(), vg.sizeY(), vg.sizeZ())
    lowpass_vf = lowpassFilter(vf, radius, 0)[0]
    
    peak_value = 0.0
    position = None
    ang = None
    for orientation in orientations:
        orientation = orientation[0]

        rotateSpline(vg, vg2, orientation[0], orientation[1], orientation[2]) # first rotate
        vg2 = wedge.apply(vg2) # then apply the wedge
        vg2 = lowpassFilter(vg2, radius, 0)[0]
        res = nXcf(lowpass_vf, vg2) # find the position
        pos = peak(res, peak_offset)
        # val = res(pos[0], pos[1], pos[2])
        pos, val = find_subpixel_peak_position(vol2npy(res), pos)
        if val > peak_value:
            position = pos
            ang = orientation
            peak_value = val

    return position, ang, peak_value
Пример #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_align_vol_rscore(vf, wf, vg, wg, b, radius=None, mask=None, peak_offset=None, weights=None, position=None):
    """Obsolete.
    """
    from pytom_volume import vol, rotateSpline, peak
    from pytom.basic.transformations import shift
    from pytom.basic.correlation import xcf
    from pytom.basic.filter import lowpassFilter
    from pytom.basic.structures import Mask
    from pytom_volume import initSphere
    from pytom_numpy import vol2npy

    if vf.sizeX()!=vg.sizeX() or vf.sizeY()!=vg.sizeY() or vf.sizeZ()!=vg.sizeZ():
        raise RuntimeError('Two volumes must have the same size!')

    if mask is None:
        mask = vol(vf.sizeX(), vf.sizeY(), vf.sizeZ())
        initSphere(mask, vf.sizeX()/2, 0,0, vf.sizeX()/2,vf.sizeY()/2,vf.sizeZ()/2)
    elif mask.__class__ == vol:
        pass
    elif mask.__class__ == Mask:
        mask = mask.getVolume()
    elif isinstance(mask, int):
        mask_radius = mask
        mask = vol(vf.sizeX(), vf.sizeY(), vf.sizeZ())
        initSphere(mask, mask_radius, 0,0, vf.sizeX()/2,vf.sizeY()/2,vf.sizeZ()/2)
    else:
        raise RuntimeError('Given mask has wrong type!')

    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!')

    # cut out the outer part which normally contains nonsense
    vf = vf*mask

    # # normalize them first
    # from pytom.basic.normalise import mean0std1
    # mean0std1(vf)
    # mean0std1(vg)

    if position is None: # if position is not given, we have to find it ourself
        # first roughtly determine the orientation (only according to the energy info)
        # get multiple candidate orientations
        orientations = frm_determine_orientation_rscore(vf, wf, vg, wg, b, radius, weights)
    else:
        # the position is given by the user
        vf2 = shift(vf, -position[0]+vf.sizeX()/2, -position[1]+vf.sizeY()/2, -position[2]+vf.sizeZ()/2, 'spline')
        res = frm_fourier_adaptive_wedge_vol_rscore(vf2, wf, vg, wg, b, radius, weights)
        orientation, max_value = frm_find_best_angle_interp(res)

        return position, orientation, max_value

    # iteratively refine the position & orientation
    from pytom.basic.structures import WedgeInfo
    from pytom.tools.maths import euclidianDistance
    max_iter = 10 # maximal number of iterations
    wedge = WedgeInfo([90+wf[0], 90-wf[1]])
    old_pos = [-1, -1, -1]
    vg2 = vol(vg.sizeX(), vg.sizeY(), vg.sizeZ())
    lowpass_vf = lowpassFilter(vf, radius, 0)[0]
    for i in range(max_iter):
        peak_value = 0.0
        position = None
        for orientation in orientations:
            orientation = orientation[0]

            rotateSpline(vg, vg2, orientation[0], orientation[1], orientation[2]) # first rotate
            vg2 = wedge.apply(vg2) # then apply the wedge
            vg2 = lowpassFilter(vg2, radius, 0)[0]
            res = xcf(lowpass_vf, vg2) # find the position
            pos = peak(res, peak_offset)
            # val = res(pos[0], pos[1], pos[2])
            pos, val = find_subpixel_peak_position(vol2npy(res), pos)
            if val > peak_value:
                position = pos
                peak_value = val

        if euclidianDistance(position, old_pos) <= 1.0:
            break
        else:
            old_pos = position

        # here we shift the target, not the reference
        # if you dont want the shift to change the energy landscape, use fourier shift
        vf2 = shift(vf, -position[0]+vf.sizeX()/2, -position[1]+vf.sizeY()/2, -position[2]+vf.sizeZ()/2, 'fourier')
        res = frm_fourier_adaptive_wedge_vol_rscore(vf2, wf, vg, wg, b, radius, weights)
        orientations = frm_find_topn_angles_interp(res)

    return position, orientations[0][0], orientations[0][1]