TableOfContents

Transformations in EMAN2

For a more information on the contents of 3D rotation matrices please consult the Sparx [http://macro-em.org/sparxwiki/Euler_angles Euler Angles] page.

The Transform3D Class

EMAN2 uses the [http://blake.bcm.edu/eman2/doxygen_html/classEMAN_1_1Transform3D.html Transform3D] class for storing/managing Euler angles and translations. At any time a Transform3D ($$T3D$$) object defines a group of 3 transformations of a rigid body that are applied in a specific order, namely

$$T3D \equiv T_{post} R T_{pre}$$

Where $$T_{pre}  is a pre translation, $$R$$ is a rotation and $$T_{post}  is a post translation. The Transform3D object stores these transformations internally in a 4x4 matrix, as is commonly the case in computer graphics applications that use homogeneous coordinate systems (i.e. OpenGL). In these approaches the 4x4 transformation matrix $$T3D$$ is constructed in this way

$$T3D = [[R,\mathbf{t}],[\mathbf{0}^T,1]]$$

Where R is a $$3x3$$ rotation matrix and $$\mathbf{t}=(dx,dy,dz)^T$$ is a post translation. In this approach a 3D point $$\mathbf{p}=(x,y,z)^T$$ as represented in homogeneous coordinates as a 4D vector $$\mathbf{p}_{hc}=(x,y,z,1)^T$$ and is multiplied by the matrix $$M$$ to produce the result of applying the transformation

$$ T3D \mathbf{p}_{hc} = ( (R\mathbf{p} +  \mathbf{t})^T, 1 )^T $$

In this way the result of applying a Transform3D to a vector is literally a rotation followed by a translation. The Transform3D allows for both pre and post translation and stores the cumulative result internally

$$T3D = T_{post} R T_{pre} = [[I,\mathbf{t}_{post}],[\mathbf{0}^T,1]] [[R,\mathbf{0}],[\mathbf{0}^T,1]] [[I,\mathbf{t}_{pre}],[\mathbf{0}^T,1]] = [[R,R\mathbf{t}_{pre}+\mathbf{t}_{post}],[\mathbf{0}^T,1]]$$

Constructing a Transform3D object in Python

In Python you can construct a Transform3D object in a number of ways

   1 from EMAN2 import Transform3D
   2 t = Transform3D() # t is the identity
   3 t = Transfrom3D(EULER_EMAN,25,45,65) # EULER_EMAN rotation convention uses the az, alt, phi 
   4 t = Transform3D(EULER_SPIDER,24,44,64) # EULER_SPIDER rotation convention uses the phi, theta, psi convention
   5 t = Transform3D(25,45,65) # EULER_EMAN convention used by default, arguments are taken as az, alt, phi
   6 t = Transform3D(Vec3f(1,2,3),25,45,65,Vec3f(4,5,6)) # Specify a pre trans, followed by EULER_EMAN convention rotations az, alt, phi, followed by the post trans
   7 t = Transform3D(25,45,65,Vec3f(4,5,6)) # EULER_EMAN convention rotations az, alt, phi, followed by the post trans
   8 t = Transform3D(1,0,0,0,1,0,0,0,1) # Explicitly setting the nine members of the rotation matrix, row wise.
   9 s = Transform3D(t) # copy constructor

Setting Transform3D rotations and translation attributes in Python

You can set the pre and post translations, as well as the rotations, directly from Python

   1 from EMAN2 import Transform3D
   2 t = Transform3D()
   3 # setting the rotations
   4 t.set_rotation(25,45,65) # EULER_EMAN convention rotations az, alt, phi
   5 t.set_rotation(EULER_SPIDER,24,44,64) # EULER_SPIDER rotation convention uses the phi, theta, psi convention
   6 t.set_rotation(EULER_EMAN, {"az":25,"alt":45,"phi":65}) # Optional dictionary style approach
   7 t.set_rotation(1,0,0,0,1,0,0,0,1) # Explicitly set the nine members of the rotation matrix, row wise.
   8 # setting translations
   9 t.set_pretrans(1,2,3)# pre translation dx, dy, dz
  10 t.set_pretrans(Vec3f(1,2,3)) # also takes Vec3f argument
  11 t.set_pretrans([1,2,3]) # also takes tuple argument
  12 t.set_posttrans(4,5,6)# post translation dx, dy, dz
  13 t.set_posttrans(Vec3f(4,5,6)) # also takes Vec3f argument
  14 t.set_posttrans([4,5,6]) # also takes tuple argument

Getting transform3D rotations and translation attributes in Python

You can get these attributes using similar syntax to that employed for the setter methods

   1 from EMAN2 import Transform3D
   2 t = Transform3D(Vec3f(1,2,3),25,45,65,Vec3f(4,5,6)) # Specify a pre trans, followed by EULER_EMAN convention rotations az, alt, phi, followed by the post trans
   3 # get rotations
   4 dictionary = t.get_rotation(EULER_EMAN) # returns a dictionary with keys "az", "alt" and "phi"
   5 dictionary = t.get_rotation(EULER_SPIDER) # returns a dictionary with keys "phi", "theta" and "psi"
   6 # get translations
   7 vector = t.get_pretrans() # Returns a Vec3f object containing the translation
   8 vector = t.get_posttrans() # Returns a Vec3f object containing the translation

Multiplication

Transform3D times a Transform3D

The main thing to consider when multiplying two Transform3D objects is what will be the ultimate result of asking for the pre_trans and post_trans vectors of the resulting Transform3D object ($$T3D_{rst}$$). To answer this question we look at the details

$$T3D_{rst} = T3D_{2} T3D_{1} = T_{2,post} R_{2} T_{2,pre} T_{1,post} R_{1} T_{1,pre} = T_{2,post} R_{2} T_{2,pre}[[R_{1},R_{1}\mathbf{t}_{1,pre}+\mathbf{t}_{1,post}],[\mathbf{0}^T,1]]$$

$$ = T_{2,post} R_{2} [[R_{1},R_{1}\mathbf{t}_{1,pre}+\mathbf{t}_{1,post}+\mathbf{t}_{2,pre}],[\mathbf{0}^T,1]]$$

The translation in right column ($$R_{1}\mathbf{t}_{1,pre}+\mathbf{t}_{1,post}+\mathbf{t}_{2,pre}$$) is now what will be returned when $$T3D_{rst}$$ is asked for its pre_translation vector from python (or C++). Similarly, the post translation vector of $$T3D_{2}$$ will now be returned by calling get_postrans on $$T3D_{rst}$$. To complete the details, internally the Transform3D object will look like

$$ T3D_{rst} = [[ R_{2}R_{1},R_{2}(R_{1}\mathbf{t}_{1,pre}+\mathbf{t}_{1,post}+\mathbf{t}_{2,pre})+\mathbf{t}_{2,post}],[\mathbf{0}^T,1]]$$

In Python the Transfrom3D x Transform3D operation can be achieved using the '*' operator

   1 T1 = Transform3D(Vec3f(1,2,3),25,45,65,Vec3f(4,5,6)) # Specify a pre trans, followed by EULER_EMAN convention rotations az, alt, phi, followed by the post trans
   2 T2 = Transform3D(25,45,65,Vec3f(4,5,6)) # EULER_EMAN convention rotations az, alt, phi, followed by the post trans
   3 Trst = T2*T1

Transform3D times a 3D vector (Vec3f)

If v is a three dimensional vector encapsulated as a Vec3f then one can right multiply it by a Transform3D object and this achieves the following result

$$T3D \mathbf{v} =  [[R,R\mathbf{t}_{pre}+\mathbf{t}_{post}],[\mathbf{0}^T,1]] \mathbf{v}  $$

$$T3D \mathbf{v} = Rv+R\mathbf{t}_{pre}+\mathbf{t}_{post}  $$

The vector v is treated implicitly as though it were an homogeneous point, but the last row of the matrix-vector multiplication is not performed.

In Python the Transfrom3D x Vec3f operation can be achieved using the '*' operator or by calling the Transform3D::transform(Vec3f) function

   1 T = Transform3D(Vec3f(1,2,3),25,45,65,Vec3f(4,5,6)) # Specify a pre trans, followed by EULER_EMAN convention rotations az, alt, phi, followed by the post trans
   2 v = Vec3f(1,2,3) # for example, pixel coordinates 1,2,3
   3 v_dash = T*v
   4 v_dash = T.transform(v) # Achieves the same result as calling T*v

Explicitly rotating a 3D vector (Vec3f)

If a Transform3D is represented as

$$T3D = [[R,\mathbf{t}],[\mathbf{0}^T,1]]$$

One can calculate

$$\mathbf{v}_R = R \mathbf{v}$$

in Python by doing

   1 T = Transform3D(Vec3f(1,2,3),25,45,65,Vec3f(4,5,6)) # Specify a pre trans, followed by EULER_EMAN convention rotations az, alt, phi, followed by the post trans
   2 v = Vec3f(1,2,3) # for example, pixel coordinates 1,2,3
   3 v_R = T.rotate(v)

2D image alignment conventions

The xform.align2d header attribute

The "xform.align2d" EMData attribute stores a Transform3D object denoted here as $$T3D_{ali2D}$$, which represents the alignment of the 2D Image $$M(x,y)$$, as given by the following

$$ M(x,y)_{ali} = T3D_{ali2D} M(x,y) $$

Where $$ M(x,y)_{ali}$$ denotes the aligned image. The Transform3D object has been designed to allow for application of 2D transformations. The internal transformation matrix of Transform3D object that stores only 2D alignment parameters $$T3D_{ali2D}$$ appears just as any other Transform3D object

$$T3D_{ali2D} = T_{post} R T_{pre} = [[I,\mathbf{t}_{post}],[\mathbf{0}^T,1]] [[R,\mathbf{0}],[\mathbf{0}^T,1]] [[I,\mathbf{t}_{pre}],[\mathbf{0}^T,1]] $$

However the rotation and translations can be made 'psuedo-2D', more specifically

$$ R =  [[cos phi,sin phi, 0],[-sin phi,cos phi,0],[0,0,1]], \mathbf{t}_{pre} = (dx_{pre},dy_{pre},0)^T, \mathbf{t}_{post} = (dx_{post},dy_{post},0)^T $$

Creating Transform3D objects that describe 2D transformations

To construct "pseudo-2D" Transform3D objects in Python you can use any of the following approaches

   1 from EMAN2 import Transform3D
   2 # set the rotation
   3 t = Transform3D(0,0,25) # 25 is phi
   4 t = Transform3D(EULER_SPIDER 0,0,24) # 24 is psi which is equivalent to setting phi
   5 # set pre and post trans
   6 t.set_pretrans(2,3) # pre translation dx and dy
   7 t.set_pretrans(Vec2f(2,3)) # use Vec2f instead
   8 t.set_posttrans(-1,-10) # post translation dx and dy
   9 t.set_posttrans(Vec2f(-1,-10)) # use Vec2f instead

Transform3D times a 2D vector (Vec2f)

A Vec2f, an EMAN2 object that stores two values $$v_x$$ and $$v_y$$, may be right multiplied against a Transform3D object to efficiently calculate transformed 2D coordinates.

$$ T3D_{ali2D} \dot \mathbf(Vec2f) \equiv [[cos phi,sin phi, cos phi * dx_{pre} + sin phi * dy_{pre} + dx_{post}],[-sin phi,cos phi,-sin phi * dx_{pre} + cos phi * dy_{pre} + dy_{post}],[0,0,1]] ((v_x),(v_y),(1)) $$

The 2D coordinates are multiplied by the internal transformation matrix in the Transform3D to mimic 2D transformation. The Transform3D object is not checked to ensure it describes a single (phi) rotation or whether the current translations are purely 2D. This responsibility is left to the programmer.

Here is an example of doing Transform3D times Vec2f in Python

   1 from EMAN2 import Transform3D
   2 # make a Transform3D that can be used as a 2D transformation
   3 t = Transform3D(0,0,25) # 25 is phi
   4 t.set_pretrans(Vec2f(2,3)) # use Vec2f instead
   5 t.set_posttrans(Vec2f(-1,-10)) # use Vec2f instead
   6 v = Vec2f(2,3) # for example, pixel coordinate 2,3
   7 v_trans = t*v # calculates the 2D transformation

3D backprojection alignment conventions

3D projection alignment is used here to denote the set of transformations that must be applied to a projection in order to backproject into a 3D volume, presumably as part of a 3D reconstruction routine.

Transformations and projections

Say the data model is a 3D map denoted M(x,y,z) and a projection is to be generated in a particular direction, possibly including pre or post translation (the latter is a default). The translation information along with the direction of the projection is to be stored in a Transform3D object $$T3D$$, and the projection is to be generated according to or equivalently to the following

$$p(x,y) = int_z T3D M(x,y,z)  dz$$

That is, the projection operation can be thought of as first transforming the 3D map M by the Transform3D object, and by subsequently taking line integrals along z. The programmer is free to construct $$T3D_{ali3D}$$ using the guidelines of the Transform3D class.

In Python one may generate a projection using a strategy similar to

   1 from EMAN2 import *
   2 t = Transform3D(23,24,25) # EMAN convent az, alt, phi
   3 t.set_pretrans(1,2,3)
   4 model = test_image_3d() # load a test model, defaults to 128x128x128. Shows the 'axes' image. model is an EMData object
   5 model = EMData("groel.mrc") # read the 3D image 'groel.mrc' from the current directory.
   6 p = model.project("standard",t) # projects using the standard method and the Transform3D object t. see e2help.py projectors

Transformations and backprojections: the xform.reconstruct header attribute

The "xform.reconstruct" EMData attribute returns a specialized Transform3D $$T3D_{rec}$$ that stores a 2D translation that is to be applied to the projection $$p(x,y)$$ before it is backprojected into the 3D volume $$V(x,y,z)$$ in the orientation dictated by the Transform3D's rotation matrix (Euler angles). More specifically $$T3D_{rec}$$ consists of a rotation and a single post translation, i.e.

$$T3D_{rec} = T_{post,rec} R_{rec}  = [[I,\mathbf{t}_{post,rec}],[\mathbf{0}^T,1]] [[R_{rec},\mathbf{0}],[\mathbf{0}^T,1]] = [[R_{rec},\mathbf{t}_{post,rec}],[\mathbf{0}^T,1]]$$

Where $$ t_{post,rec} $$ is defined as

$$ t_{post,rec} = (dx,dy,0)^T $$

[...]

$$ T_{post,rec} p(x,y) \approx int_z R_{rec} M(x,y,z)  dz$$

3D map alignment conventions

The xform.align3d header attribute

The "xform.align3d" EMData attribute stores a Transform3D object denoted as $$T3D_{ali3D}$$, which represents the transformation of the 3D map $$M(x,y,z)$$, as given by the following

$$ M(x,y,z)_{ali} = T3D_{ali3D} M(x,y,z) $$

Where $$ M(x,y,z)_{ali}$$ denotes the transformed 3D map. The programmer is free to construct $$T3D_{ali3D}$$ using the guidelines of the Transform3D class.