def frm_fourier_constrained_vol(vf, mf, vg, mg): radius = vf.sizeX() / 2 - 3 # intepolation in the outer part is nonsense b = 32 from pytom.basic.fourier import fft, ifft, ftshift, iftshift vf = ftshift(reducedToFull(fft(iftshift(vf, inplace=False))), inplace=False) vg = ftshift(reducedToFull(fft(iftshift(vg, inplace=False))), inplace=False) vfr = real(vf) vfi = imag(vf) vgr = real(vg) vgi = imag(vg) res = np.zeros((2 * b, 2 * b, 2 * b)) for r in xrange(1, radius + 1): corr = frm_fourier_constrained_corr(vol2sf(vfr, r, b), vol2sf(vfi, r, b), mf, vol2sf(vgr, r, b), vol2sf(vgi, r, b), mg, True) res += corr * (r**2) return res
def mean(volume, mask, fVolume=0, fMask=0, numberOfMaskVoxels=-1): """ suggestion frido: rename to mean_moving_mask mean: Determines the mean of volume under mask. Each assigned value is determined through the value of the voxels surrounding the current voxel that are covered by the mask. @param volume: The volume of interest @param mask: A mask under which the mean is determined @param fVolume: Optional - the fouriertransformed volume (fft must not be repeated) @param fMask: Optional - the fouriertransformed mask (fft must not be repeated) @param numberOfMaskVoxels: Optional - the number of voxels != 0 """ import pytom_volume if not fVolume.__class__ == pytom_volume.vol_comp: from pytom.basic.fourier import fft fVolume = fft(volume) if not fMask.__class__ == pytom_volume.vol_comp: from pytom.basic.fourier import fft fMask = fft(mask) if numberOfMaskVoxels < 0: numberOfMaskVoxels = pytom_volume.numberSetVoxels(mask) fMeanVol = fVolume * fMask from pytom.basic.fourier import ifft meanVolume = ifft(fMeanVol) from pytom.basic.fourier import iftshift iftshift(meanVolume) meanVolume.shiftscale(0, 1.0 / (numberOfMaskVoxels * meanVolume.numelem())) return meanVolume
def convolute(v, k, kernel_in_fourier=False): """ @param v: the volume to be convolute @type v: L{pytom_volume.vol} @param k: the convolution kernel in real space @type k: L{pytom_volume.vol} @param kernel_in_fourier: the given kernel is already in Fourier space or not (full size, shifted in the center! \ or reduced size). Default is False. @type kernel_in_fourier: L{bool} @return: Volume convoluted with kernel @rtype: L{pytom_volume.vol} """ fv = fft(v) if not kernel_in_fourier: fk = fft(k) res = fv*fk else: from pytom_volume import complexRealMult, fullToReduced if k.sizeZ() == k.sizeX(): fk = fullToReduced(ftshift(k, inplace=False)) else: fk = k res = complexRealMult(fv, fk) out = ifft(res) out.shiftscale(0.0,1/float(out.sizeX()*out.sizeY()*out.sizeZ())) return out
def xcf(volume, template, mask=None, stdV=None): """ XCF: returns the non-normalised cross correlation function. The xcf result is scaled only by the square of the number of elements. @param volume : The search volume @type volume: L{pytom_volume.vol} @param template : The template searched (this one will be used for conjugate complex multiplication) @type template: L{pytom_volume.vol} @param mask: changed: will be used if specified @type mask: L{pytom_volume.vol} @param stdV: Will be unused, only for compatibility reasons with FLCF @return: XCF volume @rtype: L{pytom_volume.vol} @author: Thomas Hrabe """ import pytom_volume from pytom.basic import fourier if mask != None: volume = volume * mask template = template * mask #determine fourier transforms of volumes if volume.__class__ == pytom_volume.vol: from pytom.basic.fourier import fft fvolume = fft(volume) else: fvolume = volume if template.__class__ == pytom_volume.vol: from pytom.basic.fourier import fft ftemplate = fft(template) else: ftemplate = template #perform element wise - conjugate multiplication pytom_volume.conjugate(ftemplate) fresult = fvolume * ftemplate #transform back to real space result = fourier.ifft(fresult) fourier.iftshift(result) n = result.numelem() if mask: n1 = pytom_volume.sum(mask) # real -> FFT requires n1, FFT -> real n result.shiftscale(0,1/float(n1*n)) else: result.shiftscale(0,1/float(n*n)) return result
def bandpassFilter(volume, lowestFrequency, highestFrequency, bpf=None, smooth=0,fourierOnly=False): """ bandpassFilter: Performs bandpass filtering of volume. @param volume: The volume to be filtered @type volume: L{pytom_volume.vol} @param lowestFrequency: The lowest frequency in the filter as absolute pixel value @type lowestFrequency: L{float} @param highestFrequency: The highest frequency in the filter as absolute pixel value @type highestFrequency: L{float} @param bpf: Bandpassfilter C++ object if it is already existing @param smooth: Adjusts the size of gaussian falloff around each band end. @return: The bandpass filtered volume, the filter and the filtered volume in fourier space @author: Thomas Hrabe """ import pytom_freqweight import pytom_volume if volume.__class__ == pytom_volume.vol: from pytom.basic.fourier import fft fvolume = fft(volume) else: fvolume = volume if not bpf: bpf = pytom_freqweight.weight(lowestFrequency,highestFrequency, fvolume.sizeX(),fvolume.sizeY(),fvolume.sizeZ(),smooth) return filter(fvolume,bpf,fourierOnly)
def convolutionCTF(volume, defocus, pixelSize=None, voltage=None, Cs=None, sigma=None): """ convolutionCTF: @param volume: input volume to be convolved with CTF @type volume: L{pytom_volume.vol} @param defocus: Negative value = underfocus (in microns) @param pixelSize: Size of pixels / voxels (in Anstroms) @param voltage: @param Cs: @param sigma: @return: CTF filtered volume @rtype L{pytom_volume.vol} @author: FF """ from pytom_volume import subvolume, complexRealMult from pytom.basic.fourier import ftshift, fft, ifft from pytom.basic.filter import volCTF dimX = volume.sizeX() dimY = volume.sizeY() dimZ = volume.sizeZ() ctf = volCTF(defocus, dimX, dimY, dimZ, pixelSize, voltage, Cs, sigma) filterCTF = subvolume(ftshift(ctf,inplace=False), 0, 0, 0, dimX, dimY, (dimZ/2)+1) filteredVolume = ifft( complexRealMult(fft(volume), filterCTF) ) return filteredVolume
def filter(volume,filterObject,fourierOnly=False): """ filter: A generic filter method. @param volume: The volume to be filtered @type volume: L{pytom_volume.vol} @type volume: L{pytom_volume.vol} @param filterObject: A filter object (either wedgeFilter, bandpassFilter, ...) @return: The filtered volume,the filter and the filtered volume in fourier space @author: Thomas Hrabe """ from pytom.basic.fourier import fft, ifft import pytom_volume if volume.__class__ == pytom_volume.vol: fvolume = fft(volume) noPixels = volume.sizeX() * volume.sizeY() * volume.sizeZ() else: fvolume = pytom_volume.vol_comp(volume.sizeX(),volume.sizeY(),volume.sizeZ()) fvolume.copyVolume(volume) if (volume.sizeZ() == 1) and (volume.sizeY() == 1): noPixels = 2 *(volume.sizeX()-1) elif volume.sizeZ() == 1: noPixels = volume.sizeX() *2 *(volume.sizeY()-1) else: noPixels = volume.sizeX() * volume.sizeY() * 2*(volume.sizeZ()-1) filterObject.apply(fvolume) if not fourierOnly: result = ifft(fvolume)/noPixels return [result,filterObject,fvolume] else: return [fvolume,filterObject]
def create_average(self, sum_ctf_conv, sum_ctf_squared, wedge_weight): """For the master node, this function is rewritten. """ from pytom_volume import vol, complexDiv, fullToReduced, initSphere, complexRealMult, limit from pytom.basic.fourier import fft, ifft, ftshift from pytom.basic.normalise import mean0std1 # limit(wedge_weight, 0.1, 0, 0,0,True,False) # set all the values below the specified value to 0 # for mask out the outside area # mask = vol(sum_ctf_conv) # mask.setAll(0) # initSphere(mask, sum_ctf_conv.sizeX()/2-1, 0,0, sum_ctf_conv.sizeX()/2, sum_ctf_conv.sizeX()/2, sum_ctf_conv.sizeX()/2) # mask = fullToReduced(ftshift(mask, inplace=False)) # Wiener filter numerator = fft(sum_ctf_conv) sum_ctf_squared = fullToReduced(ftshift(sum_ctf_squared, inplace=False)) denominator = (sum_ctf_squared+1)*wedge_weight r = complexDiv(numerator, denominator) # average = ifft(complexRealMult(r, mask)) average = ifft(r) average.shiftscale(0.0,1/float(average.sizeX()*average.sizeY()*average.sizeZ())) # nomalize the average try: average = mean0std1(average, True) except: average *= 1000 # in case the average volume is too small to normalize average = mean0std1(average, True) return average
def powerspectrum(volume): """ compute power spectrum of a volume @param volume: input volume @type volume: L{pytom_volume.vol} @return: power spectrum of vol @rtype: L{pytom_volume.vol} @author: FF """ from pytom.basic.fourier import fft, ftshift from pytom_volume import vol from pytom_volume import reducedToFull fvol = ftshift(reducedToFull(fft(volume)),inplace=False) nx=fvol.sizeX() ny=fvol.sizeY() nz=fvol.sizeZ() ps = vol(nx,ny,nz) sf = 1./(nx*ny*nz) for ix in range(0,nx): for iy in range(0,ny): for iz in range(0,nz): temp = fvol.getV(ix,iy,iz) temp = temp*temp.conjugate()*sf ps.setV(float(temp.real),ix,iy,iz) return ps
def resize(volume, factor, interpolation='Fourier'): """ resize volume in real or Fourier space @param volume: input volume @type volume: L{pytom_volume.vol} @param factor: a factor > 0. Factors < 1 will de-magnify the volume, factors > 1 will magnify. @type factor: L{float} @param interpolation: Can be 'Fourier' (default), 'Spline', 'Cubic' or 'Linear' @type interpolation: L{str} @return: The re-sized volume @rtype: L{pytom_volume.vol} @author: FF """ if (interpolation == 'Spline') or (interpolation == 'Cubic') or (interpolation == 'Linear'): return scale(volume, factor, interpolation='Spline') else: from pytom.basic.fourier import fft, ifft fvol = fft(data=volume) newfvol = resizeFourier(fvol=fvol, factor=factor) newvol = ifft(newfvol) return newvol, newfvol
def test_resize2D(self): """ test re-sizing in Fourier space """ from pytom.basic.transformations import resize from pytom_volume import vol from pytom.basic.fourier import fft dim = 32 px = 11 py = 19 scf = dim * dim myVol = vol(dim, dim, 1) myVol.setAll(0.) myVol.setV(1., px, py, 0) #fmyVol = fft(myVol) (resizeVol, resizefVol) = resize(volume=myVol, factor=2., interpolation='Fourier') resizeVol.write('test1.em') ftresizeVol = fft(data=resizeVol) for ix in range(resizefVol.sizeX()): for iy in range(resizefVol.sizeY()): diff = ftresizeVol.getV( ix, iy, 0) - scf * 4 * resizefVol.getV(ix, iy, 0) self.assertTrue(expr=abs(diff) < .05, msg="inconsistency FFT/IFFT for magnification") (resizeVol, resizefVol) = resize(volume=resizeVol, factor=.5, interpolation='Fourier') from pytom_volume import variance diff = myVol - resizeVol self.assertTrue(expr=variance(diff, False) < .0000001, msg="2D image before and after rescales differs")
def FSCSum(volume,reference,numberOfBands,wedgeAngle=-1): """ FSCSum: Determines the sum of the Fourier Shell Correlation coefficient for a volume and reference. @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 sum FSC coefficient @rtype: float @author: Thomas Hrabe """ from pytom.basic.correlation import bandCC import pytom_volume from pytom.basic.fourier import fft from math import sqrt import pytom_freqweight result = 0 numberVoxels = 0 #volume.write('vol.em'); #reference.write('ref.em'); fvolume = fft(volume) freference = fft(reference) numelem = volume.numelem() fvolume.shiftscale(0,1/float(numelem)) freference.shiftscale(0,1/float(numelem)) #print '-----' for i in range(numberOfBands): #process bandCorrelation band = [] band[0] = i*volume.sizeX()/numberOfBands band[1] = (i+1)*volume.sizeX()/numberOfBands r = bandCC(fvolume,freference,band) cc = r[0] #print cc result = result + cc #print '-----' return result*(1/float(numberOfBands))
def std(volume, mask, meanVolume=0, fMask=0, numberOfMaskVoxels=-1): """ suggestion frido: rename to std_moving_mask std: Determines the std of volume under moving mask. Each assigned value is determined through the value of the voxels surrounding the current voxel that are covered by the mask. @param volume: The volume of interest @param mask: A mask under which the std is determined @param meanVolume: Optional - the meanVolume determined by mean. (mean must not be recalculated) @param fMask: Optional - the fouriertransformed mask (fft must not be repeated) @param numberOfMaskVoxels: Optional - the number of voxels != 0 """ from pytom.basic.fourier import fft, ifft, iftshift from pytom_volume import power import pytom_volume if not fMask.__class__ == pytom_volume.vol_comp: fMask = fft(mask) if not meanVolume.__class__ == pytom_volume.vol: meanVolume = mean(volume, mask) if numberOfMaskVoxels < 0: numberOfMaskVoxels = pytom_volume.numberSetVoxels(mask) volumeSqrd = volume * volume fVolumeSqrd = fft(volumeSqrd) fVolumeSqrd = fVolumeSqrd * fMask varianceVolume = iftshift(ifft(fVolumeSqrd)) varianceVolume.shiftscale( 0, 1.0 / (numberOfMaskVoxels * varianceVolume.numelem())) power(meanVolume, 2) varianceVolume = varianceVolume - meanVolume power(varianceVolume, 0.5) return varianceVolume
def fourier_rotate(v, phi, psi, the): vf = ftshift(reducedToFull(fft(iftshift(v, inplace=False))), inplace=False) vfr = real(vf) vfi = imag(vf) rr = vol(vfr) ii = vol(vfi) rotateSpline(vfr, rr, phi, psi, the) rotateSpline(vfi, ii, phi, psi, the) # print vfr(12,12,12),rr(12,12,12) vv = mergeRealImag(rr, ii) return ftshift(ifft(fullToReduced(iftshift(vv, inplace=False))), inplace=False) / v.numelem()
def meanUnderMask(volume, mask, p): """ meanUnderMask: calculate the mean volume under the given mask (Both should have the same size) @param volume: input volume @type volume: L{pytom_volume.vol} @param mask: mask @type mask: L{pytom_volume.vol} @param p: non zero value numbers in the mask @type p: L{int} or L{float} @return: the calculated mean volume under mask @rtype: L{pytom_volume.vol} @author: Yuxiang Chen """ size = volume.numelem() from pytom.basic.fourier import fft, ifft, iftshift from pytom_volume import conjugate # for some reason, this has to be conjugated. (Otherwise the asym mask won't work) fMask = fft(mask) conjugate(fMask) result = iftshift(ifft(fMask*fft(volume)))/(size*p) return result
def create_average(self, pre, wedge): """For the master node, create the average according to the pre-wedge and wedge volumes. """ from pytom_volume import complexDiv, limit from pytom.basic.fourier import fft, ifft limit(wedge, 0.1, 0, 0, 0, True, False) # set all the values below the specified value to 0 f_pre = fft(pre) r = complexDiv(f_pre, wedge) average = ifft(r) average.shiftscale( 0.0, 1 / float(average.sizeX() * average.sizeY() * average.sizeZ())) return average
def shift(volume,shiftX,shiftY,shiftZ,imethod='fourier',twice=False): """ shift: Performs a shift on a volume @param volume: the volume @param shiftX: shift in x direction @param shiftY: shift in y direction @param shiftZ: shift in z direction @param imethod: Select interpolation method. Real space : linear, cubic, spline . Fourier space: fourier @param twice: Zero pad volume into a twice sized volume and perform calculation there. @return: The shifted volume. @author: Yuxiang Chen and Thomas Hrabe """ if imethod == 'fourier': from pytom_volume import vol_comp,reducedToFull,fullToReduced,shiftFourier from pytom.basic.fourier import fft,ifft,ftshift, iftshift fvolume = fft(volume) fullFVolume = reducedToFull(fvolume) destFourier = vol_comp(fullFVolume.sizeX(),fullFVolume.sizeY(),fullFVolume.sizeZ()) shiftFourier(fullFVolume,destFourier,shiftX,shiftY,shiftZ) resFourier = fullToReduced(destFourier) return ifft(resFourier)/volume.numelem() else: from pytom_volume import vol if imethod == 'linear': from pytom_volume import transform elif imethod == 'cubic': from pytom_volume import transformCubic as transform elif imethod == 'spline': from pytom_volume import transformSpline as transform # now results should be consistent with python2 centerX = int(volume.sizeX()/2) centerY = int(volume.sizeY()/2) centerZ = int(volume.sizeZ()/2) res = vol(volume.sizeX(),volume.sizeY(),volume.sizeZ()) transform(volume,res,0,0,0,centerX,centerY,centerZ,shiftX,shiftY,shiftZ,0,0,0) return res
def getWeightedProjectionCube(sourceVolume, thetaAngles): from pytom_volume import vol, paste from pytom_volume import complexRealMult from pytom.basic.fourier import fft from pytom.basic.fourier import ifft from pytom.basic.filter import fourierFilterShift from pytom.basic.filter import circleFilter from pytom.basic.filter import rampFilter dimX = sourceVolume.sizeX() dimY = sourceVolume.sizeY() imageCube = vol(dimX, dimY, len(thetaAngles)) imageCube.setAll(0.0) weightSlice = fourierFilterShift(rampFilter(sourceVolume)) circleFilterRadius = dimX / 2 circleSlice = fourierFilterShift( circleFilter(sourceVolume, circleFilterRadius)) for k in range(len(thetaAngles)): angle = thetaAngles[k] image = theta_vol_projection(sourceVolume, angle) ##filtered_img = ifft( complexRealMult(complexRealMult(complexRealMult(fft(image), filter_slice), circle_filter_slice), ctf) ) filteredImage = ifft( complexRealMult(complexRealMult(fft(image), weightSlice), circleSlice)) paste(filteredImage, imageCube, 0, 0, k) #for i in range(dimX): # for j in range(dimY): # imageCube.setV(filteredImage.getV(i, j, 0), i, j, k) return imageCube
def highpassFilter(volume,band,smooth=0,fourierOnly=False): """ highpassFilter: @param volume: The volume filtered @type volume: L{pytom_volume.vol} @param band: Lower end of band (in pixels) @param smooth: Adjusts the size of gaussian falloff around each band end. @return: The highpass filtered volume,the filter and the filtered volume in fourier space @author: Thomas Hrabe """ import pytom_freqweight import pytom_volume if volume.__class__ == pytom_volume.vol: from pytom.basic.fourier import fft fvolume = fft(volume) else: fvolume = volume hpf = pytom_freqweight.weight(band,fvolume.sizeX(),fvolume.sizeX(),fvolume.sizeY(),fvolume.sizeZ(),smooth) return filter(fvolume,hpf,fourierOnly)
def transformFourierSpline(volume,z1,z2,x,shiftX,shiftY,shiftZ,twice=False): """ transformFourierSpline: Rotate and shift a volume in fourierspace @param volume: @param z1: @param z2: @param x: @param shiftX: Shift after rotation @param shiftY: Shift after rotation @param shiftZ: Shift after rotation @param twice: Zero pad volume into a twice sized volume and perform calculation there. @return: The transformed volume. @author: Yuxiang Chen and Thomas Hrabe """ from pytom.basic.fourier import fft, ifft, ftshift, iftshift from pytom_volume import vol, pasteCenter, subvolume, transformFourierSpline if z1 == 0 and z2 == 0 and x == 0: return vol(volume) if twice: # paste into a twice sized volume v = vol(volume.sizeX()*2, volume.sizeY()*2, volume.sizeZ()*2) pasteCenter(volume, v) else: v = volume fvol = fft(iftshift(v, inplace=False)) # these steps have to be done in python level because of the fft resF = transformFourierSpline(fvol,z1,z2,x,shiftX,shiftY,shiftZ) res = ftshift(ifft(resF),inplace=False) / v.numelem() # reverse it back if twice: # cut the center part back res = subvolume(res, (volume.sizeX()+1)/2, (volume.sizeY()+1)/2, (volume.sizeZ()+1)/2, volume.sizeX(), volume.sizeY(), volume.sizeZ()) return res
def create_average(self, pre, wedge): """For the master node, create the average according to the pre-wedge and wedge volumes. @param pre: density prior to weighting @type pre: L{pytom_volume.vol} @param wedge: wedge @type wedge: L{pytom.basic.Wedge} @return: wedge-weighted density @rtype: L{pytom_volume.vol} """ from pytom_volume import complexDiv, limit from pytom.basic.fourier import fft, ifft limit(wedge, 0.1, 0, 0, 0, True, False) # set all the values below the specified value to 0 f_pre = fft(pre) r = complexDiv(f_pre, wedge) average = ifft(r) average.shiftscale( 0.0, 1 / float(average.sizeX() * average.sizeY() * average.sizeZ())) return average
def toProjectionStackFromAlignmentResultsFile(alignmentResultsFile, weighting=None, lowpassFilter=0.9, binning=1, circleFilter=False, num_procs=1, outdir='', prefix='sorted_aligned'): """read image and create aligned projection stack, based on the results described in the alignmentResultFile. @param alignmentResultsFile: result file generate by the alignment script. @type datatypeAR: gui.guiFunction.datatypeAR @param weighting: weighting (<0: analytical weighting, >1: exact weighting, 0/None: no weighting ) @type weighting: float @param lowpassFilter: lowpass filter (in Nyquist) @type lowpassFilter: float @param binning: binning (default: 1 = no binning). binning=2: 2x2 pixels -> 1 pixel, binning=3: 3x3 pixels -> 1 pixel, etc. @author: GvdS """ print('weighting: ', weighting) import numpy from pytom_numpy import vol2npy from pytom.basic.files import read_em, write_em from pytom.basic.functions import taper_edges from pytom.basic.transformations import general_transform2d from pytom.basic.fourier import ifft, fft from pytom.basic.filter import filter as filterFunction, bandpassFilter from pytom.basic.filter import circleFilter, rampFilter, exactFilter, fourierFilterShift, \ fourierFilterShift_ReducedComplex from pytom_volume import complexRealMult, vol, paste import pytom_freqweight from pytom.basic.transformations import resize, rotate from pytom.gui.guiFunctions import fmtAR, headerAlignmentResults, datatype, datatypeAR, loadstar from pytom.reconstruction.reconstructionStructures import Projection, ProjectionList from pytom_numpy import vol2npy import mrcfile from pytom.tompy.io import write, read_size import os print("Create aligned images from alignResults.txt") alignmentResults = loadstar(alignmentResultsFile, dtype=datatypeAR) imageList = alignmentResults['FileName'] tilt_angles = alignmentResults['TiltAngle'] imdim = int(read_size(imageList[0], 'x')) if binning > 1: imdim = int(float(imdim) / float(binning) + .5) else: imdim = imdim sliceWidth = imdim # pre-determine analytical weighting function and lowpass for speedup if (weighting != None) and (float(weighting) < -0.001): weightSlice = fourierFilterShift(rampFilter(imdim, imdim)) if circleFilter: circleFilterRadius = imdim // 2 circleSlice = fourierFilterShift_ReducedComplex( circleFilter(imdim, imdim, circleFilterRadius)) else: circleSlice = vol(imdim, imdim // 2 + 1, 1) circleSlice.setAll(1.0) # design lowpass filter if lowpassFilter: if lowpassFilter > 1.: lowpassFilter = 1. print("Warning: lowpassFilter > 1 - set to 1 (=Nyquist)") # weighting filter: arguments: (angle, cutoff radius, dimx, dimy, lpf = pytom_freqweight.weight(0.0, lowpassFilter * imdim // 2, imdim, imdim // 2 + 1, 1, lowpassFilter / 5. * imdim) # lpf = bandpassFilter(volume=vol(imdim, imdim,1),lowestFrequency=0,highestFrequency=int(lowpassFilter*imdim/2), # bpf=None,smooth=lowpassFilter/5.*imdim,fourierOnly=False)[1] projectionList = ProjectionList() imageList = [] tilt_angles = [] for n, image in enumerate(alignmentResults['FileName']): atx = alignmentResults['AlignmentTransX'][n] aty = alignmentResults['AlignmentTransY'][n] rot = alignmentResults['InPlaneRotation'][n] mag = alignmentResults['Magnification'][n] # print(image, alignmentResults['TiltAngle'][n]) # if abs(alignmentResults['TiltAngle'][n]) > 20: # continue tilt_angles.append(alignmentResults['TiltAngle'][n]) imageList.append(image) projection = Projection(imageList[-1], tiltAngle=tilt_angles[-1], alignmentTransX=atx, alignmentTransY=aty, alignmentRotation=rot, alignmentMagnification=mag) projectionList.append(projection) stack = vol(imdim, imdim, len(imageList)) stack.setAll(0.0) phiStack = vol(1, 1, len(imageList)) phiStack.setAll(0.0) thetaStack = vol(1, 1, len(imageList)) thetaStack.setAll(0.0) offsetStack = vol(1, 2, len(imageList)) offsetStack.setAll(0.0) for (ii, projection) in enumerate(projectionList): if projection._filename.split('.')[-1] == 'st': from pytom.basic.files import EMHeader, read idx = projection._index image = read(file=projection._filename, subregion=[0, 0, idx - 1, imdim, imdim, 1], sampling=[0, 0, 0], binning=[0, 0, 0]) if not (binning == 1) or (binning == None): image = resize(volume=image, factor=1 / float(binning))[0] else: # read projection files from pytom.basic.files import EMHeader, read, read_em_header image = read(str(projection._filename)) # image = rotate(image,180.,0.,0.) image = resize(volume=image, factor=1 / float(binning))[0] if lowpassFilter: filtered = filterFunction(volume=image, filterObject=lpf, fourierOnly=False) image = filtered[0] tiltAngle = projection._tiltAngle # normalize to contrast - subtract mean and norm to mean immean = vol2npy(image).mean() image = (image - immean) / immean print(ii, immean, projection._filename) # smoothen borders to prevent high contrast oscillations image = taper_edges(image, imdim // 30)[0] # transform projection according to tilt alignment transX = projection._alignmentTransX / binning transY = projection._alignmentTransY / binning rot = float(projection._alignmentRotation) mag = float(projection._alignmentMagnification) image = general_transform2d(v=image, rot=rot, shift=[transX, transY], scale=mag, order=[2, 1, 0], crop=True) # smoothen once more to avoid edges image = taper_edges(image, imdim // 30)[0] # analytical weighting if (weighting != None) and (weighting < 0): # image = (ifft(complexRealMult(fft(image), w_func)) / (image.sizeX() * image.sizeY() * image.sizeZ())) image = ifft(complexRealMult( complexRealMult(fft(image), weightSlice), circleSlice), scaling=True) elif (weighting != None) and (weighting > 0): weightSlice = fourierFilterShift( exactFilter(tilt_angles, tiltAngle, imdim, imdim, sliceWidth)) # image = (ifft(complexRealMult(fft(image), w_func)) / (image.sizeX() * image.sizeY() * image.sizeZ())) image = ifft(complexRealMult( complexRealMult(fft(image), weightSlice), circleSlice), scaling=True) thetaStack(int(round(projection.getTiltAngle())), 0, 0, ii) offsetStack(int(round(projection.getOffsetX())), 0, 0, ii) offsetStack(int(round(projection.getOffsetY())), 0, 1, ii) paste(image, stack, 0, 0, ii) fname = '{}_{:02d}.mrc'.format( prefix, int(imageList[ii].split('_')[-1].split('.')[0])) if outdir: import mrcfile # write_em(os.path.join(outdir, fname.replace('mrc', 'em')), image) write(os.path.join(outdir, fname), vol2npy(image).copy().astype('float32')) print('written file: ', fname) return [stack, phiStack, thetaStack, offsetStack]
def writeAlignedProjections(TiltSeries_, weighting=None, lowpassFilter=None, binning=None, verbose=False, write_images=True): """write weighted and aligned projections to disk1 @param TiltSeries_: Tilt Series @type TiltSeries_: reconstruction.TiltSeries @param weighting: weighting (<0: analytical weighting, >1 exact weighting (value corresponds to object diameter in pixel AFTER binning) @type weighting: float @param lowpassFilter: lowpass filter (in Nyquist) @type lowpassFilter: float @param binning: binning (default: 1 = no binning). binning=2: 2x2 pixels -> 1 pixel, binning=3: 3x3 pixels -> 1 pixel, etc. @author: FF """ import numpy from pytom_numpy import vol2npy from pytom.basic.files import read_em, write_em from pytom.basic.functions import taper_edges from pytom.basic.transformations import general_transform2d from pytom.basic.fourier import ifft, fft from pytom.basic.filter import filter as filterFunction, bandpassFilter from pytom.basic.filter import circleFilter, rampFilter, exactFilter, fourierFilterShift, rotateFilter from pytom_volume import complexRealMult, vol import pytom_freqweight from pytom.basic.transformations import resize from pytom.gui.guiFunctions import fmtAR, headerAlignmentResults, datatypeAR import os if binning: imdim = int(float(TiltSeries_._imdim) / float(binning) + .5) else: imdim = TiltSeries_._imdim print('imdim', imdim) sliceWidth = imdim # pre-determine analytical weighting function and lowpass for speedup if (weighting != None) and (weighting < -0.001): w_func = fourierFilterShift(rampFilter(imdim, imdim)) print('start weighting') # design lowpass filter if lowpassFilter: if lowpassFilter > 1.: lowpassFilter = 1. print("Warning: lowpassFilter > 1 - set to 1 (=Nyquist)") # weighting filter: arguments: (angle, cutoff radius, dimx, dimy, lpf = pytom_freqweight.weight(0.0, lowpassFilter * imdim / 2, imdim, imdim // 2 + 1, 1, lowpassFilter / 5. * imdim) #lpf = bandpassFilter(volume=vol(imdim, imdim,1),lowestFrequency=0,highestFrequency=int(lowpassFilter*imdim/2), # bpf=None,smooth=lowpassFilter/5.*imdim,fourierOnly=False)[1] tilt_angles = [] for projection in TiltSeries_._ProjectionList: tilt_angles.append(projection._tiltAngle) tilt_angles = sorted(tilt_angles) print(tilt_angles) #q = numpy.matrix(abs(numpy.arange(-imdim//2, imdim//2))) alignmentResults = numpy.zeros((len(TiltSeries_._ProjectionList)), dtype=datatypeAR) alignmentResults['TiltAngle'] = tilt_angles for (ii, projection) in enumerate(TiltSeries_._ProjectionList): alignmentResults['FileName'][ii] = os.path.join( os.getcwd(), projection._filename) transX = -projection._alignmentTransX / binning transY = -projection._alignmentTransY / binning rot = -(projection._alignmentRotation + 90.) mag = projection._alignmentMagnification alignmentResults['AlignmentTransX'][ii] = transX alignmentResults['AlignmentTransY'][ii] = transY alignmentResults['InPlaneRotation'][ii] = rot alignmentResults['Magnification'][ii] = mag if write_images: if projection._filename.split('.')[-1] == 'st': from pytom.basic.files import EMHeader, read header = EMHeader() header.set_dim(x=imdim, y=imdim, z=1) idx = projection._index if verbose: print("reading in projection %d" % idx) image = read(file=projection._filename, subregion=[ 0, 0, idx - 1, TiltSeries_._imdim, TiltSeries_._imdim, 1 ], sampling=[0, 0, 0], binning=[0, 0, 0]) if not (binning == 1) or (binning == None): image = resize(volume=image, factor=1 / float(binning))[0] else: # read projection files from pytom.basic.files import EMHeader, read, read_em_header print(projection._filename) image = read(projection._filename) image = resize(volume=image, factor=1 / float(binning))[0] if projection._filename[-3:] == '.em': header = read_em_header(projection._filename) else: header = EMHeader() header.set_dim(x=imdim, y=imdim, z=1) if lowpassFilter: filtered = filterFunction(volume=image, filterObject=lpf, fourierOnly=False) image = filtered[0] tiltAngle = projection._tiltAngle header.set_tiltangle(tiltAngle) # normalize to contrast - subtract mean and norm to mean immean = vol2npy(image).mean() image = (image - immean) / immean # smoothen borders to prevent high contrast oscillations image = taper_edges(image, imdim // 30)[0] # transform projection according to tilt alignment if projection._filename.split('.')[-1] == 'st': newFilename = (TiltSeries_._alignedTiltSeriesName + "_" + str(projection.getIndex()) + '.em') else: TiltSeries_._tiltSeriesFormat = 'mrc' newFilename = (TiltSeries_._alignedTiltSeriesName + "_" + str(projection.getIndex()) + '.' + TiltSeries_._tiltSeriesFormat) if verbose: tline = ("%30s" % newFilename) tline = tline + (" (tiltAngle=%6.2f)" % tiltAngle) tline = tline + (": transX=%6.1f" % transX) tline = tline + (", transY=%6.1f" % transY) tline = tline + (", rot=%6.2f" % rot) tline = tline + (", mag=%5.4f" % mag) print(tline) image = general_transform2d(v=image, rot=rot, shift=[transX, transY], scale=mag, order=[2, 1, 0], crop=True) # smoothen once more to avoid edges image = taper_edges(image, imdim // 30)[0] # analytical weighting if (weighting != None) and (weighting < 0): image = (ifft(complexRealMult(fft(image), w_func)) / (image.sizeX() * image.sizeY() * image.sizeZ())) elif (weighting != None) and (weighting > 0): if abs(weighting - 2) < 0.001: w_func = fourierFilterShift( rotateFilter(tilt_angles, tiltAngle, imdim, imdim, sliceWidth)) else: w_func = fourierFilterShift( exactFilter(tilt_angles, tiltAngle, imdim, imdim, sliceWidth)) image = (ifft(complexRealMult(fft(image), w_func)) / (image.sizeX() * image.sizeY() * image.sizeZ())) header.set_tiltangle(tilt_angles[ii]) if newFilename.endswith('.mrc'): data = copy.deepcopy(vol2npy(image)) mrcfile.new(newFilename, data.T.astype(float32), overwrite=True) else: write_em(filename=newFilename, data=image, header=header) if verbose: tline = ("%30s written ..." % newFilename) outname = os.path.join(os.path.dirname(TiltSeries_._alignedTiltSeriesName), 'alignmentResults.txt') numpy.savetxt(outname, alignmentResults, fmt=fmtAR, header=headerAlignmentResults) print('Alignment successful. See {} for results.'.format(outname))
def averageParallel(particleList, averageName, showProgressBar=False, verbose=False, createInfoVolumes=False, weighting=None, norm=False, setParticleNodesRatio=3, cores=6): """ compute average using parfor @param particleList: The particles @param averageName: Filename of new average @param verbose: Prints particle information. Disabled by default. @param createInfoVolumes: Create info data (wedge sum, inverted density) too? False by default. @param weighting: weight particles by exp CC in average @type weighting: bool @param setParticleNodesRatio: minimum number of particles per node @type setParticleNodesRatio: L{int} @return: A new Reference object @rtype: L{pytom.basic.structures.Reference} @author: FF """ from pytom_volume import read, complexRealMult from pytom.basic.fourier import fft, ifft from pytom.basic.filter import lowpassFilter from pytom.basic.structures import Reference from pytom.alignment.alignmentFunctions import invert_WedgeSum import os splitLists = splitParticleList(particleList, setParticleNodesRatio=setParticleNodesRatio, numberOfNodes=cores) splitFactor = len(splitLists) avgNameList = [] preList = [] wedgeList = [] for ii in range(splitFactor): avgName = averageName + '_dist' + str(ii) + '.em' avgNameList.append(avgName) preList.append(averageName + '_dist' + str(ii) + '-PreWedge.em') wedgeList.append(averageName + '_dist' + str(ii) + '-WedgeSumUnscaled.em') #reference = average(particleList=plist, averageName=xxx, showProgressBar=True, verbose=False, # createInfoVolumes=False, weighting=weighting, norm=False) from multiprocessing import Process procs = [] for i in range(splitFactor): proc = Process(target=average, args=(splitLists[i], avgNameList[i], showProgressBar, verbose, createInfoVolumes, weighting, norm)) procs.append(proc) proc.start() import time while procs: procs = [proc for proc in procs if proc.is_alive()] time.sleep(.1) #averageList = mpi.parfor( average, list(zip(splitLists, avgNameList, [showProgressBar]*splitFactor, # [verbose]*splitFactor, [createInfoVolumes]*splitFactor, # [weighting]*splitFactor, [norm]*splitFactor)), verbose=True) #collect results from files unweiAv = read(preList[0]) wedgeSum = read(wedgeList[0]) os.system('rm ' + wedgeList[0]) os.system('rm ' + avgNameList[0]) os.system('rm ' + preList[0]) for ii in range(1, splitFactor): av = read(preList[ii]) unweiAv += av os.system('rm ' + preList[ii]) w = read(wedgeList[ii]) wedgeSum += w os.system('rm ' + wedgeList[ii]) os.system('rm ' + avgNameList[ii]) if createInfoVolumes: unweiAv.write(averageName[:len(averageName) - 3] + '-PreWedge.em') wedgeSum.write(averageName[:len(averageName) - 3] + '-WedgeSumUnscaled.em') # convolute unweighted average with inverse of wedge sum invert_WedgeSum(invol=wedgeSum, r_max=unweiAv.sizeX() / 2 - 2., lowlimit=.05 * len(particleList), lowval=.05 * len(particleList)) fResult = fft(unweiAv) r = complexRealMult(fResult, wedgeSum) unweiAv = ifft(r) unweiAv.shiftscale( 0.0, 1 / float(unweiAv.sizeX() * unweiAv.sizeY() * unweiAv.sizeZ())) # low pass filter to remove artifacts at fringes unweiAv = lowpassFilter(volume=unweiAv, band=unweiAv.sizeX() / 2 - 2, smooth=(unweiAv.sizeX() / 2 - 1) / 10.)[0] unweiAv.write(averageName) return Reference(averageName, particleList)
def calculate_averages(pl, binning, mask, outdir='./'): """ calcuate averages for particle lists @param pl: particle list @type pl: L{pytom.basic.structures.ParticleList} @param binning: binning factor @type binning: C{int} last change: Jan 18 2020: error message for too few processes, FF """ import os from pytom_volume import complexDiv, vol, pasteCenter from pytom.basic.fourier import fft, ifft from pytom.basic.correlation import FSC, determineResolution from pytom_fftplan import fftShift from pytom_volume import reducedToFull pls = pl.copy().splitByClass() res = {} freqs = {} wedgeSum = {} for pp in pls: # ignore the -1 class, which is used for storing the trash class class_label = pp[0].getClass() if class_label != '-1': assert len(pp) > 3 if len(pp) >= 4 * mpi.size: spp = mpi._split_seq(pp, mpi.size) else: # not enough particle to do averaging on one node spp = [None] * 2 spp[0] = pp[:len(pp) // 2] spp[1] = pp[len(pp) // 2:] args = list( zip(spp, [True] * len(spp), [binning] * len(spp), [False] * len(spp), [outdir] * len(spp))) avgs = mpi.parfor(paverage, args) even_a, even_w, odd_a, odd_w = None, None, None, None even_avgs = avgs[1::2] odd_avgs = avgs[::2] for a, w in even_avgs: if even_a is None: even_a = a.getVolume() even_w = w.getVolume() else: even_a += a.getVolume() even_w += w.getVolume() os.remove(a.getFilename()) os.remove(w.getFilename()) for a, w in odd_avgs: if odd_a is None: odd_a = a.getVolume() odd_w = w.getVolume() else: odd_a += a.getVolume() odd_w += w.getVolume() os.remove(a.getFilename()) os.remove(w.getFilename()) # determine the resolution # raise error message in case even_a == None - only one processor used if even_a == None: from pytom.basic.exceptions import ParameterError raise ParameterError( 'cannot split odd / even. Likely you used only one processor - use: mpirun -np 2 (or higher!)?!' ) if mask and mask.__class__ == str: from pytom_volume import read, pasteCenter, vol maskBin = read(mask, 0, 0, 0, 0, 0, 0, 0, 0, 0, binning, binning, binning) if even_a.sizeX() != maskBin.sizeX() or even_a.sizeY( ) != maskBin.sizeY() or even_a.sizeZ() != maskBin.sizeZ(): mask = vol(even_a.sizeX(), even_a.sizeY(), even_a.sizeZ()) mask.setAll(0) pasteCenter(maskBin, mask) else: mask = maskBin fsc = FSC(even_a, odd_a, int(even_a.sizeX() // 2), mask) band = determineResolution(fsc, 0.5)[1] aa = even_a + odd_a ww = even_w + odd_w fa = fft(aa) r = complexDiv(fa, ww) rr = ifft(r) rr.shiftscale(0.0, 1. / (rr.sizeX() * rr.sizeY() * rr.sizeZ())) res[class_label] = rr freqs[class_label] = band ww2 = reducedToFull(ww) fftShift(ww2, True) wedgeSum[class_label] = ww2 print('done') return res, freqs, wedgeSum
def _disrtibuteAverageMPI(particleList,averageName,showProgressBar = False,verbose=False, createInfoVolumes = False,setParticleNodesRatio = 3,sendEndMessage = False): """ _distributeAverageMPI : Distributes averaging to multiple MPI nodes. @param particleList: The particles @param averageName: Filename of new average @param verbose: Prints particle information. Disabled by default. @param createInfoVolumes: Create info data (wedge sum, inverted density) too? False by default. @return: A new Reference object @rtype: L{pytom.basic.structures.Reference} @author: Thomas Hrabe """ import pytom_mpi from pytom.alignment.structures import ExpectationJob from pytom.parallel.parallelWorker import ParallelWorker from pytom.parallel.alignmentMessages import ExpectationJobMsg from pytom_volume import read,complexDiv,complexRealMult from pytom.basic.fourier import fft,ifft from pytom.basic.filter import lowpassFilter from pytom.basic.structures import Reference import os import sys numberOfNodes = pytom_mpi.size() particleNodesRatio = float(len(particleList)) / float(numberOfNodes) splitFactor = numberOfNodes if particleNodesRatio < setParticleNodesRatio: #make sure each node gets at least 20 particles. splitFactor = len(particleList) / setParticleNodesRatio splitLists = particleList.splitNSublists(splitFactor) msgList = [] avgNameList = [] preList = [] wedgeList = [] for i in range(len(splitLists)): plist = splitLists[i] avgName = averageName + '_dist' +str(i) + '.em' avgNameList.append(avgName) preList.append(averageName + '_dist' +str(i) + '-PreWedge.em') wedgeList.append(averageName + '_dist' +str(i) + '-WedgeSumUnscaled.em') job = ExpectationJob(plist,avgName) message = ExpectationJobMsg(0,i) message.setJob(job) msgList.append(message) #distribute averaging worker = ParallelWorker() worker.fillJobList(msgList) worker.parallelWork(True,sendEndMessage) #collect results result = read(preList[0]) wedgeSum = read(wedgeList[0]) for i in range(1,len(preList)): r = read(preList[i]) result += r w = read(wedgeList[i]) wedgeSum += w result.write(averageName[:len(averageName)-3]+'-PreWedge.em') wedgeSum.write(averageName[:len(averageName)-3] + '-WedgeSumUnscaled.em') invert_WedgeSum( invol=wedgeSum, r_max=result.sizeX()/2-2., lowlimit=.05*len(particleList), lowval=.05*len(particleList)) fResult = fft(result) r = complexRealMult(fResult,wedgeSum) result = ifft(r) result.shiftscale(0.0,1/float(result.sizeX()*result.sizeY()*result.sizeZ())) # do a low pass filter result = lowpassFilter(result, result.sizeX()/2-2, (result.sizeX()/2-1)/10.)[0] result.write(averageName) # clean results for i in range(0,len(preList)): os.system('rm ' + avgNameList[i]) os.system('rm ' + preList[i]) os.system('rm ' + wedgeList[i]) return Reference(averageName,particleList)
def average2(particleList, weighting=False, norm=False, determine_resolution=False, mask=None, binning=1, verbose=False): """ 2nd version of average function. Will not write the averages to the disk. Also support internal \ resolution determination. """ from pytom_volume import read, vol, complexDiv, complexRealMult from pytom_volume import transformSpline as transform from pytom.basic.fourier import fft, ifft, convolute from pytom.basic.normalise import mean0std1 from pytom.tools.ProgressBar import FixedProgBar from pytom.basic.filter import lowpassFilter, rotateWeighting from math import exp if len(particleList) == 0: raise RuntimeError('The particlelist provided is empty. Aborting!') if verbose: progressBar = FixedProgBar(0,len(particleList),'Particles averaged ') progressBar.update(0) numberAlignedParticles = 0 even = None odd = None wedgeSum_even = None wedgeSum_odd = None newParticle = None is_odd = True for particleObject in particleList: particle = read(particleObject.getFilename(), 0,0,0,0,0,0,0,0,0, binning,binning,binning) if norm: mean0std1(particle) wedgeInfo = particleObject.getWedge() # apply its wedge to itself particle = wedgeInfo.apply(particle) if odd is None: # initialization sizeX = particle.sizeX() sizeY = particle.sizeY() sizeZ = particle.sizeZ() newParticle = vol(sizeX,sizeY,sizeZ) centerX = sizeX/2 centerY = sizeY/2 centerZ = sizeZ/2 odd = vol(sizeX,sizeY,sizeZ) odd.setAll(0.0) even = vol(sizeX,sizeY,sizeZ) even.setAll(0.0) wedgeSum_odd = wedgeInfo.returnWedgeVolume(sizeX,sizeY,sizeZ) wedgeSum_odd.setAll(0) wedgeSum_even = wedgeInfo.returnWedgeVolume(sizeX,sizeY,sizeZ) wedgeSum_even.setAll(0) # create spectral wedge weighting rotation = particleObject.getRotation() rotinvert = rotation.invert() if analytWedge: # > original buggy version wedge = wedgeInfo.returnWedgeVolume(sizeX,sizeY,sizeZ,False, rotinvert) # < original buggy version else: # > FF: interpol bugfix wedge = rotateWeighting( weighting=wedgeInfo.returnWedgeVolume(sizeX,sizeY,sizeZ,False), z1=rotinvert[0], z2=rotinvert[1], x=rotinvert[2], mask=None, isReducedComplex=True, returnReducedComplex=True) # < FF # > TH bugfix #wedgeVolume = wedgeInfo.returnWedgeVolume(wedgeSizeX=sizeX, wedgeSizeY=sizeY, wedgeSizeZ=sizeZ, # humanUnderstandable=True, rotation=rotinvert) #wedge = rotate(volume=wedgeVolume, rotation=rotinvert, imethod='linear') # < TH if is_odd: wedgeSum_odd = wedgeSum_odd + wedge else: wedgeSum_even = wedgeSum_even + wedge # shift and rotate particle shiftV = particleObject.getShift() newParticle.setAll(0) transform(particle,newParticle,-rotation[1],-rotation[0],-rotation[2], centerX,centerY,centerZ,-shiftV[0]/binning, -shiftV[1]/binning,-shiftV[2]/binning,0,0,0) if is_odd: if weighting: weight = 1. - particleObject.getScore().getValue() #weight = weight**2 weight = exp(-1.*weight) odd = odd + newParticle * weight else: odd = odd + newParticle else: if weighting: weight = 1. - particleObject.getScore().getValue() #weight = weight**2 weight = exp(-1.*weight) even = even + newParticle * weight else: even = even + newParticle is_odd = not is_odd if verbose: numberAlignedParticles = numberAlignedParticles + 1 progressBar.update(numberAlignedParticles) # determine resolution if needed fsc = None if determine_resolution: # apply spectral weighting to sum f_even = fft(even) w_even = complexDiv(f_even, wedgeSum_even) w_even = ifft(w_even) w_even.shiftscale(0.0,1/float(sizeX*sizeY*sizeZ)) f_odd = fft(odd) w_odd = complexDiv(f_odd, wedgeSum_odd) w_odd = ifft(w_odd) w_odd.shiftscale(0.0,1/float(sizeX*sizeY*sizeZ)) from pytom.basic.correlation import FSC fsc = FSC(w_even, w_odd, sizeX/2, mask, verbose=False) # add together result = even+odd wedgeSum = wedgeSum_even+wedgeSum_odd invert_WedgeSum( invol=wedgeSum, r_max=sizeX/2-2., lowlimit=.05*len(particleList), lowval=.05*len(particleList)) #wedgeSum.write(averageName[:len(averageName)-3] + '-WedgeSumInverted.em') result = convolute(v=result, k=wedgeSum, kernel_in_fourier=True) # do a low pass filter #result = lowpassFilter(result, sizeX/2-2, (sizeX/2-1)/10.)[0] return (result, fsc)
def apply(self, volume, bypassFlag=False, downscale=1, particle=None): """ apply: Performs preprocessing of volume and reference @param volume: volume to be pre-processed @type volume: L{pytom_volume.vol} @param bypassFlag: Set if only bandpassFilter needed. False otherwise and all routines will be processed. @param downscale: not used anymore @param particle: particle Volume to be subtracted from input volume @type particle: L{pytom_volume.vol} @return: Returns modified volume @author: Thomas Hrabe """ from pytom_volume import vol if self._bandpassOn: from pytom.basic.filter import bandpassFilter # if frequencies specified in Nyquist, 0.5 being highest # fixed wrong adjustment of frequencies upon binning - FF if self._highestFrequency < 1: highestFrequency = self._highestFrequency * volume.sizeX() lowestFrequency = self._lowestFrequency * volume.sizeX() else: highestFrequency = self._highestFrequency lowestFrequency = self._lowestFrequency v = bandpassFilter(volume=volume, lowestFrequency=lowestFrequency, highestFrequency=highestFrequency, bpf=0, smooth=self._bandpassSmooth) volume = v[0] if self._prerotateOn and (not bypassFlag): from pytom_volume import rotate rot = vol(volume.sizeX(), volume.sizeY(), volume.sizeZ()) rotation = self.prerotate rotate(volume, rot, rotation[0], rotation[1], rotation[2]) volume = rot if self._weightingOn and (not bypassFlag): from pytom_volume import read from pytom_freqweight import weight from pytom.basic.fourier import fft, ifft wedgeSum = read(self._weightingFile) fVolume = fft(volume) weighting = weight(wedgeSum) weighting.apply(fVolume) volume = ifft(fVolume) if self._substractParticle and particle.__class__ == vol: volume -= particle if self._taper > 0: from pytom.tools.macros import volumesSameSize if self._taperMask is None or not volumesSameSize( volume, self._taperMask): from pytom.basic.functions import taper_edges volume, self._taperMask = taper_edges(volume, self._taper) else: volume = volume * self._taperMask return volume
from pytom_volume import * from pytom.basic.fourier import fft, ifft, ftshift, iftshift v = read('/fs/home/ychen/matlab/template/binning/temp80SRibosome_bin2.em') # v = read('/fs/home/ychen/matlab/template/temp80SRibosome.em') fv = fft(v) r1 = real(fv) i1 = imag(fv) fv2 = fullToReduced(reducedToFull(fv)) r2 = real(fv2) i2 = imag(fv2) (r1 - r2).info('') (i1 - i2).info('') fv3 = fullToReduced( iftshift(ftshift(reducedToFull(fv), inplace=False), inplace=False)) r3 = real(fv3) i3 = imag(fv3) (r1 - r3).info('') (i1 - i3).info('')
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)