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 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 iftshift(data, inplace = True): """ iftshift: Performs a inverse fourier shift of data. Data must be full, the center is not determined accordingly. Assumes center is always size/2. @param data: - a volume @type data: pytom_volume.vol or pytom_volume.vol_comp @return: data inverse shifted @author: Thomas Hrabe """ import pytom_fftplan if inplace: pytom_fftplan.fftShift(data,True) return data else: from pytom_volume import vol, vol_comp if data.__class__ == vol: dummy = vol(data) elif data.__class__ == vol_comp: dummy = vol_comp(data) pytom_fftplan.fftShift(dummy,True) return dummy
def ftshift(data, inplace = True): """ ftshift: Performs a forward fourier shift of data. Data must be full, the center is not determined accordingly. Assumes center is always size/2. @param data: - a volume @type data: pytom_volume.vol or pytom_volume.vol_comp @param inplace: true by default @type inplace: boolean @return: data shifted @author: Thomas Hrabe """ import pytom_fftplan if inplace: pytom_fftplan.fftShift(data,False) return None else: from pytom_volume import vol, vol_comp if data.__class__ == vol: dummy = vol(data) elif data.__class__ == vol_comp: dummy = vol_comp(data) pytom_fftplan.fftShift(dummy,False) return dummy
def bestAlignment(particle, reference, referenceWeighting, wedgeInfo, rotations, scoreObject=0, mask=None, preprocessing=None, progressBar=False, binning=1, bestPeak=None, verbose=False): """ bestAlignment: Determines best alignment of particle relative to the reference @param particle: A particle @type particle: L{pytom_volume.vol} @param reference: A reference @type reference: L{pytom_volume.vol} @param referenceWeighting: Fourier weighting of the reference (sum of wedges for instance) @type referenceWeighting: L{pytom.basic.structures.vol} @param wedgeInfo: What does the wedge look alike? @type wedgeInfo: L{pytom.basic.structures.Wedge} @param rotations: All rotations to be scanned @type rotations: L{pytom.angles.AngleObject} @param scoreObject: @type scoreObject: L{pytom.score.score.Score} @param mask: real-space mask for correlation function @type mask: L{pytom.basic.structures.Particle} @param preprocessing: Class storing preprocessing of particle and reference such as bandpass @type preprocessing: L{pytom.alignment.preprocessing.Preprocessing} @param progressBar: Display progress bar of alignment. False by default. @param binning: binning factor - e.g. binning=2 reduces size by FACTOR of 2 @type binning: int or float @param bestPeak: Initialise best peak with old values. @param verbose: Print out infos. Writes CC volume to disk!!! Default is False @return: Returns the best rotation for particle and the corresponding scoring result. @author: Thomas Hrabe """ from pytom.basic.correlation import subPixelPeak, subPixelPeakParabolic from pytom.alignment.structures import Peak from pytom_volume import peak, vol, vol_comp from pytom.basic.filter import filter,rotateWeighting from pytom.basic.structures import Rotation, Shift, Particle, Mask from pytom.angles.angle import AngleObject from pytom.alignment.preprocessing import Preprocessing from pytom.basic.transformations import resize, resizeFourier binningType = 'Fourier' # or 'Fourier' assert isinstance(rotations, AngleObject), "bestAlignment: rotations must be " \ "AngleObject!" currentRotation = rotations.nextRotation() if currentRotation == [None,None,None]: raise Exception('bestAlignment: No rotations are sampled! Something is wrong with input rotations') assert particle.__class__ == vol, "particle not of type vol" assert reference.__class__ == vol, "reference not of type vol" assert (referenceWeighting.__class__ == vol or referenceWeighting.__class__ == str), \ "referenceWeighting not volume or str" if mask: assert mask.__class__ == Mask, "Mask not of type Mask" m = mask.getVolume() if scoreObject == 0 or not scoreObject: from pytom.score.score import xcfScore scoreObject = xcfScore() # fix binning if binning == 0: binning = 1 if binning != 1: particleUnbinned = vol(particle.sizeX(), particle.sizeY(), particle.sizeZ()) particleUnbinned.copyVolume(particle) particle = resize(volume=particle, factor=1./binning, interpolation=binningType) if type(particle) == tuple: particle = particle[0] referenceUnbinned = vol(reference.sizeX(), reference.sizeY(), reference.sizeZ()) referenceUnbinned.copyVolume(reference) reference = resize(volume=reference, factor=1./binning, interpolation=binningType) if type(reference) == tuple: reference = reference[0] if mask: m = resize(volume=m, factor=1./binning, interpolation='Spline') if not referenceWeighting.__class__ == str: referenceWeightingUnbinned = vol_comp(referenceWeighting.sizeX(), referenceWeighting.sizeY(), referenceWeighting.sizeZ()) referenceWeightingUnbinned.copyVolume(referenceWeighting) if binning != 1: referenceWeighting = resizeFourier(fvol=referenceWeighting, factor=1./binning) centerX, centerY, centerZ = int(particle.sizeX()/2), int(particle.sizeY()/2), int(particle.sizeZ()/2) # create buffer volume for transformed particle particleCopy = vol(particle.sizeX(),particle.sizeY(),particle.sizeZ()) particle = wedgeInfo.apply(particle) #apply wedge to itself if preprocessing is None: preprocessing = Preprocessing() preprocessing.setTaper( taper=particle.sizeX()/10.) particle = preprocessing.apply(volume=particle, bypassFlag=True) # filter particle to some resolution particleCopy.copyVolume(particle) # compute standard veviation volume really only if needed if mask and (scoreObject._type=='FLCFScore'): from pytom_volume import sum from pytom.basic.correlation import meanUnderMask, stdUnderMask p = sum(m) meanV = meanUnderMask(particle, m, p) stdV = stdUnderMask(particle, m, p, meanV) else: meanV = None stdV = None while currentRotation != [None,None,None]: if mask: m = mask.getVolume(currentRotation) if binning != 1: m = resize(volume=m, factor=1./binning, interpolation='Spline') #update stdV if mask is not a sphere # compute standard deviation volume really only if needed if not mask.isSphere() and (scoreObject._type=='FLCFScore'): meanV = meanUnderMask(particle, m, p) stdV = stdUnderMask(particle, m, p, meanV) else: m = None simulatedVol = _rotateWedgeReference(reference, currentRotation, wedgeInfo, m, [centerX, centerY, centerZ]) simulatedVol = preprocessing.apply(volume=simulatedVol, bypassFlag=True) #weight particle if not referenceWeighting.__class__ == str: from pytom_freqweight import weight weightingRotated = rotateWeighting(weighting=referenceWeighting, z1=currentRotation[0], z2=currentRotation[1], x=currentRotation[2], isReducedComplex=True, returnReducedComplex=True, binarize=False) particleCopy.copyVolume(particle) r = list(filter(particleCopy, weight(weightingRotated))) particleCopy = r[0] scoringResult = scoreObject.score(particleCopy, simulatedVol, m, stdV) pk = peak(scoringResult) #with subPixelPeak [peakValue,peakPosition] = subPixelPeak(scoreVolume=scoringResult, coordinates=pk, interpolation='Quadratic', verbose=False) #[peakValue,peakPosition] = subPixelPeakParabolic(scoreVolume=scoringResult, coordinates=pk, verbose=False) # determine shift relative to center shiftX = (peakPosition[0] - centerX) * binning shiftY = (peakPosition[1] - centerY) * binning shiftZ = (peakPosition[2] - centerZ) * binning #NANs would fail this test. assert peakValue == peakValue, "peakValue seems to be NaN" newPeak = Peak(peakValue, Rotation(currentRotation), Shift(shiftX, shiftY, shiftZ)) if verbose: print('Rotation: z1=%3.1f, z2=%3.1f, x=%3.1f; Dx=%2.2f, Dy=%2.2f, Dz=%2.2f, CC=%2.3f' % \ (currentRotation[0], currentRotation[1], currentRotation[2], shiftX, shiftY, shiftZ, peakValue)) if bestPeak is None: bestPeak = newPeak if verbose: scoringResult.write('BestScore.em') if bestPeak < newPeak: bestPeak = newPeak if verbose: scoringResult.write('BestScore.em') currentRotation = rotations.nextRotation() # repeat ccf for binned sampling to get translation accurately if binning != 1: m = mask.getVolume(bestPeak.getRotation()) centerX, centerY, centerZ = int(particleUnbinned.sizeX()/2), int(particleUnbinned.sizeY()/2), \ int(particleUnbinned.sizeZ()/2) simulatedVol = _rotateWedgeReference(referenceUnbinned, bestPeak.getRotation(), wedgeInfo, m, [centerX, centerY, centerZ]) simulatedVol = preprocessing.apply(volume=simulatedVol, bypassFlag=True) if mask and scoreObject._type=='FLCFScore': p = sum(m) meanV = meanUnderMask(volume=particleUnbinned, mask=m, p=p) stdV = stdUnderMask(volume=particleUnbinned, mask=m, p=p, meanV=meanV) scoreObject._peakPrior.reset_weight() scoringResult = scoreObject.score(particle=particleUnbinned, reference=simulatedVol, mask=m, stdV=stdV) pk = peak(scoringResult) [peakValue,peakPosition] = subPixelPeak(scoreVolume=scoringResult, coordinates=pk, interpolation='Quadratic', verbose=False) shiftX = (peakPosition[0] - centerX) shiftY = (peakPosition[1] - centerY) shiftZ = (peakPosition[2] - centerZ) bestPeak = Peak(peakValue, bestPeak.getRotation(), Shift(shiftX, shiftY, shiftZ)) if verbose: print('BestAlignment: z1=%3.1f, z2=%3.1f, x=%3.1f; Dx=%2.2f, Dy=%2.2f, Dz=%2.2f, CC=%2.3f' % \ (bestPeak.getRotation()[0], bestPeak.getRotation()[1], bestPeak.getRotation()[2], bestPeak.getShift()[0], bestPeak.getShift()[1], bestPeak.getShift()[2], bestPeak.getScoreValue())) rotations.reset() scoreObject._peakPrior.reset_weight() return bestPeak
def fft(data, scaling=''): """ fft: Performs Fourier Transformation on input. The result is NOT scaled in any way (1/N , 1/sqrt(n),...) @param data: The source volume. @type data: pytom_volume.vol @param scaling: Describes the type of scaling is applied. 'N' 1/N, 'sqrtN' 1/sqrt(N). '' no scaling (default) @type scaling: str @rtype: pytom_volume.vol_comp @return: The fourier transformed data @author: Thomas Hrabe """ import pytom_volume if not data.__class__ == pytom_volume.vol: raise TypeError('Data must be of type pytom_volume.vol') ftSingleton = FtSingleton() theTuple = ftSingleton.findInFt(data) if not theTuple == None: plan = theTuple.plan theTuple.real.copyVolume(data) plan.transform() returnValue = pytom_volume.vol_comp(theTuple.complexVolume.sizeX(),theTuple.complexVolume.sizeY(),theTuple.complexVolume.sizeZ()) returnValue.copyVolume(theTuple.complexVolume) returnValue.setFtSizeX(data.sizeX()) returnValue.setFtSizeY(data.sizeY()) returnValue.setFtSizeZ(data.sizeZ()) if scaling=='sqrtN': from numpy import sqrt returnValue = returnValue / sqrt(data.sizeX()*data.sizeY()*data.sizeZ()) if scaling == 'N': from numpy import sqrt returnValue = returnValue / (data.sizeX() * data.sizeY() * data.sizeZ()) return returnValue else: import pytom_fftplan real = pytom_volume.vol(data.sizeX(),data.sizeY(),data.sizeZ()) real.copyVolume(data) if(data.sizeZ() > 1): complexVolume = pytom_volume.vol_comp(data.sizeX(),data.sizeY(),data.sizeZ()//2+1) returnValue = pytom_volume.vol_comp(data.sizeX(),data.sizeY(),data.sizeZ()//2+1) else: complexVolume = pytom_volume.vol_comp(data.sizeX(),data.sizeY()//2+1,1) returnValue = pytom_volume.vol_comp(data.sizeX(),data.sizeY()//2+1,1) plan = pytom_fftplan.plan(real,complexVolume) plan.transform() returnValue.copyVolume(complexVolume) returnValue.setFtSizeX(data.sizeX()) returnValue.setFtSizeY(data.sizeY()) returnValue.setFtSizeZ(data.sizeZ()) theTuple = FourierTuple(plan,real,complexVolume) ftSingleton.addFt(theTuple) if scaling=='sqrtN': from numpy import sqrt returnValue = returnValue / sqrt(data.sizeX()*data.sizeY()*data.sizeZ()) elif scaling == 'N': from numpy import sqrt returnValue = returnValue / (data.sizeX() * data.sizeY() * data.sizeZ()) return returnValue
def ifft(Fdata, scaling=''): """ ifft: Performs inverse Fourier Transformation on input. The result is NOT scaled in any way (1/N , 1/sqrt(n),...) @param Fdata: The source volume (must be complex). If FData does not have shape information of the real volume, PyTom will assume that x==y==z (See line 198) @type Fdata: pytom_volume.vol_comp @param scaling: Describes the type of scaling is applied. 'N' 1/N, 'sqrtN' 1/sqrt(N). '' no scaling (default) @type scaling: str @rtype: pytom_volume.vol @return: The inverse fourier transformed data @author: Thomas Hrabe """ import pytom_volume if not Fdata.__class__ == pytom_volume.vol_comp: raise TypeError('Data must be of type pytom_volume.vol_comp') if scaling: Fdata = Fdata/Fdata.getFtSizeX()/Fdata.getFtSizeY()/Fdata.getFtSizeZ() ftSingleton = FtSingleton() theTuple = ftSingleton.findIniFt(Fdata) if not theTuple == None: plan = theTuple.plan theTuple.complexVolume.copyVolume(Fdata) plan.transform() returnValue = pytom_volume.vol(theTuple.real.sizeX(),theTuple.real.sizeY(),theTuple.real.sizeZ()) returnValue.copyVolume(theTuple.real) if scaling=='sqrtN': from numpy import sqrt returnValue = returnValue / sqrt(Fdata.sizeX()*Fdata.sizeY()*Fdata.sizeZ()) if scaling == 'N': from numpy import sqrt returnValue = returnValue / (Fdata.sizeX() * Fdata.sizeY() * Fdata.sizeZ()) return returnValue else: import pytom_fftplan complexVolume = pytom_volume.vol_comp(Fdata.sizeX(),Fdata.sizeY(),Fdata.sizeZ()) complexVolume.copyVolume(Fdata) x = Fdata.getFtSizeX() y = Fdata.getFtSizeY() z = Fdata.getFtSizeZ() if x == 0 and y == 0 and z == 0: x = Fdata.sizeX() y = Fdata.sizeY() z = (Fdata.sizeZ() - 1)* 2 if x == y and abs(z-y) == 1: #if x == y and x is odd, then z will be one pixel off. #adjust accordingly that x == y == z z = y print('Warning: PyTom assumes that the shape of the real volume is :',x,y,z) print('Warning: Check if that is consistent with your data!') real = pytom_volume.vol(int(x),int(y),int(z)) returnValue = pytom_volume.vol(int(x),int(y),int(z)) plan = pytom_fftplan.plan(complexVolume,real) plan.transform() returnValue.copyVolume(real) theTuple = FourierTuple(plan,real,complexVolume) ftSingleton.addiFt(theTuple) if scaling=='sqrtN': from numpy import sqrt returnValue = returnValue / sqrt(Fdata.sizeX()*Fdata.sizeY()*Fdata.sizeZ()) if scaling == 'N': from numpy import sqrt returnValue = returnValue / (Fdata.sizeX() * Fdata.sizeY() * Fdata.sizeZ()) return returnValue
def resizeFourier(fvol, factor): """ resize Fourier transformed by factor @param fvol: Fourier transformed of a volume - reduced complex @type fvol: L{pytom_volume.vol_comp} @param factor: a factor > 0. Factors < 1 will de-magnify the volume, factors > 1 will magnify. @type factor: float @return: resized Fourier volume (deruced complex) @rtype: L{pytom_volume.vol_comp} @author: FF """ from pytom_volume import vol_comp assert isinstance(fvol, vol_comp), "fvol must be reduced complex" oldFNx = fvol.sizeX() oldFNy = fvol.sizeY() oldFNz = fvol.sizeZ() oldNx = oldFNx oldNy = fvol.getFtSizeY() oldNz = fvol.getFtSizeZ() # new dims in real and Fourier space newFNx = int(float(oldFNx*factor)+0.5) newNx = newFNx newNy = int(float(oldNy*factor)+0.5) # check 2D images if oldNz > 1: newNz = int(float(oldNz*factor)+0.5) newFNz = newNz // 2 +1 newFNy = newNy else: newNz = 1 newFNz = 1 newFNy = newNy //2 + 1 newfvol = vol_comp(newFNx, newFNy, newFNz) newfvol.setFtSizeX(newNx) newfvol.setFtSizeY(newNy) newfvol.setFtSizeZ(newNz) scf = 1./(newNx*newNy*newNz) # magnify image if factor >= 1.: newfvol.setAll(0.) oldFNx_2 = oldFNx//2+1 if oldNz == 1: iz = 0 for iy in range(oldFNy): for ix in range(oldFNx_2): newfvol.setV( fvol.getV(ix, iy, iz)*scf, ix, iy, iz) for ix in range(oldFNx_2-1, oldFNx): ixNew = ix + (newFNx - oldFNx) newfvol.setV( fvol.getV(ix, iy, iz)*scf, ixNew, iy, iz) else: oldFNy_2 = oldFNy//2+1 for iz in range(oldFNz): for iy in range(oldFNy_2): for ix in range(oldFNx_2): newfvol.setV( fvol.getV(ix, iy, iz)*scf, ix, iy, iz) for ix in range(oldFNx_2-1, oldFNx): ixNew = ix + (newFNx - oldFNx) newfvol.setV( fvol.getV(ix, iy, iz)*scf, ixNew, iy, iz) for iy in range(oldFNy_2-1, oldFNy): iyNew = iy + (newFNy - oldFNy) for ix in range(oldFNx_2): newfvol.setV( fvol.getV(ix, iy, iz)*scf, ix, iyNew, iz) for ix in range(oldFNx_2-1, oldFNx): ixNew = ix + (newFNx - oldFNx) newfvol.setV( fvol.getV(ix, iy, iz)*scf, ixNew, iyNew, iz) # de-magnify image else: newFNx_2 = newFNx//2+1 if oldFNz == 1: iz = 0 for iy in range(newFNy): for ix in range(newFNx_2): newfvol.setV( fvol.getV(ix, iy, iz)*scf, ix, iy, iz) for ix in range(newFNx_2-1, newFNx): ixOld = ix + (oldFNx - newFNx) newfvol.setV( fvol.getV(ixOld, iy, iz)*scf, ix, iy, iz) else: newFNy_2 = newFNy//2+1 for iz in range(newFNz): for iy in range(newFNy_2): for ix in range(newFNx_2): newfvol.setV( fvol.getV(ix, iy, iz)*scf, ix, iy, iz) for ix in range(newFNx_2-1, newFNx): ixOld = ix + (oldFNx - newFNx) newfvol.setV( fvol.getV(ixOld, iy, iz)*scf, ix, iy, iz) for iy in range(newFNy_2-1, newFNy): iyOld = iy + (oldFNy - newFNy) for ix in range(newFNx_2): newfvol.setV( fvol.getV(ix, iyOld, iz)*scf, ix, iy, iz) for ix in range(newFNx_2-1, newFNx): ixOld = ix + (oldFNx - newFNx) newfvol.setV( fvol.getV(ixOld, iyOld, iz)*scf, ix, iy, iz) return newfvol
def bandCC(volume,reference,band,verbose = False): """ bandCC: Determines the normalised correlation coefficient within a band @param volume: The volume @type volume: L{pytom_volume.vol} @param reference: The reference @type reference: L{pytom_volume.vol} @param band: [a,b] - specify the lower and upper end of band. @return: First parameter - The correlation of the two volumes in the specified band. Second parameter - The bandpass filter used. @rtype: List - [float,L{pytom_freqweight.weight}] @author: Thomas Hrabe """ import pytom_volume from pytom.basic.filter import bandpassFilter from pytom.basic.correlation import xcf from math import sqrt if verbose: print('lowest freq : ', band[0],' highest freq' , band[1]) vf = bandpassFilter(volume,band[0],band[1],fourierOnly=True) rf = bandpassFilter(reference,band[0],band[1],vf[1],fourierOnly=True) ccVolume = pytom_volume.vol_comp(rf[0].sizeX(),rf[0].sizeY(),rf[0].sizeZ()) ccVolume.copyVolume(rf[0]) pytom_volume.conj_mult(ccVolume,vf[0]) cc = pytom_volume.sum(ccVolume) cc = cc.real v = vf[0] r = rf[0] absV = pytom_volume.abs(v) absR = pytom_volume.abs(r) pytom_volume.power(absV,2) pytom_volume.power(absR,2) sumV = pytom_volume.sum(absV) sumR = pytom_volume.sum(absR) sumV = abs(sumV) sumR = abs(sumR) if sumV == 0: sumV =1 if sumR == 0: sumR =1 cc = cc / (sqrt(sumV*sumR)) #numerical errors will be punished with nan if abs(cc) > 1.1 : cc = float('nan') return [cc,vf[1]];