Finding and plotting parabola in matlab - matlab

I have been trying to find a parabola in an image. For the starting purposes I took an image with a black parabola on a white background. Then I found the black pixels on the image using the find command by
[yi xi] = find(im<10); % im is the image with black parabola and white background
After that I randomly took 3 points from the collection and solved the equation for the parabola using the symbolic toolbox using
syms x y;
%solve them for the parabola equation
A = [ x^2 x y 1 ;x0^2 x0 y0 1; x1^2 x1 y1 1; x2^2 x2 y2 1];
where
%(x0,y0) = (104,137)
%(x1,y1) = (244,161)
%(x2,y2) = (300,229)
S = solve(det(A),y);
Then I get the coeffcients a,b,c as
a = 0.0100
b = -1.6800
c = 254.1900
where a, b and c are
a*x^2 + b*x + c = y;
Since now I have got the eqn I plot the parabola by putting the coefficient values
and taking
xx = 1:300;
yy = a*xx.^2 + b*xx +c ;
then I plot the parabola on the image as
plot(xx,yy,'-');
For the confirmation that I have taken correct points I also plot the selected points on the image and they lie exactly on the parabola in the image. So that is not the problem.
The problems are :
The parabola that I plot (blue) doesn't lie on the parabola of the image(black).
When I put the value of x co-ordinates in the above equation. The value of y is not the same as of the y co-ordinate.
for eg: (104,137)
0.0100*104*104 -1.68*104 + 254.19 = 108.16 - 174.72 + 254.19 = 187.63
whereas it should be 137
My parabola is wrong. Any help will be appreciated. The images are

I think you must be rounding somewhere in your calculation of a, b, and c.
I had a go with the three points you mentioned using the function fit (with fit type poly2) and my a,b,c were 0.0053, -1.6802 and 254.1895 (or add more decimal places when using format long).
Similarly, when using same the code you give, the output of solve is:
S = (73*x^2)/13720 - (5763*x)/3430 + 87187/343
S2 = double(coeffs(S))
S2 =
254.1895 -1.6802 0.0053
This gives me the same a, b, and c as with fit/poly2 (just from looking at it, the output of 73/13720 cannot be 0.01). Also, if I plot this curve over the original points using the same code you give, it works fine. So the only remaining source of error that I can see is some sort of rounding in whatever code you use to extract values of a, b, and c from the output of solve.

The following works. The habit of imshow to swap the intuitive meaning of ordinate and abscissa as used in plot can make overlays problematic at times. Your problem might stem from how you define your coordinate system when plotting with different function (imshow or related image display routines versus plot) in particular the position of the origin in the image. Here's my code:
% create image of parabola
k =[-0.3 10 10];
x = [1:0.1:50];
y = round(k(1)*x.^2 + k(2)*x + k(3));
crd = unique(round([x(:) y(:)]),'rows');
Nx = 100;
Ny = 100;
img = ones(Nx,Ny)*255;
iok = find((crd(:,1)>0) & (crd(:,1)<=Nx) & (crd(:,2)>0) & (crd(:,2)<=Ny));
indx = sub2ind([Nx Ny],crd(iok,1),crd(iok,2));
img(indx) = 0;
imshow(img)
Next we fit the parabola
% pick three points:
x0 = crd(1,1);
y0 = crd(1,2);
x1 = crd(80,1);
y1 = crd(80,2);
x2 = crd(160,1);
y2 = crd(160,2);
% plot these on the original image
hold on
plot(y0,x0,y1,x1,y2,x2,'Markersize',20,'Linestyle','none','Marker','x','Color','r')
Solved the equation precisely as you showed, then the result is
S = -1094/3627*x^2+12073/1209*x+37415/3627
Overlay the fitted equation
a= -1094/3627;
b = 12073/1209;
c = 37415/3627;
xx = 1:100;
yy = a*xx.^2 + b*xx +c ;
% then I plot the parabola on the image as
plot(yy,xx,'g--');
A not so pretty plot (green= fit, red crosses=picked points, blue=parabola plotted without swapping order of x and y):

Related

Plot quiver polar coordinates

I want to plot the field distribution inside a circular structure with radius a.
What I expect to see are circular arrows that from the centre 0 go toward a in the radial direction like this
but I'm obtaining something far from this result. I wrote this
x_np = besselzero(n, p, 1); %toolbox from mathworks.com for the roots
R = 0.1:1:a; PHI = 0:pi/180:2*pi;
for r = 1:size(R,2)
for phi = 1:size(PHI,2)
u_R(r,phi) = -1/2*((besselj(n-1,x_np*R(1,r)/a)-besselj(n+1,x_np*R(1,r)/a))/a)*cos(n*PHI(1,phi));
u_PHI(r,phi) = n*(besselj(n,x_np*R(1,r)/a)/(x_np*R(1,r)))*sin(PHI(1,phi));
end
end
[X,Y] = meshgrid(R);
quiver(X,Y,u_R,u_PHI)
where u_R is supposed to be the radial component and u_PHI the angular component. Supposing the formulas that I'm writing are correct, do you think there is a problem with for cycles? Plus, since R and PHI are not with the same dimension (in this case R is 1x20 and PHI 1X361) I also get the error
The size of X must match the size of U or the number of columns of U.
that I hope to solve it if I figure out which is the problem with the cycles.
This is the plot that I get
The problem has to do with a difference in co-ordinate systems.
quiver expects inputs in a Cartesian co-ordinate system.
The rest of your code seems to be expressed in a polar co-ordinate system.
Here's a snippet that should do what you want. The initial parameters section is filled in with random values because I don't have besselzero or the other details of your problem.
% Define initial parameters
x_np = 3;
a = 1;
n = 1;
% Set up domain (Cartesian)
x = -a:0.1:a;
y = -a:0.1:a;
[X, Y] = meshgrid(x, y);
% Allocate output
U = zeros(size(X));
V = zeros(size(X));
% Loop over each point in domain
for ii = 1:length(x)
for jj = 1:length(y)
% Compute polar representation
r = norm([X(ii,jj), Y(ii,jj)]);
phi = atan2(Y(ii,jj), X(ii,jj));
% Compute polar unit vectors
rhat = [cos(phi); sin(phi)];
phihat = [-sin(phi); cos(phi)];
% Compute output (in polar co-ordinates)
u_R = -1/2*((besselj(n-1, x_np*r/a)-besselj(n+1, x_np*r/a))/a)*cos(n*phi);
u_PHI = n*(besselj(n, x_np*r/a)/(x_np*r))*sin(phi);
% Transform output to Cartesian co-ordinates
U(ii,jj) = u_R*rhat(1) + u_PHI*phihat(1);
V(ii,jj) = u_R*rhat(2) + u_PHI*phihat(2);
end
end
% Generate quiver plot
quiver(X, Y, U, V);

Fit plane to N dimensional points in MATLAB

I have a set of N points in k dimensions as a matrix of size N X k.
How can I find the best fitting line through these points? The line will be a plane (hyerpplane) in k dimensions. It will have k coefficients and one bias term.
Existing functions like fit seem to be usable only for points in 2 or 3 dimension.
You can fit a hyperplane (or any lower dimensional affine space) to a set of D dimensional data using Principal Component Analysis. Here's an example of fitting a plane to a set of 3D data. This is explained in more detail in the MATLAB documentation but I tried to construct the simplest example I could.
% generate some random correlated data
D = 3;
mu = zeros(1,D);
sqrt_sig = randn(D);
sigma = sqrt_sig'*sqrt_sig;
% generate 50 points in a D x 50 matrix
X = mvnrnd(mu, sigma, 50)';
% perform PCA
coeff = pca(X');
% The last principal component is normal to the best fit plane and plane goes through mean of X
a = coeff(:,D);
b = -mean(X,2)'*a;
% plane defined by a'*x + b = 0
dist = abs(a'*X+b) / norm(a);
mse = mean(dist.^2)
Edit: Added example plot of results for D = 3. I take advantage of the orthogonality of the other principal components here. Ignore the code if you want it's just to demonstrate that the plane does in fact fit the data pretty well.
% plot in 3D
X0 = bsxfun(#minus,X,mean(X,2));
b1 = coeff(:,1); b2 = coeff(:,2);
y1 = b1'*X0; y2 = b2'*X0;
y1_min = min(y1); y1_max = max(y1);
y1_span = y1_max - y1_min;
y2_min = min(y2); y2_max = max(y2);
y2_span = y2_max - y2_min;
pad = 0.2;
y1_min = y1_min - pad*y1_span;
y1_max = y1_max + pad*y1_span;
y2_min = y2_min - pad*y2_span;
y2_max = y2_max + pad*y2_span;
[y1_m,y2_m] = meshgrid(linspace(y1_min,y1_max,5), linspace(y2_min,y2_max,5));
grid = bsxfun(#plus, bsxfun(#times,y1_m(:)',b1) + bsxfun(#times,y2_m(:)',b2), mean(X,2));
x = reshape(grid(1,:),size(y1_m));
y = reshape(grid(2,:),size(y1_m));
z = reshape(grid(3,:),size(y1_m));
figure(1); clf(1);
surf(x,y,z,'FaceColor','black','FaceAlpha',0.3,'EdgeAlpha',0.6);
hold on;
plot3(X(1,:),X(2,:),X(3,:),' .');
axis equal;
axis vis3d;
Edit2: When I say "principal component" I'm being a bit sloppy (or just plain wrong) with the wording. I'm actually referring to the orthogonal basis vectors that the principal components are expressed in.
Here's a simpler solution, that just uses MATLAB's \ operator. We start with defining a plane in k dimensions:
% 0 = a + x(1) * b(1) + x(2) * b(2) + ... + x(k) * 1
k = 8;
a = randn(1);
b = randn(k-1,1);
(note that we assume b(k)=1, you can always multiply the plane parameters by any value without changing the plane).
Next we generate N random points within this plane:
N = 1000;
x = rand(N,k-1);
x(:,k) = -(a + x * b);
...sorry, it's not the best way to generate random points on the plane, but it's good enough for the demonstration here. Add noise to the points:
x = x + 0.05*randn(size(x));
To find the parameters of the plane, we solve the system of equations
% a + x(1:k-1) * b == -x(k)
in the least-squares sense. a and b are the unknowns there. We can rewrite the left-hand side as [1,x(1:k-1)] * [a;b]. If we have a matrix equation M*p=v we can solve for p by writing p=M\v:
p = [ones(N,1),x(:,1:k-1)]\(-x(:,k));
disp(['ground truth: [a,b,1] = ',mat2str([a,b',1],3)]);
disp(['estimated : [a,b,1] = ',mat2str([p',1],3)]);
This gives as output:
ground truth: [a,b,1] = [-1.35 -1.44 -1.48 1.17 0.226 -0.214 0.234 -1.59 1]
estimated : [a,b,1] = [-1.41 -1.38 -1.43 1.14 0.219 -0.195 0.221 -1.54 1]
The less noise or the more points in the dataset, the smaller the error will be of course!

Divide Mesh grid by a bisector, MATLAB

I have a piecewise function, where domain changes for each case. The function is as follows:
For
(x,y)greater than Divider v= f(x,y) (A1)
(x,y)less than Divider v = g(x,y) (A2)
The location of the divider changes with tilt angle of the rectangle given in figures 1 and 2.Figure 1 & 2 The divider will always be a bisector of the rectangle. For example, the divider makes an angle (alpha + 90) with the horizontal.
If the rectangle makes an angle 0, it's easy to implement above functions as I can create meshgrid from
x =B to C & y = A to D for A1
x =A to B & y = A to D for A2
However, when the angles for the rectangle are different, I can't figure out how to create the mesh to calculate the function v using the algorithm A1 and A2 above.
I was thinking of using some inequality and using the equation of the line (as I have the co-ordinates for the center of the rectangle and the angle of tilt). But, I can't seem to think of a way to do it for all angles (for example , slope of pi/2 as in the first figure, yields infinity). Even if I do create some kind of inequality, I can't create a mesh.
1Please help me with this problem. I have wasted a lot of time on this. It seems to be out of my reach
%% Constants
Angle1=0;
Angle1=Angle1.*pi./180;
rect_center=0; % in m
rect_length=5; % in m
rect_width=1; % in m
rect_strength=1.8401e-06;
Angle2=0;
Angle2 =Angle2.*pi./180;
%% This code calculates the outer coordinates of the rectangle by using the central point
% the following code calculates the vertices
vertexA=rect_center+(-rect_width./2.*exp(1i.*1.5708)-rect_length./2).*exp(1i.*Angle2);
vertexA=[vertexA,vertexA+2.*(rect_width./2.*exp(1i.*1.5708)).*exp(1i.*Angle2)];
vertexB=rect_center+(-rect_width./2.*exp(1i.*1.5708)+rect_length./2).*exp(1i.*Angle2);
vertexB=[vertexB,vertexB+2.*(rect_width./2.*exp(1i.*1.5708)).*exp(1i.*Angle2)];
za1=vertexA(1:numel(vertexA)/2);
za2=vertexA(1+numel(vertexA)/2:numel(vertexA));
zb1=vertexB(1:numel(vertexB)/2);
zb2=vertexB(1+numel(vertexB)/2:numel(vertexB));
arg1=exp(-1i.*Angle2);
%% This Section makes the two equations necessary for making the graphs
syms var_z
% Equation 1
Eqn1(var_z)=1.5844e-07.*exp(-1i.*Angle1).*var_z./9.8692e-13;
% subparts of the Equation 2
A = 1.0133e+12.*(-1i.*rect_strength.*exp(-1i*Angle2)./(2*pi.*rect_length.*rect_width*0.2));
ZA1 = var_z+za1-2*rect_center;
ZA2 = var_z+za2-2*rect_center;
ZB1 = var_z+zb1-2*rect_center;
ZB2 = var_z+zb2-2*rect_center;
ZAA2 = log(abs(ZA2)) + 1i*mod(angle(ZA2),2*pi);
ZAA1 = log(abs(ZA1)) + 1i*mod(angle(ZA1),2*pi);
ZBB1 = log(abs(ZB1)) + 1i*mod(angle(ZB1),2*pi);
ZBB2 = log(abs(ZB2)) + 1i*mod(angle(ZB2),2*pi);
%Equation 2 ; this is used for the left side of the center
Eqn2= A*(ZA2*(log(ZA2)-1)-(ZA1*(log(ZA1)-1))+(ZB1*(log(ZB1)-1))-(ZB2*(log(ZB2)-1)));
%Equation 3 ; this is used for the right side of the center
Eqn3 = A.*(ZA2*(ZAA2-1)-(ZA1*(ZAA1-1))+(ZB1*(ZBB1-1))-(ZB2*(ZBB2-1)));
%Equation 4 :Add Equation 2 and Equation 1; this is used for the left side of the center
Eqn4 = matlabFunction(Eqn1+Eqn2,'vars',var_z);
%Equation 5: Add Equation 3 and Equation 1; this is used for the right side of the center
Eqn5 = matlabFunction(Eqn1+Eqn3,'vars',var_z);
%% Prepare for making the plots
minx=-10; %min x coordinate
maxx=10; %max x coordinate
nr_x=1000; %nr x points
miny=-10; %min y coordinate
maxy=10; %max y coordinate
nr_y=1000; %nr y points
%This vector starts from left corner (minx) to the middle of the plot surface,
%The middle of the plot surface lies at the center of the rectange
%created earlier
xvec1=minx:(rect_center-minx)/(0.5*nr_x-1):rect_center;
%This vector starts from middle to the right corner (maxx) of the plot surface,
%The middle of the plot surface lies at the center of the rectange
%created earlier
xvec2=rect_center:(maxx-rect_center)/(0.5*nr_x-1):maxx;
%the y vectors start from miny to maxy
yvec1=miny:(maxy-miny)/(nr_y-1):maxy;
yvec2=miny:(maxy-miny)/(nr_y-1):maxy;
% create mesh from above vectors
[x1,y1]=meshgrid(xvec1,yvec1);
[x2,y2]=meshgrid(xvec2,yvec2);
z1=x1+1i*y1;
z2=x2+1i*y2;
% Calculate the above function using equation 4 and equation 5 using the mesh created above
r1 = -real(Eqn5(z1));
r2 = -real(Eqn4(z2));
%Combine the calculated functions
Result = [r1 r2];
%Combine the grids
x = [x1 x2];
y = [y1 y2];
% plot contours
[c,h]=contourf(x,y,Result(:,:,1),50,'LineWidth',1);
% plot the outerboundary of the rectangle
line_x=real([vertexA;vertexB]);
line_y=imag([vertexA;vertexB]);
line(line_x,line_y,'color','r','linestyle',':','linewidth',5)
The final Figure is supposed to look like this.Final Expected Figure.
I'm not sure which angle defines the dividing line so I assume it's Angle1. It looks like logical indexing is the way to go here. Instead of creating two separate mesh grids we simply create the entire mesh grid then partition it into two sets and operate on each independently.
%% Prepare for making the plots
minx=-10; %min x coordinate
maxx=10; %max x coordinate
nr_x=1000; %nr x points
miny=-10; %min y coordinate
maxy=10; %max y coordinate
nr_y=1000; %nr y points
% create full mesh grid
xvec=linspace(minx,maxx,nr_x);
yvec=linspace(miny,maxy,nr_y);
[x,y]=meshgrid(xvec,yvec);
% Partition mesh based on divider line
% Assumes the line passes through (ox,oy) with normal vector defined by Angle1
ox = rect_center;
oy = rect_center;
a = cos(Angle1);
b = sin(Angle1);
c = -(a*ox + b*oy);
% use logical indexing to opperate on the appropriate parts of the mesh
idx1 = a*x + b*y + c < 0;
idx2 = ~idx1;
z = zeros(size(x));
z(idx1) = x(idx1) + 1i*y(idx1);
z(idx2) = x(idx2) + 1i*y(idx2);
% Calculate the above function using equation 4 and equation 5
% using the mesh created above
Result = zeros(size(z));
Result(idx1) = -real(Eqn5(z(idx1)));
Result(idx2) = -real(Eqn4(z(idx2)));
For example with Angle1 = 45 and Angle2 = 45 we get the following indexing
>> contourf(x,y,idx1);
>> line(line_x,line_y,'color','r','linestyle',':','linewidth',5);
where the yellow region uses Eqn5 and the blue region uses Eqn4. This agrees with the example you posted but I don't know what the resulting contour map for other cases is supposed to look like.
Hope this helps.

Parabola plot with data in Octave

I have been trying to fit a parabola to parts of data where y is positive. I am told, that P1(x1,y1) is the first data point, Pg(xg,yg) is the last, and that the top point is at x=(x1+xg)/2. I have written the following:
x=data(:,1);
y=data(:,2);
filter=y>0;
xp=x(filter);
yp=y(filter);
P1=[xp(1) yp(1)];
Pg=[xp(end) yp(end)];
xT=(xp(1)+xp(end))/2;
A=[1 xp(1) power(xp(1),2) %as the equation is y = a0 + x*a1 + x^2 * a2
1 xp(end) power(xp(end),2)
0 1 2*xT]; % as the top point satisfies dy/dx = a1 + 2*x*a2 = 0
b=[yg(1) yg(end) 0]'; %'
p=A\b;
x_fit=[xp(1):0.1:xp(end)];
y_fit=power(x_fit,2).*p(3)+x_fit.*p(2)+p(1);
figure
plot(xp,yp,'*')
hold on
plot(x_fit,y_fit,'r')
And then I get this parabola which is completely wrong. It doesn't fit the data at all! Can someone please tell me what's wrong with the code?
My parabola
Well, I think the primary problem is some mistake in your calculation. I think you should use three points on the parabola to obtain a system of linear equations. There is no need to calculate the derivative of your function as you do with
dy/dx = a1 + 2*x*a2 = 0
Instead of a point on the derivative you choose another point in your scatter plot, e.g. the maximum: PT = [xp_max yp_max]; and use it for your matrix A and b.
The equation dy/dx = a1 + 2*x*a2 = 0 does not fulfill the basic scheme of your system of linear equations: a0 + a1*x + a2*x^2 = y;
By the way: If you don't have to calculate your parabola necessarily in this way, you can maybe have a look at the Matlab/Octave-function polyfit() which calculates the least squares solution for your problem. This would result in a simple implementation:
p = polyfit(x, y, 2);
y2 = polyval(p, x);
figure(); plot(x, y, '*'); hold on;
plot(x, y2, 'or');

Coloring the Mandelbrot set in Matlab

I made a program to calculate points that are in the mandelbrot set. For the points not belonging to the mandelbrot set I keep track of how many iterations it take for the starting point to diverge to where the magnitude is greater that 2. Basically for every point not in the mandelbrot set I have a counter of how fast it diverges on a scale of 1 to 256. What id like to do is give each point a color according to how fast it diverges. For instance the points that diverge in 255 iterations could be white and the faster it diverges the more it gets colored. I've made an easy adjustment where diverging points that diverge in more than 20 steps are colored red, the ones that diverge in 10-19 steps are blue and one that diverge in 5-9 steps are yellow and it looks like this.
Now I cant do this for all possible 255 rates of divergence. How can I make a graduating scale and implement it in Matlab. Thanks in advance for any help. If anyone would like to know any more please ask. Thanks!
EDIT I am sorry but the image seems to not work. Basically what I need it this. I am plotting points, to each point a value between 1 and 255 is assigned and I want the color to gradually change depending on the value assigned to it. Thanks!
A simple approach to plotting the mandelbrot set in Matlab is as follows
function mandelbrot(n, niter)
x0 = -2; x1 = 1;
y0 = -1.5; y1 = 1.5;
[x,y] = meshgrid(linspace(x0, x1, n), linspace(y0, y1, n));
c = x + 1i * y;
z = zeros(size(c));
k = zeros(size(c));
for ii = 1:niter
z = z.^2 + c;
k(abs(z) > 2 & k == 0) = niter - ii;
end
figure,
imagesc(k),
colormap hot
axis square
This just keeps track of the number of iterations until divergence in the array k, and plots it using a linear color scale by using imagesc. The result is
>> mandelbrot(800, 40)
The image doesn't come in the link and I don't know Matlab, but can you not make the color of each point a function of its divergence? A lot of tools will allow you to specify RGB values, say, from 0-255. Can you not input its divergence for all three RGB values (or whatever color scale you're using) to get shades of gray? i.e. RGB(20,20,20)
I did a little improvement to the code, this will now run given a specific starting point for (x,y) and a starting position. For those looking to zoom in a little further.
function mandelbrot(n, n2, x0, y0, g)
x1 = x0 - g; x2 = x0 + g;
y1 = y0 - g; y2 = y0 + g;
[x,y] = meshgrid(linspace(x1, x2, n), linspace(y1, y2, n));
c = x + 1i * y;
z = zeros(size(c));
k = zeros(size(c));
for ii = 1:n2
z = z.^2 + c;
k(abs(z) > 2 & k == 0) = n2 - ii;
end
figure,
imagesc(k),
colormap hot
axis square
end