Size: 148
Comment:
|
Size: 11941
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
== Transforms in the context of Projections, Reconstructions, and in General == === Transforming an EMData Object === When an EMData object |
[[TableOfContents]] = Transformations in EMAN2 = == Helpful Links == 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 [http://en.wikipedia.org/wiki/Affine_transformations affine transformations] 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 against the matrix {{{$$M$$}}} to produce the result of applying the transformation {{{$$ T3D \mathbf{p}_{hc} = ( (R\mathbf{p} + \mathbf{t})^T, 1 )^T yuck fixme$$}}} 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 {{{#!python from EMAN2 import Transform3D t = Transform3D() # t is the identity t = Transfrom3D(EULER_EMAN,25,45,65) # EULER_EMAN rotation convention uses the az, alt, phi t = Transform3D(EULER_SPIDER,24,44,64) # EULER_SPIDER rotation convention uses the phi, theta, psi convention t = Transform3D(25,45,65) # EULER_EMAN convention used by default, arguments are taken as az, alt, phi 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 t = Transform3D(25,45,65,Vec3f(4,5,6)) # EULER_EMAN convention rotations az, alt, phi, followed by the post trans t = Transform3D(1,0,0,0,1,0,0,0,1) # Explicitly setting the nine members of the rotation matrix, row wise. 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 {{{#!python from EMAN2 import Transform3D t = Transform3D() # setting the rotations t.set_rotation(25,45,65) # EULER_EMAN convention rotations az, alt, phi t.set_rotation(EULER_SPIDER,24,44,64) # EULER_SPIDER rotation convention uses the phi, theta, psi convention t.set_rotation(EULER_EMAN, {"az":25,"alt":45,"phi":65}) # Optional dictionary style approach t.set_rotation(1,0,0,0,1,0,0,0,1) # Explicitly set the nine members of the rotation matrix, row wise. # setting translations t.set_pretrans(1,2,3)# pre translation dx, dy, dz t.set_pretrans(Vec3f(1,2,3)) # also takes Vec3f argument t.set_pretrans([1,2,3]) # also takes tuple argument t.set_posttrans(4,5,6)# post translation dx, dy, dz t.set_posttrans(Vec3f(4,5,6)) # also takes Vec3f argument 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 {{{#!python from EMAN2 import Transform3D 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 # get rotations dictionary = t.get_rotation(EULER_EMAN) # returns a dictionary with keys "az", "alt" and "phi" dictionary = t.get_rotation(EULER_SPIDER) # returns a dictionary with keys "phi", "theta" and "psi" # get translations vector = t.get_pretrans() # Returns a Vec3f object containing the translation 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 {{{#!python 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 T2 = Transform3D(25,45,65,Vec3f(4,5,6)) # EULER_EMAN convention rotations az, alt, phi, followed by the post trans 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 {{{#!python 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 v = Vec3f(1,2,3) # for example, pixel coordinates 1,2,3 v_dash = T*v 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 {{{#!python 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 v = Vec3f(1,2,3) # for example, pixel coordinates 1,2,3 v_R = T.rotate(v) }}} = Alignment conventions and EMData header attributes = == 2D image alignment and the xform.align2d header attribute == 2D image alignment is generally characterized by a single 2D translation and a single 2D rotation. Whether the translation occurs before or after the rotation is dependent on the alignment algorithm. The Transform3D object has been designed to allow for the encapsulation of 2D alignment parameters. Specifically, the EULER_EMAN phi ({{{$$\phi$$}}}) angle or the EULER_SPIDER psi ({{{$$\psi$$}}}) may be used to store the alignment angle. In regards to translation, either or both of the pre/post translational approaches may be taken in their 2D equivalent form. Given that the rotational alignment angle is denoted {{{$$\phi$$}}} and the pre and post translation vectors are written {{{$$(dx_{pre},dy_{pre})^T$$}}} and {{{$$(dx_{post},dy_{post})^T$$}}} respectively, the Transform3D object that has been constructed using the Python syntax {{{#!python t = Transform3D(0,0,25) # 25 is phi t.set_pretrans(2,3) # pre translation dx and dy t.set_posttrans(-1,-10) # post translation dx and dy }}} and this will create a Transform3D matrix {{{$$T3D_{2D}$$}}} that stores the transformation matrix as {{{$$T3D_{2D} \equiv [[cos phi,sin phi, 0, cos phi * dx_{pre} + sin phi * dy_{pre} + dx_{post}],[-sin phi,cos phi,0,-sin phi * dx_{pre} + cos phi * dy_{pre} + dy_{post}],[0,0,1,0],[0,0,0,1]]$$}}} === The Vec2f object === The Vec2f object was created specifically to be used with Transform3D objects in situations involving 2D alignments. You can set Transform3D pre and post translations using Vec2f objects in Python as follows {{{#!python from EMAN2 import Transform3D, Vec2f t = Transform3D(0,0,25) # 25 is phi pretrans = Vec2f(2,3) posttrans = Vec2f(-1,10) t.set_pretrans(pretrans) # pre translation dx and dy t.set_posttrans(postrans) # post translation dx and dy }}} === Transform3D times a 2D vector (Vec2f) === A Vec2f may be right multiplied against a Transform3D object to efficiently calculate transformed 2D coordinates. In this mode of operation the Transform3D object is treated implicitly as though it were 2D affine transformation matrix - {{{$$ T3D_{2D} \dot \mathbf(Vec2f) = [[cos phi,sin phi, 0, cos phi * dx_{pre} + sin phi * dy_{pre} + dx_{post}],[-sin phi,cos phi,0,-sin phi * dx_{pre} + cos phi * dy_{pre} + dy_{post}],[0,0,1,0],[0,0,0,1]] \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 contents of the Transform3D object are not checked to make sure they describe a single (phi) rotation and or whether the current translations are purely 2D, quite literally the contents of the internal transformation matrix are multiplied against the 2D transformation using the above formula. == 3D object alignment == text === The xform.align3d header attribute === text == 3D projection alignment == text === The xform.reconstruct header attribute === text = 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. The model may also be pre and/or post translated as part of the projection process. The translation information along with the direction of the projection is to be stored in a Transform3D object T, 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 planar integrals along z. = Transformations and backprojections = If a projection was generated as described above using a Transform3D object, the operation of backprojection (in the same direction) requires inverse of the original Transform3D object. = Using 3D symmetry (Symmetry3D) objects together with Transform3D objects = Description will go here |
Transformations in EMAN2
Helpful Links
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 [http://en.wikipedia.org/wiki/Affine_transformations affine transformations] 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 against the matrix $$M$$ to produce the result of applying the transformation
$$ T3D \mathbf{p}_{hc} = ( (R\mathbf{p} + \mathbf{t})^T, 1 )^T yuck fixme$$
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
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
Alignment conventions and EMData header attributes
2D image alignment and the xform.align2d header attribute
2D image alignment is generally characterized by a single 2D translation and a single 2D rotation. Whether the translation occurs before or after the rotation is dependent on the alignment algorithm. The Transform3D object has been designed to allow for the encapsulation of 2D alignment parameters. Specifically, the EULER_EMAN phi ($$\phi$$) angle or the EULER_SPIDER psi ($$\psi$$) may be used to store the alignment angle. In regards to translation, either or both of the pre/post translational approaches may be taken in their 2D equivalent form. Given that the rotational alignment angle is denoted $$\phi$$ and the pre and post translation vectors are written $$(dx_{pre},dy_{pre})^T$$ and $$(dx_{post},dy_{post})^T$$ respectively, the Transform3D object that has been constructed using the Python syntax
and this will create a Transform3D matrix $$T3D_{2D}$$ that stores the transformation matrix as
$$T3D_{2D} \equiv [[cos phi,sin phi, 0, cos phi * dx_{pre} + sin phi * dy_{pre} + dx_{post}],[-sin phi,cos phi,0,-sin phi * dx_{pre} + cos phi * dy_{pre} + dy_{post}],[0,0,1,0],[0,0,0,1]]$$
The Vec2f object
The Vec2f object was created specifically to be used with Transform3D objects in situations involving 2D alignments. You can set Transform3D pre and post translations using Vec2f objects in Python as follows
Transform3D times a 2D vector (Vec2f)
A Vec2f may be right multiplied against a Transform3D object to efficiently calculate transformed 2D coordinates. In this mode of operation the Transform3D object is treated implicitly as though it were 2D affine transformation matrix -
$$ T3D_{2D} \dot \mathbf(Vec2f) = [[cos phi,sin phi, 0, cos phi * dx_{pre} + sin phi * dy_{pre} + dx_{post}],[-sin phi,cos phi,0,-sin phi * dx_{pre} + cos phi * dy_{pre} + dy_{post}],[0,0,1,0],[0,0,0,1]] \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 contents of the Transform3D object are not checked to make sure they describe a single (phi) rotation and or whether the current translations are purely 2D, quite literally the contents of the internal transformation matrix are multiplied against the 2D transformation using the above formula.
3D object alignment
text
The xform.align3d header attribute
text
3D projection alignment
text
The xform.reconstruct header attribute
text
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. The model may also be pre and/or post translated as part of the projection process. The translation information along with the direction of the projection is to be stored in a Transform3D object T, 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 planar integrals along z.
Transformations and backprojections
If a projection was generated as described above using a Transform3D object, the operation of backprojection (in the same direction) requires inverse of the original Transform3D object.
Using 3D symmetry (Symmetry3D) objects together with Transform3D objects
Description will go here