Source code for segclassreconstruct_assist

# Author: Carsten Sachse 08-Jun-2011
# Copyright: EMBL (2010 - 2018), Forschungszentrum Juelich (2019 - 2021)
# License: see license.txt for details
from EMAN2 import EMData, Util, Transform, Vec2f, Reconstructors
from spring.micprgs.scansplit import Micrograph
from spring.segment2d.segment import Segment
from spring.segment3d.segclassreconstruct_prep import SegClassReconstructCylinderMask
from tabulate import tabulate
from utilities import compose_transform2, model_circle, get_sym
import numpy as np


[docs]class SegClassReconstructAssist(SegClassReconstructCylinderMask):
[docs] def compute_transform_with_aligned_helix_segment(self, phi, theta, psi): transform = Transform({'type':'spider', 'phi':phi, 'theta':theta, 'psi':psi}) transform_helical_origin = Transform({'type':'spider', 'phi':0.0, 'theta':90.0, 'psi':270.0}) transposed_helical_origin = transform_helical_origin.transpose() composite_transform = transform * transposed_helical_origin RABTeuler = composite_transform.get_rotation('spider') return RABTeuler
[docs] def compute_helical_inplane_rotation_from_Euler_angles(self, phi, theta, psi): """ >>> from spring.segment3d.segclassreconstruct import SegClassReconstruct >>> SegClassReconstruct().compute_helical_inplane_rotation_from_Euler_angles(180, 90, 270) 0.0 >>> SegClassReconstruct().compute_helical_inplane_rotation_from_Euler_angles(0, 90, 270) 0.0 >>> SegClassReconstruct().compute_helical_inplane_rotation_from_Euler_angles(33, 90, 334) 63.999997560564 >>> SegClassReconstruct().compute_helical_inplane_rotation_from_Euler_angles(180, 90, 240) 329.999999554708 >>> SegClassReconstruct().compute_helical_inplane_rotation_from_Euler_angles(150.0, 94.0, 315) 44.999997495521825 >>> SegClassReconstruct().compute_helical_inplane_rotation_from_Euler_angles(150.0, 86.0, 315) 224.99999749552182 >>> SegClassReconstruct().compute_helical_inplane_rotation_from_Euler_angles(170.0, 90.0, 315) 44.999997495521825 """ RABTeuler = self.compute_transform_with_aligned_helix_segment(phi, 90.0, psi) RABTphi = RABTeuler['phi'] RABTpsi = RABTeuler['psi'] # delta_inplane_rotation = (RABTpsi + RABTphi) % 360 if theta >= 90: delta_inplane_rotation = (RABTpsi + RABTphi) % 360 else: delta_inplane_rotation = (RABTpsi + RABTphi + 180) % 360 return delta_inplane_rotation
[docs] def compute_point_where_normal_and_parallel_line_intersect(self, shift_x, shift_y, inplane_angle): """ >>> from spring.segment3d.segclassreconstruct import SegClassReconstruct >>> s = SegClassReconstruct() >>> s.compute_point_where_normal_and_parallel_line_intersect(3, 1, 0) (3.0, -1.8369701987210297e-16) >>> s.compute_point_where_normal_and_parallel_line_intersect(3, 1, 45) (2.0000000000000004, 2.0) >>> s.compute_point_where_normal_and_parallel_line_intersect(3, 1, -45) (0.9999999999999998, -0.9999999999999999) >>> s.compute_point_where_normal_and_parallel_line_intersect(3, 1, 90) (1.7449489701899453e-12, 1.000000000005235) """ if inplane_angle == 90.0 or inplane_angle == 270.0: inplane_angle -= 1e-10 if 90.0 + inplane_angle == 0: slope = np.tan(np.deg2rad(360.0)) else: slope = np.tan(np.deg2rad(90.0 + inplane_angle)) t = shift_y - slope * shift_x point_x = -t / (1/slope + slope) point_y = -point_x / slope return point_x, point_y
[docs] def compute_distances_to_helical_axis(self, shift_x, shift_y, inplane_angle): """ >>> from spring.segment3d.segclassreconstruct import SegClassReconstruct >>> SegClassReconstruct().compute_distances_to_helical_axis(22, 2, 0) (-22.0, 2.0000000000000013) >>> SegClassReconstruct().compute_distances_to_helical_axis(22, 2, 180) (22.0, -2.000000000000004) >>> SegClassReconstruct().compute_distances_to_helical_axis(22, 2, 90) (-2.000000000038389, -21.99999999999651) >>> SegClassReconstruct().compute_distances_to_helical_axis(3, 1, -45) (-1.414213562373095, 2.82842712474619) >>> SegClassReconstruct().compute_distances_to_helical_axis(3, 1, 45) (-2.8284271247461903, -1.4142135623730947) >>> SegClassReconstruct().compute_distances_to_helical_axis(22, 2, 20) (-21.357277943941323, -5.645057911592895) >>> s = SegClassReconstruct() >>> hx, hy = s.compute_distances_to_helical_axis(22, 2, 180) >>> SegClassReconstruct().compute_distances_to_helical_axis(hx, hy, 180) (22.0, 2.0) """ point_x, point_y = self.compute_point_where_normal_and_parallel_line_intersect(shift_x, shift_y, inplane_angle) dist_x, dst_y = Segment().rotate_coordinates_by_angle(-point_x, -point_y, inplane_angle) centered_x = shift_x - point_x centered_y = shift_y - point_y dst_x, dist_y = Segment().rotate_coordinates_by_angle(centered_x, centered_y, inplane_angle) return dist_x, dist_y
[docs] def prepare_symmetry_computation(self, alignment_parameters, each_symmetry_pair, pixelsize, symmetry_views_count): helical_rise = each_symmetry_pair[0] / pixelsize helical_rotation = each_symmetry_pair[1] symmetry_views = np.arange(-symmetry_views_count / 2, symmetry_views_count / 2, dtype='float64') x_norm, y_parallel = self.compute_distances_to_helical_axis(alignment_parameters.x_shift, alignment_parameters.y_shift, alignment_parameters.inplane_angle) if helical_rise != 0: multiple_off_center = np.round(y_parallel / helical_rise) else: multiple_off_center = np.float(0) symmetry_views += multiple_off_center out_of_plane_correction = np.sin(np.deg2rad(alignment_parameters.theta)) return symmetry_views, helical_rotation, out_of_plane_correction, helical_rise
[docs] def compute_straight_phi_and_yshift(self, each_symmetry_view, phi, helical_rotation, out_of_plane_correction, helical_rise): symmetrized_phi = (phi + each_symmetry_view * helical_rotation) % 360 straight_yshift = out_of_plane_correction * each_symmetry_view * helical_rise return straight_yshift, symmetrized_phi
[docs] def compute_sx_sy_from_shifts_normal_and_parallel_to_helix_axis_with_inplane_angle(self, helix_shift_x, helix_shift_y, inplane_angle): """ >>> from spring.segment3d.segclassreconstruct import SegClassReconstruct >>> hx, hy = SegClassReconstruct().compute_distances_to_helical_axis(3, 1, -45) >>> s = SegClassReconstruct() >>> s.compute_sx_sy_from_shifts_normal_and_parallel_to_helix_axis_with_inplane_angle(hx, hy, -45) (2.9999999999999996, 1.0000000000000002) >>> s.compute_sx_sy_from_shifts_normal_and_parallel_to_helix_axis_with_inplane_angle(3, 0, -45) (-2.121320343559643, 2.1213203435596424) >>> hx, hy = SegClassReconstruct().compute_distances_to_helical_axis(22, 2, 20) >>> s.compute_sx_sy_from_shifts_normal_and_parallel_to_helix_axis_with_inplane_angle(hx, hy, 20) (22.0, 2.0) """ point_x, point_y = Segment().rotate_coordinates_by_angle(helix_shift_x, 0, -inplane_angle) helix_y_from_point = helix_shift_y - point_y sx, sy = Segment().rotate_coordinates_by_angle(-point_x, helix_y_from_point, -inplane_angle, -point_x, -point_y) return sx, sy
[docs] def correct_straight_symmetry_parameters_for_in_plane_rotation_and_shifts_old(self, inplane_angle, x_shift, y_shift, straight_yshift): # x_contribution, y_contribution = self.compute_sx_sy_from_shifts_normal_and_parallel_to_helix_axis_with_inplane_angle(0.0, straight_yshift, inplane_angle) new_rot, x_contribution, y_contribution, scale = compose_transform2(0.0, 0, straight_yshift, 1.0, inplane_angle, 0.0, 0.0, 1.0) total_symmetrized_xshift = x_contribution + x_shift total_symmetrized_yshift = y_contribution + y_shift return total_symmetrized_xshift, total_symmetrized_yshift
[docs] def correct_straight_symmetry_parameters_for_in_plane_rotation_and_shifts(self, inplane_angle, x_shift, y_shift, straight_yshift): x_norm, y_parallel = self.compute_distances_to_helical_axis(x_shift, y_shift, inplane_angle) total_symmetrized_xshift, total_symmetrized_yshift = \ self.compute_sx_sy_from_shifts_normal_and_parallel_to_helix_axis_with_inplane_angle(x_norm, y_parallel + \ straight_yshift, inplane_angle) return -total_symmetrized_xshift, -total_symmetrized_yshift
[docs] def setup_reconstructor(self, imgsize): fftvol = EMData() weight = EMData() #ds.humanize_bytes(s.compute_byte_size_of_image_stack(4 * 200,4 * 200,4 * 200)) = 1.91 GB if 0 < imgsize <= 200: npad = 4 # ds.humanize_bytes(s.compute_byte_size_of_image_stack(3 * 267,3 * 267,3 * 267)) = 1.91GB elif 200 < imgsize <= 267: npad = 3 #ds.humanize_bytes(s.compute_byte_size_of_image_stack(2 * 400,2 * 400,2 * 400)) = 1.91 GB elif 267 < imgsize <= 400: npad = 2 elif imgsize > 400: npad = 1.5 params = {'size':imgsize, 'npad':npad, 'symmetry':'c1', 'fftvol':fftvol, 'weight':weight} r = Reconstructors.get('nn4', params) r.setup() return r, fftvol, weight
[docs] def setup_transform_with_reduced_alignment_parameters(self, each_phi, each_theta, each_psi, each_x, each_y): transform_projection = Transform({'type':'spider', 'phi':each_phi, 'theta':each_theta, 'psi':each_psi}) transform_projection.set_trans(Vec2f(-each_x, -each_y)) return transform_projection
[docs] def get_symmetry_transformations(self, point_symmetry): angs = get_sym(point_symmetry) sym_transformations = [Transform({'type':'spider', 'phi':each_phi, 'theta':each_theta, 'psi':each_psi}) for \ each_phi, each_theta, each_psi in angs] return sym_transformations
[docs] def get_Euler_angles_after_transformation(self, each_phi, each_theta, each_psi, each_x, each_y, each_sym_transform): current_transform = Transform({'type':'spider', 'phi':each_phi, 'theta':each_theta, 'psi':each_psi, 'tx': each_x, 'ty': each_y}) transform_projection = current_transform * each_sym_transform trans = transform_projection.get_params('spider') return transform_projection, trans['phi'], trans['theta'], trans['psi'], trans['tx'], trans['ty']
[docs] def convert_alignment_parameters_to_symmetry_alignment_parameters(self, each_param): sym_align_parameters = np.vstack([[each_param.stack_id, each_param.phi, each_param.theta, each_param.psi, each_param.x_shift, each_param.y_shift, each_param.mirror, each_param.seg_ref_id]]) return sym_align_parameters, each_param.inplane_angle
[docs] def project_from_volume_and_backproject(self, alignment_parameters, trimmed_image_size, xvol, pxvol): for each_image_parameters in alignment_parameters: for (each_stack_id, each_phi, each_theta, each_psi, each_x, each_y, each_ref_id) in each_image_parameters: transform_projection = \ self.setup_transform_with_reduced_alignment_parameters(trimmed_image_size, each_phi, each_theta, each_psi, each_x, each_y) myparams = {'transform':transform_projection, 'anglelist':[each_phi, each_theta, each_psi], 'radius':(trimmed_image_size/2 - 2)} data = xvol.project('chao', myparams) pxvol += data.backproject('chao', myparams) return pxvol