Differences between revisions 1 and 74 (spanning 73 versions)
Revision 1 as of 2008-08-14 21:08:55
Size: 148
Comment:
Revision 74 as of 2008-08-19 17:32:45
Size: 8324
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 == [[TableOfContents]]
Line 3: Line 3:
=== Transforming an EMData Object === = Transformations in EMAN2 =
Line 5: Line 5:
When an EMData object == 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 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,\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
{{{#!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}\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

{{{#!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 =

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 line 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.

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 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,\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}$$). 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 operation can be thought of as first transforming the 3D map M by the Transform3D object, and by subsequently taking line 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.

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