There are two coordinate systems. We know the 3D coordinates of the origin and the 3D vectors of the axes of the second coordinate system with respect to the first coordinates system. Then how can we find the rotation matrix that transforms the first coordinate system into the second coordinate system?
The problem described can be solved as follows. Let
M = m_11 m_12 m_13
m_21 m_22 m_23
m_31 m_32 m_33
denote the desired rotation matrix. We require
1 0 0 * M + t = x_x x_y x_z
0 1 0 y_x y_y y_z
0 0 1 z_x z_y z_y
where t denotes the translation; we see that this matrix equality can be solved by multiplying from the left with the identity matrix, which is the inverse of itself; hence we obtain the following equality.
M + t = x_x x_y x_z
y_x y_y y_z
z_x z_y z_y
This can be rearranged by subtracting t from both sides to obtain the desired matrix M as follows.
M = x_x x_y x_z - t = x_x-t_x x_y-t_y x_z-t_z
y_x y_y y_z y_x-t_x y_y-t_y y_z-t_z
z_x z_y z_y z_x-t_x z_y-t_y z_z-t_z
Note that this was relatively easy as the initial matrix consists out of the basic vectors of the standard base. In general it is more difficult and involves a basis transformation, which basically can be done by Gaussian elimination, but can be numerically difficult.
I've written an article about it that demonstrates how to do it, with source code. The short answer is that you build a 3x3 matrix with the dot products of the different axis
http://www.meshola.com/Articles/converting-between-coordinate-systems
I think the change of basis could help youWiki Link. Its quite easy to implement.
Let A be the 4x4 matrix defining the relationship between the two coordinate systems.
Then the angle between the two is:
θ = arcos(trace(A)/2.0)
Related
I'm currently implementing an algorithm for 3D pointcloud filtering following a scientific paper.
I run in some problems when computing the rotation matrix for specific values. The goal is to rotate points into the coordinatesystem which is defined by the direction of the normal vector ( Z Axis). Since the following query is rotationally symmetric in X,Y axis, the orientation of these axis does not matter.
R is defined as follows: Rotationmatrix
[1 1 -(nx+ny)/nz]
R = [ (row1 x row3)' ]
[nx ny nz ]
n is normalized. The problem occures when n_z becomes really small or zero. Therefore i considered to normalize row 1 before computing the crossproduct for row 2.
Nevertheless the determinant becomes -1. Will the rotationmatrix sill lead to correct results? R is orthogonal but det|R| not +1
thanks for any suggestions
You always get that
det(a, a×b, b) = - det( a, b, a×b)
= - dot(a×b, a×b)
is always negative. Thus you need to change the second row by negating it or by re-arranging the overall order of the rows.
Are you interested in rotating points around arbitrary axis? If yes, maybe quaternions is good solution.
You can check this if you want to transform a quaternion to matrix before you actually use it.
Say I have 2 3D vectors, each describing a direction in 3D space (or a rotation, but I'm not sure if that terminology is correct). How would I calculate the difference between the two vectors as an Euler angle? That is, if I applied the angle to the first vector, it would rotate to equal the other? I understand how Euler angles have issues and are implementation-dependant, but I don't know what the implications of this are on a question such as mine.
To clarify a little, when I say "3D vectors", I'm picturing the "translation" gizmo you get in most 3D modelling packages or in Unity (which is what I'm using).
EDIT: Actually I just reviewed the "vectors" that I'm using, and what I said is not quite correct. I actually have 6 vectors, 3 for each rotation. Each vector is a position in 3D space offset from the centre of rotation. This probably makes an already-difficult question near-impossible, right?
ADDITIONAL INFORMATION: Ok, so I've worked out what I actually want to ask (because this question is really badly done), and it applies more to Unity, so I've asked a more Unity-specific question over on Unity Answers.
I'm don't normally understand mathematical formulae that are posted online, so C++-styled pseudo-code would be by far the most helpful for me.
Any help would be much appreciated, and if my question lacks certain information, please just ask for more :)
If you are going to do 3d you need to understand linear algebra and matrix notation.[1] Affine 4x4 matrices are the basis of space transformations in all 3d applications I've ever seen, (Euler angles just give alternate means to describe that matrix). Even unity uses matrices, although to be able to efficiently do the Euler-Lagrange particle motion equation they prefer to have the decomposed form. A matrix encodes a entire space with 4 vectors. This is conceptually easy in this case (not the only use for matrices), the matrix encodes the directions x y z and offset vector w.
The reason matrix notation is useful is: It becomes possible to manipulate the things like normal math symbols. If you remember from school solving x from:
a * x = b
Divide both sides by a and you get
a/a * x = b /a ->
x = b / a
Now if you have 2 spaces with 3 vectors each you essentially have 2 fully formed spaces at origin. Assuming the vectors span a 3D space (in other words dont point all in one plane, its even better if they are orthogonal to each other in which case you can just use transformation functions directly). That means you have 3 spaces. So your problem is given you know 2 spaces. You need to know the space transform form space A -> space B (its customary to give matrices big letters to denote they are more complex). This is mathematically:
A * X = B
Where * is a matrix multiplications and A, X and B are transformation matrices. So then divide by A, but alas there's no matrix division, fortunately there is inverse and division is multiplication by inverse so that's what we do instead. Also one other note rotations are not commutative so we need to specify on which side we multiply so because A is before X we multiply on the left hand side with inverse of A. So we get:
A^-1 * A * X = A^-1 * B
Where ^-1 denotes matrix inverse. This simplifies to :
I * X = A^-1 * B ->
X = A^-1 * B
X is the rotation space. In unity code this looks like:
X = A.inverse * B
Where X, A and B are Matrix4x4 elements The language you use may have other conventions I'm using the java script reference here. You can covert this matrix to a quaternion and from there to Euler angles an example of this can be found here.
How to form A and B from the vectors? Just put the vector for starting space to A's columns 0-2 and destination spaces correspondingly to B columns[2].
[1] Yes its compulsory, its much simpler than it may seem at first. While you can live quite far without them they aren't any harder to use than saying rotate about x axis fro so and so. Also learn quats.
[2] I should check this, but unity seems to use column matrices so it should be right
PS: By the way if you have noisy data and more then 3 vectors per instance then you can use least squares to average the matrix t a 3 by 3 sub matrix.
sorry - I should know this but I don't.
I have computed the position of a reference frame (S1) with respect to a base reference frame (S0) through two different processes that give me two different 4x4 affine transformation matrices. I'd like to compute an error between the two but am not sure how to deal with the rotational component. Would love any advice.
thank you!
If R0 and R1 are the two rotation matrices which are supposed to be the same, then R0*R1' should be identity. The magnitude of the rotation vector corresponding to R0*R1' is the rotation (in radians, typically) from identity. Converting rotation matrices to rotation vectors is efficiently done via Rodrigues' formula.
To answer your question with a common use case, Python and OpenCV, the error is
r, _ = cv2.Rodrigues(R0.dot(R1.T))
rotation_error_from_identity = np.linalg.norm(r)
You are looking for the single axis rotation from frame S1 to frame S0 (or vice versa). The axis of the rotation isn't all that important here. You want the rotation angle.
Let R0 and R1 be the upper left 3x3 rotation matrices from your 4x4 matrices S0 and S1. Now compute E=R0*transpose(R1) (or transpose(R0)*R1; it doesn't really matter which.)
Now calculate
d(0) = E(1,2) - E(2,1)
d(1) = E(2,0) - E(0,2)
d(2) = E(0,1) - E(1,0)
dmag = sqrt(d(0)*d(0) + d(1)*d(1) + d(2)*d(2))
phi = asin (dmag/2)
I've left out some hairy details (and these details can bite you). In particular, the above is invalid for very large error angles (error > 90 degrees) and is imprecise for large error angles (angle > 45 degrees).
If you have a general-purpose function that extracts the single axis rotation from a matrix, use it. Or if you have a general-purpose function that extracts a quaternion from a matrix, use that. (Single axis rotation and quaternions are very closely related to one another).
I would like to know how to find the rotation matrix for a set of features in a frame.
I will be more specific. I have 2 frames with 20 features, let's say frame 1 and frame 2. I could estimate the location of the features in both frames. For example let say a certain frame 1 feature at location (x, y) and I know exactly where it is so let's say (x',y').
My question is that the features are moved and probably rotated so I wanna know how to compute the rotation matrix, I know the rotation matrix for 2D:
But I don't know how to compute the angle, and how to do that? I tried a function in OpenCV which is cv2DRotationMatrix(); but the problem which as I mentioned above I don't know how to compute the angle for the rotation matrix and another problem which it gives 2*3 matrix, so it won't work out cause if I will take this 20*2 matrix, (20 is the number of features and 2 are the location in (x,y)) and multiply it by the matrix by 2*3 which is the results from the function then I will get 20*3 matrix which it doesn't seem to be realistic cause I'm working with 2D.
So what should I do? To be more specific again, show me how to compute the angle to use it in the matrix?
I'm not sure I've understood your question, but if you want to find out the angle of rotation resulting from an arbitrary transform...
A simple hack is to transform the points [0 0] and [1 0] and getting the angle of the ray from the first transformed point to the second.
o = M • [0 0]
x = M • [1 0]
d = x - o
θ = atan2(d.y, d.x)
This doesn't consider skew and other non-orthogonal transforms, for which the notion of "angle" is vague.
Have a look at this function:
cvGetAffineTransform
You give it three points in the first frame and three in the second. And it computes the affine transformation matrix (translation + rotation)
If you want, you could also try
cvGetPerspectiveTransform
With that, you can get translation+rotation+skew+lot of others.
I have two squares, S1 = (x1,y1,x2,y2) and S2 = (a1,b1,a2,b2)
I'm looking for the A transformation matrix with which
A * S1 = S2
As far as I see, A is an affine 3x3 matrix, so I have 9 unknown values.
How can I calculate these values?
thanks and best,
Viktor
There are really only four unknown values here. A rotation angle, a scale factor and an x and y translation. Of your three by three matrix the bottom row is always 0,0,1 which reduces you to six unknowns. The right hand column will be Tx,Ty,1 which are your translations (and the 1 we already know about).
The two by two "matrix" left will be your rotation and scaling. This will (off the top of my head) be something like:
ACos(B), -Asin(B)
ASin(B), aCos(B)
So in total:
ACos(B), -Asin(B), Tx
ASin(B), ACos(B), Ty
0 , 0 , 1
You extend your co-ordinate matrices with the 1 on the end of each co-ordinate to give 2x3 matrices and they then multiply to give you the four equations you need to solve for the four variables. That is left as an exercise for the reader.
A transformation matrix is a factor of scaling matrix Ss, transition matrix St and rotation matrix Sr.
Assume the old point is Po is (Xo,Yo) and as vector will be represented as (Xo Yo 1)' same for the new point Pn
Then Pnv =SsStSrPov
Where Sx is
Sx 0 0
0 Sy 0
0 0 1
St is
1 0 Tx
0 1 Ty
0 0 1
Sr is
Cos(th) -Sin(th) 0
Sin(th) Cos(th) 0
0 0 1
Now back to your question. if two point are giving to represent a rectangle we can just find the parameter of two matrix and the third one will be an identity matrix.
Rect1 is represented as Top-Left point P11 and Bottom-Right Point P12
Rect2 is represented as Top-Left point P21 and Bottom-Right Point P22
S=Ss*St
Sx 0 Tx
0 Sy Ty
0 0 1
Now you have 4 missing parameters and 4 set of equations
P21=S*P11
P22=S*P12
X[P21] =Sx*X[P11]+Tx
Y[P21] =Sy*Y[P11]+Ty
X[P22] =Sx*X[P12]+Tx
Y[P22] =Sy*Y[P12]+Ty
Solve it and you'll get your answer.
and if you have transition and rotation then
S=Sr*St.
Cos(th) -Sin(th) Tx
Sin(th) Cos(th) Ty
0 0 1
Now you have 3 missing parameters and 4 set of equations
P21=S*P11
P22=S*P12
X[P21] =Cos(th)*X[P11]-Sin(th)*Y[P11]+Tx
Y[P21] =Sin(th)*X[P11]+Cos(th)*Y[P11]+Ty
X[P22] =Cos(th)*X[P11]-Sin(th)*Y[P12]+Tx
Y[P22] =Sin(th)*X[P11]+Cos(th)*Y[P12]+Ty
Replace Cos(th) with A and Sin(th) With B and solve the equations.
X[P21] =A*X[P11]-B*Y[P11]+Tx
Y[P21] =B*X[P11]+A*Y[P11]+Ty
X[P22] =A*X[P11]-B*Y[P12]+Tx
Y[P22] =B*X[P11]+A*Y[P12]+Ty
Check if its correct A^2+B^2 =? 1 if is true then th = aCos(A)
The last part of the solution, if you'll have all three matrixes, then S=SrStSs is
Sx*sin(th) -Sx*cos(th) Tx
Sy*cos(th) Sy*sin(th) Ty
0 0 1
Now we have 5 missing variables and we need 6 different set of equations to solve it. which is mean 3 points from each rectangle.
You shouldn't have a 3x3 matrix if you're just looking to transform a 2D object. What you're looking for is a 2x2 matrix that solves A*S1=S2. This can be done in many different ways; in MATLAB, you'd do a S2/S1 (right matrix division), and generally this performs some kind of Gaussian elimination.
How can I calculate these values?
When applied to 2d/3d transformations, matrix can be represented a coordinate system, unless we are talking about projections.
Matrix rows (or columns, depending on notation) form axes of a new coordinate system, in which object will be placed placed if every object vertex is multiplied by the matrix. Last row (or columne, depending on notation) points to the center of the new coordinate system.
Standard OpenGL/DirectX transformation matrix (NOT a projection matrix):
class Matrix{//C++ code
public:
union{
float f[16];
float m[4][4];
};
};
Can be represented as combination of 4 vectors vx (x axis of the new coordinate system), vy(y axis of a new coordinate system), vz(z axis of a new coordinate system), and vp (center of the new system). Like this:
vx.x vx.y vx.z 0
vy.x vy.y vy.z 0
vz.x vz.y vz.z 0
vp.x vp.y vp.z 1
All "calculate rotation matrix", "calculate scale matrix", etc go down to this idea.
Thus, for 2d matrix, you'll have 3x3 matrix that consists of 3 vectors - vx, vy, vp, because there is no z vector in 2d. I.e.:
vx.x vx.y 0
vy.x vy.y 0
vp.x vp.y 1
To find a transform that would transform quad A into quad B, you need to find two transforms:
Transform that will move quad A into origin (i.e. at point zero), and convert it into quad of fixed size. Say, quad (rectangle) whose one vertex x = 0, y = 0, and whose vertices are located at (0, 1), (1, 0), (1, 1).
Transform that turns quad of fixed size into quad B.
You CANNOT do that it this way if opposite edges of quad are not parallel. I.e. parallelograms are fine, but random 4-sided polygons are not.
A quad can be represented by base point (vp) which can be any vertex of the quad and two vectors that define quad sizes (direction of the edge multiplied by edge's length). I.e. "up" vector and "side" vector. Which makes it a matrix:
side.x side.y 0
up.x up.y 0
vp.x vp.y 1
So, multiplying a quad (vp.x = 0, vp.y = 0, side.x = 1, side.y = 0, up.x = 0, up.y = 1) by this matrix will turn original quad into your quad. Which means, that in order to transform
quad A into quad B, you need to do this:
1) make a matrix that would transform "base 1unit quad" into quad A. Let's call it matA.
2) make a matrix that would transform "base 1 unit quad" into quad B. let's call it matB.
3) invert matA and store result into invMatA.
4) the result matrix is invMatA * matB.
Done. If you multiply quad A by result matrix, you'll get quad B. This won't work if quads have zero widths or heights, and it won't work if quads are not parallelograms.
This is hard to understand, but I cannot to make it simpler.
What do you mean by S1 = (x1,y1,x2,y2)?
Do they represent the top-left and bottom-right corners of the square?
Also, can you guarantee there's only rotation between the squares or do you need a full affine transformation which allows for scaling, skewing, and translation?
Or do you also need a perspective transformation?
Only if it's a perspective transformation, will you need 3x3 matrix with 8 dof as you've mentioned in your post.