Extract outline from MATLAB Isosurface - matlab

I have an isosurface I've plotted in MATLAB, e.g.:
And I'd like to extract the outline from this, for the given view settings that I currently have. The output I expect is like this (produced by GIMP):
Is there any way to programatically do this so I don't have to manually do it in GIMP?

Is this good enough? Edge detection taken from the bwboundaries documentation.
clear, close all
[x y z v] = flow;
figure(1)
p = patch(isosurface(x, y, z, v, -3));
set(p, 'FaceColor', 'red', 'EdgeColor', 'none');
daspect([1 1 1])
view(3)
grid off
axis off
print -dbmp test
I=imread('test.bmp');
G = im2bw(I, graythresh(I));
[B,L] = bwboundaries(~G,'noholes');
for k = 1:length(B)
boundary = B{k};
plot(boundary(:,2), -boundary(:,1), 'k', 'LineWidth', 2)
hold on
end
hold off
Which results in:

Related

How to combine a 3D surf plot and a comet3 plot in MATLAB?

I'm writing a code to plot the circular orbit of a satellite (created using comet3() function) around a 3d model of the Earth (created using surf() and set() functions). The problem is that I can't seem to find a way to get them together in the same plot. I have tried using hold on and hold off but that doesn't seem to work either. I'm pasting the MATLAB code below for reference.
Edit: All the other functions like sv_from_coe(), odeset, etc. are working perfectly, the only place I'm facing issue is combining the plots from comet3() and set().
G = 6.67E-11;
Me = 5.976E24;
coe = [6776, 0.0005638, 2.0543, 0.9, 5.549, 0];
[r, v] = sv_from_coe(coe);
rv = [r v];
opt = odeset('RelTol', 1e-6, 'AbsTol', 1e-6);
[t,X] = ode45(#rate, [0 2*1.5*3600], rv, opt);
[x,y,z] = sphere;
r_earth = 6378*1000;
figure
hs1 = surf(x*r_earth,y*r_earth,-z*r_earth);
cdata = imread('1024px-Land_ocean_ice_2048.jpg');
alpha = 1;
hold on
axis equal
comet3(X(:,1), X(:,2), X(:,3))
set(hs1, 'FaceColor', 'texturemap', 'CData', cdata, 'FaceAlpha', alpha, 'EdgeColor', 'none')
You just have to reverse the order, first plot the earth and set the texture. Then use comet3 to animate the trajectory:
% earth
[x,y,z] = sphere;
r_earth = 6378*1000;
% some simple trajectory
phi = 0:0.01:2*pi;
r_orbit = r_earth + 408*1e3; % ISS orbit height
xv = r_orbit * cos(phi);
yv = r_orbit * sin(phi);
zv = zeros(size(yv));
% draw figure
figure(1); clf;
ax = axes;
% first plot the earth and set texture
hs1 = surf(x*r_earth,y*r_earth,-z*r_earth);
alpha = 1;
cdata = imread("Land_ocean_ice_2048.jpg");
set(hs1, 'FaceColor', 'texturemap', 'CData', cdata, 'FaceAlpha', alpha, 'EdgeColor', 'none')
hold on
axis equal
% finally, animate using comet3
comet3(xv,yv,zv)

Smoothing/interpolation of a 3D surface colormap

I'm trying to smooth or interpolate away the "steps" building up to a intensity maximum, and at the same time preserving the shape of the surface so that the estimated width does not get shifted or changed. I have tried interpolating to a higher resolution using 2D spline, but the "steps" are still present and the estimated maxima region changes. Could someone please help me in smoothing/interpolating away those steps to make the surface look more continuous while conserving the surface shape?
As always, many thanks in advance for any advice or help!!
Uninterpolated
Interpolated
Attempt
conversion = 1/49.0196; % in mm/pixel
new_xData = linspace(xData(1), xData(end), 10*length(xData));
new_yData = linspace(yData(1), yData(end), 10*length(yData)).';
new_zData = interp2(xData, yData, zData, new_xData, new_yData, 'spline');
xData = new_xData; yData = new_yData; zData = new_zData;
h = figure();
surf(xData, yData, zData, 'LineStyle', 'none', 'FaceColor', 'interp');
xlim([xData(1) xData(end)])
ylim([yData(1) yData(end)])
zlim([0 ceil(max(zData(:)))]);
colormap(jet(4096))
xlabel('mm'); ylabel('mm'); zlabel('ln(Intensity)');
set(gca,'Ydir', 'reverse')
grid on
shading interp
view(3); axis vis3d; camlight;
% Change x and y tick labels from pixels to mm
addMM = #(x) sprintf('%.1f', x * conversion);
xticklabels(cellfun(addMM,num2cell(xticks'),'UniformOutput',false));
yticklabels(cellfun(addMM,num2cell(yticks'),'UniformOutput',false));
% Find maxium intensity region and plot it
hold on
maxValue = max(zData(:));
[rowsOfMaxes, colsOfMaxes] = find(zData == maxValue);
x_minind = min(colsOfMaxes(:));
x_maxind = max(colsOfMaxes(:));
p = zeros(1, 2);
p(1) = plot3(linspace(xData(x_minind), xData(x_minind), ...
length(yData)), yData, zData(:, x_minind), 'Linestyle', '-.', ...
'Color', 'black', 'LineWidth', 2.0);
p(2) = plot3(linspace(xData(x_maxind), xData(x_maxind), ...
length(yData)), yData, zData(:, x_maxind), 'Linestyle', '-.', ...
'Color', 'black', 'LineWidth', 2.0);
hold off
legend(p(1), 'Estimated width of maximum intensity', 'Location', 'North')
set(gca, 'FontSize', 14)

How can I fill an area below a 3D graph in MATLAB?

I created the following 3d plot in MATLAB using the function plot3:
Now, I want to get a hatched area below the "2d sub-graphs" (i.e. below the blue and red curves). Unfortunately, I don't have any idea how to realize that.
I would appreciate it very much if somebody had an idea.
You can do this using the function fill3 and referencing this answer for the 2D case to see how you have to add points on the ends of your data vectors to "close" your filled polygons. Although creating a pattern (i.e. hatching) is difficult if not impossible, an alternative is to simply adjust the alpha transparency of the filled patch. Here's a simple example for just one patch:
x = 1:10;
y = rand(1, 10);
hFill = fill3(zeros(1, 12), x([1 1:end end]), [0 y 0], 'b', 'FaceAlpha', 0.5);
grid on
And here's the plot this makes:
You can also create multiple patches in one call to fill3. Here's an example with 4 sets of data:
nPoints = 10; % Number of data points
nPlots = 4; % Number of curves
data = rand(nPoints, nPlots); % Sample data, one curve per column
% Create data matrices:
[X, Y] = meshgrid(0:(nPlots-1), [1 1:nPoints nPoints]);
Z = [zeros(1, nPlots); data; zeros(1, nPlots)];
patchColor = [0 0.4470 0.7410]; % RGB color for patch edge and face
% Plot patches:
hFill = fill3(X, Y, Z, patchColor, 'LineWidth', 1, 'EdgeColor', patchColor, ...
'FaceAlpha', 0.5);
set(gca, 'YDir', 'reverse', 'YLim', [1 nPoints]);
grid on
And here's the plot this makes:

Shade and calculate specific area

I tried to change the code in a way so that only the first area is shaded grey. How can I set the horizontal line in a way that it only appears under the area I want to shade?
Furthermore I want to calculate the area of ONE region. How do I achieve that? I know it is trapz but I am not sure how to set the boundaries. Thanks!
x = 0:.01:4*pi; %// x data
y = sin(x); %// y data
level = 0.5; %// level
plot(x, y)
hold on
area(x, max(y, level), level, 'EdgeColor', 'none', 'FaceColor', [.7 .7 .7])
Curve:-
you can try also this simple option:
x = 0:.01:4*pi; %// x data
y = sin(x); %// y data
level = 0.5; %// level
lineStart = find(y>=level,1);
lineEnd = find(y(lineStart:end)<=level,1)+lineStart;
plot(x,y)
hold all
area(x(lineStart:lineEnd),y(lineStart:lineEnd),...
level,'EdgeColor', 'none', 'FaceColor', [.7 .7 .7],'ShowBaseLine','off')
line([x(lineStart),x(lineEnd)],[level level ])
hold off
without defining areas of interest a-priory:
And don't forget to hold off...
To calaulate the area:
A = trapz(x(lineStart:lineEnd),y(lineStart:lineEnd))
You can limit the range of your x axis in the area plot to the range of interest, e.g. from 0 to 4 and then calculate the resulting values of the function in this range. For the base line: you can hide it in the area command and add it manually using the line command.
x = 0:.01:4*pi; %// x data
y = sin(x); %// y data
level = 0.5; %// level
plot(x, y)
hold on
x_interest = 0:.01:4;
y_interest = sin(x_interest);
area(x_interest, max(y_interest, level), level, ...
'EdgeColor', 'none', 'FaceColor', [.7 .7 .7], ...
'ShowBaseLine', 'off');
line( [ min(x_interest) max(x_interest) ], [ level level ] )

Multi dimensional (2d better 3d) scatter-plot with different errorbars in matlab

I am trying to program scatterplot with specific errorbars. The only build in function i found is
errorbar()
but this only enables me to make a 2d plot with errorbars in y direction. What i am asking for is a method to plot this with errorbars in x and y direction.
At the end my goal is to make a 3D-scatter-plot with 3 errorbars.
Perfect would be if the resulting image would be a 3d-plot with 3d geometric shapes (coordinate x,y,z with expansion in the dimension proportional to the errorbars) as 'marker'.
I found this page while searching the internet: http://code.izzid.com/2007/08/19/How-to-make-a-3D-plot-with-errorbars-in-matlab.html
But unfortunately they use only one errorbar.
My data is set of 6 arrays each containing either the x,y or z coordinate or the specific standard derivation i want to show as errorbar.
The code you posted looks very easy to adapt to draw all three error bars. Try this (note that I adapted it also so that you can change the shape and colour etc of the plots as you normally would by using varargin, e.g. you can call plot3d_errorbars(...., '.r'):
function [h]=plot3d_errorbars(x, y, z, ex, ey, ez, varargin)
% create the standard 3d scatterplot
hold off;
h=plot3(x, y, z, varargin{:});
% looks better with large points
set(h, 'MarkerSize', 25);
hold on
% now draw the vertical errorbar for each point
for i=1:length(x)
xV = [x(i); x(i)];
yV = [y(i); y(i)];
zV = [z(i); z(i)];
xMin = x(i) + ex(i);
xMax = x(i) - ex(i);
yMin = y(i) + ey(i);
yMax = y(i) - ey(i);
zMin = z(i) + ez(i);
zMax = z(i) - ez(i);
xB = [xMin, xMax];
yB = [yMin, yMax];
zB = [zMin, zMax];
% draw error bars
h=plot3(xV, yV, zB, '-k');
set(h, 'LineWidth', 2);
h=plot3(xB, yV, zV, '-k');
set(h, 'LineWidth', 2);
h=plot3(xV, yB, zV, '-k');
set(h, 'LineWidth', 2);
end
Example of use:
x = [1, 2];
y = [1, 2];
z = [1, 2];
ex = [0.1, 0.1];
ey = [0.1, 0.5];
ez = [0.1, 0.3];
plot3d_errorbars(x, y, z, ex, ey, ez, 'or')