9749
Comment:
|
13605
|
Deletions are marked like this. | Additions are marked like this. |
Line 3: | Line 3: |
= The center of the image = ---- The center of the image for purposes of rotations is different for odd and even sized images. For even images, the center is at (nx/2,ny/2) where the first pixel is at (0,0). For odd sized images, the center is at ((nx-1)/2,(ny-1)/2). The same concept extends to 3-D. {{attachment:center1.png}} {{attachment:center2.png}} |
|
Line 5: | Line 11: |
Line 17: | Line 21: |
= Supported Rotation Conventions = ---- ||Convention ||Angle Names ||Matrices || ||EMAN ||$$phi$$, Alt, Az ||{{{$$ [[cos phi,sin phi, 0],[-sin phi,cos phi,0],[0,0,1]] [[1,0,0],[0, cos al, sin al],[0, -sin al, cos al]] [[cos az,sin az, 0],[-sin az,cos az,0],[0,0,1]] $$}}} || ||Imagic ||$$gamma$$, $$beta$$, $$alpha$$ ||{{{$$ [[cos gamma,sin gamma, 0],[-sin gamma,cos gamma,0],[0,0,1]] [[1,0,0],[0, cos beta, sin beta],[0, -sin beta, cos beta]] [[cos alpha,sin alpha, 0],[-sin alpha,cos alpha,0],[0,0,1]] $$}}} || ||Spider ||$$psi$$, $$theta$$, $$phi$$ ||{{{$$ [[cos psi,sin psi, 0],[-sin psi,cos psi,0],[0,0,1]] [[cos theta,0,sin theta],[0, 1, 0],[-sin theta, 0, cos theta]] [[cos phi,sin phi, 0],[-sin phi,cos phi,0],[0,0,1]] $$}}} || ||MRC ||$$psi$$, $$theta$$, $$Omega$$ ||{{{$$ [[cos psi,sin psi, 0],[-sin psi,cos psi,0],[0,0,1]] [[cos theta,0,sin theta],[0, 1, 0],[-sin theta, 0, cos theta]] [[cos Omega,sin Omega, 0],[-sin Omega,cos Omega,0],[0,0,1]] $$}}} || ||XYZ ||z, y, x ||{{{$$ [[cos z,sin z, 0],[-sin z, cos z,0],[0,0,1]] [[cos y,0,sin y],[0, 1, 0],[-sin y, 0, cos y]] [[1,0,0],[0, cos x, sin x],[0, -sin x, cos x]] $$}}} || ||spin ||$$Omega$$, n1, n2, n3 ||Quaternion rotation by $$ Omega $$ degrees about the vector $$[n1,n2\,n3]$$ || ||sgirot ||q, n1, n2, n3 ||Quaternion rotation by q degrees about the vector $$[n1,n2\,n3]$$ || ||quaternion ||e0, e1, e2, e3 ||Literal quaternion rotation using $$ q = e0 + e1\mathbf{i} + e2\mathbf{j} + e2\mathbf{k} $$ || |
|
Line 20: | Line 39: |
Line 31: | Line 49: |
'''NOTE:''' All the CONVENTIONS listed on the table above can be supplied as arguments or "values" for the "type" key in the Transform's dictionary. For example: {{{ t=Tranform({"type":"spin"}) t=Tranform({"type":"quaternion"}) t=Tranform({"type":"imagic"}) Etc. }}} |
|
Line 34: | Line 63: |
Line 43: | Line 71: |
'''NOTE:''' The '''get_rotation() method can take a string as an argument, but it does NOT require one'''; it is defaulted to 'eman'.''' That is, it will return the rotation of the transform object in 'eman' convention. You can supply ANY rotation CONVENTION as a string to get the rotation in the corresponding convention, irrespective of the "type" you set for the transform. For example, from an 'eman' type Transform, {{{ t=Transform({'type':'eman'}) You can still get the rotation in other conventions: t.get_rotation('spin') gives {'Omega': 0.0, 'n1': 0.0, 'n2': 0.0, 'n3': 0.0, 'type': 'spin'} t.get_rotation('quaternion') gives {'e0': 1.0, 'e1': 0.0, 'e2': 0.0, 'e3': 0.0, 'type': 'quaternion'} }}} |
|
Line 44: | Line 84: |
Line 51: | Line 90: |
Line 53: | Line 91: |
Line 65: | Line 101: |
Line 67: | Line 102: |
Line 74: | Line 108: |
s = Transform("tx":v[0],"ty":v[1],"tz":v[2]) # set translation as part of construction }}} |
s = Transform({"tx":v[0],"ty":v[1],"tz":v[2]}) # set translation as part of construction }}} |
Line 78: | Line 111: |
Line 91: | Line 123: |
For more information the behaviour of set_params see [[#set_params|a more in depth look at set_params ]] |
For more information the behaviour of set_params see [[#set_params|a more in depth look at set_params]] |
Line 95: | Line 126: |
Line 109: | Line 139: |
Line 111: | Line 140: |
Line 117: | Line 145: |
t.set_trans(...) | t.set_trans( ... ) |
Line 121: | Line 149: |
Line 126: | Line 153: |
t.set_params(...) t.set_trans(...) f = e.process("math.transform",{"transform":t} # memory efficient e.proceess_inplace("math.transform",{"transform":t}) }}} In fact {{{e.transform(t)}}} actually calls {{{e.proceess_inplace("math.transform",{"transform":t})}}} internally on C++ side. |
t.set_params({"type":"eman","az":10,"alt":150,"scale":2.0,"mirror":True,"tx":3.4}) t.set_trans( ... ) f = e.process("xform",{"transform":t}) # memory efficient e.proceess_inplace("xform",{"transform":t}) }}} In fact {{{e.transform(t)}}} actually calls {{{e.proceess_inplace("math.transform",{"transform":t})}}} internally on the C++ side. |
Line 139: | Line 165: |
Line 147: | Line 172: |
}}} |
}}} |
Line 151: | Line 174: |
Line 161: | Line 183: |
Line 164: | Line 184: |
Line 169: | Line 188: |
t.set_params({"type":"2d","alpha":10,"scale":2.0,"mirror":True,"dx":3.4,"dy":0.0}) # no special interface required for 2D, use the same as 3D | t.set_params({"type":"2d","alpha":10,"scale":2.0,"mirror":True,"tx":3.4,"ty":0.0}) # no special interface required for 2D, use the same as 3D |
Line 173: | Line 192: |
Line 175: | Line 193: |
Line 189: | Line 206: |
== Transforming a 2D image == Transforming a 2D image is achieved using a single function call {{{#!python t = Transform() t.set_params({"type":"2d","alpha":10,"scale":2.0,"mirror":True,"tx":3.4}) e = test_image() e.transform(t) }}} You can alternatively use the EMData processing framework, for example: {{{#!python t = Transform() t.set_params({"type":"2d","alpha":10,"scale":2.0,"mirror":True,"tx":3.4}) f = e.process("xform",{"transform":t}) # memory efficient e.proceess_inplace("xform",{"transform":t}) }}} As stated previously, {{{e.transform(t)}}} actually calls {{{e.proceess_inplace("math.transform",{"transform":t})}}} internally on the C++ side. Note that if you try to transform a 2D image using a Transform that contains 3D rotations or translations you will get an error: {{{#!python t = Transform({"type":"eman","alt":22}) # 3D rotation a = test_image() # 2D a.transform(t) # ERROR is thrown t = Transform({"tz":3}) # 3D translation a.transform(t) # ERROR is thrown }}} |
|
Line 194: | Line 238: |
Line 196: | Line 239: |
Line 200: | Line 244: |
Line 207: | Line 250: |
Line 213: | Line 255: |
Line 220: | Line 261: |
Line 226: | Line 266: |
Line 230: | Line 268: |
= A more in depth look at set_params = ---- Constructing a Transform with some dictionary is the same as calling set_params on a Transform that is the identity. |
= A more in depth look at set_params = ---- Constructing a Transform with some dictionary is the same as calling set_params on a Transform that is the identity. |
Line 240: | Line 278: |
Line 243: | Line 280: |
Line 245: | Line 281: |
Line 251: | Line 286: |
== For rotation and translation, setting one is equivalent to setting them all == |
== For rotation and translation, setting one is equivalent to setting them all == |
Contents
The center of the image
The center of the image for purposes of rotations is different for odd and even sized images. For even images, the center is at (nx/2,ny/2) where the first pixel is at (0,0). For odd sized images, the center is at ((nx-1)/2,(ny-1)/2). The same concept extends to 3-D.
What is a Transform?
We use the Transform class for storing/managing Euler angles,translations, scales and x mirroring. At any time a Transform object $$Tr$$ defines a group of 4 transformations of a rigid body that are applied in a specific order, namely
$$ Tr \equiv M T S R $$
Where $$M$$ is a mirroring operation about the x-axis, $$T$$ is a translation, $$S$$ is a uniform, positive, non zero scaling operation and $$R$$ is a rotation. The Transform object stores these transformations internally in a 3x4 matrix, which appears as
$$ Tr = [sMR,M\mathbf{t}]$$
Where $$s$$ is the constant scaling factor, $$M$$ is the identity or the x-mirroring matrix, $$R$$ is a $$3x3$$ rotation matrix and $$\mathbf{t}=(tx,ty,tz)^T$$ is the translation.
Supported Rotation Conventions
Convention |
Angle Names |
Matrices |
EMAN |
$$phi$$, Alt, Az |
$$ [[cos phi,sin phi, 0],[-sin phi,cos phi,0],[0,0,1]] [[1,0,0],[0, cos al, sin al],[0, -sin al, cos al]] [[cos az,sin az, 0],[-sin az,cos az,0],[0,0,1]] $$ |
Imagic |
$$gamma$$, $$beta$$, $$alpha$$ |
$$ [[cos gamma,sin gamma, 0],[-sin gamma,cos gamma,0],[0,0,1]] [[1,0,0],[0, cos beta, sin beta],[0, -sin beta, cos beta]] [[cos alpha,sin alpha, 0],[-sin alpha,cos alpha,0],[0,0,1]] $$ |
Spider |
$$psi$$, $$theta$$, $$phi$$ |
$$ [[cos psi,sin psi, 0],[-sin psi,cos psi,0],[0,0,1]] [[cos theta,0,sin theta],[0, 1, 0],[-sin theta, 0, cos theta]] [[cos phi,sin phi, 0],[-sin phi,cos phi,0],[0,0,1]] $$ |
MRC |
$$psi$$, $$theta$$, $$Omega$$ |
$$ [[cos psi,sin psi, 0],[-sin psi,cos psi,0],[0,0,1]] [[cos theta,0,sin theta],[0, 1, 0],[-sin theta, 0, cos theta]] [[cos Omega,sin Omega, 0],[-sin Omega,cos Omega,0],[0,0,1]] $$ |
XYZ |
z, y, x |
$$ [[cos z,sin z, 0],[-sin z, cos z,0],[0,0,1]] [[cos y,0,sin y],[0, 1, 0],[-sin y, 0, cos y]] [[1,0,0],[0, cos x, sin x],[0, -sin x, cos x]] $$ |
spin |
$$Omega$$, n1, n2, n3 |
Quaternion rotation by $$ Omega $$ degrees about the vector $$[n1,n2\,n3]$$ |
sgirot |
q, n1, n2, n3 |
Quaternion rotation by q degrees about the vector $$[n1,n2\,n3]$$ |
quaternion |
e0, e1, e2, e3 |
Literal quaternion rotation using $$ q = e0 + e1\mathbf{i} + e2\mathbf{j} + e2\mathbf{k} $$ |
The Transform object in Python
Constructing a Transform
There a four ways to construct a Transform object in Python
1 t = Transform() # default constructor, t is the identity
2 t = Transform({"type":"eman","az":10,"alt":150,"scale":2.0,"mirror":True,"tx":3.4}) # construction using a dictionary
3 p = Transform({"type":"eman","az":10,"mirror":True,"tx":3.4}) # construction using a dictionary
4 q = Transform([1,0,0,0,0,1,0,0,0,0,1,0]) # specify the 12 entries of the matrix explicitly, row wise (3 rows of 4)
5 s = Transform(t) # copy construction - s is precisely the same as t
NOTE: All the CONVENTIONS listed on the table above can be supplied as arguments or "values" for the "type" key in the Transform's dictionary. For example:
t=Tranform({"type":"spin"}) t=Tranform({"type":"quaternion"}) t=Tranform({"type":"imagic"}) Etc.
For more information on default parameters and what happens when some parameters are not set see a more in depth look at the dictionary constructor
Setting/getting rotations
NOTE: The get_rotation() method can take a string as an argument, but it does NOT require one; it is defaulted to 'eman'. That is, it will return the rotation of the transform object in 'eman' convention. You can supply ANY rotation CONVENTION as a string to get the rotation in the corresponding convention, irrespective of the "type" you set for the transform. For example, from an 'eman' type Transform,
You can tell a Transform deduce any of its parameters from a dictionary. Similarly you can get the parameters of a Transform as a dictionary For more information the behaviour of set_params see a more in depth look at set_params
The transformation of a 3D vector $$ v = (v_x,v_y,v_z)^T $$ by a Transform is defined as $$ Tr \mathbf{v} = [sMR,M\mathbf{t}] (v_x,v_y,v_z,1)^T = sMR\mathbf{v}+ M\mathbf{t} $$ This can be done in Python using the following
Transforming a 3D image is achieved using a single function call You can alternatively use the EMData processing framework, for example: In fact e.transform(t) actually calls e.proceess_inplace("math.transform",{"transform":t}) internally on the C++ side.
The Transform object can be used as though it were a 2D transformation matrix. In this case the interface for setting/getting scale and mirror is unchanged. However setting the rotation should be done using the euler type "2d", and there are some accommodations for setting and getting 2d translations and parameters.
Use the "2d" euler type, and the angle is specified using "alpha"
The interface is more or less identical to the 3D case
For getting the parameters in 2D form use the following
The transformation of a 2D vector $$ v_{2D} = (v_x,v_y)^T $$ by a Transform is equivalent to setting the z component of 3D vector to 0. If $$ v = (v_x,v_y,0)^T $$ then the 2D transformation is equivalent to the following, $$ Tr \mathbf{v_{2D}} = [sMR,M\mathbf{t}] (v_x,v_y,0,1)^T = sMR\mathbf{v}+ M\mathbf{t} $$ and the z component is ignored. Note that the internal implementation is efficient. 2D vector transformation can be done in Python using the following
Transforming a 2D image is achieved using a single function call You can alternatively use the EMData processing framework, for example: As stated previously, e.transform(t) actually calls e.proceess_inplace("math.transform",{"transform":t}) internally on the C++ side. Note that if you try to transform a 2D image using a Transform that contains 3D rotations or translations you will get an error:
The dictionary constructor, which is equivalent to calling the default constructor followed by the set_params function, takes up to 9 parameters as exemplified in the following If any of the angles or not specified they are implicitly set to 0 If no euler type is specified then the rotation matrix is the identity Similarly if any of the translation parameters are not specified they are implicitly set to 0 If scale is not specified it is by default 1.0, similarly if mirror is not specified it is be default False
Constructing a Transform with some dictionary is the same as calling set_params on a Transform that is the identity. The main difference between calling set_params explicitly on a Transform as opposed to constructing a Tranform with a dictionary lies in the fact that the construction method first sets the Transform object to the identity before calling set_params. So if calling the set_params function on a Transform that has already been initialized and had many things done than you should be aware of the following...
t=Transform({'type':'eman'})
You can still get the rotation in other conventions:
t.get_rotation('spin') gives {'Omega': 0.0, 'n1': 0.0, 'n2': 0.0, 'n3': 0.0, 'type': 'spin'}
t.get_rotation('quaternion') gives {'e0': 1.0, 'e1': 0.0, 'e2': 0.0, 'e3': 0.0, 'type': 'quaternion'}
Setting/getting scale
Setting/getting mirror
Setting/getting translation
Setting/getting parameters
1 t = Transform()
2 t.set_params({"type":"eman","az":10,"alt":150,"scale":2.0,"mirror":True,"tx":3.4})
3 d = t.get_params("eman") # must specify the euler convention
4 s = Transform(d) # s is the same as t
5 d = t.get_params("spider")
6 s = Transform(d) # s is the same as t
7 d = t.get_params("matrix")
8 s = Transform(d) # s is the same as t
A Transform multiplied by a Vec3f
Transforming a 3D image
2D degenerate use of the Transform object in Python
Setting/getting 2D rotations
Setting/getting 2D translation
Setting/getting 2D parameters
A Transform multiplied by a Vec2f
Transforming a 2D image
A more in depth look at the dictionary constructor
1 t = Transform({"scale":2.0,"mirror":True,"tx":3.4,"ty":3,"tz":2}) # Rotation matrix is the identity
1 t = Transform({"tx":3.4,"ty":3,"tz":3}) # scale is 1.0, mirror is False
A more in depth look at set_params
If unspecified, old parameters are retained
For rotation and translation, setting one is equivalent to setting them all