Differences between revisions 15 and 68 (spanning 53 versions)
Revision 15 as of 2008-08-15 00:16:31
Size: 3082
Comment:
Revision 68 as of 2008-08-19 17:06:27
Size: 8572
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
== Transformations in the context of projections, reconstructions, and in general == [[TableOfContents]]
Line 3: Line 3:
=== Definition of transformations === = Transformations in EMAN2 =
Line 5: Line 5:
The approach taken in EMAN2/Sparx is based on homogeneous coordinates which enables transformations such as rotations, translations and others (e.g. scale and shear) to be concisely represented in a 4x4 matrix. A pixel with coordinates [x,y,z] is written in homogeneous coordinates as [x,y,z,1] (z=0 in 2D), where the extra '1' literally means that the the homogeneous coordinate can be translated by the 4x4 transformation matrix. In EMAN2 and Sparx the fourth coordinate is always '1', but in other applications such as OpenGL it can be '0' to indicate that the coordinates represent a vector (such as a normal), not a point. In EMAN2/Sparx, the 4x4 transformation object is encapsulated in the Transform3D object. == The Transform3D Class ==
Line 7: Line 7:
=== Rotations === 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 affine transformations that are applied in a specific order, namely
Line 9: Line 9:
A rotation of a pixel coordinate at [x,y,z] about the y axis looks like {{{$$T3D \equiv T_{post} R T_{pre}$$}}}
Line 11: Line 11:
4x4 Rotation matrix x homog pix coord 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
Line 13: Line 13:
In general a rotation matrix will look like this {{{$$T3D = [[R,\hat{t}],[\hat{0}^T,1]]$$}}}
Line 15: Line 15:
4x4 general rotation matrix Where R is a {{{$$3x3$$}}} rotation matrix and {{{$$\hat{t}=(dx,dy,dz)^T$$}}} is a post translation. In this approach a 3D point {{{$$\hat{p}=(x,y,z)^T$$}}} as represented in homogeneous coordinates as a 4D vector {{{$$\hat{p_{hc}}=(x,y,z,1)^T$$}}} and is multiplied against the matrix {{{$$M$$}}} to produce the result of applying the transformation
Line 17: Line 17:
Note that only the upper left 3x3 block is used to store the rotation information {{{$$ T3D \hat{p}_{hc} = ( R\hat{p} + \hat{t}, 1 )^T $$}}}
Line 19: Line 19:
In this way the result of applying a Transform3D to a vector is literally a rotation follow by a translation. The Transform3D allows for both pre and post translation and stores the cumulative result internally
Line 20: Line 21:
=== Translations === {{{$$T3D = T_{post} R T_{pre} = [[I,\hat{t}_{post}],[\hat{0}^T,1]] [[R,\hat{0}],[\hat{0}^T,1]] [[I,\hat{t}_{pre}],[\hat{0}^T,1]] = [[R,R\hat{t}_{pre}+\hat{t}_{post}],[\hat{0}^T,1]]$$}}}
Line 22: Line 23:
Translation of a pixel coordinate at [x,y,z] by [dx,dy,dz] looks like === Constructing a Transform3D Object In Python ===
Line 24: Line 25:
4x4 depiction of translation matrix x homog pix coord 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
}}}
Line 26: Line 38:
This shows how the homogeneous coordinate representation is used to achieve translation === Setting Transform3D Rotations and Translation Attributes in Python ===
Line 28: Line 40:
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
}}}
Line 29: Line 58:
=== Rotations and Translations === === Getting Transform3D Rotations and Translation Attributes in Python ===
Line 31: Line 60:
Rotation


Need MathML

=== Transforming an EMData object ===

An EMData object may be transformed using the following syntax
You can get these attributes using similar syntax to that employed for the setter methods
Line 41: Line 63:
e = EMData("mydata.hdf")
t = Transform3D(EULER_EMAN,10,23,0) # three angles in the EMAN convention are az=10,alt=23,phi=0.
# The convention may also be EULER_SPIDER, EULER_IMAGIC, EULER_MRC, EULER_SPIN, EULER_XYZ
t.set_pretrans(1,1,1)
t.set_postrans(2,2,2)
e.rotate_translate(t)
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
Line 49: Line 73:
This next section will look better once we get mathml working == Multiplication ==
Line 51: Line 75:
A pixel given at coordinate vector v = [x,y,z]^T will be transformed using the following" === Transform3D Times a Transform3D ===
Line 53: Line 77:
{{{`vhat = T_post R T_pre v`}}} 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}$$}}}) from Python. To answer this question we look at the details
Line 55: Line 79:
Where the rotation matrix R and associated conventions are defined in Baldwin and Penczek 2007. {{{$$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}\hat{t}_{1,pre}+\hat{t}_{1,post}],[\hat{0}^T,1]]$$}}}
Line 57: Line 81:
{{{$$ = T_{2,post} R_{2} [[R_{1},R_{1}\hat{t}_{1,pre}+\hat{t}_{1,post}+\hat{t}_{2,pre}],[\hat{0}^T,1]]$$}}}
Line 58: Line 83:
=== Transformations and projections === The translation in right column ({{{$$R_{1}\hat{t}_{1,pre}+\hat{t}_{1,post}+\hat{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}\hat{t}_{1,pre}+\hat{t}_{1,post}+\hat{t}_{2,pre})+\hat{t}_{2,post}],[\hat{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 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 \hat{v} = [[R,R\hat{t}_{pre}+\hat{t}_{post}],[\hat{0}^T,1]] \hat{v} $$}}}

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

The vector v is treated implicitly as though it were an homogeneous coordinate, 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 Vector (Vec3f) ===

If a Transform3D is represented as

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

One can calculate

{{{$$\hat{v}_R = R \hat{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)
}}}

== Transformations and projections ==
Line 62: Line 136:
{{{`p(x,y) = int T M(x,y,z) dz`}}} {{{$$p(x,y) = int_z T3D M(x,y,z) dz$$}}}
Line 64: Line 138:
That is, the projection is generated by first transforming the 3D map M by the Transform3D object, and proceeded by taking line integrals along z. That is, the projection is generated in an equivalent fashion to first transforming the 3D map M by the Transform3D object, and followed by taking line integrals along z. In EMAN2 real space projection applies the inverse of the Transform3D object to the coordinate system to achieve the same result, and this is to avoid having to interpolate multiple times.
Line 66: Line 140:
=== Transformations and recontructors === == Transformations and recontructors ==

TableOfContents

Transformations in EMAN2

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 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,\hat{t}],[\hat{0}^T,1]]$$

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

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

In this way the result of applying a Transform3D to a vector is literally a rotation follow 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,\hat{t}_{post}],[\hat{0}^T,1]] [[R,\hat{0}],[\hat{0}^T,1]] [[I,\hat{t}_{pre}],[\hat{0}^T,1]] = [[R,R\hat{t}_{pre}+\hat{t}_{post}],[\hat{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}$$) from Python. 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}\hat{t}_{1,pre}+\hat{t}_{1,post}],[\hat{0}^T,1]]$$

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

The translation in right column ($$R_{1}\hat{t}_{1,pre}+\hat{t}_{1,post}+\hat{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}\hat{t}_{1,pre}+\hat{t}_{1,post}+\hat{t}_{2,pre})+\hat{t}_{2,post}],[\hat{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 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 \hat{v} =  [[R,R\hat{t}_{pre}+\hat{t}_{post}],[\hat{0}^T,1]] \hat{v}  $$

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

The vector v is treated implicitly as though it were an homogeneous coordinate, 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 Vector (Vec3f)

If a Transform3D is represented as

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

One can calculate

$$\hat{v}_R = R \hat{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)

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 is generated in an equivalent fashion to first transforming the 3D map M by the Transform3D object, and followed by taking line integrals along z. In EMAN2 real space projection applies the inverse of the Transform3D object to the coordinate system to achieve the same result, and this is to avoid having to interpolate multiple times.

Transformations and recontructors

In order to insert a projection as generated in the conventional way (above) into a 3D volume in the correct orientation, one must invert the Transform3D object that was used to generate the projection prior to slice insertion.

EMAN2/TransformConventions (last edited 2009-02-04 21:14:56 by DavidWoolford)