I am attempting to use the inverse mapping approach to multiply an inv(3x3) matrix to an image(540x420) to rotate it! I cannot use any toolbox functions and am attempting to do a double FOR loop. I am confused about how this works if anyone could help me out it would be greatly appreciated!
NOTE: A is the image! I have a bilinear interpretation code after this that will fix the image accordingly. I am just a having a hard time wrapping my head around this (3x3) * (540x420) matrix.
[xold,yold,k] = size(A);
xnew = xold;
ynew = yold;
Rot = [cosd(angle) -sind(angle) 0 ; sin(angle) cos(angle) 0; 0 0 1];
InverseRot = double(inv(Rot));
E = zeros(xnew, ynew,k);
E = double(E);
A = double(A);
for i=1:ynew
for j=1:xnew
E(i,:) = %This is where I'm confused
end
end
You're not multiplying the inverse rotation matrix by the image, you're multiplying it by the homogeneous coordinates of a point in the new image to get the corresponding homogeneous coordinates in the original image.
newpt = [xnew ynew 1].';
origpt = InverseRot*newpt;
xold = origpt(1);
yold = origpt(2);
Notes:
Your rotation matrix mixes the degree and radian versions of the trig functions. That will mess up your results.
Rotations without translations are about the origin. Your image is not centered at the origin. You'll need to do something about that.
The inverse of a rotation matrix is the same as its transpose. If you fix the note above, you'll end up with an affine transformation matrix rather than a straight rotation matrix. This also has an easier way to calculate the inverse. If the affine transformation matrix is [R | t; 0 | 1], the inverse is [RT | -RT*t; 0 | 1] where RT is the transpose of R.
The coordinates in the original image that you get after transformation are not likely to be integers, so you won't be able to simply assign the value of a pixel in the old image to a pixel in the new image. As you said, you'll have to find some way to interpolate the value and assign that to the point in the new image.
Related
Decomposing rotation matrix (x,y',z'') - Cartesian angles
Im currently working with rotation matrices and I have the following problem:
Given three coordinate systems (O0,x0,y0,z0; O1,x1,y1,z1; O2,x2,y2,z2) which coincide. We rotate first the frame #1 with the respect to frame #0, then the frame #2 with respect to frame #1.
The order of the rotations: R = Rx_alpha * Ry_beta * Rz_gamma, so first about x, then y', then z'', which are also known as the Cartesian angles.
If R1 stands for the 1st and R2 for the 2nd rotation, we are looking for the angles of the 2nd frame with respect to initial frame (#0) after both of the rotations. This can be done by decomposing the rotation matrix R (where:R = R1*R2 ). There are many literature available, how it can be done by Euler- and RPY-angles, but I don't find any, how to solve this problem in case of Cartesian angles.
I have a matlab function which works only by simple rotations. If all the angles have values different than 0 (example below), then the result becomes really unstable.
Orientation of the 1st frame with respect to the frame #0:
alpha1 = 30*pi/180;
beta1 = 10*pi/180;
gamma1 = 0*pi/180;
Orientation of the 2nd frame with respect to the frame #1
alpha2 = 10*pi/180;
beta2 = 10*pi/180;
gamma2 = 0*pi/180;
The matlab function I was using for solving the problem:
function [q] = cartesian_angles(R)
beta = asin(R(1,3));
*% Catching the numerical singularty*
if abs(abs(beta)-pi/2) > eps;
*% singulartiy of acos*
gamma1 = acos(R(1,1) / cos(beta));
gamma2 = asin(-R(1,2) / cos(beta));
if gamma2<0
gamma=2*pi-gamma1;
else
gamma=gamma1;
end
alpha1 = acos(R(3,3) / cos(beta));
alpha2 = asin(-R(2,3) / cos(beta));
if alpha2<0
alpha = 2*pi-alpha1;
else
alpha = alpha1;
end
else
fprintf('beta=pi/2 \n')
gamma = 0;
alpha = 0;
beta = 0;
end;
alpha = alpha*180/pi;
beta = beta*180/pi;
gamma = gamma*180/pi;
q = [alpha; beta; gamma];
Thank you for any help! If you have some questions don't hesitate to ask!
Marci
First, I'm going to assume you are passing into your function a well conditioned, right-handed rotation matrix. I'm going to use the same rotation sequence as you listed above, X Y' Z''
If you know the symbolic construction of the rotation matrix you are trying to extract angles from, the math is pretty straight forward. Below is an example of matlab code to determine the construction of the rotation matrix of order X-Y'-Z''
a = sym('a');%x
b = sym('b');%y
g = sym('g');%z
Rx = [1 0 0;0 cos(a) -sin(a);0 sin(a) cos(a)];
Ry = [cos(b) 0 sin(b);0 1 0;-sin(b) 0 cos(b)];
Rz = [cos(g) -sin(g) 0;sin(g) cos(g) 0;0 0 1];
R = Rz*Ry*Rx
The output looks like this:
R =
[ cos(b)*cos(g), cos(g)*sin(a)*sin(b) - cos(a)*sin(g), sin(a)*sin(g) + cos(a)*cos(g)*sin(b)]
[ cos(b)*sin(g), cos(a)*cos(g) + sin(a)*sin(b)*sin(g), cos(a)*sin(b)*sin(g) - cos(g)*sin(a)]
[ -sin(b), cos(b)*sin(a), cos(a)*cos(b)]
Here's the same result in a nicer looking format:
Now let's go over the math to extract the angles from this matrix. Now would be a good time to become comfortable with the atan2() function.
First solve for the beta angle (by the way, alpha is the rotation about the X axis, beta is the rotation about Y' axis, and gamma is the angle about the Z'' axis):
beta = atan2(-1*R(3,1),sqrt(R(1,1)^2+R(2,1)^2))
Written more formally,
Now that we have solved for the beta angle we can solve more simply for the other two angles:
alpha = atan2(R(3,2)/cos(beta),R(3,3)/cos(beta))
gamma = atan2(R(2,1)/cos(beta),R(1,1)/cos(beta))
Simplified and in a nicer format,
The above method is a pretty robust way of getting the Euler angles out of your rotation matrix. The atan2 function really makes it much simpler.
Finally I will answer how to solve for the rotation angles after a series of rotations. First consider the following notation. A vector or rotation matrix will be notated in the following way:
Here "U" represents the universal frame, or global coordinate system. "Fn" represents the nth local coordinate system that is different from U. R means rotation matrix (this notation could also be used for homogeneous transformations). The left side superscript will always represent the parent frame of reference of the rotation matrix or vector. The left side subscript indicates the child frame of reference. For example, if I have a vector in F1 and I want to know what it is equivalently in the universal frame of reference I would perform the following operation:
To get the vector resolved in the universal frame I simply multiplied it by the rotation matrix that transforms things from F1 to U. Notice how the subscripts are "cancelled" out by the superscript of the next item in the equation. This is a clever notation to help someone from getting things mixed up. If you recall, a special property of well conditioned rotation matrices is that the inverse matrix is the transpose of the matrix, which is will also be the inverse transformation like this:
Now that the notation details are out of the way, we can start to consider solving for complicated series of rotations. Lets say I have "n" number of coordinate frames (another way of saying "n" distinct rotations). To figure out a vector in the "nth" frame in the universal frame I would do the following:
To determine the Cardan/Euler angles that result from "n" rotations, you already know how to decompose the matrix to get the correct angles (also known as inverse kinematics in some fields), you simply need the correct matrix. In this example I am interested in the rotation matrix that takes things in the "nth" coordinate frame and resolves them into the Universal frame U:
There is it, I combined all the rotations into the one of interest simply by multiplying in the correct order. This example was easy. More complicated cases come when someone wants to find the reference frame of one rigid body resolved in the frame of another and the only thing the two rigid bodies have in common is their measurement in a universal frame.
I want to also note that this notation and method can also be used with homogeneous transformations but with some key differences. The inverse of a rotation matrix is its transpose, this is not true for homogeneous transformations.
Thank you for you answer willpower2727, your answer was really helpful!
But I would like to mention, that the code you have shown is useful to decompose rotational matrices, which are built in the following way:
R = Rz*Ry*Rx
What I'm looking for:
R = Rx*Ry*Rz
Which results into the following rotational matrix:
However, it's not a problem, as following the method how you calculate the angles alpha, beta and gamma, it was easy to modify the code so it decomposes the matrix shown above.
The angles:
beta = atan2( R(1,3), sqrt(R(1,1)^2+(-R(1,2))^2) )
alpha = atan2( -(R(2,3)/cos(beta)),R(3,3)/cos(beta) )
gamma = atan2( -(R(1,2)/cos(beta)),R(1,1)/cos(beta) )
One thing is still not clear though. The method is perfectly useful, bunt only if I calculate the angles after one rotation. As there are more rotations linked after each other, the results are false. However, it's still solvable, I guess, considering the following way: Let's say, we have two rotations linked after each other (R1 and R2). q1 shows the angles of R1, q2 of R2. after decomposing the single matrices. The total angle of rotation of the matrix R=R1*R2can be easily calculated through summing up the rangles before: q=q1+q2
Is there no way, how to calculate the angles of the total rotation, not by summing the partial angles, but decomposing the matrix R=R1*R2?
UPDATE:
Considering the following basic example. The are to rotations linked after each other:
a1 = 10*pi/180
b1 = 20*pi/180
g1 = 40*pi/180
R1 = Rx_a1*Ry_b1_Rz_g1
a2 = 20*pi/180
b2 = 30*pi/180
g2 = 30*pi/180
R2 = Rx_a2*Ry_b2*Rz_g2
Decomposing the individual matrices R1 and R2 results in the rights angles. The problem occures, when I link the rotations after each other and I try to determinate the angles of the last frame in the inertial frame. Theoretically this could be done by decomposing the product of all rotational matrices of the chain of transformations.
R = R1*R2
Decomposing this matrix gives the following false result shown in degrees:
a = 0.5645
b = 54.8024
g = 61.4240
Marci
I have images (matrix) in matlab and I look for the maximum intensity point from the center of the matrix in every direction to obtain edges. (I use the gradient of the image and I'm looking for a quadrilateral).
For M (n,m)
My first try was to consider one vector M(1:n/2, m/2), look for the maximum and rotate the image to find all maximums in all other directions.
But : the imrotate function causes many errors (crop or loose) and the reconstructed image doesn't correspond to the shape of the original one.
I tried also to consider vectors directly in the original image from center to all points in the perimeter... but it's not easy!
Do you have an idea to solve this ? Any subtlety in Matlab I don't know?
Thanks guy;
My actual code is
s_im = size(ima, 2)/2;
ima_max = zeros(size(ima));
ima_new = zeros(size(ima));
for a=0:359
im_r = imrotate(ima, a, 'crop');
c= floor(size(im_r,1)/2);
vect_h1 = im_r(c, 1:c);
l = length(vect_h1);
[~, id_h1] = max(vect_h1(:));
[x,y] = rotatePoint([id_h1, c], [c,c], deg2rad(a-180));
ima_max(floor(y), floor(x))= 1;
ima_new(floor(y), floor(x)) = 1;
An error is also that the center computed is not the same in all images...
I suppose you can use improfile to get the intensity along rays emitting from the center pixel:
sz = size(ima);
X = sz(2);
Y = sz(1);
all_end_points = cat(1, [ones(1,Y); 1:Y]', ...
[1:X; Y*ones(1,X)]', ...
[X*ones(1,Y); Y:-1:1]', ...
[X:-1:1; ones(1,X)]' );
cent = repmat( [X/2 Y/2], [size(all_end_points,1), 1]);
all_profs = improfile(ima, all_end_points(:,1), all_end_points(:,2));
Now you have all the profiles from the center, you can look for the max intensity along each.
I have two images which one of them is the Original image and the second one is Transformed image.
I have to find out how many degrees Transformed image was rotated using 3x3 transformation matrix. Plus, I need to find how far translated from origin.
Both images are grayscaled and held in matrix variables. Their sizes are same [350 500].
I have found a few lecture notes like this.
Lecture notes say that I should use the following matrix formula for rotation:
For translation matrix the formula is given:
Everything is good. But there are two problems:
I could not imagine how to implement the formulas using MATLAB.
The formulas are shaped to find x',y' values but I already have got x,x',y,y' values. I need to find rotation angle (theta) and tx and ty.
I want to know the equivailence of x, x', y, y' in the the matrix.
I have got the following code:
rotationMatrix = [ cos(theta) sin(theta) 0 ; ...
-sin(theta) cos(theta) 0 ; ...
0 0 1];
translationMatrix = [ 1 0 tx; ...
0 1 ty; ...
0 0 1];
But as you can see, tx, ty, theta variables are not defined before used. How can I calculate theta, tx and ty?
PS: It is forbidden to use Image Processing Toolbox functions.
This is essentially a homography recovery problem. What you are doing is given co-ordinates in one image and the corresponding co-ordinates in the other image, you are trying to recover the combined translation and rotation matrix that was used to warp the points from the one image to the other.
You can essentially combine the rotation and translation into a single matrix by multiplying the two matrices together. Multiplying is simply compositing the two operations together. You would this get:
H = [cos(theta) -sin(theta) tx]
[sin(theta) cos(theta) ty]
[ 0 0 1]
The idea behind this is to find the parameters by minimizing the error through least squares between each pair of points.
Basically, what you want to find is the following relationship:
xi_after = H*xi_before
H is the combined rotation and translation matrix required to map the co-ordinates from the one image to the other. H is also a 3 x 3 matrix, and knowing that the lower right entry (row 3, column 3) is 1, it makes things easier. Also, assuming that your points are in the augmented co-ordinate system, we essentially want to find this relationship for each pair of co-ordinates from the first image (x_i, y_i) to the other (x_i', y_i'):
[p_i*x_i'] [h11 h12 h13] [x_i]
[p_i*y_i'] = [h21 h22 h23] * [y_i]
[ p_i ] [h31 h32 1 ] [ 1 ]
The scale of p_i is to account for homography scaling and vanishing points. Let's perform a matrix-vector multiplication of this equation. We can ignore the 3rd element as it isn't useful to us (for now):
p_i*x_i' = h11*x_i + h12*y_i + h13
p_i*y_i' = h21*x_i + h22*y_i + h23
Now let's take a look at the 3rd element. We know that p_i = h31*x_i + h32*y_i + 1. As such, substituting p_i into each of the equations, and rearranging to solve for x_i' and y_i', we thus get:
x_i' = h11*x_i + h12*y_i + h13 - h31*x_i*x_i' - h32*y_i*x_i'
y_i' = h21*x_i + h22*y_i + h23 - h31*x_i*y_i' - h32*y_i*y_i'
What you have here now are two equations for each unique pair of points. What we can do now is build an over-determined system of equations. Take each pair and build two equations out of them. You will then put it into matrix form, i.e.:
Ah = b
A would be a matrix of coefficients that were built from each set of equations using the co-ordinates from the first image, b would be each pair of points for the second image and h would be the parameters you are solving for. Ultimately, you are finally solving this linear system of equations reformulated in matrix form:
You would solve for the vector h which can be performed through least squares. In MATLAB, you can do this via:
h = A \ b;
A sidenote for you: If the movement between images is truly just a rotation and translation, then h31 and h32 will both be zero after we solve for the parameters. However, I always like to be thorough and so I will solve for h31 and h32 anyway.
NB: This method will only work if you have at least 4 unique pairs of points. Because there are 8 parameters to solve for, and there are 2 equations per point, A must have at least a rank of 8 in order for the system to be consistent (if you want to throw in some linear algebra terminology in the loop). You will not be able to solve this problem if you have less than 4 points.
If you want some MATLAB code, let's assume that your points are stored in sourcePoints and targetPoints. sourcePoints are from the first image and targetPoints are for the second image. Obviously, there should be the same number of points between both images. It is assumed that both sourcePoints and targetPoints are stored as M x 2 matrices. The first columns contain your x co-ordinates while the second columns contain your y co-ordinates.
numPoints = size(sourcePoints, 1);
%// Cast data to double to be sure
sourcePoints = double(sourcePoints);
targetPoints = double(targetPoints);
%//Extract relevant data
xSource = sourcePoints(:,1);
ySource = sourcePoints(:,2);
xTarget = targetPoints(:,1);
yTarget = targetPoints(:,2);
%//Create helper vectors
vec0 = zeros(numPoints, 1);
vec1 = ones(numPoints, 1);
xSourcexTarget = -xSource.*xTarget;
ySourcexTarget = -ySource.*xTarget;
xSourceyTarget = -xSource.*yTarget;
ySourceyTarget = -ySource.*yTarget;
%//Build matrix
A = [xSource ySource vec1 vec0 vec0 vec0 xSourcexTarget ySourcexTarget; ...
vec0 vec0 vec0 xSource ySource vec1 xSourceyTarget ySourceyTarget];
%//Build RHS vector
b = [xTarget; yTarget];
%//Solve homography by least squares
h = A \ b;
%// Reshape to a 3 x 3 matrix (optional)
%// Must transpose as reshape is performed
%// in column major format
h(9) = 1; %// Add in that h33 is 1 before we reshape
hmatrix = reshape(h, 3, 3)';
Once you are finished, you have a combined rotation and translation matrix. If you want the x and y translations, simply pick off column 3, rows 1 and 2 in hmatrix. However, we can also work with the vector of h itself, and so h13 would be element 3, and h23 would be element number 6. If you want the angle of rotation, simply take the appropriate inverse trigonometric function to rows 1, 2 and columns 1, 2. For the h vector, this would be elements 1, 2, 4 and 5. There will be a bit of inconsistency depending on which elements you choose as this was solved by least squares. One way to get a good overall angle would perhaps be to find the angles of all 4 elements then do some sort of average. Either way, this is a good starting point.
References
I learned about homography a while ago through Leow Wee Kheng's Computer Vision course. What I have told you is based on his slides: http://www.comp.nus.edu.sg/~cs4243/lecture/camera.pdf. Take a look at slides 30-32 if you want to know where I pulled this material from. However, the MATLAB code I wrote myself :)
In MATLAB I make a cylinder r and shift it to the position I want which is Pos. In MATLAB I use affine2d and imwarp but unfortunately Octave doesn't have these functions.
Does anybody know how I can do this in Octave without affine2d and imwarp?
The MATLAB code is
% get image limits
limX = size(image,1)/2;
limY = size(image,2)/2;
steps = 1;
% add 30% to the inner diameter to make sure it covers the complete sparse area
largeradius = 1.5*diaStart/2;
smallradius = diaStart/2;
% generate x/y points
[x,y] = meshgrid(-limX:steps:limX,-limY:steps:limY);
% calculate the radius values:
r = sqrt(x.^2 + y.^2);
r(r>largeradius) = 0;
r(r<smallradius) = 0;
% Shift translate circle in place
r = im2bw(r);
xPos = (Pos(1)-limX);
yPos = Pos(2)-limY;
tform = affine2d([1 0 0; 0 1 0; xPos yPos 1]);
r_trans = imwarp(r,tform,'OutputView',imref2d(size(image)));
It should be easy to do. affine2d is not a problem, as it is a function that changes the data type, but doesn't modify anything.
imwarp does [x y 1] = [u v 1] * T (being T the affine transformation Matrix) for each of the pixels.
So, if you know that you want the values of the pixels in some specific locations in the transformed image, then its easy to know them
In other words: you have an image r (composed by [u v 1] pixels, a transformation tform and you know that you want to know how a new image is created by that. The new image r_trans is composed by [x y 1] pixels, and you know [x,y,1] values.
Basically, you want to get r(u,v) for each [u,v,1]=[x y 1]*T^(-1);.
x will be 1:size(r,1), and y=1:size(r,2).
Therefore computing [u,v,1]=[x y 1]*T^(-1); is not a problem.
Now, you want to access r(u,v), and u and v wont be integers, they will be floating point values. To be able to get ther` values you will need interpolation.
For that, you need to use this simple piece of code;
[X,Y]=meshgrid(1:size(r,1),1:size(r,2));
value=interp2(X,Y,r,ui,vi,method); %chose method from https://www.gnu.org/software/octave/doc/interpreter/Multi_002ddimensional-Interpolation.html
r_trans(xi,yi)=value;
I didn't give you the whole code, but hopefully you understand how to do it.
I have a 3D matrix and want to calculate the gradient for this matrix. The only step which I did is defining image gradient for a 2D image as follow:
sx = [-1 0 1; -2 0 2; -1 0 1];
sy = [1 2 1; 0 0 0; -1 -2 -1];
Gx = conv2(input, sx, 'same');
Gy = conv2(input, sy, 'same');
grdmg = sqrt(Gx.^2+Gy.^2);
grddr = atan2(Gy,Gx);
I am wondering that how I can extend this code to 3D? I know that in 3D matrix I should use convn, but do not know that how I should change the sx, sy and make sz.
If you want to calculate a 3D gradient, you would have to make your kernel 3D as well. Not only are you checking for changes in the ith slice of your matrix, but you also need to check the (i-1)th slice and the (i+1)th slice as well.
As a minor comment, sy should be the transpose of sx, but you don't have that here. Make sure you change this before you do anything.
Also, with the added dimension, you have three more possible kernels because you need to check for changes horizontally in each slice, vertically in each slice, or temporally. As such, you would simply make sz either by replicating sx along the third dimension three times, or replicating sy along the third dimension three times or making a temporal kernel where the first slice is all 1, the second slice is all zero and the third slice is all -1. Therefore, calling all of these kernels szx, szy and szz, you would create them as:
szx = cat(3, sx, sx, sx);
szy = cat(3, sy, sy, sy);
szz = cat(3, ones(3,3), zeros(3,3), -ones(3,3));
To compute the magnitude, you would simply find the magnitude of all of these components together and use convn as you have suggested:
Gx = convn(input, szx, 'same');
Gy = convn(input, szy, 'same');
Gz = convn(input, szz, 'same');
grdmg = sqrt(Gx.^2 + Gy.^2 + Gz.^2);
As for the angle, this is very ambiguous because you now have three components, and if you want to find the angle, you would need to have two vectors in 3D space and find the angle in between those two vectors. For 2D this is well defined as you have already created 2 vectors, and so the angle is simply the arctan between the vertical and horizontal components. Because you have three components, and there are two to choose from, there are three possible angles you can compute, each with respect to either the x, y or z axis.
I don't have an answer for you here in this case, but this particular example from Math StackExchange may give you further insight on how to calculate the angle using the 3D gradient. The important point is that you need to know which axis you are measuring the angle with respect to.
https://math.stackexchange.com/questions/569019/how-do-you-get-3d-gradient-direction-and-magnitude
Good luck!