Inverting 3d rotation sequence - rotation

I have a transformation matrix constructed as
H = Rz * Ry * Rx. So rotations are performed in xyz order.
Now, given rotation angles around x, y, and z axes, is there a way to find rotation angles to perform inverse operation, such that
v = Rz * Ry * Rx * v0
v0 = Rz' * Ry' * Rx' * v
Just for completion sake. In the end I extracted the Euler angles from transformation matrix as described in:
Computing Euler angles from a rotation matrix - Gregory G. Slabaugh

If your matrices are purely rotation (i.e. no translation), the inverse is simply the transpose:
R-1 = RT
If your transformation includes translation like so:
A =
| R T |
| 0 1 |
Then use the transpose of the rotation matrix as above and for the translation portion, use:
T-1 = -RTT
Then
A-1 =
| R-1 T-1 |
| 0 1 |
Also note that you will have to do the inverse rotations in the inverse order:
v0 = Rx-1 * Ry-1 * Rz-1 * v

Related

Calculating the angles of the rotation giving the vertices

I have 4 points (black A, black B, black C and black D) which are the vertices of the rotated red square.
Is it possible to determine what were the three angles (x angle, y angle and z angle) used to rotate the red square into the black square?
In this case, the angles were:
X = 1rad
Y = 0.2rad
Z = 0.3rad
EDIT: I just have the four black points, not the red ones.
The only thing I know about the red square is that it is a square
There is method to find affine matrix needed to transform point set into another one.
Having natrix, you can find angles.
Description for 2D case is here, 3D case is similar.
M * A = B
where
| xa xb xc xd|
A =| ya yb yc yd|
| za zb zc zd|
| 1 1 1 1 |
| xa' xb' xc' xd'|
B =| ya' yb' yc' yd'|
| za' zb' zc' zd'|
| 1 1 1 1 |
To find unknown M, we can multiply both sides of the expression by inverse of A matrix
M * A * Inv(A) = B * Inv(A)
M = B * Inv(A)
But solution is unique for non-complanar point quadruplet - in your case points lie in the same plane, so if solution exists, it is really a family of solutions and you have to choose arbitrary one. (Perhaps angles will be defined unambiguously)

How to find given 2D point position based on axis system

I have a axis system(origin,u direction,v direction).How to know given 2D point lie on the line which is used to denote the u or v direction line(ie, u=0 or v =0)?
The axis OU has equation
Uy.(X - Ox) - Ux.(Y - Oy) = 0
and similarly for OV
Vy.(X - Ox) - Vx.(Y - Oy) = 0
Because of rounding errors, strict equality to zero will not hold, but if the vectors U and V are normalized,
|Uy.(X - Ox) - Ux.(Y - Oy)|
and
|Vy.(X - Ox) - Vx.(Y - Oy)|
are the shortest distances from the point (X, Y) to the axes.
If "given 2D point" P coordinates are presented in fixed coordinate system, then you have to represent vector P-origin in o-u-v basis.
op = P - origin
s * u.x + t * v.x = op.x
s * u.y + t * v.y = op.y
Solve last system of linear equations for unknown coefficients s and t. Check for zero coefficients.

Applying different transformations to a polygon given a describing transformation matrix

I have a 2D polygon and a 2D transformation matrix M that I use to transform the vertices of the polygon. The matrix may describe...
rotation around z axis,
scaling along x and y,
sheering along x and y axis,
translation along x and y axis.
Since we are in 2D the transformation matrix is of type 3x3. Here as an example a translation matrix by vector t and a rotation by angle a:
M_t = |1 0 t2| M_r = | cos(a) sin(a) 0|
|0 1 t1| |-sin(a) cos(a) 0|
|0 0 1 | | 0 0 1|
In my custom framework I don't have any access to the matrix values but can apply other matrixes in a row:
vertice = ( M_r * M_t ) * vertice
The above formula rotates the vertice around (0, 0) by angle a and then translates it by vector t. I know that matrix multiplications aren't commutative. So the order of multiplications is important.
My problem is now that I want to get a transformation matrix N that reflects a rotation R around the new center of the polygon, followed by a translation T, after applying an unknown transformation matrix M. Or in other words: I want to rotate and translate the polygon relative to its position and rotation given by M.
I can imagine this way of doing it, incorporating an unknown rotation and translation as part of M:
N = R * M * T
My questions are:
Is that mathematically correct?
What about an unknown sheering and scaling as part of M?
Is there a better way of doing this?

Shear Matrix as a combination of basic transformation?

I know the transformation matrices for rotation, scaling, translation etc. I also know the matrix for shear transformation. Now, I need to have the shear matrix--
[1 Sx 0]
[0 1 0]
[0 0 1]
in the form of a combination of other aforesaid transformations. Tried searching, tried brainstorming, but unable to strike! Thanks!
The x-shear operation for a shearing angle thetareduces to rotations and scaling as
follows:
(a) Rotate by theta/2 counter-clockwise.
(b) Scale with x-scaling factor = sin(theta/2) and y-scaling factor = cos(theta/2).
(c) Rotate by 45 degree clockwise.
(d) Scale with x-scaling factor = sqrt(2)/sin(theta) , and y-scaling factor= sqrt(2).
Yup it can be done, a rotation followed by non uniform scaling and reverse rotation. You can find the details here in third question http://www.cs.cmu.edu/~djames/15-462/Fall03/assts/15-462-Fall03-wrAssign1-answer.pdf. you can try the following openGL code as well. It rotates a rectangle by 45 degree then scales in x-axis. and then rotates in -26 degree i.e. atan(0.5). 0.5 comes from finding the angle between x-axis and one side after scaling in x-direction.
glRotatef(-26.0, 0.0, 0.0, 1.0);
glScalef(2,1,1);
glRotatef(45.0, 0.0, 0.0, 1.0);
glRectf(0, 0, 25.0, 25.0);
In 3D Graphics we often use a 4x4 Matrix with 16 useful elements. The Identity 4x4 Matrix is as following:
Between those sixteen elements there are 6 different shearing coefficients:
shear XY
shear XZ
shear YX
shear YZ
shear ZX
shear ZY
In Shear Matrix they are as followings:
Because there are no Rotation coefficients at all in this Matrix, six Shear coefficients along with three Scale coefficients allow you rotate 3D objects about X, Y, and Z axis using magical trigonometry (sin and cos).
Here's an example how to rotate 3D object (CCW) about its Z axis using Shear and Scale elements:
Look at 3 different Rotation patterns using Shear and Scale elements:
Shears are an elementary matrix operation, so while you can express them as "a combination of other matrix operations", doing so is really weird. Shears take the two forms:
| 1 V | | 1 0 |
| 0 1 | , | V 1 |
Whereas a rotation matrix is much more involved; the idea of expressing a shear using rotations suggests you haven't actually written these things out yet to see what you need, so let's look at this. A rotation matrix is of the form:
| cos -sin |
| sin cos |
Which can be composed as a sequence of three particular shear matrices, R = Sx x Sy x Sx:
| cos(a) -sin(a) | | 1 0 | | 1 sin(a) | | 1 0 |
| | = | | x | | x | |
| sin(a) cos(a) | | -tan(a/2) 1 | | 0 1 | | -tan(a/2) 1 |
Now, we can do some trivial matrix manipulation to get Sy. First left-multiply:
R = Sx x Sy x Sx
Sx⁻¹ x R = Sx⁻¹ x Sy x Sx
Sx⁻¹ x R = I x Sy x Sx
Sx⁻¹ x R = Sy x Sx
And then right-multiply:
Sx⁻¹ x R x Sx⁻¹ = Sy x Sx x Sx⁻¹
Sx⁻¹ x R x Sx⁻¹ = Sy x I
Sx⁻¹ x R x Sx⁻¹ = Sy
As a trivial rewrite, one shear is now two shears and a rotation.
But the much more important question is: why do you need to express the shear matrix as something else? It's already an elementary matrix form, what bizare computing environment are you in, or what crazy thing are you trying to do, that requires you to express an elementary transform as a way more complex, way slower thing to compute? =)

3D Least Squares Plane

What's the algorithm for computing a least squares plane in (x, y, z) space, given a set of 3D data points? In other words, if I had a bunch of points like (1, 2, 3), (4, 5, 6), (7, 8, 9), etc., how would one go about calculating the best fit plane f(x, y) = ax + by + c? What's the algorithm for getting a, b, and c out of a set of 3D points?
If you have n data points (x[i], y[i], z[i]), compute the 3x3 symmetric matrix A whose entries are:
sum_i x[i]*x[i], sum_i x[i]*y[i], sum_i x[i]
sum_i x[i]*y[i], sum_i y[i]*y[i], sum_i y[i]
sum_i x[i], sum_i y[i], n
Also compute the 3 element vector b:
{sum_i x[i]*z[i], sum_i y[i]*z[i], sum_i z[i]}
Then solve Ax = b for the given A and b. The three components of the solution vector are the coefficients to the least-square fit plane {a,b,c}.
Note that this is the "ordinary least squares" fit, which is appropriate only when z is expected to be a linear function of x and y. If you are looking more generally for a "best fit plane" in 3-space, you may want to learn about "geometric" least squares.
Note also that this will fail if your points are in a line, as your example points are.
The equation for a plane is: ax + by + c = z. So set up matrices like this with all your data:
x_0 y_0 1
A = x_1 y_1 1
...
x_n y_n 1
And
a
x = b
c
And
z_0
B = z_1
...
z_n
In other words: Ax = B. Now solve for x which are your coefficients. But since (I assume) you have more than 3 points, the system is over-determined so you need to use the left pseudo inverse. So the answer is:
a
b = (A^T A)^-1 A^T B
c
And here is some simple Python code with an example:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
N_POINTS = 10
TARGET_X_SLOPE = 2
TARGET_y_SLOPE = 3
TARGET_OFFSET = 5
EXTENTS = 5
NOISE = 5
# create random data
xs = [np.random.uniform(2*EXTENTS)-EXTENTS for i in range(N_POINTS)]
ys = [np.random.uniform(2*EXTENTS)-EXTENTS for i in range(N_POINTS)]
zs = []
for i in range(N_POINTS):
zs.append(xs[i]*TARGET_X_SLOPE + \
ys[i]*TARGET_y_SLOPE + \
TARGET_OFFSET + np.random.normal(scale=NOISE))
# plot raw data
plt.figure()
ax = plt.subplot(111, projection='3d')
ax.scatter(xs, ys, zs, color='b')
# do fit
tmp_A = []
tmp_b = []
for i in range(len(xs)):
tmp_A.append([xs[i], ys[i], 1])
tmp_b.append(zs[i])
b = np.matrix(tmp_b).T
A = np.matrix(tmp_A)
fit = (A.T * A).I * A.T * b
errors = b - A * fit
residual = np.linalg.norm(errors)
print("solution:")
print("%f x + %f y + %f = z" % (fit[0], fit[1], fit[2]))
print("errors:")
print(errors)
print("residual:")
print(residual)
# plot plane
xlim = ax.get_xlim()
ylim = ax.get_ylim()
X,Y = np.meshgrid(np.arange(xlim[0], xlim[1]),
np.arange(ylim[0], ylim[1]))
Z = np.zeros(X.shape)
for r in range(X.shape[0]):
for c in range(X.shape[1]):
Z[r,c] = fit[0] * X[r,c] + fit[1] * Y[r,c] + fit[2]
ax.plot_wireframe(X,Y,Z, color='k')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.show()
unless someone tells me how to type equations here, let me just write down the final computations you have to do:
first, given points r_i \n \R, i=1..N, calculate the center of mass of all points:
r_G = \frac{\sum_{i=1}^N r_i}{N}
then, calculate the normal vector n, that together with the base vector r_G defines the plane by calculating the 3x3 matrix A as
A = \sum_{i=1}^N (r_i - r_G)(r_i - r_G)^T
with this matrix, the normal vector n is now given by the eigenvector of A corresponding to the minimal eigenvalue of A.
To find out about the eigenvector/eigenvalue pairs, use any linear algebra library of your choice.
This solution is based on the Rayleight-Ritz Theorem for the Hermitian matrix A.
See 'Least Squares Fitting of Data' by David Eberly for how I came up with this one to minimize the geometric fit (orthogonal distance from points to the plane).
bool Geom_utils::Fit_plane_direct(const arma::mat& pts_in, Plane& plane_out)
{
bool success(false);
int K(pts_in.n_cols);
if(pts_in.n_rows == 3 && K > 2) // check for bad sizing and indeterminate case
{
plane_out._p_3 = (1.0/static_cast<double>(K))*arma::sum(pts_in,1);
arma::mat A(pts_in);
A.each_col() -= plane_out._p_3; //[x1-p, x2-p, ..., xk-p]
arma::mat33 M(A*A.t());
arma::vec3 D;
arma::mat33 V;
if(arma::eig_sym(D,V,M))
{
// diagonalization succeeded
plane_out._n_3 = V.col(0); // in ascending order by default
if(plane_out._n_3(2) < 0)
{
plane_out._n_3 = -plane_out._n_3; // upward pointing
}
success = true;
}
}
return success;
}
Timed at 37 micro seconds fitting a plane to 1000 points (Windows 7, i7, 32bit program)
This reduces to the Total Least Squares problem, that can be solved using SVD decomposition.
C++ code using OpenCV:
float fitPlaneToSetOfPoints(const std::vector<cv::Point3f> &pts, cv::Point3f &p0, cv::Vec3f &nml) {
const int SCALAR_TYPE = CV_32F;
typedef float ScalarType;
// Calculate centroid
p0 = cv::Point3f(0,0,0);
for (int i = 0; i < pts.size(); ++i)
p0 = p0 + conv<cv::Vec3f>(pts[i]);
p0 *= 1.0/pts.size();
// Compose data matrix subtracting the centroid from each point
cv::Mat Q(pts.size(), 3, SCALAR_TYPE);
for (int i = 0; i < pts.size(); ++i) {
Q.at<ScalarType>(i,0) = pts[i].x - p0.x;
Q.at<ScalarType>(i,1) = pts[i].y - p0.y;
Q.at<ScalarType>(i,2) = pts[i].z - p0.z;
}
// Compute SVD decomposition and the Total Least Squares solution, which is the eigenvector corresponding to the least eigenvalue
cv::SVD svd(Q, cv::SVD::MODIFY_A|cv::SVD::FULL_UV);
nml = svd.vt.row(2);
// Calculate the actual RMS error
float err = 0;
for (int i = 0; i < pts.size(); ++i)
err += powf(nml.dot(pts[i] - p0), 2);
err = sqrtf(err / pts.size());
return err;
}
As with any least-squares approach, you proceed like this:
Before you start coding
Write down an equation for a plane in some parameterization, say 0 = ax + by + z + d in thee parameters (a, b, d).
Find an expression D(\vec{v};a, b, d) for the distance from an arbitrary point \vec{v}.
Write down the sum S = \sigma_i=0,n D^2(\vec{x}_i), and simplify until it is expressed in terms of simple sums of the components of v like \sigma v_x, \sigma v_y^2, \sigma v_x*v_z ...
Write down the per parameter minimization expressions dS/dx_0 = 0, dS/dy_0 = 0 ... which gives you a set of three equations in three parameters and the sums from the previous step.
Solve this set of equations for the parameters.
(or for simple cases, just look up the form). Using a symbolic algebra package (like Mathematica) could make you life much easier.
The coding
Write code to form the needed sums and find the parameters from the last set above.
Alternatives
Note that if you actually had only three points, you'd be better just finding the plane that goes through them.
Also, if the analytic solution in unfeasible (not the case for a plane, but possible in general) you can do steps 1 and 2, and use a Monte Carlo minimizer on the sum in step 3.
CGAL::linear_least_squares_fitting_3
Function linear_least_squares_fitting_3 computes the best fitting 3D
line or plane (in the least squares sense) of a set of 3D objects such
as points, segments, triangles, spheres, balls, cuboids or tetrahedra.
http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Principal_component_analysis_ref/Function_linear_least_squares_fitting_3.html
It sounds like all you want to do is linear regression with 2 regressors. The wikipedia page on the subject should tell you all you need to know and then some.
All you'll have to do is to solve the system of equations.
If those are your points:
(1, 2, 3), (4, 5, 6), (7, 8, 9)
That gives you the equations:
3=a*1 + b*2 + c
6=a*4 + b*5 + c
9=a*7 + b*8 + c
So your question actually should be: How do I solve a system of equations?
Therefore I recommend reading this SO question.
If I've misunderstood your question let us know.
EDIT:
Ignore my answer as you probably meant something else.
We first present a linear least-squares plane fitting method that minimizes the residuals between the estimated normal vector and provided points.
Recall that the equation for a plane passing through origin is Ax + By + Cz = 0, where (x, y, z) can be any point on the plane and (A, B, C) is the normal vector perpendicular to this plane.
The equation for a general plane (that may or may not pass through origin) is Ax + By + Cz + D = 0, where the additional coefficient D represents how far the plane is away from the origin, along the direction of the normal vector of the plane. [Note that in this equation (A, B, C) forms a unit normal vector.]
Now, we can apply a trick here and fit the plane using only provided point coordinates. Divide both sides by D and rearrange this term to the right-hand side. This leads to A/D x + B/D y + C/D z = -1. [Note that in this equation (A/D, B/D, C/D) forms a normal vector with length 1/D.]
We can set up a system of linear equations accordingly, and then solve it by an Eigen solver in C++ as follows.
// Example for 5 points
Eigen::Matrix<double, 5, 3> matA; // row: 5 points; column: xyz coordinates
Eigen::Matrix<double, 5, 1> matB = -1 * Eigen::Matrix<double, 5, 1>::Ones();
// Find the plane normal
Eigen::Vector3d normal = matA.colPivHouseholderQr().solve(matB);
// Check if the fitting is healthy
double D = 1 / normal.norm();
normal.normalize(); // normal is a unit vector from now on
bool planeValid = true;
for (int i = 0; i < 5; ++i) { // compare Ax + By + Cz + D with 0.2 (ideally Ax + By + Cz + D = 0)
if ( fabs( normal(0)*matA(i, 0) + normal(1)*matA(i, 1) + normal(2)*matA(i, 2) + D) > 0.2) {
planeValid = false; // 0.2 is an experimental threshold; can be tuned
break;
}
}
We then discuss its equivalence to the typical SVD-based method and their comparison.
The aforementioned linear least-squares (LLS) method fits the general plane equation Ax + By + Cz + D = 0, whereas the SVD-based method replaces D with D = - (Ax0 + By0 + Cz0) and fits the plane equation A(x-x0) + B(y-y0) + C(z-z0) = 0, where (x0, y0, z0) is the mean of all points that serves as the origin of the new local coordinate frame.
Comparison between two methods:
The LLS fitting method is much faster than the SVD-based method, and is suitable for use when points are known to be roughly in a plane shape.
The SVD-based method is more numerically stable when the plane is far away from origin, because the LLS method would require more digits after decimal to be stored and processed in such cases.
The LLS method can detect outliers by checking the dot product residual between each point and the estimated normal vector, whereas the SVD-based method can detect outliers by checking if the smallest eigenvalue of the covariance matrix is significantly smaller than the two larger eigenvalues (i.e. checking the shape of the covariance matrix).
We finally provide a test case in C++ and MATLAB.
// Test case in C++ (using LLS fitting method)
matA(0,0) = 5.4637; matA(0,1) = 10.3354; matA(0,2) = 2.7203;
matA(1,0) = 5.8038; matA(1,1) = 10.2393; matA(1,2) = 2.7354;
matA(2,0) = 5.8565; matA(2,1) = 10.2520; matA(2,2) = 2.3138;
matA(3,0) = 6.0405; matA(3,1) = 10.1836; matA(3,2) = 2.3218;
matA(4,0) = 5.5537; matA(4,1) = 10.3349; matA(4,2) = 1.8796;
// With this sample data, LLS fitting method can produce the following result
// fitted normal vector = (-0.0231143, -0.0838307, -0.00266429)
// unit normal vector = (-0.265682, -0.963574, -0.0306241)
// D = 11.4943
% Test case in MATLAB (using SVD-based method)
points = [5.4637 10.3354 2.7203;
5.8038 10.2393 2.7354;
5.8565 10.2520 2.3138;
6.0405 10.1836 2.3218;
5.5537 10.3349 1.8796]
covariance = cov(points)
[V, D] = eig(covariance)
normal = V(:, 1) % pick the eigenvector that corresponds to the smallest eigenvalue
% normal = (0.2655, 0.9636, 0.0306)

Resources