Gradient fill of a function inside a circular area Matlab - matlab

I'm trying to create a gradient fill inside a circular area according to a given function. I hope the plot below explains it at best
I'm not sure how to approach this, as in the simulation I'm working on the direction of the gradient changes (not always in the x direction as below, but free to be along all the defined angles), so I'm looking for a solution that will be flexible in that manner as well.
The code I have is below
clear t
N=10;
for i=0:N
t(i+1) = 0+(2*i*pi) / N;
end
F = exp(-cos(t))./(2.*pi*besseli(1,1));
figure(1)
subplot(1,3,1)
plot(t*180/pi,F,'-ob')
xlim([0 360])
xlabel('angle')
subplot(1,3,2)
hold on
plot(cos([t 2*pi]), sin([t 2*pi]),'-k','linewidth',2);
plot(cos([t 2*pi]), sin([t 2*pi]),'ob');
plot(cos(t).*F,sin(t).*F,'b','linewidth',2);
subplot(1,3,3)
hold on
plot(cos([t 2*pi]), sin([t 2*pi]),'-k','linewidth',2);
plot(cos([t 2*pi]), sin([t 2*pi]),'ob');

To fill surface, you need to use the patch command.
t = linspace(0, 2*pi, 100);
x = cos(t);
y = sin(t);
c = x; % colored following x value and current colormap
figure
patch(x,y,c)
hold on
scatter(x,y)
hold off
colorbar
Resulting graph:
Colors are defined in c per point, and are interpolated inside the shape, so I'm sure that you should have all freedom to color as you want!
For example, the rotated version:
t = linspace(0, 2*pi, 100);
x = cos(t);
y = sin(t);
c = cos(t+pi/4)
figure
patch(x,y,c)
colorbar
To understand how it is going on, just think that every point has a color, and matlab interpolate inside. So here I just rotated the intensity per point by pi /4.
For this to work you need to have a filled shape, and you may need to customize the color (c) parameter so that it matches your need. For example, if your gradient direction is encoded in a vector, you want to project all your point onto that vector to get the value along the gradient for all points.
For example:
% v controls the direction of the gradient
v = [0.1, 1];
t = linspace(0, 2*pi, 100);
F = exp(-cos(t))./(2.*pi*besseli(1,1));
% reconstructing point coordinate all around the surface
% this closes the path so with enough points so that interpolation works correctly
pts = [[t', F']; [t(end:-1:1)', ones(size(t'))*min(F)]];
% projecting all points on the vector to get the color
c = pts * (v');
clf
patch(pts(:,1),pts(:,2),c)
hold on
scatter(t, F)
hold off

Related

Matlab: patch area between two curves which depend on the curves values

I'm trying to fill an area between two curves with respect to a function which depends on the values of the curves.
Here is the code of what I've managed to do so far
i=50;
cc = #(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
N=[n_vec,fliplr(n_vec)];
X=[x_vec,fliplr(y_vec)];
figure(1)
subplot(2,1,1)
hold on
plot(n_vec,x_vec,n_vec,y_vec)
hp = patch(N,X,'b')
plot([n_vec(i) n_vec(i)],[x_vec(i),y_vec(i)],'linewidth',5)
xlabel('n'); ylabel('x')
subplot(2,1,2)
xx = linspace(y_vec(i),x_vec(i),100);
plot(xx,cc(xx,y_vec(i),x_vec(i)))
xlabel('x'); ylabel('c(x)')
This code produces the following graph
The color code which I've added represent the color coding that each line (along the y axis at a point on the x axis) from the area between the two curves should be.
Overall, the entire area should be filled with a gradient color which depends on the values of the curves.
I've assisted the following previous questions but could not resolve a solution
MATLAB fill area between lines
Patch circle by a color gradient
Filling between two curves, according to a colormap given by a function MATLAB
NOTE: there is no importance to the functional form of the curves, I would prefer an answer which refers to two general arrays which consist the curves.
The surf plot method
The same as the scatter plot method, i.e. generate a point grid.
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px = linspace(min(n_vec), max(n_vec), resolution(1));
py = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px, py);
Generate a logical array indicating whether the points are inside the polygon, but no need to extract the points:
in = inpolygon(px, py, N, X);
Generate Z. The value of Z indicates the color to use for the surface plot. Hence, it is generated using the your function cc.
pz = 1./(1+(exp(-py_)/(exp(-y_vec(i))-exp(-x_vec(i)))));
pz = repmat(pz',1,resolution(2));
Set Z values for points outside the area of interest to NaN so MATLAB won't plot them.
pz(~in) = nan;
Generate a bounded colourmap (delete if you want to use full colour range)
% generate colormap
c = jet(100);
[s,l] = bounds(pz,'all');
s = round(s*100);
l = round(l*100);
if s ~= 0
c(1:s,:) = [];
end
if l ~= 100
c(l:100,:) = [];
end
Finally, plot.
figure;
colormap(jet)
surf(px,py,pz,'edgecolor','none');
view(2) % x-y view
Feel free to turn the image arround to see how it looks like in the Z-dimention - beautiful :)
Full code to test:
i=50;
cc = #(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
% generate grid
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px_ = linspace(min(n_vec), max(n_vec), resolution(1));
py_ = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px_, py_);
% extract points
in = inpolygon(px, py, N, X);
% generate z
pz = 1./(1+(exp(-py_)/(exp(-y_vec(i))-exp(-x_vec(i)))));
pz = repmat(pz',1,resolution(2));
pz(~in) = nan;
% generate colormap
c = jet(100);
[s,l] = bounds(pz,'all');
s = round(s*100);
l = round(l*100);
if s ~= 0
c(1:s,:) = [];
end
if l ~= 100
c(l:100,:) = [];
end
% plot
figure;
colormap(c)
surf(px,py,pz,'edgecolor','none');
view(2)
You can use imagesc and meshgrids. See comments in the code to understand what's going on.
Downsample your data
% your initial upper and lower boundaries
n_vec_long = linspace(2,10,1000000);
f_ub_vec_long = linspace(2, 10, length(n_vec_long));
f_lb_vec_long = abs(sin(n_vec_long));
% downsample
n_vec = linspace(n_vec_long(1), n_vec_long(end), 1000); % for example, only 1000 points
% get upper and lower boundary values for n_vec
f_ub_vec = interp1(n_vec_long, f_ub_vec_long, n_vec);
f_lb_vec = interp1(n_vec_long, f_lb_vec_long, n_vec);
% x_vec for the color function
x_vec = 0:0.01:10;
Plot the data
% create a 2D matrix with N and X position
[N, X] = meshgrid(n_vec, x_vec);
% evaluate the upper and lower boundary functions at n_vec
% can be any function at n you want (not tested for crossing boundaries though...)
f_ub_vec = linspace(2, 10, length(n_vec));
f_lb_vec = abs(sin(n_vec));
% make these row vectors into matrices, to create a boolean mask
F_UB = repmat(f_ub_vec, [size(N, 1) 1]);
F_LB = repmat(f_lb_vec, [size(N, 1) 1]);
% create a mask based on the upper and lower boundary functions
mask = true(size(N));
mask(X > F_UB | X < F_LB) = false;
% create data matrix
Z = NaN(size(N));
% create function that evaluates the color profile for each defined value
% in the vectors with the lower and upper bounds
zc = #(X, ub, lb) 1 ./ (1 + (exp(-X) ./ (exp(-ub) - exp(-lb))));
CData = zc(X, f_lb_vec, f_ub_vec); % create the c(x) at all X
% put the CData in Z, but only between the lower and upper bound.
Z(mask) = CData(mask);
% normalize Z along 1st dim
Z = normalize(Z, 1, 'range'); % get all values between 0 and 1 for colorbar
% draw a figure!
figure(1); clf;
ax = axes; % create some axes
sc = imagesc(ax, n_vec, x_vec, Z); % plot the data
ax.YDir = 'normal' % set the YDir to normal again, imagesc reverses it by default;
xlabel('n')
ylabel('x')
This already looks kinda like what you want, but let's get rid of the blue area outside the boundaries. This can be done by creating an 'alpha mask', i.e. set the alpha value for all pixels outside the previously defined mask to 0:
figure(2); clf;
ax = axes; % create some axes
hold on;
sc = imagesc(ax, n_vec, x_vec, Z); % plot the data
ax.YDir = 'normal' % set the YDir to normal again, imagesc reverses it by default;
% set a colormap
colormap(flip(hsv(100)))
% set alpha for points outside mask
Calpha = ones(size(N));
Calpha(~mask) = 0;
sc.AlphaData = Calpha;
% plot the other lines
plot(n_vec, f_ub_vec, 'k', n_vec, f_lb_vec, 'k' ,'linewidth', 1)
% set axis limits
xlim([min(n_vec), max(n_vec)])
ylim([min(x_vec), max(x_vec)])
there is no importance to the functional form of the curves, I would prefer an answer which refers to two general arrays which consist the curves.
It is difficult to achieve this using patch.
However, you may use scatter plots to "fill" the area with coloured dots. Alternatively, and probably better, use surf plot and generate z coordinates using your cc function (See my seperate solution).
The scatter plot method
First, make a grid of points (resolution 500*500) inside the rectangular space bounding the two curves.
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px = linspace(min(n_vec), max(n_vec), resolution(1));
py = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px, py);
figure;
scatter(px(:), py(:), 1, 'r');
The not-interesting figure of the point grid:
Next, extract the points inside the polygon defined by the two curves.
in = inpolygon(px, py, N, X);
px = px(in);
py = py(in);
hold on;
scatter(px, py, 1, 'k');
Black points are inside the area:
Finally, create color and plot the nice looking gradient colour figure.
% create color for the points
cid = 1./(1+(exp(-py)/(exp(-y_vec(i))-exp(-x_vec(i)))));
c = jet(101);
c = c(round(cid*100)+1,:); % +1 to avoid zero indexing
% plot
figure;
scatter(px,py,16,c,'filled','s'); % use size 16, filled square markers.
Note that you may need a fairly dense grid of points to make sure the white background won't show up. You may also change the point size to a bigger value (won't impact performance).
Of cause, you may use patch to replace scatter but you will need to work out the vertices and face ids, then you may patch each faces separately with patch('Faces',F,'Vertices',V). Using patch this way may impact performance.
Complete code to test:
i=50;
cc = #(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
% generate point grid
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px_ = linspace(min(n_vec), max(n_vec), resolution(1));
py_ = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px_, py_);
% extract points
in = inpolygon(px, py, N, X);
px = px(in);
py = py(in);
% generate color
cid = 1./(1+(exp(-py)/(exp(-y_vec(i))-exp(-x_vec(i)))));
c = jet(101);
c = c(round(cid*100)+1,:); % +1 to avoid zero indexing
% plot
figure;
scatter(px,py,16,c,'filled','s');

Specifying quiver vector color by density

I have some vectors with defined position and orientation. I could show them in space by using the below code:
theta = [pi/2,-pi/2,pi/2,pi/2,pi/2,pi/2,pi/2];
r = 0.25; % magnitude (length) of arrow to plot
x = [4,3.5,3.75,4.5,8,10,12]; y = [8.5,8.2,8.3,8,9,10,8];
u = r * cos(theta); % convert polar (theta,r) to cartesian
v = r * sin(theta);
h = quiver(x,y,u,v,'linewidth',2);
set(gca, 'XLim', [2 15], 'YLim', [4 15]);
As is clear from the image, in some regions the number of arrows is more than in other places. I want to show the arrows by color, where each color represents the density of the arrows.
Could anyone help me to do that? It would also be a good solution if there is a continuous background color which shows local densities.
Edit: Below are some options for colouring the background of the plot depending on the density of your points. I'm editing this into the top of my answer because it actually answers your question - individually colouring quiver arrows based on density!
x = rand(200,1)*10; y = rand(200,1)*10; % Set up random points
r = 1; u = r * cos(x); v = r * sin(y); % Quiver directions
colormap winter; c = colormap; % Set colourmap and assign to matrix
% Get density of points broken into a 10x10 grid
[n,~,~,binX,binY] = histcounts2(x,y,[10,10]);
% Get colour based on histogram density and chosen colormap colours
col = c(ceil(n(sub2ind(size(n), binX, binY))/max(n(:))*size(c,1)),:);
figure; hold on;
% Each quiver point must be plotted individually (slow!) because colours can
% only be applied to individual quivers. This could be sped up by plotting
% all of the same colour at once.
for ii = 1:size(x,1);
quiver(x(ii),y(ii),u(ii),v(ii),0,'color',col(ii,:));
end
Output:
Note: unlike the below example, you cannot use hist3 because you need it to return the bin index too. You could try this File Exchange function to achieve the same result (untested).
Here is an option using hist3 to get the density (in this example I use a 10x10 grid, as specified when calling hist3). Then using pcolor to display the density, and shading interp to smooth the colours.
Note: hist3 requires the Stats & ML toolbox, if you have Matlab 2015b or newer you can instead use the standard function histcounts2(x,y).
% Generate points and quiver directions
x = rand(200,1)*10; y = rand(200,1)*10;
u = r * cos(x); v = r * sin(y);
% Get density of points, format for input to pcolor
n = hist3([x,y],[10,10]); % Get density of points broken into a 10x10 grid
colx = linspace(min(x),max(x),size(n,1)+1);
coly = linspace(min(y),max(y),size(n,1)+1);
n = n'; n(size(n,2)+1,size(n,1)+1) = 0;
% Plot
figure
pcolor(colx,coly,n) % Density plot
hold on; colorbar; % Hold on for next plot and show colour bar key
quiver(x,y,u,v,'r') % Quiver plot
shading interp % Smooth plot colours
Output:
Edit: making the colours more muted
You can control the colours using colormap. This could be one of the defaults, or you can create a custom map of RGB triplets and have whatever colours you want! Here is an example, simply calling colormap bone; at the end of the above code:
In a custom colour map, you could make the colours even more muted / less contrasting.
Additionally, you can use caxis to scale the colour axis of a plot! Simply call
caxis([0,2*max(n(:))]);
at the end of the above code to double the maximum colour map value. You can tweak the 2 to get desired results:
this looks way less fancy but specifies the arrow color as function of the number of arrows in a certain number of bins of the x-axis
close all;
cm=colormap;
theta = [pi/2,-pi/2,pi/2,pi/2,pi/2,pi/2,pi/2];
r = 0.25; % magnitude (length) of arrow to plot
x = [4,3.5,3.75,4.5,8,10,12]; y = [8.5,8.2,8.3,8,9,10,8];
[n,c]=hist(x,5); %count arroes in bins
u = r * cos(theta); % convert polar (theta,r) to cartesian
v = r * sin(theta);
figure;hold on
for ii=1:numel(n) %quiver bin by bin
if n(ii)>0
if ii==1
wx=find(x<(c(ii)+(c(ii+1) - c(ii))/2)); %Which X to plot
elseif ii==numel(n)
wx=find(x>c(numel(n)-1));
else
wx=find((x>(c(ii)-(c(ii)-c(ii-1))/2)).*(x<(c(ii+1)-(c(ii+1)-c(ii))/2)));
end
indCol=ceil( (size(cm,1)*n(ii)-0) / max(n));%color propto density of arrows %in this bin
col = cm(indCol,:);%color for this bin
h = quiver(x(wx),y(wx),u(wx),v(wx),0,'linewidth',2,'color',col);
end
end
colorbar
caxis([0 max(n)])

MATLAB: Drawing atop a surface plot

I'm plotting an R^2 to R function in MATLAB as a surface plot, which I colormap and view from above.
surf(X, Y, data);
colormap(jet);
colobar;
view(2);
It produces (with some additional code) something like
though the true nature of the function (for the purpose of understanding this question) is better observed from an angle like:
I want to plot a circle atop my original plot (seen from above). Something like...
I can't seem to achieve this however, since plotting in-a-plane elements on plots makes them appear on the x-y axis, which is covered by my surface plot. For example, calling
circle_pos = [ +1 +1; -1 -1; -1 +1; +1 -1;]
circle_rad = 0.2 * ones(4,1);
viscircles(circle_pos, circle_rad);
after my surface plot results in no visible circles when viewed from the top. Zooming and rotating reveals these circles were plotted on the x-y plane, and so are invisible from above.
How do I plot my circles on top of the surface plot, so that they are visible from above?
A similar issue arises when plotting text atop the surface, but is remedied by specifying a z position value just above the underlying functions z value. There doesn't seem to be any way to specify the z position of these graphical elements.
There may not be a direct way to specify the z position of the objects returned by viscircles, but in general there is (most of the time) a way to modify properties and position of any graphic object afterwards.
Method 1: modifying circles after creation.
If you plan to do modifications of a graphic object, the first thing to do is always to retrieve its handle. So in your case, you would have to call viscircles by specifying a return value (which will contain the handle you want).:
hg = viscircles(circle_pos, circle_rad);
I do not have the Image Processing Toolbox so I do not have access to the viscircles function. However I read from the documentation that the handle returned is an hggroup. An hggroup is simply a container containing one or more handles of more primitive graphic objects. In this case the hggroup contains the handles of 4 lines (your 4 circles).
The easiest way to transform all the objects in an hggroup is to use a hgtransform object. We will define a Translation transformation and the hgtransform will apply it to the 4 circles (all the children of the hggroup).
To define the translation, we will use a makehgtform object.
Here we go:
ht = hgtransform ; % create the transform object
set(hg,'Parent',ht) ; % make it a "parent" of the hggroup
zc = max(max(Z)) ; % Find by how much we want to translate the circles on the Z axis
Tz = makehgtform('translate',[0 0 zc]) ; % create the TRANSLATION transform
set(ht,'Matrix',Tz) % apply the transformation (translation) to the hggroup/hgtransform
Done, your 4 circles should now be on top of your surface. Note that you can specify any other values for zc (not only the max of the surface).
Method 2: DIY
In case you do not want to be reliant on the image processing toolbox, or if you do not have it at all, it is relatively easy to create circles in a 3D space by yourself.
Here is a function which will create circles in a way comparable to viscircles but it also let you specify an optional z coordinate for the circle centre positions.
code for circles_3D.m:
function hg = circles_3d( pos , rad , varargin )
% get current axes handle and hold state
ax = gca ;
holdState = get(ax,'NextPlot') ; % save state to reinstate after function
set(ax,'NextPlot','add') ; % equivalent of "hold off"
tt = linspace(0,2*pi) ;
hg = hggroup(ax) ;
for k = 1:numel(rad)
c = pos(k,:) ;
r = rad(k) ;
x = c(1) + r.*cos(tt) ;
y = c(2) + r.*sin(tt) ;
z = zeros(size(x)) ;
if numel(c)==3 ; z = z + c(3) ; end
plot3(hg,x,y,z,varargin{:}) ;
end
set(ax,'NextPlot',holdState) ; % restore axes hold state
You can now call this function instead of viscircles. I used the varargin parameter to transfer any line property to the circles created (so you can specify the Color, LineWidth, and any other typical parameter you like.
For the sake of an example, I need to recreate a surface comparable to your, with 4x "zero" poles distributed around the maxima:
pc = 0.5 ; % pole centers
pw = 0.05 ; % pole widths
% surface definition
[X,Y] = meshgrid(-5:.1:5);
R = sqrt(X.^2 + Y.^2) + eps ;
Z = sin(R)./R;
% zero surface values around the defined poles
[idxPoles] = find(abs(X)>=pc-pw & abs(X)<=pc+pw & abs(Y)>=pc-pw & abs(Y)<=pc+pw ) ;
Z(idxPoles)= 0 ;
% display
hs = surf(X,Y,Z) ; shading interp
Which produces:
Now you can simply get your circles with the circles_3D function:
zc = max(max(Z)) ;
circle_pos = [ pc pc zc ; -pc -pc zc ; -pc +pc zc ; +pc -pc zc ] ;
circle_rad = 0.2 * ones(4,1);
h = circles_3d( circle_pos , circle_rad , 'Color','r','LineWidth',2) ;
and get:
Note that I made this function so it also return an hggroup object containing your lines (circles). So if you want to move them later, apply the same trick than in the first part of the answer.
Several options spring to mind.
The simplest will be to plot a marker in 3d using plot3:
figure;
peaks;
shading interp;
hold;
x = 0; y = 2; z = 10;
plot3(x, y, z, 'ro', 'MarkerSize', 24);
That will work, but the circle will always appear to be facing the viewer:
Alternatively, you can plot a circle in 3d:
vfTheta = linspace(0, 2*pi, 300);
figure; peaks; shading interp; hold;
x = 0; y = 2; z = 10; r = 0.2;
plot3(x + r.*cos(vfTheta), y + r.*sin(vfTheta), z .* ones(size(vfTheta)), 'r-', 'LineWidth', 2);
The result: a nice halo in 3d!

matlab: moving circle along a graph and axis equal

Hello and pardon me if my english is a bit rusty. I'm trying to create a circle that moves along a parametric function (coordinates are stored in vectors). I have written a function for drawing the circle and I know that you can use the axis equal command in matlab in order to create a circle shape and avoid an ellipse. My problem is that when I do this the figure window becomes very wide relative to the plotted graph. Any input is appreciated.
MAIN CODE:
t = linspace(0,3);
x = 30*cos(pi/4)/2*(1-exp(-0.5*t));
y = (30*sin(pi/4)/2 + 9.81/0.5^2)*(1-exp(0.5*t)) - 9.81*t/0.5;
for i = 1:length(t)
plot(x,y)
axis equal
hold on
cirkel(x(i),y(i),1,1,'r') % argument #3 is the radius #4 is 1 for fill
hold off
pause(0.01)
end
CIRCLE CODE:
function cirkel(x,y,r,f,c)
angle = linspace(0, 2*pi, 360);
xp = x + r*cos(angle);
yp = y + r*sin(angle);
plot(x,y)
if f == 1 && nargin == 5
fill(xp,yp,c)
end
When you call axis equal it makes one unit of the x axis be the same size as one unit of the y axis. You are seeing what you are because your y values span a much larger range than the x values.
One way to deal with this would be to query the aspect ratio and x/y limits of the current axes as shown in the second part of this answer. However, an easier approach is rather than using fill to plot your circle, you could instead use scatter with a circular marker which will be circular regardless of the aspect ratio of your axes.
t = linspace(0,3);
x = 30*cos(pi/4)/2*(1-exp(-0.5*t));
y = (30*sin(pi/4)/2 + 9.81/0.5^2)*(1-exp(0.5*t)) - 9.81*t/0.5;
% Plot the entire curve
hplot = plot(x, y);
hold on;
% Create a scatter plot where the area of the marker is 50. Store the handle to the plot
% in the variable hscatter so we can update the position inside of the loop
hscatter = scatter(x(1), y(1), 50, 'r', 'MarkerFaceColor', 'r');
for k = 1:length(t)
% Update the location of the scatter plot
set(hscatter, 'XData', x(k), ... % Set the X Position of the circle to x(k)
'YData', y(k)) % Set the Y Position of the circle to y(k)
% Refresh the plot
drawnow
end
As a side note, it is best to update existing plot objects rather than creating new ones.
If you want the small dot to appear circular, and you want to have a reasonable domain (x-axis extent), try this:
function cirkel(x,y,r,f,c)
angle = linspace(0, 2*pi, 360);
xp = x + 0.04*r*cos(angle); %% adding scale factor of 0.04 to make it appear circular
yp = y + r*sin(angle);
plot(x,y)
if f == 1 && nargin == 5
fill(xp,yp,c)
end
Note the addition of the scale factor in the computation of xp. If you want to automate this, you can add another parameter to cirkel(), let's call it s, that contains the scale factor. You can calculate the scale factor in your script by computing the ratio of the range to the domain (y extent divided by x extent).

examples to convert image to polar coordinates do it explicitly - want a slick matrix method

I am trying to convert an image from cartesian to polar coordinates.
I know how to do it explicitly using for loops, but I am looking for something more compact.
I want to do something like:
[x y] = size(CartImage);
minr = floor(min(x,y)/2);
r = linspace(0,minr,minr);
phi = linspace(0,2*pi,minr);
[r, phi] = ndgrid(r,phi);
PolarImage = CartImage(floor(r.*cos(phi)) + minr, floor(r.sin(phi)) + minr);
But this obviously doesn't work.
Basically I want to be able to index the CartImage on a grid.
The polar image would then be defined on the grid.
given a matrix M (just a 2d Gaussian for this example), and a known origin point (X0,Y0) from which the polar transform takes place, we expect that iso-intensity circles will transform to iso-intensity lines:
M=fspecial('gaussian',256,32); % generate fake image
X0=size(M,1)/2; Y0=size(M,2)/2;
[Y X z]=find(M);
X=X-X0; Y=Y-Y0;
theta = atan2(Y,X);
rho = sqrt(X.^2+Y.^2);
% Determine the minimum and the maximum x and y values:
rmin = min(rho); tmin = min(theta);
rmax = max(rho); tmax = max(theta);
% Define the resolution of the grid:
rres=128; % # of grid points for R coordinate. (change to needed binning)
tres=128; % # of grid points for theta coordinate (change to needed binning)
F = TriScatteredInterp(rho,theta,z,'natural');
%Evaluate the interpolant at the locations (rhoi, thetai).
%The corresponding value at these locations is Zinterp:
[rhoi,thetai] = meshgrid(linspace(rmin,rmax,rres),linspace(tmin,tmax,tres));
Zinterp = F(rhoi,thetai);
subplot(1,2,1); imagesc(M) ; axis square
subplot(1,2,2); imagesc(Zinterp) ; axis square
getting the wrong (X0,Y0) will show up as deformations in the transform, so be careful and check that.
I notice that the answer from bla is from polar to cartesian coordinates.
However the question is in the opposite direction.
I=imread('output.png'); %read image
I1=flipud(I);
A=imresize(I1,[1024 1024]);
A1=double(A(:,:,1));
A2=double(A(:,:,2));
A3=double(A(:,:,3)); %rgb3 channel to double
[m n]=size(A1);
[t r]=meshgrid(linspace(-pi,pi,n),1:m); %Original coordinate
M=2*m;
N=2*n;
[NN MM]=meshgrid((1:N)-n-0.5,(1:M)-m-0.5);
T=atan2(NN,MM);
R=sqrt(MM.^2+NN.^2);
B1=interp2(t,r,A1,T,R,'linear',0);
B2=interp2(t,r,A2,T,R,'linear',0);
B3=interp2(t,r,A3,T,R,'linear',0); %rgb3 channel Interpolation
B=uint8(cat(3,B1,B2,B3));
subplot(211),imshow(I); %draw the Original Picture
subplot(212),imshow(B); %draw the result