How to convert a rotation matrix to axis angle form? - matlab

theta=acos((trace(R)-1)/2);
if trace(R)==3
vec = [0 0 0];
axang=[0 0 0 0];
vec(1)=R(3,2)-R(2,3);
vec(2)=R(1,3)-R(3,1);
vec(3)=R(2,1)-R(1,2);
vec=(1/(2*sin(theta)))*vec;
axang = [vec, theta];
elseif trace(R)==-1
vec=[0 0 0;0 0 0];
axang=[0 0 0 0;0 0 0 0];
X=[0 0];
Y=[0 0];
Z=[0 0];
Y(1)=sqrt((R(2,2)+1)/2);
Y(2)=-Y(1);
X(1)=R(2,1)/(2*Y(1));
X(2)=R(2,1)/(2*Y(2));
Z(1)=R(2,3)/(2*Y(1));
Z(2)=R(2,3)/(2*Y(2));
vec(1,:)=[X(1) Y(1) Z(1)];
vec(2,:)=[X(2) Y(2) Z(2)];
axang(1,:)=[vec(1,:), theta];
axang(2,:)=[vec(2,:), theta];
else
vec = [0 0 0];
axang=[0 0 0 0];
vec(1)=R(3,2)-R(2,3);
vec(2)=R(1,3)-R(3,1);
vec(3)=R(2,1)-R(1,2);
vec=(1/(2*sin(theta)))*vec;
axang = [vec, theta];
end
So this was my code but it didn't work when the rotation matrix is
R = [-1 0 0;
0 -1 0;
0 0 1]
What is wrong with the code ? axang is a vector that stores axis in the first three positions and the angle in the last position.

It seems to me that you are looking for a conversion of a rotation matrix to quaternions, which is a built-in feature of Matlab if you installed the Robotics System Toolbox, i.e. rotm2quat:
axang = rotm2quat(R)
Note that the output format is slightly different as documented by Matlab:
Unit quaternion, returned as an n-by-4 matrix containing n
quaternions. Each quaternion, one per row, is of the form q = [w x y
z], with w as the scalar number.
Therefore you may need to swap the columns as follows:
axang = axang(:, [2 3 4 1]);

In a similar vein to the above answer you may wish to look into the use of the MatLab tool Translation1 = se2(StructuringElement, TranslationOffset).
The variable TranslationOffset can be applied as an angle in the form of 60*pi/180 for example.

In case of trace(R)==-1, the sign of axis term may be flipped. To get rid of it, following steps compute the axis angle vector.
find X(1) = sqrt((R(1,1)+1)/2);
if it is not zero, compute Y(1) = R(1,2)/(2*X(1)) and Y(2) = R(1,2)/(2*X(2)) and Z(1) = R(1,3)/(2*X(1)) Z(2) = R(1,3)/(2*X(2));
If X(1) = 0, then find Y(1) = sqrt((R(2,2)+1)/2)
if Y(1) is not zero then find the other terms from Y(1)
else find Z(1) and find the other terms from Z(1)

Related

How to plot discrete signals (delta equation)?

Plot 2 discrete signals:
x[n] = delta[n] - delta[n-1] + delta[n+4]
y[n] = 0.5^n*u[n]
Also plot the convolution.
I don't know what the delta is supposed to be and how to approach these kind of signals. If I have a simple signal, I know how to do it.
n = 0:7;
x1 = cos(pi*n);
subplot(1,2,1)
stem(n,x1)
Using the dirac (delta) function in matlab will not work for discrete functions as the outcome is Inf at n=0. Instead use the value 1 at the right locations. Furthermore, u[n] is the step function or in matlab the heaviside function. It is zero for negative x and 1 for positive x, making a step at exactly x = 0.
The following code will plot all your functions:
n = -5:5
x = [0 1 0 0 0 1 1 0 0 0 0]; %x[n] from n =-5 to n=5
%y = 0.5.^n .* heaviside(n); %[y[n] from n =-5 to n=5
y = 0.5.^n .* [0 0 0 0 0 1 1 1 1 1 1]; %stepfunction from n =-5 to n=5
z = conv(x,y); %z[n] from n = -10 to n=10
subplot(3,1,1);stem(n,y1)
subplot(3,1,2);stem(n,y2)
subplot(3,1,3);stem(-10:10,y3)
It appears to the be the Dirac delta function. Which has a function in Matlab.
x = dirac(n)
Also, the convolution of two functions has a function.
w = conv(u,v)
Not knowing the interval you have for these, I can't say. I could generate some code. Also the function u is unknown.

Error: Inner matrix dimensions must agree while scaling

I'm performing scaling operation on grid created. But the dimensions seem improper for the scaling the grid. Any ideas how to do it?
Code:
% plot grid
[X,Y] = meshgrid(-1:0.1:5, 0:0.1:1);
X = X(:);
Y = Y(:);
plot(X,Y,'b.');
xlabel('X');
ylabel('Y');
sx = 0.75;
sy = 0.6;
Tscale = [sx 0 0;
0 sy 0;
0 0 1];
Scale_val=Tscale*[X Y].';
X_Scale=Scale_val(1,:);
Y_Scale=Scale_val(2,:);
figure, plot(X_Scale, Y_Scale);
error:
Error using *
Inner matrix dimensions must agree.
Error in: Scale_val=Tscale*[X Y].';
Scale_val=Tscale*[X Y].';
you were making 2 mistakes i think.
first of all your input coordinates are 2D with just X and Y, but you are trying to do a 3D transformation. second, the matrix multiplication format is not correct. this is what i think you were trying to do
Tscale = [sx 0 0;
0 sy 0;
0 0 1];
Scale_val=Tscale*[X'; Y'; zeros(1,length(X))];
X_Scale=Scale_val(1,:);
Y_Scale=Scale_val(2,:);
figure, plot(X_Scale, Y_Scale,'*');

Image rotation about an arbitrary point

I was asked to perform an image rotation about an arbitrary point. The framework they provided was in matlab so I had to fill a function called MakeTransformMat that receives the angle of rotation and the point where we want to rotate.
As I've seen in class to do this rotation first we translate the point to the origin, then we rotate and finally we translate back.
The framework asks me to return a Transformation Matrix. Am I right to build that matrix as the multiplication of the translate-rotate-translate matrices? otherwise, what am I forgetting?
function TransformMat = MakeTransformMat(theta,center_y,center_x)
%Translate image to origin
trans2orig = [1 0 -center_x;
0 1 -center_y;
0 0 1];
%Rotate image theta degrees
rotation = [cos(theta) -sin(theta) 0;
sin(theta) cos(theta) 0;
0 0 1];
%Translate back to point
trans2pos = [1 0 center_x;
0 1 center_y;
0 0 1];
TransformMat = trans2orig * rotation * trans2pos;
end
This worked for me. Here I is the input image and J is the rotated image
[height, width] = size(I);
rot_deg = 45; % Or whatever you like (in degrees)
rot_xc = width/2; % Or whatever you like (in pixels)
rot_yc = height/2; % Or whatever you like (in pixels)
T1 = maketform('affine',[1 0 0; 0 1 0; -rot_xc -rot_yc 1]);
R1 = maketform('affine',[cosd(rot_deg) sind(rot_deg) 0; -sind(rot_deg) cosd(rot_deg) 0; 0 0 1]);
T2 = maketform('affine',[1 0 0; 0 1 0; width/2 height/2 1]);
tform = maketform('composite', T2, R1, T1);
J = imtransform(I, tform, 'XData', [1 width], 'YData', [1 height]);
Cheers.
I've answered a very similar question elsewhere: Here is the link.
In the code linked to, the point about which you rotate is determined by how the meshgrid is defined.
Does that help? Have you read the Wikipedia page on rotation matrices?

How to zero pad a matlab array?

What is the easiest way to (zero) pad a matlab array?
i.e. given [1,2,3,4] and length 6 return [1,2,3,4,0,0]
Background
I have a data array which I would like to apply a windowing function to before running fft on the data.
I use to pass data directly to fft which would zero pad to the next power of 2, but now I need it zero padding before the fft so I can multiply by the window function.
fs = 100; % Sample frequency (Hz)
t = 0:1/fs:10-1/fs; % 10 sec sample
x = (1.3)*sin(2*pi*15*t) ... % 15 Hz component
+ (1.7)*sin(2*pi*40*(t-2)) ... % 40 Hz component
+ (2.5)*randn(size(t)); % Gaussian noise;
m = length(x); % Window length
n = pow2(nextpow2(m)); % Transform length
w = barthannwin( n ); % FFT Window
y = fft(data, n); % DFT
windowed_data = x*w ; % Dimensions do not match as x not padded
y = fft(windowed_data, n); % DFT
I am aware of padarray as part of the Image Processing Toolbox, which I do not have.
EDIT
This method is probably even better for vectors as it does not break when they are transposed, note that it will change the original vector which may not be desirable:
myVec = 1:7;
myVec(end+3)=0
Alternately you can just concatenate zeros and the vector that you have and create a new variable with it.
myVec = 1:7;
requiredpadding = 10-7;
myVecPadded=[myVec zeros(1,requiredpadding)]
There is no built in function to do padding, but here is a little function to pad vector x given a minimum length n.
function y = pad(x, n)
y = x;
if length(x) < n
y(n) = 0;
end
this should pad it with zeros to the nearest power of 2 for an array a:
a(2^ceil(log2(length(a))))=0;
The image-processing toolbox of Matlab has a built-in function to pad arrays padarray(A,dim,value
For your example:
A = [1, 2, 3, 4];
dimension = [0 1]; % pad with extra columns
size = 2; % how much to pad
B = padarray(A,size*dimension,'post') % 'post' says to pad at the end
% just for demonstration, let's pre-pad the first dimension (rows)
dimension = [1 0];
C = padarray(A,dimension,'pre') % just as an example
% or pad in both directions
dimension = [1 2];
D = padarray(A,dimension) % by default, it will pad both pre and post
returns
B =
1 2 3 4 0 0
C =
0 0 0 0
1 2 3 4
D =
0 0 0 0 0 0 0 0
0 0 1 2 3 4 0 0
0 0 0 0 0 0 0 0
You can also use this for multi-dimensional arrays, the dimension vector just needs to be extended correspondingly, i.e. dimension = [0 0 1] will extend in the 3rd dimension.

3d grayscale volume projection onto 2D plane

I have a 3-D grayscale volume corresponding to ultrasound data. In Matlab this 3-D volume is simply a 3-D matrix of MxNxP. The structure I'm interested in is not oriented along the z axis, but along a local coordinate system already known (x'y'z'). What I have up to this point is something like the figure shown below, depicting the original (xyz) and the local coordinate systems (x'y'z'):
I want to obtain the 2-D projection of this volume (i.e. an image) through a specific plane on the local coordinate system, say at z' = z0. How can I do this?
If the volume was oriented along the z axis this projection could be readily achieved. i.e. if the volume, in Matlab, is V, then:
projection = sum(V,3);
thus, the projection can be computed just as the sum along the 3rd dimension of the array. However with a change of orientation the problem becomes more complicated.
I've been looking at radon transform (2D, that applies only to 2-D images and not volumes) and also been considering ortographic projections, but at this point I'm clueless as to what to do!
Thanks for any advice!
New attempt at solution:
Following the tutorial http://blogs.mathworks.com/steve/2006/08/17/spatial-transformations-three-dimensional-rotation/ and making some small changes, I might have something which could help you. Bear in mind, I have little or no experience with volumetric data in MATLAB, so the implementation is quite hacky.
In the below code I use tformarray() to rotate the structure in space. First, the data is centered, then rotated using rotationmat3D to produce the spacial transformation, before the data is moved back to its original position.
As I have never used tformarray before, I handeled datapoints falling outside the defined region after rotation by simply padding the data matrix (NxMxP) with zeros all around. If anyone know a better way, please let us know :)
The code:
%Synthetic dataset, 25x50x25
blob = flow();
%Pad to allow for rotations in space. Bad solution,
%something better might be possible to better understanding
%of tformarray()
blob = padarray(blob,size(blob));
f1 = figure(1);clf;
s1=subplot(1,2,1);
p = patch(isosurface(blob,1));
set(p, 'FaceColor', 'red', 'EdgeColor', 'none');
daspect([1 1 1]);
view([1 1 1])
camlight
lighting gouraud
%Calculate center
blob_center = (size(blob) + 1) / 2;
%Translate to origin transformation
T1 = [1 0 0 0
0 1 0 0
0 0 1 0
-blob_center 1];
%Rotation around [0 0 1]
rot = -pi/3;
Rot = rotationmat3D(rot,[0 1 1]);
T2 = [ 1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1];
T2(1:3,1:3) = Rot;
%Translation back
T3 = [1 0 0 0
0 1 0 0
0 0 1 0
blob_center 1];
%Total transform
T = T1 * T2 * T3;
%See http://blogs.mathworks.com/steve/2006/08/17/spatial-transformations-three-dimensional-rotation/
tform = maketform('affine', T);
R = makeresampler('linear', 'fill');
TDIMS_A = [1 2 3];
TDIMS_B = [1 2 3];
TSIZE_B = size(blob);
TMAP_B = [];
F = 0;
blob2 = ...
tformarray(blob, tform, R, TDIMS_A, TDIMS_B, TSIZE_B, TMAP_B, F);
s2=subplot(1,2,2);
p2 = patch(isosurface(blob2,1));
set(p2, 'FaceColor', 'red', 'EdgeColor', 'none');
daspect([1 1 1]);
view([1 1 1])
camlight
lighting gouraud
The arbitrary visualization below is just to confirm that the data is rotated as expected, plotting a closed surface when the data passed the value '1'. With blob2, you should know be able to project by using simple sums.
figure(2)
subplot(1,2,1);imagesc(sum(blob,3));
subplot(1,2,2);imagesc(sum(blob2,3));
Assuming you have access to the coordinate basis R=[x' y' z'], and that those vectors are orthonormal, you can simply extract the representation in this basis by multiplying your data with the the 3x3 matrix R, where x',y',z' are column vectors.
With the data stored in D (Nx3), you can get the representation with R, by multiplying by it:
Dmarked = D*R;
and now D = Dmarked*inv(R), so going back and forth is stragihtforward.
The following code might provide help to see the transformation. Here I create a synthetic dataset, rotate it, and then rotate it back. Doing sum(DR(:,3)) would then be your sum along z'
%#Create synthetic dataset
N1 = 250;
r1 = 1;
dr1 = 0.1;
dz1 = 0;
mu1 = [0;0];
Sigma1 = eye(2);
theta1 = 0 + (2*pi).*rand(N1,1);
rRand1 = normrnd(r1,dr1,1,N1);
rZ1 = rand(N1,1)*dz1+1;
D = [([rZ1*0 rZ1*0] + repmat(rRand1',1,2)).*[sin(theta1) cos(theta1)] rZ1];
%Create roation matrix
rot = pi/8;
R = rotationmat3D(rot,[0 1 0]);
% R = 0.9239 0 0.3827
% 0 1.0000 0
% -0.3827 0 0.9239
Rinv = inv(R);
%Rotate data
DR = D*R;
%#Visaulize data
f1 = figure(1);clf
subplot(1,3,1);
plot3(DR(:,1),DR(:,2),DR(:,3),'.');title('Your data')
subplot(1,3,2);
plot3(DR*Rinv(:,1),DR*Rinv(:,2),DR*Rinv(:,3),'.r');
view([0.5 0.5 0.2]);title('Representation using your [xmarked ymarked zmarked]');
subplot(1,3,3);
plot3(D(:,1),D(:,2),D(:,3),'.');
view([0.5 0.5 0.2]);title('Original data before rotation');
If you have two normalized 3x1 vectors x2 and y2 corresponding to your local coordinate system (x' and y').
Then, for a position P, its local coordinate will be xP=P'x2 and yP=P'*y2.
So you can try to project your volume using accumarray:
[x y z]=ndgrid(1:M,1:N,1:P);
posP=[x(:) y(:) z(:)];
xP=round(posP*x2);
yP=round(posP*y2);
xP=xP+min(xP(:))+1;
yP=yP+min(yP(:))+1;
V2=accumarray([xP(:),yP(:)],V(:));
If you provide your data, I will test it.