def distance(p, ref, freq, mask, binning): from pytom.basic.correlation import nxcc from pytom_volume import vol, initSphere, read, pasteCenter from pytom.basic.filter import lowpassFilter from pytom.basic.transformations import resize v = p.getTransformedVolume(binning) w = p.getWedge() r = ref.getVolume() a = lowpassFilter(w.apply(v, p.getRotation().invert()), freq)[0] b = lowpassFilter(w.apply(r, p.getRotation().invert()), freq)[0] if not mask: mask = vol(r) initSphere(mask, r.sizeX() // 2 - 3, 3, 0, r.sizeX() // 2, r.sizeY() // 2, r.sizeZ() // 2) else: #THE MASK is binning (sampled every n-points). This does lead to a reduction of the smoothing of the edges. maskBin = read(mask, 0, 0, 0, 0, 0, 0, 0, 0, 0, binning, binning, binning) if a.sizeX() != maskBin.sizeX() or a.sizeY() != maskBin.sizeY( ) or a.sizeZ() != maskBin.sizeZ(): mask = vol(a.sizeX(), a.sizeY(), a.sizeZ()) mask.setAll(0) pasteCenter(maskBin, mask) else: mask = maskBin s = nxcc(a, b, mask) d2 = 2 * (1 - s) return d2
def initSphere(cubeSize, radius, smoothing=0, centerX=None, centerY=None, centerZ=None): """ initSphere: Initilizes a volume with a sphere @param cubeSize: The size of the whole volume @param radius: Radius of the sphere @param smoothing: Smoothing at the edges of the sphere @param centerX: Center of shpere along X axis @param centerY: Center of shpere along Y axis @param centerZ: Center of shpere along Z axis """ from pytom_volume import vol, initSphere sphere = vol(cubeSize, cubeSize, cubeSize) sphere.setAll(0) if centerX is None: centerX = cubeSize / 2 - 1 if centerY is None: centerY = cubeSize / 2 - 1 if centerZ is None: centerZ = cubeSize / 2 - 1 initSphere(sphere, radius, smoothing, 0, centerX, centerY, centerZ) return sphere
def setUp(self): from helper_functions import create_RandomParticleList from pytom.tompy.io import read_size from pytom_volume import vol, initSphere self.reffile = './testData/ribo.em' self.pl_filename = 'pl.xml' self.pdir = './testparticles' self.pl = create_RandomParticleList(reffile=self.reffile, pl_filename=self.pl_filename, pdir=self.pdir, nparticles=10) # set parameters for GLocal self.settings = {} self.settings["binning"] = 4 self.settings["niteration"] = 1 self.settings["mask"] = './testData/ribo_mask.em' dims = read_size(self.reffile) maskvol = vol(int(dims[0]), int(dims[1]), int(dims[2])) initSphere(maskvol, 30, 5, 0, int(dims[0] / 2), int(dims[1] / 2), int(dims[2] / 2)) maskvol.write(self.settings["mask"]) self.settings["destination"] = './' #self.settings["score"] = 'nxcf' self.settings["score"] = 'flcf' self.settings["pixelsize"] = 2. self.settings["diameter"] = 250. self.settings["job"] = './myGLocal.xml'
def initVolume(self, sizeX, sizeY, sizeZ): """ initVolume: @param sizeX: @param sizeY: @param sizeZ: @return: @author: Thomas Hrabe """ from pytom_volume import vol, initSphere self._weight = vol(sizeX, sizeY, sizeZ) if self._radius > 0 or self._smooth > 0: initSphere(self._weight, self._radius, self._smooth, 0.0, sizeX / 2, sizeY / 2, sizeZ / 2) else: self._weight.setAll(1)
def initSphere(sizeX, sizeY, sizeZ, radius, smooth=0, maxradius=0, cent=None, filename=''): """ initSphere: Initializes a sphere @param sizeX: X size of cube @type sizeX: int @param sizeY: Y size of cube @type sizeY: int @param sizeZ: Z size of cube @type sizeZ: int @param radius: Radius of sphere mask @type radius: float @param smooth: Smooth of sphere mask @type smooth: float @param maxradius: maximum radius - data will be set to zero beyond this radius - default 0 does not do anything @param cent: centre vector @type cent: array (3-dim) @param filename: If specified by the user, the spherical mask will be written to disk. """ from pytom_volume import initSphere, vol v = vol(sizeX, sizeY, sizeZ) if cent: initSphere(v, radius, smooth, maxradius, cent[0], cent[1], cent[2]) else: initSphere(v, radius, smooth, maxradius, sizeX / 2, sizeY / 2, sizeZ / 2) if filename != '': v.write(filename) return v
def setUp(self): """set up""" from pytom_volume import vol, initSphere from pytom.basic.structures import WedgeInfo from pytom.simulation.EMSimulation import simpleSimulation self.wedge = 0. self.shift = [-1, 2, 3] self.rotation = [0, 0, 0] # create sphere self.v = vol(32, 32, 32) self.mask = vol(32, 32, 32) initSphere(self.v, 10, 2, 0, 15, 15, 15) # there is a slight inconsistency when smoothing > 0 - # cleaner implementation would be multipliction with sqrt(mask) in corr function initSphere(self.mask, 13, 0, 0, 16, 16, 16) self.wi = WedgeInfo(wedgeAngle=self.wedge, rotation=[10.0, 20.0, 30.0], cutoffRadius=0.0) self.s = simpleSimulation(volume=self.v, rotation=self.rotation, shiftV=self.shift, wedgeInfo=self.wi, SNR=10.)
def create_bfactor_vol(size, ps, bfactor, FSC=None, apply_range=None): """Create a B-factor volume in Frequency space. @param size: The size of the volume, assuming it is a cube @param ps: The pixel size in angstrom @param bfactor: B factor @param FSC: Fourier Shell Correlation @param apply_range: The apply range (also in angstrom) of the B factor correction """ if FSC is None: FSC = np.ones(size / 2) # transfer the pixel size to angstrom x = (ps * size) / np.arange(1, size / 2 + 1, 1) # starts from 1! if apply_range is None: apply_range_pixel = [1, size / 2] # starts from 1! else: assert apply_range[0] > apply_range[1] apply_range_pixel = [ size * ps / apply_range[0], size * ps / apply_range[1] ] # create the FSC weight FSC_weight = np.sqrt((2 * np.array(FSC)) / (1 + np.array(FSC))) # calculate the decay function decay = FSC_weight * np.exp(-bfactor / (np.power(x, 2) * 4)) # make the decay volume v = sph2cart(decay, size) # transfer to the volume format and multiple with the mask from pytom_volume import vol, initSphere from pytom_numpy import npy2vol vv = npy2vol(np.array(v, dtype='float32', order='F'), 3) if apply_range_pixel[0] == 1: mask = vol(size, size, size) initSphere(mask, apply_range_pixel[1] - 1, 0, 0, size / 2, size / 2, size / 2) # minus 1 to make it consistent with python else: mask1 = vol(size, size, size) mask2 = vol(size, size, size) initSphere(mask1, apply_range_pixel[0] - 1, 0, 0, size / 2, size / 2, size / 2) initSphere(mask2, apply_range_pixel[1] - 1, 0, 0, size / 2, size / 2, size / 2) mask = mask2 - mask1 return vv * mask
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
def extractPeaks(volume, reference, rotations, scoreFnc=None, mask=None, maskIsSphere=False, wedgeInfo=None, **kwargs): ''' Created on May 17, 2010 @param volume: target volume @type volume: L{pytom_volume.vol} @param reference: reference @type reference: L{pytom_volume.vol} @param rotations: rotation angle list @type rotations: L{pytom.angles.globalSampling.GlobalSampling} @param scoreFnc: score function that is used @type scoreFnc: L{pytom.basic.correlation} @param mask: mask volume @type mask: L{pytom_volume.vol} @param maskIsSphere: flag to indicate whether the mask is sphere or not @type maskIsSphere: boolean @param wedgeInfo: wedge information @type wedgeInfo: L{pytom.basic.structures.WedgeInfo} @return: both the score volume and the corresponding rotation index volume @rtype: L{pytom_volume.vol} @author: chen ''' # from pytom.tools.timing import timing # t = timing(); t.start() # parse the parameters nodeName = kwargs.get('nodeName', '') verbose = kwargs.get('verboseMode', True) if verbose not in [True, False]: verbose = True moreInfo = kwargs.get('moreInfo', False) if moreInfo not in [True, False]: moreInfo = False from pytom.basic.correlation import FLCF from pytom.basic.structures import WedgeInfo, Wedge from pytom_volume import vol, pasteCenter from pytom_volume import rotateSpline as rotate # for more accuracy from pytom_volume import updateResFromIdx from pytom.basic.files import write_em if scoreFnc == None: scoreFnc = FLCF # only FLCF needs mask if scoreFnc == FLCF: if mask.__class__ != vol: # construct a sphere mask by default from pytom_volume import initSphere mask = vol(reference.sizeX(), reference.sizeY(), reference.sizeZ()) mask.setAll(0) initSphere(mask, reference.sizeX() / 2, 0, 0, reference.sizeX() / 2, reference.sizeX() / 2, reference.sizeX() / 2) maskIsSphere = True # result volume which stores the score result = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) result.setAll(-1) # result orientation of the peak value (index) orientation = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) orientation.setAll(0) currentRotation = rotations.nextRotation() index = 0 if verbose == True: from pytom.tools.ProgressBar import FixedProgBar max = rotations.numberRotations() - 1 prog = FixedProgBar(0, max, nodeName) if moreInfo: sumV = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) sumV.setAll(0) sqrV = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) sqrV.setAll(0) else: sumV = None sqrV = None if wedgeInfo.__class__ == WedgeInfo or wedgeInfo.__class__ == Wedge: print('Applied wedge to volume') volume = wedgeInfo.apply(volume) while currentRotation != [None, None, None]: if verbose == True: prog.update(index) # rotate the reference ref = vol(reference.sizeX(), reference.sizeY(), reference.sizeZ()) rotate(reference, ref, currentRotation[0], currentRotation[1], currentRotation[2]) # apply wedge if wedgeInfo.__class__ == WedgeInfo or wedgeInfo.__class__ == Wedge: ref = wedgeInfo.apply(ref) # rotate the mask if it is asymmetric if scoreFnc == FLCF: if maskIsSphere == False: # if mask is not a sphere, then rotate it m = vol(mask.sizeX(), mask.sizeY(), mask.sizeZ()) rotate(mask, m, currentRotation[0], currentRotation[1], currentRotation[2]) else: m = mask # compute the score # if mask is sphere and it is the first run, compute the standard deviation of the volume under mask for late use if scoreFnc == FLCF and index == 0 and maskIsSphere == True: # compute standard deviation of the volume under mask maskV = m if volume.sizeX() != m.sizeX() or volume.sizeY() != m.sizeY( ) or volume.sizeZ() != m.sizeZ(): maskV = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) maskV.setAll(0) pasteCenter(m, maskV) from pytom_volume import sum p = sum(m) from pytom.basic.correlation import meanUnderMask, stdUnderMask meanV = meanUnderMask(volume, maskV, p) stdV = stdUnderMask(volume, maskV, p, meanV) # ref.write('template_cpu.em') if scoreFnc == FLCF: if maskIsSphere == True: score = scoreFnc(volume, ref, m, stdV, wedge=1) else: score = scoreFnc(volume, ref, m) else: # not FLCF, so doesn't need mask as parameter and perhaps the reference should have the same size _ref = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) _ref.setAll(0) pasteCenter(ref, _ref) score = scoreFnc(volume, _ref) # update the result volume and the orientation volume updateResFromIdx(result, score, orientation, index) if moreInfo: sumV = sumV + score sqrV = sqrV + score * score currentRotation = rotations.nextRotation() index = index + 1 # if moreInfo: # sumV = sumV/rotations.numberRotations() # sqrV = sqrV/rotations.numberRotations() # time = t.end(); print 'The overall execution time: %f' % time return [result, orientation, sumV, sqrV]
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
def simpleSimulation(volume, rotation, shiftV, wedgeInfo=None, SNR=0.1, mask=None): """ simpleSimulation: Simulates an ET by applying rotation,shift,wedge and noise to an volume @param volume: the volume used for simulations @param rotation: the rotation applied to volume @param shiftV: shift vector applied to volume @param wedgeInfo: wedge applied to volume @param SNR: noise level applied to volume @param mask: Apodisation mask @return: a simple cryo em simulation of volume """ from pytom_volume import vol, rotate, shift, initSphere from pytom.simulation import whiteNoise if not rotation == [0, 0, 0]: #print '---ROTATE---' #print 'EMSimulation simpleSimulation: in rotation 1 ' + str(rotation) rotatedCopy = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) rotate(volume, rotatedCopy, rotation[0], rotation[1], rotation[2]) else: rotatedCopy = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) rotatedCopy.copyVolume(volume) #print 'EMSimulation simpleSimulation: after rotation ' if not mask: #print 'EMSimulation simpleSimulation: in mask 1' mask = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) initSphere(mask, volume.sizeX() // 2 - 1, 0, 0, volume.sizeX() // 2, volume.sizeX() // 2, volume.sizeX() // 2) maskedCopy = rotatedCopy * mask if not mask.__class__ == vol: #print 'EMSimulation simpleSimulation: in mask 2' mask = mask.getVolume(rotation) maskedCopy = rotatedCopy * mask else: #print 'EMSimulation simpleSimulation: in mask 3' maskedCopy = rotatedCopy * mask #print 'EMSimulation simpleSimulation: after mask' if not shiftV == [0, 0, 0]: #print '--SHIFT---' shiftedCopy = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) shift(maskedCopy, shiftedCopy, shiftV[0], shiftV[1], shiftV[2]) else: shiftedCopy = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) shiftedCopy.copyVolume(maskedCopy) if (shiftV == [0, 0, 0]) and (rotation == [0, 0, 0]): #no shift and no rotation -> simply take the original volume c = vol(maskedCopy.sizeX(), volume.sizeY(), volume.sizeZ()) c.copyVolume(maskedCopy) noisyCopy = whiteNoise.add(c, SNR) else: noisyCopy = whiteNoise.add(shiftedCopy, SNR) if wedgeInfo: #print '---WEDGE---' result = wedgeInfo.apply(noisyCopy) else: result = noisyCopy #print 'EMSimulation simpleSimulation: end function' if result.__class__ == list: return result[0] else: return result
def maskOut(self, mask, center, size): """ maskOut: Set part of mask volume to all zero. The region is specified by center and size. @param mask: volume that you handle with @type mask: L{pytom_volume.vol} @param center: center of the region @type center: [x,y,z] @param size: size of the region @type size: [sizeX, sizeY, sizeZ] or radius """ from pytom_volume import vol, putSubVolume if size.__class__ == list: p_sizeX = size[0] p_sizeY = size[1] p_sizeZ = size[2] elif size.__class__ == vol: mm = size p_sizeX = mm.sizeX() p_sizeY = mm.sizeY() p_sizeZ = mm.sizeZ() else: radius = size p_sizeX = radius * 2 p_sizeY = radius * 2 p_sizeZ = radius * 2 maskSize = [mask.sizeX(), mask.sizeY(), mask.sizeZ()] if maskSize < center: raise RuntimeError('Center out of range!') # [) # mask out double size. CHANGED!!! startX = int(center[0] - p_sizeX / 2) endX = int(center[0] + p_sizeX / 2) startY = int(center[1] - p_sizeY / 2) endY = int(center[1] + p_sizeY / 2) startZ = int(center[2] - p_sizeZ / 2) endZ = int(center[2] + p_sizeZ / 2) # only used for radius sub_startX = 0 sub_startY = 0 sub_startZ = 0 if startX < 0: sub_startX = -startX startX = 0 if endX > maskSize[0]: endX = maskSize[0] if startY < 0: sub_startY = -startY startY = 0 if endY > maskSize[1]: endY = maskSize[1] if startZ < 0: sub_startZ = -startZ startZ = 0 if endZ > maskSize[2]: endZ = maskSize[2] sizeX = endX - startX sizeY = endY - startY sizeZ = endZ - startZ if size.__class__ == list: subV = vol(sizeX, sizeY, sizeZ) subV.setAll(0) elif size.__class__ == vol: from pytom_volume import limit, subvolume subV = (mm - 1) / -1 limit(subV, 0.999, 0, 0, 0, True, False) subV = subvolume(subV, sub_startX, sub_startY, sub_startZ, sizeX, sizeY, sizeZ) tempV = subvolume(mask, startX, startY, startZ, sizeX, sizeY, sizeZ) subV = subV * tempV # AND operation else: from pytom_volume import initSphere, subvolume subV = vol(radius * 2, radius * 2, radius * 2) initSphere(subV, radius, 0, 0, radius, radius, radius) tempV = vol(radius * 2, radius * 2, radius * 2) tempV.setAll(1) subV = tempV - subV subV = subvolume(subV, sub_startX, sub_startY, sub_startZ, sizeX, sizeY, sizeZ) tempV = subvolume(mask, startX, startY, startZ, sizeX, sizeY, sizeZ) subV = subV * tempV # AND operation putSubVolume(subV, mask, startX, startY, startZ)
def FLCF(volume, template, mask=None, stdV=None): ''' Created on Apr 13, 2010 FLCF: compute the fast local correlation function This functions works only when the mask is in the middle. @param volume: target volume @type volume: L{pytom_volume.vol} @param template: template to be searched. It can have smaller size then target volume. @type template: L{pytom_volume.vol} @param mask: template mask. If not given, a default sphere mask will be generated which has the same size with the given template. @type mask: L{pytom_volume.vol} @param stdV: standard deviation of the target volume under mask, which do not need to be calculated again when the mask is identical. @type stdV: L{pytom_volume.vol} @return: the local correlation function @rtype: L{pytom_volume.vol} @author: Yuxiang Chen ''' from pytom_volume import vol, pasteCenter from pytom.basic.fourier import fft, ifft, iftshift from pytom_volume import conjugate from pytom.basic.structures import Mask from pytom_volume import sum from pytom.basic.files import write_em if volume.__class__ != vol and template.__class__ != vol: raise RuntimeError('Wrong input type!') if volume.sizeX()<template.sizeX() or volume.sizeY()<template.sizeY() or volume.sizeZ()<template.sizeZ(): raise RuntimeError('Template size is bigger than the target volume') # generate the mask if mask.__class__ != vol: from pytom_volume import initSphere mask = vol(template.sizeX(), template.sizeY(), template.sizeZ()) mask.setAll(0) initSphere(mask, template.sizeX()/2,0,0,template.sizeX()/2, template.sizeY()/2, template.sizeZ()/2) else: if template.sizeX()!=mask.sizeX() and template.sizeY()!=mask.sizeY() and template.sizeZ()!=mask.sizeZ(): raise RuntimeError('Template and mask size are not consistent!') # calculate the non-zeros p = sum(mask) # normalize the template under mask meanT = meanValueUnderMask(template, mask, p) stdT = stdValueUnderMask(template, mask, meanT, p) temp = (template - meanT)/stdT temp = temp * mask # construct both the template and the mask which has the same size as target volume tempV = temp if volume.sizeX() != temp.sizeX() or volume.sizeY() != temp.sizeY() or volume.sizeZ() != temp.sizeZ(): tempV = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) tempV.setAll(0) pasteCenter(temp, tempV) maskV = mask if volume.sizeX() != mask.sizeX() or volume.sizeY() != mask.sizeY() or volume.sizeZ() != mask.sizeZ(): maskV = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) maskV.setAll(0) pasteCenter(mask, maskV) # calculate the mean and std of volume if stdV.__class__ != vol: meanV = meanUnderMask(volume, maskV, p) stdV = stdUnderMask(volume, maskV, p, meanV) size = volume.numelem() fT = fft(tempV) conjugate(fT) result = iftshift(ifft(fT*fft(volume)))/stdV result.shiftscale(0,1/(size*p)) return result
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
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)
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]