Curve Fitting in a binary image, MATLAB - matlab

I have this Binary image bw:
edges of an object to carry out some measurements. But firstly I have to do curve fitting for both edges. The result should be two smooth curves representing edges.
I have the indices for each edge but I can not use them in making x-y data to be input data to a fitting function. I mean they are not x and f(x), actually, they all have the same value (1) with different positions. It is not right to say [x y]=find(BW) ; y here is not the value at x, but for sure there should be a way to use them to some kind of scale the binary image. I seem confused and I'm stuck here.
Any recommendations?

Why not use polyfit?
[y x] = find( bw ); %// get x y coordinates of all curve points
There are two small "tricks" you need to use here:
You have two curves, thus you need to split your data points to the left and right curves
right = x<300;
xr = x(right);
yr = y(right);
xl = x(~right);
yl = y(~right);
Since your curves are close to vertical, it would be better to fit x=f(y) rather than the "classic" y=f(x):
pr = polyfit( yr, xr, 3 ); %// fit 3rd deg poly
pl = polyfit( yl, xl, 3 );
Now you can plot them
yy = linspace( 1, size(bw,1), 50 );
figure; imshow(bw, 'border', 'tight' );
hold all
plot( polyval( pr, yy ), yy, '.-', 'LineWidth', 1 );
plot( polyval( pl, yy ), yy, '.-', 'LineWidth', 1 );
And you get:
If you want to create a new refined mask from the estimated curves, you can do the following:
yy = 1:size(bw,1); %// single value per row
xxr=polyval(pr,yy); %// corresponding column values
xxl=polyval(pl,yy);
Set a new mask of the same size
nbw = false(size(bw));
nbw( sub2ind(size(bw),yy,round(xxr)) )=true;
nbw( sub2ind(size(bw), yy, round(xxl) )) = true;
And the result
figure;imshow(nbw,'border','tight');

Related

Plot line between all the scattered points and adjust the thickness of line according to the distance between points

Here are the coordinates that I am planning to plot, filename is Coords:
x y
0.0110 0.1105
-0.2730 0.2559
0.3610 0.1528
-0.0077 -0.2520
-0.2412 -0.1979
0.0444 -0.0526
0.0543 -0.0076
-0.1710 0.1170
0.12741 -0.0448
0.0949 -0.0811
Here is my code that plots the scatter graph first:
Hold on
%Plot Coordinate
For i=1:10
dot_size = 100;
scatter ( Coords(i,1) ,Coords(i,2), dot_size, 'filled', 'MarkerEdgeColor', 'k' );
end
%Draw line distance between each points
for i=1:10
for j=1:10
plot( [Coords(i,1) Coords(i,2)], [Coords(j,1) Coords(j,2)] );
end
end
Hold off
%Sets the size of the y and x axis
xlim( [ min( Coords(:,1)) max( Coords(:,1)) ] );
ylim( [ min( Coords(:,2)) max( Coords(:,2)) ] );
axis off;
Here is the result I get:
I don't know why the lines are being drawn everywhere. I also notice that even when plot(x,y) = 0, the line is still being drawn.
I also would like to change the thickness and opacity of the line depending on the distance between the two points: E.g. thicker and darker line for short distance between points. And thinner /lighter line if the distance between two points are long.
I want my plot to look something like this:
The reason your lines do not match the scattered points is the coordinates you give to plot; The coordinates are in wrong order and therefore they do not define the lines correctly.
I modified your code to correct this issue. I replaced plot with line, but you can also do the same with plot. In addition, I defined the anonymous functions f and g to define the color and thickness of each line based on distance of the two ends, d. You can modify these functionalities to get different graphical behaviors.
n = 10; % number of points
dot_size = 100;
Coords = rand(n, 2);
% maximum possible length in your coordination plane:
L = norm([max(Coords(:,1))-min(Coords(:,1)),max(Coords(:,2))-min(Coords(:,2))]);
% this function defines the line width:
f = #(x) L / (x + 0.1); % 0.1 avoids huge line widths in very small distances
% this function defines the color:
g = #(x) x * [1 1 1] / L;
figure
hold on
for ii = 1:n-1
for jj = ii+1:n
d = norm([Coords(ii,1)-Coords(jj,1), Coords(ii,2)-Coords(jj,2)]);
line([Coords(ii,1) Coords(jj,1)], [Coords(ii,2) Coords(jj,2)], ...
'LineWidth', f(d), 'Color', g(d));
end
end
scatter (Coords(:,1), Coords(:,2), dot_size, 'filled', 'MarkerEdgeColor', 'k');
axis tight
axis off
With this output:
Notes:
axis tight is a command that sets the limits to the tightest possible. It is equivalent to your xlim( [ min( Coords(:,1)) max( Coords(:,1)) ] ); and the next line.
In the for-loops you should try to avoid choosing one pair of points twice or same point as both sides of a line.
For scattering you do not need a loop. It could all be done at once.
I brought scatter after plotting the lines, so the circles are drawn on top.
There is also a specialized MATLAB function for generating plots like this: gplot.
data = [
0.0110 0.1105
-0.2730 0.2559
0.3610 0.1528
-0.0077 -0.2520
-0.2412 -0.1979
0.0444 -0.0526
0.0543 -0.0076
-0.1710 0.1170
0.12741 -0.0448
0.0949 -0.0811]; % Coordinates
adjM = squareform(pdist(data)); %
adjM (adjM > 0) = 1; % Form adjacency matrix based on Euclidean distances
figure; gplot(adjM, data, '-o') % Plot figure based on coordinates and adjacency matrix
Then, customize to your liking, e.g. if you want to change marker type, remove the axis, add labels etc.

Issue with scatter3

Probably it's scatter3 what I don't understand. I have a matrix of which all slices but the last are NaNed (M(:,:,1:10) = NaN;) and then it's permuted switching first and last dimension. So there are only values in M(11,:,:). I expect all plotted values to be in the Y-Z plane at x==11, but the plot looks differently (see code and picture below). Any explanations?
M = rand(22,55,11);
M(:,:,1:10) = NaN;
M = permute(M,[3 2 1]);
shape = size(M)
[x, y, z] = meshgrid(1:shape(1), 1:shape(2), 1:shape(3));
scatter3(x(:), y(:), z(:), 4, M(:), 'fill');
view([60 60]);
xlabel('X ', 'FontSize', 16);
ylabel('Y ', 'FontSize', 16);
zlabel('Z ', 'FontSize', 16);
The explanation is that meshgrid switches x and y:
From meshgrid documentation:
MESHGRID is like NDGRID except that the order of the first two input
and output arguments are switched (i.e., [X,Y,Z] = MESHGRID(x,y,z)
produces the same result as [Y,X,Z] = NDGRID(y,x,z)).
At first sight, this should result in a plot with values in the X-Z plane at y==11 (i.e. x and y interchanged with respect to what you initially expected). But note that your code treats x and y sizes incorrectly (because of meshgrid). This has the additional effect that the x and y coordinates get "shuffled" and you don't see a plane (even in X-Z), but rather a lattice.
So the solution is to use ndgrid, which doesn't do any switching. Just replace "meshgrid" by "ndgrid" in your code. The resulting figure is now as expected:

Plot function in 2D intensity plot in matlab

I'm trying to visualise a function into a more intuitive color-coded plot, which can be used into a image. I try to visualise the range in which fluorescent proteins can efficiently transfer energy from one to another. A very important factor in this process is the distance between the two proteins. Therefore I want to plot the theoretical graph of energy transfer as a function of distance on top of one of these proteins.
I would like to have an 2D intensity plot which I can use to incorporate into my protein model.
The function describing efficient energy transfer is:
E = R^6/(R^6+r^6)
E = efficiency of energy transfer
R = Förster distance 50% chance of transfer
r = actual distance between the fluorescent proteins
Low values for r cause high values of E, meaning efficient energy transfer --> Green
High values for r cause low values of E, inefficient energy transfer --> red
My question is if someone can help me to transform the graph into a color-coded circle, where the middle of the circle corresponds with high E (green) and the borders are more red.
So far, I tried the mesh + surf function, but these require a matrix so that doesn't work.
I appreciate all your help, thank you for your replies!
Cheers,
Reinier
If I understand correctly then
[R r] = meshgrid( 0.1:0.1:5 ); % define 2D inputs
E = (R.^6)./( R.^6 + r.^6 ); % compute 2D function
figure;
surf( R, r, E, 'EdgeColor','none'); % plot using surf
xlabel('R');
ylabel('r');
colormap( [ 1:-0.05:0; 0:.05:1; zeros( 1, numel(0:.05:1) )]' ); % colormap red->green
What you get is
If you want to plot the 2D function E( x,y ; R=5.1 ) with r(x,y) = || x - y || then you can try
[X Y] = meshgrid(-120:1:120); % x,y range -120:120 nm
r = sqrt( X.^2 + Y.^2 );
R=5.1; % fixing R to 5.1 nm
figure;
surf( X, Y, (R.^6)./( R.^6 + r.^6 ), 'EdgeColor','none');
xlabel('X[nm]');
ylabel('Y[nm]');
zlabel('E');
colormap( [ 1:-0.05:0; 0:.05:1; zeros( 1, numel(0:.05:1) )]' );
colorbar;
In that case you'll get

Matlab 3D interpolation

I have 3 matrices(129x129) corresponding to x, y and z coordinates. I used the function mesh
mesh(x,y,z);
to plot the corresponding figure. It comes out to be a sphere. Now, I have another set of x, y, z(again 129) which gives a different sphere. What I want is to use interpolation in MATLAB to obtain the figures that come in between. I looked at the function interp3 in MATLAB but could not figure out what to do with it.
It seems like you are interested in the evolution of the surface z(x,y) from one surface z0 to another z1. I would suggest the following process
T = 5; % number of "time steps" from z0 to z1
t = linspace( 0, 1, T );
for ii = 1 : T
zt = t(ii).*z1 + (1-t(ii)).*z0;
mesh( x, y, zt ); title( sprintf( 'time %d', ii ) );
drawnow;
pause(1); wait a sec
end

3D plot of part of hyperboloid

I would like to plot a 3D figure of a hyperbole that is cut down at the bottom of it in the following way (figure)
any ideas?
OK, here's my stab at your problem. This is the experimental script I've been using:
%%# first part
%#------------------
clf
%# use cylinder to get unit cone
[x,y,z] = cylinder( linspace(1, 0, 1e3), 1e3);
%# intersect the cone with this surface
inds = z < (cos(x).*sin(pi*y/2)+1)/4;
x(inds) = NaN; %# remove all corresponding
y(inds) = NaN; %# indices, in all arrays
z(inds) = NaN;
%# Now plot the cone. Note that edges are ugly when
%# using a large number of points
surf(x, y, z, 'edgecolor', 'none');
%%# second part
%#------------------
hold on
%# the surface to intersect the cone with
f = #(x,y) (cos(x).*sin(pi*y/2)+1)/4;
%# add the surfacfe to the cone plot
[x,y] = meshgrid( linspace(-1,1, 1e3) );
surf(x,y, f(x,y), 'edgecolor', 'none')
The first part shows a cone intersected with a curve. You might want to tinker a bit with the curve to get the overall shape right, which is what the second part is for.
If you want a paraboloid (or other), just use
[x,y] = meshgrid( linspace(-1,1, 1e3) );
z = 1-x.^2-y.^2; %# or whatever other equation
instead of the cylinder command.