def interpolate_nn(f_2d, f_3d, phi, theta, psi, pad): # sizes size_2d = f_2d.shape[0] # f_3d already padded half_size_2d = size_2d // 2 size_3d = f_3d.shape[0] max_r = size_3d // 2 - 1 for i in range(f_2d.shape[0]): if i >= half_size_2d: k = i - size_2d else: k = i for j in range(f_2d.shape[1]): h = j # get rotation matrix rot_mat = np.empty((3, 3)) rotation_matrix_euler(rot_mat, phi, theta, psi, inv=False) # rotate h, k, l, taking padding into account x = (rot_mat[0][0] * h + rot_mat[0][1] * k) * pad y = (rot_mat[1][0] * h + rot_mat[1][1] * k) * pad z = (rot_mat[2][0] * h + rot_mat[2][1] * k) * pad # only interpolate within max_r circle if x**2 + y**2 + z**2 < max_r**2: # find friedel's pair for x < 0 if x < 0: neg = True x = -x y = -y z = -z else: neg = False # nearest neighbor interpolation x0 = int(np.round(x)) y0 = int(np.round(y)) z0 = int(np.round(z)) # coordinates shift if y0 < 0: y0 += size_3d if z0 < 0: z0 += size_3d value = f_3d[z0][y0][x0] if neg: f_2d[i][j] = np.conj(value) else: f_2d[i][j] = value
def inv_interpolate_nn(f_2d, f_3d, w_2d, w_3d, phi, theta, psi, pad): # sizes size_2d = f_2d.shape[0] # f_3d already padded half_size_2d = size_2d // 2 size_3d = f_3d.shape[0] max_r = size_3d // 2 - 1 # for each pixel in 2D slice for i in range(f_2d.shape[0]): if i >= half_size_2d: k = i - size_2d else: k = i for j in range(f_2d.shape[1]): h = j # rotate the matrix, take padding into account rot_mat = np.empty((3, 3)) rotation_matrix_euler(rot_mat, phi, theta, psi, inv=False) x = (rot_mat[0][0] * h + rot_mat[0][1] * k) * pad y = (rot_mat[1][0] * h + rot_mat[1][1] * k) * pad z = (rot_mat[2][0] * h + rot_mat[2][1] * k) * pad # only interpolate within max_r circle if x**2 + y**2 + z**2 < max_r**2: # find friedel's pair if x < 0 if x < 0: x = -x y = -y z = -z value = np.conj(f_2d[i][j]) else: value = f_2d[i][j] # assign initial weight if w_2d[i][j] > 0: weight = w_2d[i][j] else: weight = 1.0 # inverse nearest neighbor interpolation x0 = int(np.round(x)) y0 = int(np.round(y)) z0 = int(np.round(z)) if y0 < 0: y0 += size_3d if z0 < 0: z0 += size_3d f_3d[z0][y0][x0] += value w_3d[z0][y0][x0] += weight
def interpolate_tri(f_2d, f_3d, phi, theta, psi, pad): # sizes size_2d = f_2d.shape[0] # f_3d already padded half_size_2d = size_2d // 2 size_3d = f_3d.shape[0] max_r = size_3d // 2 - 1 for i in range(f_2d.shape[0]): if i >= half_size_2d: k = i - size_2d else: k = i for j in range(f_2d.shape[1]): h = j # get rotation matrix rot_mat = np.empty((3, 3)) rotation_matrix_euler(rot_mat, phi, theta, psi, inv=False) # rotate h, k, l, taking padding into account x = (rot_mat[0][0] * h + rot_mat[0][1] * k) * pad y = (rot_mat[1][0] * h + rot_mat[1][1] * k) * pad z = (rot_mat[2][0] * h + rot_mat[2][1] * k) * pad # only interpolate within max_r circle if x**2 + y**2 + z**2 < max_r**2: # find friedel's pair for x < 0 if x < 0: neg = True x = -x y = -y z = -z else: neg = False # trilinear interpolation x0 = int(np.floor(x)) x1 = x0 + 1 xd = x - x0 y0 = int(np.floor(y)) y1 = y0 + 1 yd = y - y0 z0 = int(np.floor(z)) z1 = z0 + 1 zd = z - z0 # coordinates shift if y0 < 0: y0 += size_3d if y1 < 0: y1 += size_3d if z0 < 0: z0 += size_3d if z1 < 0: z1 += size_3d d000 = f_3d[z0][y0][x0] d100 = f_3d[z0][y0][x1] d010 = f_3d[z0][y1][x0] d001 = f_3d[z1][y0][x0] d110 = f_3d[z0][y1][x1] d101 = f_3d[z1][y0][x1] d011 = f_3d[z1][y1][x0] d111 = f_3d[z1][y1][x1] d00 = d000 * (1 - xd) + d100 * xd d01 = d001 * (1 - xd) + d101 * xd d10 = d010 * (1 - xd) + d110 * xd d11 = d011 * (1 - xd) + d111 * xd d0 = d00 * (1 - yd) + d10 * yd d1 = d01 * (1 - yd) + d11 * yd value = d0 * (1 - zd) + d1 * zd if neg: f_2d[i][j] = np.conj(value) else: f_2d[i][j] = value
def inv_interpolate_tri(f_2d, f_3d, w_2d, w_3d, phi, theta, psi, pad): # sizes size_2d = f_2d.shape[0] # f_3d already padded half_size_2d = size_2d // 2 size_3d = f_3d.shape[0] max_r = size_3d // 2 - 1 # for each pixel in 2D slice for i in range(f_2d.shape[0]): if i >= half_size_2d: k = i - size_2d else: k = i for j in range(f_2d.shape[1]): h = j # rotate the matrix, take padding into account rot_mat = np.empty((3, 3)) rotation_matrix_euler(rot_mat, phi, theta, psi, inv=False) x = (rot_mat[0][0] * h + rot_mat[0][1] * k) * pad y = (rot_mat[1][0] * h + rot_mat[1][1] * k) * pad z = (rot_mat[2][0] * h + rot_mat[2][1] * k) * pad # only interpolate within max_r circle if x**2 + y**2 + z**2 < max_r**2: # find friedel's pair if x < 0 if x < 0: x = -x y = -y z = -z value = np.conj(f_2d[i][j]) else: value = f_2d[i][j] # assign initial weight if w_2d[i][j] > 0: weight = w_2d[i][j] else: weight = 1.0 # inverse trilinear interpolation x0 = int(np.floor(x)) x1 = x0 + 1 xd = x - x0 y0 = int(np.floor(y)) y1 = y0 + 1 yd = y - y0 z0 = int(np.floor(z)) z1 = z0 + 1 zd = z - z0 # calculate distance weights d0 = 1 - zd d1 = zd d00 = d0 * (1 - yd) d01 = d1 * (1 - yd) d10 = d0 * yd d11 = d1 * yd d000 = d00 * (1 - xd) d100 = d00 * xd d010 = d10 * (1 - xd) d001 = d01 * (1 - xd) d110 = d10 * xd d101 = d01 * xd d011 = d11 * (1 - xd) d111 = d11 * xd # coordinates shift if y0 < 0: y0 += size_3d if y1 < 0: y1 += size_3d if z0 < 0: z0 += size_3d if z1 < 0: z1 += size_3d f_3d[z0][y0][x0] += d000 * value f_3d[z0][y0][x1] += d001 * value f_3d[z0][y1][x0] += d010 * value f_3d[z1][y0][x0] += d100 * value f_3d[z0][y1][x1] += d011 * value f_3d[z1][y0][x1] += d101 * value f_3d[z1][y1][x0] += d110 * value f_3d[z1][y1][x1] += d111 * value w_3d[z0][y0][x0] += d000 * weight w_3d[z0][y0][x1] += d001 * weight w_3d[z0][y1][x0] += d010 * weight w_3d[z1][y0][x0] += d100 * weight w_3d[z0][y1][x1] += d011 * weight w_3d[z1][y0][x1] += d101 * weight w_3d[z1][y1][x0] += d110 * weight w_3d[z1][y1][x1] += d111 * weight
def projection(f_2d, f_3d, phi, theta, psi, x_shift, y_shift, pad=2, ctf=False, defocus_u=-1, defocus_v=-1, defocus_a=-1, cs=-1, apix=-1, kv=-1, ac=-1, b_fac=-1, white=True, trilinear=True): # some useful numbers size_2d = f_2d.shape[0] half_size_2d = size_2d // 2 size_3d = f_3d.shape[0] max_r = size_3d // 2 - 1 # for each pixel in 2D slice for i in range(f_2d.shape[0]): if i >= half_size_2d: k = i - size_2d else: k = i for j in range(f_2d.shape[1]): h = j # rotate the matrix, take padding into account rot_mat = np.empty((3, 3)) rotation_matrix_euler(rot_mat, phi, theta, psi, inv=False) x = (rot_mat[0][0] * h + rot_mat[0][1] * k) * pad y = (rot_mat[1][0] * h + rot_mat[1][1] * k) * pad z = (rot_mat[2][0] * h + rot_mat[2][1] * k) * pad # only interpolate within max_r circle if x ** 2 + y ** 2 + z ** 2 < max_r ** 2: # find friedel's pair if x < 0 if x < 0: neg = True x = -x y = -y z = -z else: neg = False # trilinear interpolation if trilinear: x0 = int(np.floor(x)) x1 = x0 + 1 xd = x - x0 y0 = int(np.floor(y)) y1 = y0 + 1 yd = y - y0 z0 = int(np.floor(z)) z1 = z0 + 1 zd = z - z0 if y0 < 0: y0 += size_3d if y1 < 0: y1 += size_3d if z0 < 0: z0 += size_3d if z1 < 0: z1 += size_3d # flip phase to center the object in 3D volume if (z0 + y0 + x0) % 2 == 1: flip = -1 else: flip = 1 d000 = f_3d[z0][y0][x0] * flip d100 = f_3d[z0][y0][x1] * (-flip) d010 = f_3d[z0][y1][x0] * (-flip) d001 = f_3d[z1][y0][x0] * (-flip) d110 = f_3d[z0][y1][x1] * flip d101 = f_3d[z1][y0][x1] * flip d011 = f_3d[z1][y1][x0] * flip d111 = f_3d[z1][y1][x1] * (-flip) d00 = d000 * (1 - xd) + d100 * xd d01 = d001 * (1 - xd) + d101 * xd d10 = d010 * (1 - xd) + d110 * xd d11 = d011 * (1 - xd) + d111 * xd d0 = d00 * (1 - yd) + d10 * yd d1 = d01 * (1 - yd) + d11 * yd value = d0 * (1 - zd) + d1 * zd # nearest neighbor interpolation else: x0 = int(np.round(x)) y0 = int(np.round(y)) z0 = int(np.round(z)) if y0 < 0: y0 += size_3d if z0 < 0: z0 += size_3d # flip phase to center the object in 3D volume if (z0 + y0 + x0) % 2 == 1: flip = -1 else: flip = 1 value = f_3d[z0][y0][x0] * flip # conjugate if the pixel is friedel's pair if neg: f_2d[i][j] = np.conj(value) else: f_2d[i][j] = value # apply translation ph = h * x_shift / size_2d + k * y_shift / size_2d f_2d[i][j] *= np.exp(-2 * np.pi * ph * 1.0j) # apply ctf if ctf: ctf_value = ctf_2d_arr(h, k, size_2d, defocus_u, defocus_v, defocus_a, cs, apix, kv, ac, b_fac) if white: f_2d[i][j] *= ctf_value else: f_2d[i][j] *= -ctf_value # flip phase to center the object in 2D slice if (h + k) % 2 == 1: f_2d[i][j] *= -1
def back_projection(f_2d, f_3d, w_2d, w_3d, phi, theta, psi, x_shift, y_shift, pad=2, ctf=False, defocus_u=-1, defocus_v=-1, defocus_a=-1, cs=-1, apix=-1, kv=-1, ac=-1, b_fac=-1, white=True, trilinear=True): # some useful numbers size_2d = f_2d.shape[0] half_size_2d = size_2d // 2 size_3d = f_3d.shape[0] max_r = size_3d // 2 - 1 # for each pixel in 2D slice for i in range(f_2d.shape[0]): # fourier space coordinates l = 0 if i >= half_size_2d: k = i - size_2d else: k = i for j in range(f_2d.shape[1]): # fourier space coordinates h = j # rotate the matrix, take padding into account rot_mat = np.empty((3, 3)) rotation_matrix_euler(rot_mat, phi, theta, psi, inv=False) x = (rot_mat[0][0] * h + rot_mat[0][1] * k + rot_mat[0][2] * l) * pad y = (rot_mat[1][0] * h + rot_mat[1][1] * k + rot_mat[1][2] * l) * pad z = (rot_mat[2][0] * h + rot_mat[2][1] * k + rot_mat[2][2] * l) * pad # only interpolate within max_r circle if x**2 + y**2 + z**2 < max_r**2: # apply translation ph = h * x_shift / size_2d + k * y_shift / size_2d f_2d[i][j] *= np.exp(-2 * np.pi * ph * 1.0j) # flip phase to center the object in 2D slice if (h + k) % 2 == 1: f_2d[i][j] *= -1 # find friedel's pair if x < 0 if x < 0: x = -x y = -y z = -z value = np.conj(f_2d[i][j]) else: value = f_2d[i][j] # apply ctf if ctf: ctf_value = ctf_2d_arr(h, k, size_2d, defocus_u, defocus_v, defocus_a, cs, apix, kv, ac, b_fac) if white: value *= ctf_value else: value *= -ctf_value # assign initial weight if w_2d[i][j] > 0: weight = w_2d[i][j] elif ctf: weight = ctf_value**2 else: weight = 1.0 # trilinear interpolation if trilinear: x0 = int(np.floor(x)) x1 = x0 + 1 xd = x - x0 y0 = int(np.floor(y)) y1 = y0 + 1 yd = y - y0 z0 = int(np.floor(z)) z1 = z0 + 1 zd = z - z0 # calculate distance weights d0 = 1 - zd d1 = zd d00 = d0 * (1 - yd) d01 = d1 * (1 - yd) d10 = d0 * yd d11 = d1 * yd d000 = d00 * (1 - xd) d100 = d00 * xd d010 = d10 * (1 - xd) d001 = d01 * (1 - xd) d110 = d10 * xd d101 = d01 * xd d011 = d11 * (1 - xd) d111 = d11 * xd # coordinates shift if y0 < 0: y0 += size_3d if y1 < 0: y1 += size_3d if z0 < 0: z0 += size_3d if z1 < 0: z1 += size_3d f_3d[z0][y0][x0] += d000 * value f_3d[z0][y0][x1] += d001 * value f_3d[z0][y1][x0] += d010 * value f_3d[z1][y0][x0] += d100 * value f_3d[z0][y1][x1] += d011 * value f_3d[z1][y0][x1] += d101 * value f_3d[z1][y1][x0] += d110 * value f_3d[z1][y1][x1] += d111 * value w_3d[z0][y0][x0] += d000 * weight w_3d[z0][y0][x1] += d001 * weight w_3d[z0][y1][x0] += d010 * weight w_3d[z1][y0][x0] += d100 * weight w_3d[z0][y1][x1] += d011 * weight w_3d[z1][y0][x1] += d101 * weight w_3d[z1][y1][x0] += d110 * weight w_3d[z1][y1][x1] += d111 * weight # nearest neighbor interpolation else: x0 = int(np.round(x)) y0 = int(np.round(y)) z0 = int(np.round(z)) if y0 < 0: y0 += size_3d if z0 < 0: z0 += size_3d f_3d[z0][y0][x0] += value w_3d[z0][y0][x0] += weight
def rotate_3d(x, y, z, phi, theta, psi, pad): rot_mat = rotation_matrix_euler(phi, theta, psi, inv=False) x_ = (rot_mat[0][0] * x + rot_mat[0][1] * y + rot_mat[0][2] * z) * pad y_ = (rot_mat[1][0] * x + rot_mat[1][1] * y + rot_mat[1][2] * z) * pad z_ = (rot_mat[2][0] * x + rot_mat[2][1] * y + rot_mat[2][2] * z) * pad return x_, y_, z_