def returnWedgeVolume(self, size, rotation=None): """Return the wedge volume in full size and zero in the center @param size: size of wedge @type size: C{list} @param rotation: rotation (3-dim vector if Euler angles) @type rotation: C{list} @return: wedge volume @rtype: Numpy array """ assert len(size) == 3, "returnWedgeVolume: size must be 3-dim list" if self._volume is not None and np.array_equal(self._volume_shape, size): pass else: self._create_wedge_volume(size) from pytom.tompy.transform import rotate3d, fourier_reduced2full, fftshift isodd = self._volume_shape[2] % 2 wedge_vol = fftshift(fourier_reduced2full(self._volume, isodd)) if rotation is not None: # rotate the wedge first assert len(rotation) == 3 wedge_vol = rotate3d(wedge_vol, rotation[0], rotation[1], rotation[2], order=1) return wedge_vol
def apply(self, data, rotation=None): """ @param rotation: apply rotation to the wedge first """ # if no missing wedge if self.start_ang == -90 and self.end_ang == 90: return data if self._volume is not None and np.array_equal(self._volume_shape, data.shape): pass else: self._create_wedge_volume(data.shape) if rotation is not None: # rotate the wedge first assert len(rotation) == 3 from pytom.tompy.transform import rotate3d, fourier_reduced2full, fourier_full2reduced, fftshift, ifftshift isodd = self._volume_shape[2] % 2 filter_vol = fftshift(fourier_reduced2full(self._volume, isodd)) filter_vol = rotate3d(filter_vol, rotation[0], rotation[1], rotation[2], order=1) # linear interp! filter_vol = fourier_full2reduced(ifftshift(filter_vol)) else: filter_vol = self._volume from pytom.tompy.transform import fourier_filter res = fourier_filter(data, filter_vol, False) return res
def FLCF(volume, template, mask=None, stdV=None): '''Fast local correlation function @param volume: target volume @param template: template to be searched. It can have smaller size then target volume. @param mask: template mask. If not given, a default sphere mask will be used. @param stdV: standard deviation of the target volume under mask, which do not need to be calculated again when the mask is identical. @return: the local correlation function ''' if volume.shape[0] < template.shape[0] or volume.shape[1] < template.shape[ 1] or volume.shape[2] < template.shape[2]: raise Exception('Template size is bigger than the target volume!') # generate the mask if mask is None: from tools import create_sphere mask = create_sphere(template.shape) else: if template.shape[0] != mask.shape[0] and template.shape[ 1] != mask.shape[1] and template.shape[2] != mask.shape[2]: raise Exception('Template and mask sizes are not the same!') # normalize the template under mask meanT = mean_under_mask(template, mask) stdT = std_under_mask(template, mask, meanT) temp = (template - meanT) / stdT temp = temp * mask # construct both the template and the mask which has the same size as target volume from tools import paste_in_center tempV = temp if volume.shape[0] != temp.shape[0] or volume.shape[1] != temp.shape[ 1] or volume.shape[2] != temp.shape[2]: tempV = np.zeros(volume.shape) tempV = paste_in_center(temp, tempV) maskV = mask if volume.shape[0] != mask.shape[0] or volume.shape[1] != mask.shape[ 1] or volume.shape[2] != mask.shape[2]: maskV = np.zeros(volume.shape) maskV = paste_in_center(mask, maskV) # calculate the mean and std of volume meanV = mean_vol_under_mask(volume, maskV) stdV = std_vol_under_mask(volume, maskV, meanV) from transform import rfft, irfft, fftshift size = volume.shape fT = rfft(tempV) fT = np.conjugate(fT) result = fftshift(irfft(fT * rfft(volume), size)) / stdV return result / np.sum(mask)
def toSphericalFunc(self, bw, radius=None, threshold=0.5): """Convert the wedge from k-space to a spherical function. \ currently some hard-coded parameters in - bw <=128, r=45 for max bw, default vol 100 @param bw: bandwidth of the spherical function (must be <=128). @param radius: radius in k-space. For general Wedge, not used for SingleTiltWedge. @param threshold: threshold, above which the value there would be set to 1. @return: a spherical function in numpy.array - default 100x100x100 if no self.vol defined """ assert (bw <= 128), "toSphericalFunc: bw currently limited to <= 128" # if no missing wedge if self.start_ang == -90 and self.end_ang == 90: self._sf = np.ones((4 * bw**2, )) return self._sf r = 45 # this radius and the volume size should be sufficient for sampling b <= 128 if self._volume is None or np.min(self._volume.shape) < 100: self._create_wedge_volume((100, 100, 100)) if self._bw == bw and self._sf is not None: return self._sf else: self._bw = bw from pytom.tompy.transform import fourier_reduced2full, fftshift isodd = self._volume_shape[2] % 2 filter_vol = fftshift(fourier_reduced2full(self._volume, isodd)) # start sampling from math import pi, sin, cos res = [] for j in range(2 * bw): for k in range(2 * bw): the = pi * (2 * j + 1) / (4 * bw) # (0,pi) phi = pi * k / bw # [0,2*pi) # this part actually needs interpolation x = int(cos(phi) * sin(the) * r + 50) y = int(sin(phi) * sin(the) * r + 50) z = int(cos(the) * r + 50) # if the value is bigger than the threshold, we include it if filter_vol[x, y, z] > threshold: res.append(1.0) else: res.append(0.0) # store it so that we don't have to recompute it next time self._sf = np.array(res) return self._sf
def set_wedge_volume(self, wedge_vol, half=True, isodd=False): if half: self._volume = wedge_vol # human understandable version with 0-freq in the center from transform import fourier_reduced2full, fftshift self._whole_volume = fftshift( fourier_reduced2full(self._volume, isodd)) else: self._whole_volume = wedge_vol from transform import fourier_full2reduced, ifftshift self._volume = fourier_full2reduced(ifftshift(self._whole_volume))
def mean_vol_under_mask(volume, mask): """Calculate the mean volume under the mask (Both should have the same size). @param volume: input volume. @param mask: mask. @return: the calculated mean volume under mask. """ p = np.sum(mask) # do the (circular) convolution from transform import rfft, irfft, fftshift size = volume.shape # somehow this should be conjugated res = fftshift(irfft(rfft(volume) * np.conjugate(rfft(mask)), size)) / p return res
def _create_wedge_volume(self, size): from transform import fftshift, fourier_full2reduced # if no missing wedge if self.start_ang == -90 and self.end_ang == 90: filter_vol = np.ones(size) self._volume = fourier_full2reduced(filter_vol) self._volume_shape = size return filter_vol = np.ones(size) x, z = scipy.mgrid[0.:size[0], 0.:size[2]] x -= size[0] / 2 ind = np.where(x) # find the non-zeros z -= size[2] / 2 angles = np.zeros(z.shape) angles[ind] = np.arctan(z[ind] / x[ind]) * 180 / np.pi angles = np.reshape(angles, (size[0], 1, size[2])) angles = np.repeat(angles, size[1], axis=1) filter_vol[angles > -self.start_ang] = 0 filter_vol[angles < -self.end_ang] = 0 filter_vol[size[0] / 2, :, :] = 0 filter_vol[size[0] / 2, :, size[2] / 2] = 1 # create a sphere and multiple it with the wedge from tools import create_sphere mask = create_sphere(size) filter_vol *= mask # shift and cut in half filter_vol = fftshift(filter_vol) self._volume = fourier_full2reduced(filter_vol) self._volume_shape = size