Calculate size of resulting array (matrix transformation) - matlab

So I have this code to rotate and skew an image. it works well for the rotation, and the image will fit exactly in the canvas. However if I apply skewing the image doesn't fit anymore. Can someone explain how to calculate the proper array dimension for the resulting image rotated and skewed by specific angles? In particular, I'm using this 2 lines for the rotated image (and it works although I don't fully understand them). How should I modify them such as even when skewed, the final image will fit? Thanks!
rows_new = ceil(rows_init_img * abs(cos(rads)) + cols_init_img * abs(sin(rads)));
cols_new = ceil(rows_init_img * abs(sin(rads)) + cols_init_img * abs(cos(rads)));
full code
clc;
clear;
%% init values
%loading initial image
init_img = imread('name2.png');
% define rows/cols dimension of original image pixel matrix
[rows_init_img, cols_init_img,z]= size(init_img);
% skew angle in radians
sk_angle = 50;
sk_rads = 2*pi*sk_angle/360;
% rotation angle in radians
angle = 20;
rads = 2*pi*angle/360;
%% calculate size of final_image
orig_corners = [ 1, 1; 1, rows_init_img; 1, cols_init_img; rows_init_img, cols_init_img];
new_corners = uint8(zeros(size(orig_corners)));
for i = 1:size(orig_corners, 1)
for j = 1:size(orig_corners, 2)
% translate
a = i - final_origin_x;
b = j - final_origin_y;
% rotate
x = a * cos(rads) - b * sin(rads);
y = a * sin(rads) + b * cos(rads);
% skew along x axis (AFTER rotation)
x = x + sk_rads * y;
% translate
x = x + init_origin_x;
y = y + init_origin_y;
% round to turn values to positive integers
x = round(x);
y = round(y);
if (x >= 1 && y >= 1 && x <= size(orig_corners, 1) && y <= size(orig_corners, 2) )
new_corners(i, j) = init_img(x, y);
end
end
end
% calculating array dimesions such that rotated image gets fit in it exactly.
% rows_new = ceil(rows_init_img * abs(cos(rads)) + cols_init_img * abs(sin(rads)));
% cols_new = ceil(rows_init_img * abs(sin(rads)) + cols_init_img * abs(cos(rads)));
% define an array with calculated dimensions and fill the array with zeros ie.,black
% uint8 is important. without it will show noise WHY?
final_img = uint8(zeros([rows_new cols_new 3 ]));
%calculating center of original image
init_origin_x = ceil(rows_init_img/2);
init_origin_y = ceil(cols_init_img/2);
%calculating center of final image
final_origin_x = ceil( size(final_img, 1)/2 );
final_origin_y = ceil( size(final_img, 2)/2 );
%% main loop
% apply transformation to each pixel of the image
for i = 1:size(final_img ,1)
for j = 1:size(final_img, 2)
% translate
a = i - final_origin_x;
b = j - final_origin_y;
% rotate
x = a * cos(rads) - b * sin(rads);
y = a * sin(rads) + b * cos(rads);
% skew along x axis
x = x + sk_rads * y;
% translate
x = x + init_origin_x;
y = y + init_origin_y;
% round to turn values to positive integers
x = round(x);
y = round(y);
% make sure values exists (are part of the initial image) and copy
% them in the final image matrix
if (x >= 1 && y >= 1 && x <= size(init_img, 1) && y <= size(init_img, 2) )
final_img(i, j, :) = init_img(x, y, :);
end
end
end
%% display images
% original image
% figure('name','Original Image','numbertitle','off');
% imshow(init_img);
% result image
figure('name','Manipulated Image','numbertitle','off');
imshow(final_img);
updated code
clc;
clear;
%% init values
%loading initial image
init_img = imread('name2.png');
% define rows/cols dimension of original image pixel matrix
[rows_init_img, cols_init_img, z]= size(init_img);
% skew angle in radians
sk_angle = 50;
sk_rads = 2*pi*sk_angle/360;
% rotation angle in radians
angle = 20;
rads = 2*pi*angle/360;
%calculating center of original image
init_origin_x = ceil(rows_init_img/2);
init_origin_y = ceil(cols_init_img/2);
%% calculate size of final_image
orig_corners = [ 1, 1; 1, rows_init_img; 1, cols_init_img; rows_init_img, cols_init_img];
new_corners = uint8(zeros(size(orig_corners)));
for i = 1:size(orig_corners, 1)
for j = 1:size(orig_corners, 2)
% translate
a = i - final_origin_x; %at this point I don't have this variable because I can't create it yet
b = j - final_origin_y;
% rotate
x = a * cos(rads) - b * sin(rads);
y = a * sin(rads) + b * cos(rads);
% skew along x axis (AFTER rotation)
x = x + sk_rads * y;
% translate
x = x + init_origin_x;
y = y + init_origin_y;
% round to turn values to positive integers
x = round(x);
y = round(y);
if (x >= 1 && y >= 1 && x <= size(orig_corners, 1) && y <= size(orig_corners, 2) )
new_corners(i, j) = init_img(x, y);
end
end
end
% calculating array dimesions such that rotated image gets fit in it exactly.
rows_new = abs(max(new_corners(1, :)) - min(new_corners(1, :)));
cols_new = abs(max(new_corners(2, :)) - min(new_corners(2, :)));
% define an array with calculated dimensions and fill the array with zeros ie.,black
final_img = uint8(zeros([rows_new cols_new 3 ]));
%calculating center of final image
final_origin_x = ceil( size(final_img, 1)/2 );
final_origin_y = ceil( size(final_img, 2)/2 );
%% main loop
% apply transformation to each pixel of the image
for i = 1:size(final_img ,1)
for j = 1:size(final_img, 2)
% translate
a = i - final_origin_x;
b = j - final_origin_y;
% skew along x axis (BEFORE rotation)
a = a + sk_rads * b;
% rotate
x = a * cos(rads) - b * sin(rads);
y = a * sin(rads) + b * cos(rads);
% skew along x axis (AFTER rotation)
%x = x + sk_rads * y;
% translate
x = x + init_origin_x;
y = y + init_origin_y;
% round to turn values to positive integers
x = round(x);
y = round(y);
% make sure values exists (are part of the initial image) and copy
% them in the final image matrix
if (x >= 1 && y >= 1 && x <= size(init_img, 1) && y <= size(init_img, 2) )
final_img(i, j, :) = init_img(x, y, :);
end
end
end
%% display images
% original image
% figure('name','Original Image','numbertitle','off');
% imshow(init_img);
% result image
figure('name','Manipulated Image','numbertitle','off');
imshow(final_img);

Related

Index in position __ exceeds array bounds

Having Trouble with this Error "Index in position 2 is invalid. Array indices must be positive integers or logical values." It only occurs when I enter certain values for the translation. Such as -25 x-direction and +50 in the y-direction. But it will work if I enter in any decimal values such as (12.75,-19.3). Please help me out.
Note: A is an imported image
if (delta_x == 0 && delta_y == 0) % Allows the Orginal Image to be displayed
figure(1)
image(0:ynew-1,0:xnew-1,A) % display a matrix as an image
axis equal
axis ij % put 0,0 in UL corner
axis tight
colormap(gray(L)) % use an 8-bit grayscale
xlabel('y')
ylabel('x')
title('Original Image')
return
end
%Translation Matrix 3x3
Trans = [1 0 delta_x; 0 1 delta_y; 0 0 1];
InverseTrans = (inv(Trans)); %Inverse Mapping Begins
%Allocate Space
E = zeros(xnew, ynew,k);
for i=1:xold
for j=1:yold
% matrix math assumes origin is (0,0) not (1,1)
vw=InverseTrans*[i; j; 1]; % vw will be [v; w; 1]
v = vw(1);
w = vw(2);
if (v < 0 || v >(xold-1)) % Testing for Out of Bounds
E(i,j) = 0;
elseif (w < 0 || w >(yold-1)) % Testing for out of Bounds
E(i,j) = 0;
else
%Takes the Real INTEGER Part
v_fix = fix(v);
w_fix = fix(w);
v_fix1 = v_fix +1;%Indexing
w_fix1 = w_fix +1;
%Change in the Values
dX = v - v_fix;
dY = w - w_fix;
%Indexing Purposes **This is where I'm getting my error**
D1(i,j) = A(v_fix1, w_fix1);
D2(i,j) = A(v_fix1 + 1, w_fix1);
D3(i,j) = A(v_fix1, w_fix1 + 1);
D4(i,j) = A(v_fix1 + 1, w_fix1 + 1);
end
end
end```

The camera calibration "Dual Absolute Quadric" cost function isn't converging

I tried to implement the cost function of the Dual Absolute Quadric in Matlab according to the following equation mentioned in this paper, with this data.
My problem is that the results didn't converge.
The code is down.
main code
%---------------------
% clear and close all
%---------------------
clearvars
close all
clc
%---------------------
% Data type long
%---------------------
format long g
%---------------------
% Read data
%---------------------
load('data.mat')
%---------------------------
% Display The Initial Guess
%---------------------------
disp('=======================================================')
disp('Initial Intrinsic parameters: ');
disp(A);
disp('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
%=========================================================================
DualAbsoluteQuadric = Optimize(A,#DAQ);
%---------------------
% Display The Results
%---------------------
disp('=======================================================')
disp('Dual Absoute Quadric cost function: ');
disp(DualAbsoluteQuadric);
disp('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
The optimization function used is:
function output = Optimize(A,func)
%------------------------------
options = optimoptions('lsqnonlin','Algorithm','levenberg-marquardt',...
'Display','iter','FunctionTolerance',1e-16,'Tolx',1e-16,...
'MaxFunctionEvaluations', 1000, 'MaxIterations',39,...
'OptimalityTolerance',1e-16);
%------------------------------
% NonLinear Optimization
%------------------------------
output_line = lsqnonlin(func,[A(1,1), A(1,3), A(2,2), A(2,3), A(1,2)],...
[],[],options);
%------------------------------------------------------------------------
output = Reshape(output_line);
The Dual Absolute Quadric Function:
function cost = DAQ(params)
Aj = [params(1) params(5) params(2) ;
0 params(3) params(4) ;
0 0 1 ];
Ai = [params(1) params(5) params(2) ;
0 params(3) params(4) ;
0 0 1 ];
% W^-1 (IAC Image of the Absolute Conic)
W_inv = Ai * Aj';
%----------------
%Find plane at infinity from MQM' ~ w (Dual Absolute Quadric)
Plane_at_infinity = PlaneAtInfinity(W_inv);
%Find H_Infty = [e21]F+e21*n'
Homography_at_infty = H_Infty(Plane_at_infinity);
%----------------
% Initialization
%----------------
global Fs;
% Initialize the cost as a vector
% (N-1 * N-2)/2: 9*8/2 = 36
vector_size = (size(Fs,3)-1)*(size(Fs,4)-2)/2;
cost = zeros(1, vector_size);
% Cost Function
k = 0;
loop_size = 3 * vector_size;
Second_Term = W_inv / norm(W_inv,'fro');
for i=1:3:loop_size
k = k+1;
First_Term = Homography_at_infty(:,i:i+2) * W_inv * ((Homography_at_infty(:,i:i+2))');
First_Term = First_Term / norm(First_Term, 'fro');
cost(k) = norm(First_Term - Second_Term,'fro');
end
end
Plane at infinity function:
function P_infty = PlaneAtInfinity(W_inv)
global PPM;
% Symbolic variables
X = sym('X', 'real');
Y = sym('Y', 'real');
Z = sym('Z', 'real');
L2 = sym('L2','real');
n = [X; Y; Z];
% DAQ
Q = [W_inv , (W_inv * n) ;
(n' * W_inv) , (n' * W_inv * n)];
% Get one only camera matrix (any)
M = PPM(:, :, 3);
% Autocalibration equation
m = M * Q * M';
% solve linear equations
solution = solve(m(1, 1) == (L2 * W_inv(1, 1)), ...
m(2, 2) == (L2 * W_inv(2, 2)), ...
m(3, 3) == (L2 * W_inv(3, 3)), ...
m(1, 3) == (L2 * W_inv(1, 3)));
P_infty = [double(solution.X(1)) double(solution.Y(1))...
double(solution.Z(1))]';
Homography at infinity function:
function H_Inf = H_Infty(planeInf)
global Fs;
k = 1;
% (3 x 3) x ((N-1)*(N-2) /2)
H_Inf = zeros(3,3*(size(Fs,3)-1)*(size(Fs,4)-2)/2);%(3*3)*36
for i = 2:size(Fs,3)
for j = i+1:size(Fs,4)
[~, ~, V] = svd(Fs(:,:,i,j)');
epip = V(:,end);
H_Inf(:,k:k+2) = epipole(Fs(:,:,i,j)) * Fs(:,:,i,j)+ epip * planeInf';
k = k+3;
end
end
end
Reshape function:
function output = Reshape(input)
%---------------------
% Reshape Intrinsics
%---------------------
% K = [a skew u0 ;
% 0 B v0 ;
% 0 0 1 ];
output = [input(1) input(5) input(2) ;
0 input(3) input(4) ;
0 0 1 ];
end
Epipole Function:
function epip = epipole(Fs)
% SVD Decompostition of (Fs)^T
[~,~,V] = svd(Fs');
% Get the epipole from the last vector of the SVD
epi = V(:,end);
% Reshape the Vector into Matrix
epip = [ 0 -epi(3) epi(2);
epi(3) 0 -epi(1);
-epi(2) epi(1) 0 ];
end
The plane at infinity has to be calculated as following:
function plane = computePlaneAtInfinity(P, K)
%Input
% P - Projection matrices
% K - Approximate Values of Intrinsics
%
%Output
% plane - coordinate of plane at infinity
% Compute the DIAC W^-1
W_invert = K * K';
% Construct Symbolic Variables to Solve for Plane at Infinity
% X,Y,Z is the coordinate of plane at infinity
% XX is the scale
X = sym('X', 'real');
Y = sym('Y', 'real');
Z = sym('Z', 'real');
XX = sym('XX', 'real');
% Define Normal to Plane at Infinity
N = [X; Y; Z];
% Equation of Dual Absolute Quadric (DAQ)
Q = [W_invert, (W_invert * N); (N' * W_invert), (N' * W_invert * N)];
% Select Any One Projection Matrix
M = P(:, :, 2);
% Left hand side of the equation
LHS = M * Q * M';
% Solve for [X, Y, Z] considering the System of Linear Equations
% We need 4 equations for 4 variables X,Y,Z,XX
S = solve(LHS(1, 1) == (XX * W_invert(1, 1)), ...
LHS(1, 2) == (XX * W_invert(1, 2)), ...
LHS(1, 3) == (XX * W_invert(1, 3)), ...
LHS(2, 2) == (XX * W_invert(2, 2)));
plane = [double(S.X(1)); double(S.Y(1)); double(S.Z(1))];
end

Running an old project of mine, but on a newer matlab version. Errors popping up with table() method. Did something change?

This is the lbp function of a facial expression recognition project that I'd created. The matlab version that this was created in as 2013. I am currently running this on 2017a.
Here is the function that I'm trying to run:
% result = lbp(I) returns the LBP histogram of the image I
function result = lbp(image)
d_image=double(image);
radius=1;
neighbours=8;
neighbour_points=zeros(neighbours,2);
% Angle step.
a = 2*pi/neighbours;
for i = 1:neighbours
neighbour_points(i,1) = -radius*sin((i-1)*a);
neighbour_points(i,2) = radius*cos((i-1)*a);
end
% Determine the dimensions of the input image.
[m1,n1]=size(image);
miny=min(neighbour_points(:,1));
maxy=max(neighbour_points(:,1));
minx=min(neighbour_points(:,2));
maxx=max(neighbour_points(:,2));
blocksizey=ceil(max(maxy,0))-floor(min(miny,0))+1;
blocksizex=ceil(max(maxx,0))-floor(min(minx,0))+1;
% Coordinates of origin (0,0) in the block
origy=1-floor(min(miny,0));
origx=1-floor(min(minx,0));
% Minimum allowed size for the input image depends
% on the radius of the used LBP operator.
if(n1 < blocksizex || m1 < blocksizey)
error('Small input image. Must be at least (2*radius+1) x (2*radius+1)');
end
% Calculate dx and dy;
dx = n1 - blocksizex;
dy = m1 - blocksizey;
% Fill the center pixel matrix C.
C = image(origy:origy+dy,origx:origx+dx);
%disp(C);
d_C = double(C);
% Initialize the result matrix with zeros.
result=zeros(dy+1,dx+1);
%Computing the LBP code image
for i = 1:neighbours
y = neighbour_points(i,1)+origy;
x = neighbour_points(i,2)+origx;
% Calculate floors, ceils and rounds for the x and y.
fy = floor(y); cy = ceil(y); ry = round(y);
fx = floor(x); cx = ceil(x); rx = round(x);
% Check if interpolation is needed.
if (abs(x - rx) < 1e-6) && (abs(y - ry) < 1e-6)
% Interpolation is not needed, use original datatypes
N = image(ry:ry+dy,rx:rx+dx);
D = N >= C;
else
% Interpolation needed, use double type images
ty = y - fy;
tx = x - fx;
% Calculate the interpolation weights.
w1 = roundn((1 - tx) * (1 - ty),-6);
w2 = roundn(tx * (1 - ty),-6);
w3 = roundn((1 - tx) * ty,-6);
% w4 = roundn(tx * ty,-6) ;
w4 = roundn(1 - w1 - w2 - w3, -6);
% Compute interpolated pixel values
N = w1*d_image(fy:fy+dy,fx:fx+dx) + w2*d_image(fy:fy+dy,cx:cx+dx) + w3*d_image(cy:cy+dy,fx:fx+dx) + w4*d_image(cy:cy+dy,cx:cx+dx);
N = roundn(N,-4);
D = N >= d_C;
end
% Update the result matrix.
v = 2^(i-1);
result = result + v*D;
if i==neighbours
end
end
load('binvector.mat');
bins = 59;
for i = 1:size(result,1)
for j = 1:size(result,2)
result(i,j)=table(result(i,j)+1);
end
end
% calculating histogram
result=hist(result(:),0:(bins-1));
end
function x = roundn(x, n)
if n<0
p=10 ^ -n;
x=round(p*x)/p;
elseif n>0
p=10^n;
x=p*round(x/p);
else
x=round(x);
end
end
And here is the error that popped up:
Error using tabular/double (line 148)
Undefined function 'double' for input arguments of type 'table'. To convert to numeric, use the TABLE2ARRAY function, or
extract data using dot or brace subscripting.
Error in lbp (line 104)
result(i,j)=table(result(i,j)+1);
I havent touched matlab in a long while, and so not sure how to tackle this, or what a suitable replacement method would be. Any input would be appreciated.

solving integral in rectangular method in matlab

This is my code to make an integration in the rectangular method in the matlab
f=#(x) (x^(1/2))
a = 1
b = 10
% step size
h = 0.25
n = 0 % the counter
xn= a + (n * h)
%%
%Rectangle Method:
s=0
for i =0:n-1
s = s + f(xn)
end
Rectangle = h * s
the answer should be around 20, but i'm getting 29.5
what's the problem?
Two errors:
1) xn is not updated.
2) number of points n is set to zero.
There are other minor issues which I did not fix, e.g. right and left boundary points should both contribute to the sum with weight 1/2.
Quick fix:
f=#(x) (x^(1/2));
a = 1;
b = 10 ;
% step size
h = 0.25;
n = (b-a)/h; % the counter
%%
%Rectangle Method:
s=0;
for i =0:n-1
xn= a + (i * h);
s = s + f(xn);
end
Rectangle = h * s;

Best way to get the bounding rectangle of a set of 3D points on a plane in Matlab

I need to get the four edges of the bounding rectangle of a set of 3D points stored as a 3xN matrix (tt). N >=4. The points lies on a plane.
Code sample:
% Simulate some points
deltaXY = 20;
[xx,yy] = meshgrid(-100:deltaXY:100,-100:deltaXY:100);
XYZ = [xx(:)'; yy(:)'; zeros(1,numel(xx))];
% Add some imperfection to data removing the top rigth point
maxXids = find(XYZ(1,:) == max(XYZ(1,:)));
maxYids = find(XYZ(2,:) == max(XYZ(2,:)));
id = intersect(maxXids,maxYids);
XYZ = removerows(XYZ',id)';
% Lets rotate a bit
XYZ = roty(5)*rotx(7)*rotz(0)*XYZ;
% Plot points
figure;
grid on;
rotate3d on;
axis vis3d;
hold on;
plot3(XYZ(1,:),XYZ(2,:),XYZ(3,:),'.r');
% Find bounding rectangle
% ??? :(
%Currently I'm using this code:
tt = XYZ;
%Get the max and min indexes
minX = find(tt(1,:) == min(tt(1,:)));
minY = find(tt(2,:) == min(tt(2,:)));
maxX = find(tt(1,:) == max(tt(1,:)));
maxY = find(tt(2,:) == max(tt(2,:)));
%Intersect to find the common index
id1 = intersect(minX,minY);
id2 = intersect(maxX,minY);
id3 = intersect(maxX,maxY);
id4 = intersect(minX,maxY);
%Get the points
p1 = tt(:,id1(1));
p2 = tt(:,id2(1));
p3 = tt(:,id3(1));
p4 = tt(:,id4(1));
Sample points plot:
The problem is that intersect some times can be null, eg: if the points does not form a rectangle. Resulting this error:
Index exceeds matrix dimensions.
First solution : Use logical indexing to get rid of the find calls
p1=tt(:,tt(1,:)==min(tt(1,:))&tt(2,:)==min(tt(2,:)));
p2=tt(:,tt(1,:)==max(tt(1,:))&tt(2,:)==min(tt(2,:)));
p3=tt(:,tt(1,:)==max(tt(1,:))&tt(2,:)==max(tt(2,:)));
p4=tt(:,tt(1,:)==min(tt(1,:))&tt(2,:)==max(tt(2,:)));
Second solution : Use convhull to get the corners :
k=convhull(tt(1,:),tt(2,:));
Corners=[tt(:,k(1:end-1))];
Ok found a solution:
% Find bounding rectangle
tt = XYZ;
%Get the max and min indexes
minXids = find(tt(1,:) == min(tt(1,:)));
minYids = find(tt(2,:) == min(tt(2,:)));
maxXids = find(tt(1,:) == max(tt(1,:)));
maxYids = find(tt(2,:) == max(tt(2,:)));
%Intersect to find the common index
id1 = intersect(minXids,minYids);
id2 = intersect(maxXids,minYids);
id3 = intersect(maxXids,maxYids);
id4 = intersect(minXids,maxYids);
%Get the points
% Find affine plane on points
[np,~,pp] = affine_fit(tt');
% Converts to cart. eq.
% ax + yb + cz + d = 0
% Find d
a = np(1); b = np(2); c = np(3);
x = pp(1); y = pp(2); z = pp(3);
d = - (a*x + y*b + c*z);
% Get only one value
minX = min(tt(1,minXids)); maxX = max(tt(1,maxXids));
minY = min(tt(2,minYids)); maxY = max(tt(2,maxYids));
if numel(id1) == 0
x = minX; y = minY;
% Calculate z at xy.
z = - (d + a*x + y*b)/c;
p1 = [x y z]';
else
p1 = tt(:,id1(1));
end
if numel(id2) == 0
x = maxX; y = minY;
z = - (d + a*x + y*b)/c;
p2 = [x y z]';
else
p2 = tt(:,id1(1));
end
if numel(id3) == 0
x = maxX; y = maxY;
z = - (d + a*x + y*b)/c;
p3 = [x y z]';
else
p3 = tt(:,id1(1));
end
if numel(id4) == 0
x = minX; y = maxY;
z = - (d + a*x + y*b)/c;
p4 = [x y z]';
else
p4 = tt(:,id1(1));
end
ps = [p1 p2 p3 p4];
plot3(ps(1,:),ps(2,:),ps(3,:),'ob');