Drawing shape context logpolar bins in MATLAB - matlab

I am using shape context histograms as a feature descriptor to encode silhouette images. To assist with debugging, I would like to view the shape context logpolar bins overlaid on a silhouette image (the sample points taken from the edge image).
An example of what it should look like for one of the points is as follows:
I know how to display the circles (radial bins), but I am having difficulty in producing the angular bins (lines).
Given a set of angles, how can I draw line segments similar to those shown in the example image?

You can use this function:
function scDrawPolar(samp,point,r_min,r_max,nbins_theta,nbins_r)
%SCDRAWPOLAR draw a polar on the center point
% point - the center point
% r_min - min radius
% r_max - max radius
% nbins_theta - theta divide
% nbins_r - r divide
% fig_handle - draw the diagram on which figure
gca;
hold on;
plot(samp(1,:)',samp(2,:)','r.');
plot(point(1),point(2),'ko');
r_bin_edges=logspace(log10(r_min),log10(r_max),nbins_r);
% draw circles
th = 0 : pi / 50 : 2 * pi;
xunit = cos(th);
yunit = sin(th);
for i=1:length(r_bin_edges)
line(xunit * r_bin_edges(i) + point(1), ...
yunit * r_bin_edges(i) + point(2), ...
'LineStyle', ':', 'Color', 'k', 'LineWidth', 1);
end
% draw spokes
th = (1:nbins_theta) * 2*pi / nbins_theta;
cs = [cos(th);zeros(1,size(th,2))];
sn = [sin(th);zeros(1,size(th,2))];
line(r_max*cs + point(1), r_max*sn + point(2),'LineStyle', ':', ...
'Color', 'k', 'LineWidth', 1);
axis equal;
axis off;
hold off;
end
See the result here:

Doing this:
>> figure
>> axes
>> hold on
>> radius = 1;
>> theta = 0:30:360;
>> for angle = theta
line([0 radius * cosd(angle)], [0 radius * sind(angle)]);
end
produces this:

Related

can't include plot fully in graph for matlab gui, shows half of plot only

This is a projectile motion graph, I have included the full calculations until the plotting of the graph. I don't understand how to change the settings of the graph using the code after the calculations part.
this is what i've plotted using this code below
time = linspace(0, t, 1000);
legends = {}; % Instantiate an empty cell for the angle legend.
counter = 1;
for A = 10: 10 : 90
% Get the components of velocity in the x and y directions for this angle.
vx = v*cosd(A);
vy = v*sind(A);
% Compute the distance along the x direction. x = x0 + x_velocity * time.
xfinal = vx * time;
% Compute the distance along the y direction. y = y0 + y_velocity_initial *
%time + (1/2)*g*time^2
yfinal = vy * time + (1/2) * 9.81 * time .^ 2;
% Clip y to zero because we assume the projectile stays on the ground when
%it hits.
% It does not penetrate and have a negative y.
yfinal(yfinal < 0) = 0;
indexHitGround = find(yfinal > 0, 1, 'last');
fontSize=10
plot(xfinal, yfinal, '-', 'LineWidth', 2);
hold on;
legends{end+1} = sprintf('Angle = %d', A);
% Calculate the range in the x direction.
xFinal(counter) = xfinal(indexHitGround);
counter = counter + 1;
end
grid on;
xlabel('X Coordinate', 'FontSize', fontSize);
ylabel('Y Coordinate', 'FontSize', fontSize);
title ('Projectile Trajectory', 'FontSize', fontSize)
legend(legends);
% Find the max xFinal and set the range of the graph to be that.
xlim([0, max(xFinal)]);
% Set up figure properties:
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0.2, 0.3, 0.8, 0.7]);
% Get rid of tool bar and pulldown menus that are along top of figure.
set(gcf, 'Toolbar', 'none', 'Menu', 'none');
% Give a name to the title bar.
set(gcf, 'Name', 'Projectile Trajectory Demo Part 2', 'NumberTitle', 'Off')
whereas I'm trying to plot something like this
projectile trajectory
I'm a newbie to matlab so I would really appreciate if you would point out the errors in my code or give me a few suggestions. Thanks!
The problem is not in the way you plot the data but in the equation used to compute the trajectory.
You have to change the sign of the acceleration component to minus.
Change
yfinal = vy * time + (1/2) * 9.81 * time .^ 2;
to
yfinal = vy * time - (1/2) * 9.81 * time .^ 2;
In your code, t and v are not defined, I've used some values to test the code.
Also with respect to the picture of the desired graph, the y0 is not defined (and not used in the equation), perhaps you might change the equation to
yfinal = y0+ vy * time - (1/2) * 9.81 * time .^ 2;
setting y0=10 the trajectories look like:

How do i obtain a cross section from a 3D volume?

I want to obtain a 2D slice from the 3D volume in the example (slightly modified) How do I resolve this issue with 3D image visualization? as follows:
% create input image
imageSizeX = 10;
imageSizeY = 10;
imageSizeZ = 10
% generate 3D grid using voxel size = 0.5
[Xq, Yq, Zq] = ndgrid(1:0.5:imageSizeX-1, 1:0.5:imageSizeY-1, 1:0.5:imageSizeZ-1);
% obtain coordinates of all internal vertices, faces, and edges
allCoords = [Xq(:), Yq(:), Zq(:)]; % i need this bit for something very important but not shown in the question.
% Re-generate 3D grid using voxel size = 1
[columnsInImage, rowsInImage, pagesInImage] = ndgrid(1: imageSizeX-1, 1: imageSizeY-1, 1: imageSizeZ-1);
% create the sphere in the image.
centerY = imageSizeY/2;
centerX = imageSizeX/2;
centerZ = imageSizeZ/2;
diameter = 4;
radius = diameter/2;
sphereVoxels = flipud((rowsInImage - centerY).^2 ...
+ (columnsInImage - centerX).^2 + (pagesInImage - centerZ).^2 <= radius.^2);
% change image from logical to numeric labels.
Img = double(sphereVoxels);
for ii = 1:numel(Img)
if Img(ii) == 0
Img(ii) = 2; % intermediate phase voxels
end
end
% specify the desired angle
angle = 30;
% specify desired pixel height and width of solid
width = imageSizeX;
height = imageSizeY;
page = imageSizeZ;
% Find the row point at which theta will be created
y = centerY - ( radius*cos(angle * pi/180) )
% determine top of the solid bar
y0 = max(1, y-height);
% label everything from y0 to y to be = 3 (solid)
Img(1:width, y0:y, 1:page)=3;
%%%%%% Plot the surfaces
[X, Y, Z, C] = build_voxels(Img > 0);
hSurface = patch(X, Y, Z, Img(C),...
'AmbientStrength', 0.5, ...
'BackFaceLighting', 'unlit', ...
'EdgeColor', 'none', ...
'FaceLighting', 'flat');
colormap([1 0 0; 1 1 0]);
axis equal;
axis tight;
view(45, 45);
grid on;
xlabel('x-axis (voxels)');
ylabel('y-axis (voxels)');
zlabel('z-axis (voxels)');
light('Position', get(gca, 'CameraPosition'), 'Style', 'local');
zoom on;
hold on;
Vq = griddata(columnsInImage, rowsInImage, pagesInImage, Img, Xq, Yq, Zq);
figure
h1 = slice(permute(Xq, [2 1 3]),permute(Yq, [2 1 3]),permute(Zq, [2 1 3]), Vq, 5,2,5);
When i run the code, i get an Error message:
"The number of data point locations should equal the number of data point values.
Error in griddata>useScatteredInterp (line 188)
F = scatteredInterpolant(inargs{1}(:),inargs{2}(:),inargs{3}(:), ..."
I want to believe this is so because the size of columnsInImage and size of pagesInImage are not equal to size(P,1) and size(P,3), respectively.
Nonetheless, I also tried to use a vector as follows:
figure
h1 = slice(Img(:,1), Img(:,2), Img(:,3), Img, 5,2,5);
I however still end up with the error message:
"Error using griddedInterpolant
The grid was created from grid vectors that were not strictly monotonic increasing.
Error in interp3 (line 142)
F = griddedInterpolant(X, Y, Z, V, method,extrap);"
Please, guys i need suggestions/ideas on how i could remedy these. Many thanks in advance!..

Replace quiver arrowheads with images

I have a circular lattice and on the lattice sites I plot normalized arrows that remain in the same magnitude and change direction according to a simulation, the details of which don't matter.
My plots look like this
Is it possible to replace the arrow in the quiver plot by an jpg/bmp/gif/png image? or by any other command?
Ideally, it would look something like this (although not necessarily arrows)
Explanation
One way that you can do this, would be to use a surface object with a texture-map as the FaceColor.
In MATLAB, you can create a simple rectangular surface. You can set the FaceColor to be texturemap which will cause the value assigned to CData to be mapped across the surface.
Then to get transparency, you can also set the FaceAlpha value to be texturemap and set the AlphaData and those transparency values will be mapped across the extent of the surface as well.
For this to be applied to your case, you want to set the CData to the image that you want to use to replace your arrows. And you will want the AlphaData to be the same size as your image data with values of 1 where you want it to be opaque and 0 where you want it to be transparent. This will allow it to not look like the image that you have posted where you can clearly see the bounding box. Then you will need to draw one of these surfaces where each of the arrows would go and scale/position it appropriately.
Implementation
Update: A more polished version of this code (ImageQuiver) is now available on Github as well as the MATLAB File Exchange.
As a demonstration of what I'm talking about, I have created the following function which essentially does just this. It accepts the same inputs as quiver (with the image data being supplied first and an optional AlphaData parameter at the end) and creates a surface at all of the requested coordinates pointing in the requested direction, and scaled by the specified amount.
function h = quiverpic(im, X, Y, dX, dY, scale, alpha)
% im - RGB or indexed image
% X - X positions
% Y - Y positions
% dX - X direction vector
% dY - Y direction vector
% scale - Any scaling (Default = 1)
% alpha - Transparency (same size as im), if not specified = ~isnan(im)
h = hggroup();
if ~exist('scale', 'var')
% By default there is no scaling
scale = 1;
end
if ~exist('alpha', 'var')
% By default, any NaN will be transparent
alpha = ~isnan(im);
end
% Determine aspect ratio of the source image
width_to_height = size(im, 2) / size(im, 1);
for k = 1:numel(X)
% Determine angle from displacement vectors
theta = atan2(dY(k), dX(k));
% Subtract pi/2 to +y is considered "up"
theta = theta + pi/2;
% Setup surface plot boundary
[xx,yy] = meshgrid([-0.5, 0.5] * width_to_height, [0 1]);
% Scale depending on magnitude of dX and dY
this_scale = scale * sqrt(dX(k).^2 + dY(k).^2);
% Scale X and Y components prior to rotating
xx = xx .* this_scale;
yy = yy .* this_scale;
% Rotate to align with the desired direction
xdata = xx .* cos(theta) - yy .* sin(theta);
ydata = xx .* sin(theta) + yy .* cos(theta);
% Determine what is considered the "anchor" of the graphic.
% For now this is assumed to be the "bottom-middle"
xoffset = X(k) - mean(xdata(2,:));
yoffset = Y(k) - mean(ydata(2,:));
% Actually plot the surface.
surf(xdata + xoffset, ...
ydata + yoffset, zeros(2), ...
'Parent', h, ...
'FaceColor', 'texture', ...
'EdgeColor', 'none', ...
'CData', im, ...
'FaceAlpha', 'texture', ...
'AlphaData', double(alpha));
end
end
Example
I wrote a little test script to show how this can be used and to show the results.
t = linspace(0, 2*pi, 13);
dX = cos(t(1:end-1));
dY = sin(t(1:end-1));
X = (3 * dX) + 5;
Y = (3 * dY) + 5;
scale = 1;
% Load the MATLAB logo as an example image
png = fullfile(matlabroot,'/toolbox/matlab/icons/matlabicon.gif');
[im, map] = imread(png);
im = ind2rgb(im, map);
% Determine alpha channel based on upper left hand corner pixel
flatim = reshape(im, [], 3);
alpha = ~ismember(flatim, squeeze(im(1,1,:)).', 'rows');
alpha = reshape(alpha, size(im(:,:,1)));
% Plot some things prior to creating the quiverpic object
fig = figure();
hax = axes('Parent', fig);
axis(hax, 'equal');
% Plot a full circle
t = linspace(0, 2*pi, 100);
plot((cos(t) * 3) + 5, (sin(t) * 3) + 5, '-')
hold(hax, 'on')
% Plot markers at all the quiver centers
plot(X, Y, 'o', 'MarkerFaceColor', 'w')
% Plot a random image behind everything to demonstrate transparency
him = imagesc(rand(9));
uistack(him, 'bottom')
axis(hax, 'equal')
colormap(fig, 'gray')
set(hax, 'clim', [-4 4]);
% Now plot the quiverpic
h = quiverpic(im, X, Y, dX, dY, 1, alpha);
axis(hax, 'tight')
Results
Absurdity
Same image with varying vectors and scaling
Any image of any aspect ratio will work just fine

Plotting too slow on Matlab

I am having some issues with a code I am writing, simply because it is too long to plot. What I am trying to do is for matlab to plot a series of ellipses filled with colors depending on a specific parameter.
Here is the code I am using:
clearvars -except data colheaders
close all
clc
data(:,15)=data(:,9)*pi/180; % Convers Column 9 (angle of rotation) in rad
data(:,16)=1196-data(:,6); % Reset the Y coordinate axis to bottom left
delta = 0 : 0.01 : 2*pi; % Converts roation angle in rad
theta=45*pi/180; % Sample cutting angle
imax=5352; % Numbers of rows in data sheet
% Define variables for colors
beta=acos(data(1:imax,8)./data(1:imax,7));%./acos(0);
phi=atan(sin(beta).*cos(data(1:imax,15))./(sin(theta)*sin(beta).*sin(data(1:imax,15))+cos(theta)*cos(beta)))/(pi/2);
phi2=phi/2+1/2; % Set phi within 0 and 1 for colormap
gamma=atan((cos(theta)*sin(beta).*sin(data(1:imax,15))-sin(theta)*cos(beta))./...
(sin(theta)*sin(beta).*sin(data(1:imax,15))+cos(theta)*cos(beta)))/(pi/2);
gamma2=gamma+1/2; % Set gamma between 0 and 1 for colormap
cm = colormap(jet) ; % returns the current color map
% Sort and get their index to access the color array
[~,idx] = sort(phi);
for i=1:imax
x = data(i,7)/2 * cos(delta) * cos(data(i,15)) - data(i,8)/2 * sin(delta) * sin(data(i,15)) + data(i,5);
y = data(i,8)/2 * sin(delta) * cos(data(i,15)) + data(i,7)/2 * cos(delta) * sin(data(i,15)) + data(i,16);
colorID1 = max(1, sum(phi2(i) > [0:1/length(cm(:,1)):1]));
colorID2 = max(1, sum(gamma2(i) > [0:1/length(cm(:,1)):1]));
ColorMap1(i,:) = cm(colorID1, :); % returns your color
ColorMap2(i,:) = cm(colorID2, :); % returns your color
hold on
% Columns (5,6) are the centre (x,y) of the ellipse
% Columns (7,8) are the major and minor axes (a,b)
% Column 9 is the rotation angle with the x axis
figure(1);
fill(x,y,ColorMap1(i,:),'EdgeColor', 'None');
title('Variation of In-plane angle \phi')
colorbar('SouthOutside')
grid on;
caxis([-90 90])
%text(data(i,5),data(i,16),[num2str(0.1*round(10*acos(0)*180*phi(i)/pi))])
figure(2);
fill(x,y,ColorMap2(i,:),'EdgeColor', 'None');
title('Variation of Out-of-plane angle \gamma')
colorbar('SouthOutside')
grid on;
caxis([-45 45])
%text(data(i,5),data(i,16),[num2str(0.1*round(10*acos(0)*180*gamma(i)/pi))])
% Assigns angle data to each ellipse
end
axis equal;
Maybe someone knows how to make that it doesnt take ages to plot ( i know figure is a bad method, but I want 2 specific colormap for the 2 variables phi and gamma).
Cheers guys
Example data you can use to run the code
data(:,5) = [3 ;5 ;12; 8]; % Centre location X
data(:,6) = [1; -5 ;-2; 4]; % Centre location Y
data(:,7) = [6 ;7;8;9]; % Major Axis a
data(:,8) = [2;3;3;5]; % Minor axis b
data(:,9) = [10;40;45;90]; % Angle of rotation
All you need to do is change imax for 4 instead of 5352 and it should work
Dorian

Matlab: contourf or colormap to plot filled ellipses according to radius

I am trying to use either the contourf or colormap functions to plot filled ellipses with colors according to their arcsin(b/a) value (a=major axis, b=minor axis).
clearvars -except data colheaders
close all
clc
data(:,9)=data(:,9)*pi/180; % Convers Column 9 (angle of rotation) in rad
data(:,6)=1196-data(:,6); % Reset the Y coordinate axis to bottom left
theta = 0 : 0.01 : 2*pi; % Converts phi in rad
imax=29;
% Define colors
cvalues=asin(data(1:imax,8)./data(1:imax,7))./asin(1);
cm = colormap; % returns the current color map
% Sort and get their index to access the color array
[~,idx] = sort(cvalues);
% Create colormap
%ColorMap=jet;
for i=1:imax
x = data(i,7)/2 * cos(theta) * cos(data(i,9)) - data(i,8)/2 * sin(theta) * sin(data(i,9)) + data(i,5);
y = data(i,8)/2 * sin(theta) * cos(data(i,9)) + data(i,7)/2 * cos(theta) * sin(data(i,9)) + data(i,6);
colorID = max(1, sum(cvalues(i) > [0:1/length(cm(:,1)):1]));
ColorMap(i,:) = cm(colorID, :); % returns your color
hold on
% Columns (5,6) are the centre (x,y) of the ellipse
% Columns (7,8) are the major and minor axes (a,b)
% Column 9 is the rotation angle with the x axis
%% TRYING A FASTER WAY OF PLOTTING
%A(:,i)=x';
%B(:,i)=y';
%%
fill(x,y,ColorMap(i,:),'EdgeColor', 'None')
text(data(i,5),data(i,6),[num2str(asin(1)*180*cvalues(i)/pi)]) % Assigns number to each ellipse
end
%%
%fill(A,B,ColorMap(1:200,3)','EdgeColor', 'None')
%%
% Adds colorbar to plot
colorbar('SouthOutside')
caxis([0 90])
axis equal;
%xlim([0 7649]);
%ylim([0 15927]);
grid on;
I get a picture that looks like this which I think works well:
Instead of adding numbers in the ellipses, I have added the angle I obtained (90 for circles, 0 for very long ellipse). Now is my real experiment i will have to plot several thousands ellipses, and we found out that it takes quite alot of time to plot them, you'll see we tried another method to basically record the data and plot all in one go. But we haven't succeeded so far if you have any advice :)
Here is a way using built-in colormaps in Matlab (look here for a complete list).
The trick is to create a n x 3 array where n is the number of colors you wish to represent. Here it's the number of ellipses.
You can create a colormap like so:
MyColorMap = jet(n)); %// jet or anything listed in the link above. You can also create your own colormap.
So that's what we're going to do in the following code. In order to get the order right, we need to sort the values of asin(b/a) and fetch each index for the right ellipse. The code is commented so it's quite easy to follow. I added 4 ellipses in the plot to see the difference in color better:
clear
clc
close all
%// Define dummy data
data = zeros(8,9);
data(:,5) = [3;5;12;8;2;7;4;6]; % Centre location X
data(:,6) = [1; -5 ;-2; 4;2;-3;9;5]; % Centre location Y
data(:,7) = [6 ;7;8;6;1;4;2;5]; % Major Axis a
data(:,8) = [2;5;4;2;2;5;3;7]; % Minor axis b
data(:,9) = [10;40;45;90;35;70;85;110]; % Angle of rotation phi
data(:,9)=data(:,9)*pi/180; % Converts phi in rads
theta = 0 : 0.01 : 2*pi;
%// Define colors here
cvalues = asin(data(:,8)./data(:,7));
%// Sort and get their index to access the color array
[~,idx] = sort(cvalues);
%// Create colormap with the "jet" colors
ColorMap = jet(numel(cvalues));
This is the array containing the "colors". It looks like this:
ColorMap =
0 0 1
0 0.5 1
0 1 1
0.5 1 0.5
1 1 0
1 0.5 0
1 0 0
0.5 0 0
So each row represents a combination of red, blue and green (RGB) and there are as many rows as there are ellipses to plot. Now filling the ellipses:
hold all
for i=1:numel(idx)
k = idx(i);
x = data(k,8)/2 * cos(theta) * cos(data(k,9)) - data(k,7)/2 * sin(theta) * sin(data(k,9)) + data(k,5);
y = data(k,7)/2 * sin(theta) * cos(data(k,9)) + data(k,8)/2 * cos(theta) * sin(data(k,9)) + data(k,6);
fill(x,y,ColorMap(i,:))
plot(x, y, 'LineWidth', 1);
% Label each ellipse with a number
text(data(i,5),data(i,6),num2str(i),'Color','k','FontSize',12)
end
axis equal;
grid on;
Output with the jet colormap: blue is the first ellipse plotted and red is the last. You can add a colorbar if you want (add colorbar)
Using another colormap, the bone colormap, gives the following:
Hope that helps!