Rotate discrete dataset Octave - matlab

I have a discrete dataset, X=[x1,x2,..,x12] & Y=[y1,y2,...,y12]. X ranges from [-25, 0] and Y ranges from [1e-6, 1e0]. X does not increase uniformly - as x approaches a value of 0, data sampling density increases from increments of 2.5 to increments of 1. Each x value is units of cm. I cannot get a good fit to the data from fitting a function (I've tried quite a few). I'm left with the discrete data. My need is to sweep the X, Y data completly around the Z axis and put the resulting swept data values into a matrix Z of size (51, 51). I've tried using the cylinder function, [u,v,w] = cylinder(Y) thinking I could extract the data or create a matrix Z from [u, v, w]. I can't seem to sort that out. surf(u,v,w) plots almost correctly - the scaling on the (u, v) axes ranges from [-1, 1] instead of [-25, 25]. This is, I assume, because I'm using cylinder(Y). When I try [u,v,w] = cylinder(X,Y) I get, error: linspace: N must be a scalar. It seems like there should be a better way then my approach of using cylinder to take the X & Y data, interpolate between points (to fill Z where data isn't), rotate it, and put the result into a matrix Z. Any suggestions are welcome. I'm using Octave 6.3.0. Thank you in advance.

Create a matrix R containing distance from origin values.
Use for loops and single value interpolation to cover the R space.
Place the interpolated values into the matrix Z.
% Original data X = [-25,-22.5,...,0]; size(X) = 1 12
% Original data Y = [1e-6, 1.3e-6,...,1] size(Y) = 1 12
u = [-range(X):1:range(X)]; v = [-range(X):1:range(X)]';
R = -sqrt(u.^2.+v.^2);
Z = zeros( 2 .* range(X) + 1);
for i = 1:size(R,1)
for j = 1:size(R,2)
if R(i,j) < min(X); Z(i,j) = 0; endif
if R(i,j) >= min(X); Z(i,j) = interp1(X,Y,R(i,j)); endif
endfor
endfor

Related

While Plotting x-y contour, it plot a single point

I have tried many times to create an x and y plot.
Every time I get only a point, and not a contour which I want. It should be the arc of a circle or an ellipse.
My current Matlab code:
a = 8*pi/5;
u = 1;
z=0.15;
x = cosh(u)*sqrt(1 - (sin(a)*sin(a)*sinh(u)*sinh(u))/square((sqrt(1-z)*cosh(u) + cos(a))));
y= -1*((sinh(u)*sinh(u)*sin(a))/(sqrt(1-z)*cosh(u) + cos(a)));
plot(x,y,'o')
assume any value of u.
u is a scalar, so you are plotting single points.
Make u an array
a = 8*pi/5;
u = 1:0.02:2; % Your u values as an array
z = 0.15;
And make your operations element-wise in the x and y calculations
x = cosh(u).*sqrt(1 - (sin(a).*sin(a).*sinh(u).*sinh(u))./square((sqrt(1-z).*cosh(u) + cos(a))));
y= -1.*((sinh(u).*sinh(u).*sin(a))./(sqrt(1-z).*cosh(u) + cos(a)));
Use a line style which isn't just a point (like 'o' is), for instance for a line with circles at each value you can use
plot(x,y,'-o')
Note: your x and y calculations give complex results for these values, and plot ignores imaginary parts of the inputs by default.
I forgot u should be an array to get the points in the plot
a = 8*pi/5;
% assigning an array from 1 to 2 with stepsize = 0.1
u = 1:0.02:2;
z = 0.15;
Since, u is an array the multiplication should be element-wise(.*)
x = cosh(u).*sqrt(1 - (sin(a).*sin(a).*sinh(u).*sinh(u))./square((sqrt(1-z).*cosh(u) + cos(a))));
y= -1.*((sinh(u).*sinh(u).*sin(a))./(sqrt(1-z).*cosh(u) + cos(a)));
% Ignoring the complex value since it only provide some phase
plot(abs(x),abs(y),'r');
hold on
plot(real(x),real(y),'g')
legend('abs values','real Values')

Curve fitting of complex variable in Matlab

I want to solve the following system of equations shown in the image below,
The matrix system
where the component of the matrix A is complex numbers with the angle (theta) runs from 0 to 2*pi which has m divisions, and n = 9. The known value z = x + iy. Suppose the x and y of matrix z is
z =
0 1.0148
0.1736 0.9848
0.3420 0.9397
0.5047 0.8742
0.6748 0.8042
0.8419 0.7065
0.9919 0.5727
1.1049 0.4022
1.1757 0.2073
1.1999 0
1.1757 -0.2073
1.1049 -0.4022
0.9919 -0.5727
0.8419 -0.7065
0.6748 -0.8042
0.5047 -0.8742
0.3420 -0.9397
0.1736 -0.9848
0 -1.0148
How do you solve them iteratively? Notice that the value of the first component of the desired constants must equal 1. I am working with Matlab.
You can apply simple multilinear regression for complex valued data.
Step 1. Get the matrix ready for linear regression
Your linear system
written without matrices, becomes
that rearranged yelds
If you rewrite it with matrices you get
Step 2. Apply multiple linear regression
Let the system above be
where
Now you can apply linear regression, that returns the best fit for α when
where
is the conjugate transpose.
In MATLAB
Y = Z - A(:,1); % Calculate Y subtracting the first col of A from Z
R = A(:,:); R(:,1) = []; % Calculate R as an exact copy of A, just without first column
Rs = ctranspose(R); % Calculate R-star (conjugate transpose of R)
alpha = (Rs*R)^(-1)*Rs*Y; % Finally apply multiple linear regression
alpha = cat(1, 1, alpha); % Add alpha1 back, whose value is 1
or, if you prefer built-ins, have a look at regress function:
Y = Z - A(:,1); % Calculate Y subtracting the first col of A from Z
R = A(:,:); R(:,1) = []; % Calculate R as an exact copy of A, just without first column
alpha = regress(Y, R); % Finally apply multiple linear regression
alpha = cat(1, 1, alpha); % Add alpha1 back, whose value is 1

Equally spaced points in a contour

I have a set of 2D points (not ordered) forming a closed contour, and I would like to resample them to 14 equally spaced points. It is a contour of a kidney on an image. Any ideas?
One intuitive approach (IMO) is to create an independent variable for both x and y. Base it on arc length, and interpolate on it.
% close the contour, temporarily
xc = [x(:); x(1)];
yc = [y(:); y(1)];
% current spacing may not be equally spaced
dx = diff(xc);
dy = diff(yc);
% distances between consecutive coordiates
dS = sqrt(dx.^2+dy.^2);
dS = [0; dS]; % including start point
% arc length, going along (around) snake
d = cumsum(dS); % here is your independent variable
perim = d(end);
Now you have an independent variable and you can interpolate to create N segments:
N = 14;
ds = perim / N;
dSi = ds*(0:N).'; %' your NEW independent variable, equally spaced
dSi(end) = dSi(end)-.005; % appease interp1
xi = interp1(d,xc,dSi);
yi = interp1(d,yc,dSi);
xi(end)=[]; yi(end)=[];
Try it using imfreehand:
figure, imshow('cameraman.tif');
h = imfreehand(gca);
xy = h.getPosition; x = xy(:,1); y = xy(:,2);
% run the above solution ...
Say your contour is defined by independent vector x and dependent vector y.
You can get your resampled x vector using linspace:
new_x = linspace(min(x),max(x),14); %14 to get 14 equally spaced points
Then use interp1 to get new_y values at each new_x point:
new_y = interp1(x,y,new_x);
There are a few interpolation methods to choose from - default is linear. See interp1 help for more info.

Ideas for reducing the complexity of a 3D density function for generating a ternary surface plot in Matlab

I have a 3D density function q(x,y,z) that I am trying to plot in Matlab 8.3.0.532 (R2014a).
The domain of my function starts at a and ends at b, with uniform spacing ds. I want to plot the density on a ternary surface plot, where each dimension in the plot represents the proportion of x,y,z at a given point. For example, if I have a unit of density on the domain at q(1,1,1) and another unit of density on the domain at q(17,17,17), in both cases there is equal proportions of x,y,z and I will therefore have two units of density on my ternary surface plot at coordinates (1/3,1/3,1/3). I have code that works using ternsurf. The problem is that the number of proportion points grows exponentially fast with the size of the domain. At the moment I can only plot a domain of size 10 (in each dimension) with unit spacing (ds = 1). However, I need a much larger domain than this (size 100 in each dimension) and much smaller than unit spacing (ideally as small as 0.1) - this would lead to 100^3 * (1/0.1)^3 points on the grid, which Matlab just cannot handle. Does anyone have any ideas about how to somehow bin the density function by the 3D proportions to reduce the number of points?
My working code with example:
a = 0; % start of domain
b = 10; % end of domain
ds = 1; % spacing
[x, y, z] = ndgrid((a:ds:b)); % generate 3D independent variables
n = size(x);
q = zeros(n); % generate 3D dependent variable with some norm distributed density
for i = 1:n(1)
for j = 1:n(2)
for k = 1:n(2)
q(i,j,k) = exp(-(((x(i,j,k) - 10)^2 + (y(i,j,k) - 10)^2 + (z(i,j,k) - 10)^2) / 20));
end
end
end
Total = x + y + z; % calculate the total of x,y,z at every point in the domain
x = x ./ Total; % find the proportion of x at every point in the domain
y = y ./ Total; % find the proportion of y at every point in the domain
z = z ./ Total; % find the proportion of z at every point in the domain
x(isnan(x)) = 0; % set coordinate (0,0,0) to 0
y(isnan(y)) = 0; % set coordinate (0,0,0) to 0
z(isnan(z)) = 0; % set coordinate (0,0,0) to 0
xP = reshape(x,[1, numel(x)]); % create a vector of the proportions of x
yP = reshape(y,[1, numel(y)]); % create a vector of the proportions of y
zP = reshape(z,[1, numel(z)]); % create a vector of the proportions of z
q = reshape(q,[1, numel(q)]); % create a vector of the dependent variable q
ternsurf(xP, yP, q); % plot the ternary surface of q against proportions
shading(gca, 'interp');
colorbar
view(2)
I believe you meant n(3) in your innermost loop. Here are a few tips:
1) Loose the loops:
q = exp(- ((x - 10).^2 + (y - 10).^2 + (z - 10).^2) / 20);
2) Loose the reshapes:
xP = x(:); yP = y(:); zP = z(:);
3) Check Total once, instead of doing three checks on x,y,z:
Total = x + y + z; % calculate the total of x,y,z at every point in the domain
Total( abs(Total) < eps ) = 1;
x = x ./ Total; % find the proportion of x at every point in the domain
y = y ./ Total; % find the proportion of y at every point in the domain
z = z ./ Total; % find the proportion of z at every point in the domain
PS: I just recognized your name.. it's Jonathan ;)
Discretization method probably depends on use of your plot, maybe it make sense to clarify your question from this point of view.
Overall, you probably struggling with an "Out of memory" error, a couple of relevant tricks are described here http://www.mathworks.nl/help/matlab/matlab_prog/resolving-out-of-memory-errors.html?s_tid=doc_12b?refresh=true#brh72ex-52 . Of course, they work only up to certain size of arrays.
A more generic solution is too save parts of arrays on hard drive, it makes processing slower but it'll work. E.g., you can define several q functions with the scale-specific ngrids (e.g. ngridOrder0=[0:10:100], ngridOrder10=[1:1:9], ngridOrder11=[11:1:19], etc... ), and write an accessor function which will load/save the relevant grid and q function depending on the part of the plot you're looking.

Creating a matrix containing a filled ellipse based on a non-contiguous outline

I'm trying to create a matrix of 0 values, with 1 values filling a ellipse shape. My ellipse was generated using minVolEllipse.m (Link 1) which returns a matrix of the ellipse equation in the 'center form' and the center of the ellipse. I then use a snippet of code from Ellipse_plot.m (from the aforementioned link) to parameterize the vector into major/minor axes, generate a parametric equation, and generate a matrix of transformed coordinates. You can see their code to see how this is done. The result is a matrix that has index locations for points along the ellipse. It does not encompass every value along the outline of the ellipse unless I set the number of grid points, N, to a ridiculously high value.
When I use the MATLAB plot or patch commands I see exactly the result I'm looking for. However, I want this represented as a matrix of 0 values with 1s where patch 'fills in' the blanks. It is apparent that MATLAB has this functionality, but I have yet to find the code to execute it. What I am looking for is similar to how bwfill of the image processing toolbox works (Link 2). bwfill does not work for me because my ellipse is not contiguous, so the function returns a matrix filled completely with 1 values.
Hopefully I have outlined the problem well enough, if not please comment and I can edit the post to clarify.
EDIT:
I have devised a strategy using the 2-D X vector from Ellipse_plot.m as an input to EllipseDirectFit.m (Link 3). This function returns the coefficients for the ellipse function ax^2+bxy+cy^2+dx+dy+f=0. Using these coefficients I calculate the angle between the x-axis and the major axis of the ellipse. This angle, along with the center and major/minor axes are passed into ellipseMatrix.m (Link 4), which returns a filled matrix. Unfortunately, the matrix appears to be out of rotation from what I want. Here is the portion of my code:
N = 20; %Number of grid points in ellipse
ellipsepoints = clusterpoints(clusterpoints(:,1)==i,2:3)';
[A,C] = minVolEllipse(ellipsepoints,0.001,N);
%%%%%%%%%%%%%%
%
%Adapted from:
% Ellipse_plot.m
% Nima Moshtagh
% nima#seas.upenn.edu
% University of Pennsylvania
% Feb 1, 2007
% Updated: Feb 3, 2007
%%%%%%%%%%%%%%
%
%
% "singular value decomposition" to extract the orientation and the
% axes of the ellipsoid
%------------------------------------
[U D V] = svd(A);
%
% get the major and minor axes
%------------------------------------
a = 1/sqrt(D(1,1))
b = 1/sqrt(D(2,2))
%theta values
theta = [0:1/N:2*pi+1/N];
%
% Parametric equation of the ellipse
%----------------------------------------
state(1,:) = a*cos(theta);
state(2,:) = b*sin(theta);
%
% Coordinate transform
%----------------------------------------
X = V * state;
X(1,:) = X(1,:) + C(1);
X(2,:) = X(2,:) + C(2);
% Output: Elip_Eq = [a b c d e f]' is the vector of algebraic
% parameters of the fitting ellipse:
Elip_Eq = EllipseDirectFit(X')
% http://mathworld.wolfram.com/Ellipse.html gives the equation for finding the angle theta (teta).
% The coefficients from EllipseDirectFit are rescaled to match what is expected in the wolfram link.
Elip_Eq(2) = Elip_Eq(2)/2;
Elip_Eq(4) = Elip_Eq(4)/2;
Elip_Eq(5) = Elip_Eq(5)/2;
if Elip_Eq(2)==0
if Elip_Eq(1) < Elip_Eq(3)
teta = 0;
else
teta = (1/2)*pi;
endif
else
tetap = (1/2)*acot((Elip_Eq(1)-Elip_Eq(3))/(Elip_Eq(2)));
if Elip_Eq(1) < Elip_Eq(3)
teta = tetap;
else
teta = (pi/2)+tetap;
endif
endif
blank_mask = zeros([height width]);
if teta < 0
teta = pi+teta;
endif
%I may need to switch a and b, depending on which is larger (so that the fist is the major axis)
filled_mask1 = ellipseMatrix(C(2),C(1),b,a,teta,blank_mask,1);
EDIT 2:
As a response to the suggestion from #BenVoigt, I have written a for-loop solution to the problem, here:
N = 20; %Number of grid points in ellipse
ellipsepoints = clusterpoints(clusterpoints(:,1)==i,2:3)';
[A,C] = minVolEllipse(ellipsepoints,0.001,N);
filled_mask = zeros([height width]);
for y=0:1:height
for x=0:1:width
point = ([x;y]-C)'*A*([x;y]-C);
if point < 1
filled_mask(y,x) = 1;
endif
endfor
endfor
Although this is technically a solution to the problem, I am interested in a non-iterative solution. I'm running this script over many large images, and need it to be very fast and parallel.
EDIT 3:
Thanks #mathematical.coffee for this solution:
[X,Y] = meshgrid(0:width,0:height);
fill_mask=arrayfun(#(x,y) ([x;y]-C)'*A*([x;y]-C),X,Y) < 1;
However, I believe there is yet a better way to do this. Here is a for-loop implementation that I did that runs faster than both above attempts:
ellip_mask = zeros([height width]);
[U D V] = svd(A);
a = 1/sqrt(D(1,1));
b = 1/sqrt(D(2,2));
maxab = ceil(max(a,b));
xstart = round(max(C(1)-maxab,1));
xend = round(min(C(1)+maxab,width));
ystart = round(max(C(2)-maxab,1));
yend = round(min(C(2)+maxab,height));
for y = ystart:1:yend
for x = xstart:1:xend
point = ([x;y]-C)'*A*([x;y]-C);
if point < 1
ellip_mask(y,x) = 1;
endif
endfor
endfor
Is there a way to accomplish this goal (the total image size is still [width height]) without this for-loop? The reason this is faster is because I don't have to iterate over the entire image to determine if my point is within the ellipse. Instead, I can simply iterate over a square region that is the length of the center +/- the largest principle axis.
Expanding the matrix multiply, which is an elliptic norm, gives a fairly simply vectorized expression:
[X,Y] = meshgrid(0:width,0:height);
X = X - C(1);
Y = Y - C(2);
fill_mask = X.^2 * A(1,1) + X.*Y * (A(1,2) + A(2,1)) + Y.^2 * A(2,2) < 1;
This is what I intended by my original comment.