The Monte Carlo method for estimating pi in MATLAB - matlab

I want to estimate the value of pi using the Monte Carlo method, this is, A random number generator can be used to estimate the value of pi. So I have found the following code
n=input('Number of points: ');
x=rand(n,1);
y=rand(n,1);
figure('color','white');
hold all
axis square;
x1=x-0.5;
y1=y-0.5; %cirle has centre at (0.5,0.5)
r=x1.^2+y1.^2;
m=0; %Number of points inside circle
for i=1:n
if r(i)<=0.25
m=m+1;
plot(x(i),y(i),'b.');
else
plot(x(i),y(i),'r.');
end
end
m/(0.25*n)
The thing is How Can I modify it so it gives me a square of length 2 and a circle of radius 1?
I've done this so far but it only give a quarter of what is suppose to give me:
n=input('Number of points: ');
x=rand(n,1);
y=rand(n,1);
figure('color','white');
hold all
axis square;
axis ([0 2 0 2])
x1=x-1;
y1=y-1; %cirle has centre at (0.5,0.5)
r=x1.^2+y1.^2;
m=0; %Number of points inside circle
for i=1:n
if r(i)<=1
m=m+1;
plot(x(i),y(i),'b.');
else
plot(x(i),y(i),'r.');
end
end
m/(0.25*n)
NOTE: the method is the following: generate random points in a square with sides of length 2 and count what proportion of these points falls in the unit radius circle that fits exactly into the square.This proportion will be the ratio of the area of the circle to the area of the square, hence, this estimates pi.

Try that
n=input('Number of points: ');
x=2*rand(n,1);
y=2*rand(n,1);
figure('color','white');
hold all
axis square;
x1=x-1;
y1=y-1; %cirle has centre at (1,1)
r=x1.^2+y1.^2;
m=0; %Number of points inside circle
ii = r<=1;
m = sum(ii);
plot(x(ii), y(ii), '.b');
plot(x(~ii), y(~ii), '.r');
m/(0.25*n)

Related

How to convert the estimated radius of a circle to its actual range?

I generate a random number between 1 and 2 as a radius for my circle. Then I plot my circle and saves it as a png. Also, several data points are generated both inside and outside the circle to make it noisy.
Then I will use Hough Transform to estimate the radius for the circle but, the number which it returns is more than 100. Although they are the same circles(I plotted to make sure).
I have tried to use polyfit function to map these two numbers but, the estimated radius seems to be smaller than the real one in some examples. After mapping It returns the same number. For example, a random radius is 1.2 and Hough estimates it 110 however it seems that it should be near 1.(Because I plot it and it is clear that is it smaller). Also, for Hough Transform I am using this code https://www.mathworks.com/matlabcentral/fileexchange/35223-circle-detection-using-hough-transforms
I tried the predefined Matlab function (imfindcircles) but it returns null for all my circles.
r1 = 1 + abs((1)*randn(1,1)); %radius of inner circle
r1 = abs(r1);
r2 = (1.2)*r1; %radius of outercircle
k = 500; %number of random numbers
% circle coordinate points
t = 0:2*pi/59:2*pi;
xv = cos(t)';
yv = sin(t)';
%%%%%%%%random points
xq = 2*randn(k,1)-1;
yq = 2*randn(k,1)-1; %distribution 1
xq1 = 2*(rand(k,1))-1; %distribution 2
yq1 = 2*(rand(k,1))-1;
in = inpolygon(xq1,yq1,r1*xv,r1*yv); %number of points inside the geometry
in1= inpolygon(xq,yq,r2*xv,r2*yv); %points inside outer circle
in2 = xor(in,in1); %points between circle
in3= inpolygon(xq1,yq1,r2*xv,r2*yv); %points inside outer circle
fig = figure(22);hold on;
% Random points
plot(xq(in2),yq(in2),'bo','MarkerFaceColor','r','MarkerSize',5,'Marker','o','MarkerEdgeColor','none');
axis equal;
plot(xq1(~in2),yq1(~in2),'bo','MarkerFaceColor','r','MarkerSize',5,'Marker','o','MarkerEdgeColor','none');
axis equal;
img= getframe(fig);
figure;
imshow(img.cdata)
hold on;
[r,c,rad] = circlefinder(img.cdata);
[m I] = max(rad);
%ploting the bigest estimated circle
angle = 2*pi*randn(k,1);
haffpointX = rad(I).*cos(angle)+ c(I);
haffpointY = rad(I).*sin(angle)+ r(I);
scatter(haffpointX,haffpointY,'g');
axis equal
I expect that for different random circles with noisy data Hough Transform estimates its circle with the number between the range of 1 and 2 so, I can use its results.
Thank you in advance

Keystoning in Matlab - projecting a square on the floor

So, as a part of an experiment I need a function that could use the projector to project something on the floor. The projector is angled so the Keystone effect comes in to play and I'd like to correct it.
I try to do that by calculating the homography matrix H. I project a square at the bottom of the projected area, measure its properties (it is shown as a trapezoid on the ground) and calculate the matrix. And then I reverse the process with the idea to use the homography matrix H (it's inverse) to calculate and project a shape on the ground that would look like the original square and not a trapezoid.
But I'm not successful. I calculate a shorter quadrangle and still get a trapeze on the ground. I'm pretty sure I'm doing something wrong with the calculations but I'm not sure. I am new to Matlab :) Thx for the help. The code, with a lot of comments, is bellow.
function keystoning()
projArea = 100; % 100%
testSquare = 20; % test square dimension
%% Drawing a "what's supposed to be a square" on the floor
% black background, red "sqare" dimensions 20x20, attached to the base
% of the projection area so the base dimension of the "sqare" don't change
% and minimal measuring is required
testX=[40 40+testSquare 40+testSquare 40];
testY=[0 0 testSquare testSquare];
scrsz = get(groot,'screensize');
f = figure('position',[0 0 scrsz(3) scrsz(4)],...
'OuterPosition',[0 0 scrsz(3) scrsz(4)],...
'toolbar','none','menubar','none','name','none',...
'units','normalized',...
'Color','black','Resize','Off'...
);
figure(f); % focus window
fill(testX, testY,'r');
axis ([0 projArea 0 projArea])
pbaspect([1 1 1])
drawnow
disp('*** PLACE THE NEAR PART OF THE ELEMENT AT THE END OF THE TREADMILL ***');
%% Measuring of the shape in order to calculate the homography matrix H
disp('*** Measure the width of the base of the projection area in centimeters. ***');
prompt = 'Enter the measured distance: ';
projAreaM = input(prompt);
projAreaCoef=projAreaM/projArea; % coefficient between the axes scale and the projection area
disp('*** Measure the distance between the paralel lines of the trapezoid in centimeters. ***');
prompt = 'Enter the measured distance: ';
trapYm = input(prompt)/projAreaCoef
disp('*** Measure the length of the longer paralel line of the trapezoid in centimeters. ***');
prompt = 'Enter the measured length: ';
trapXm = input(prompt)/projAreaCoef
%% Calculating the homography matrix H
% trapezoid definition
% coordinates of the first two points for the trapezoid and the square
% are the same since its at the start of the projection area
difX=(trapXm-testSquare)/2; % length of the "pertrusions"
trapX=[testX(1) testX(2) testX(3)+difX testX(4)-difX];
trapY=[testY(1) testY(2) trapYm trapYm];
% variable definition
P=[testX;testY;ones(size(testX))]; % test rectangle
Q=[trapX;trapY;ones(size(trapX))]; % shown trapezoid
% homography matrix H calculation
H=Q/P; % solution to the equation HP = Q
%% Testing the homography matrix H
% we want to show the rectangle on the ground
Pnew=inv(H)*P;
fill(Pnew(1,:),Pnew(2,:),'r');
axis ([0 projArea 0 projArea])
pbaspect([1 1 1])
drawnow

mean value in a sphere

I'm trying to calculate the mean value of the pixels inside a circle. In the future this needs to be extended to 3D, but for now a 2D sollution would already help me out.
As can be seen in the image, some pixels are entirely inside the circle, but some are only partly inside the circle. The ones partly in the circle also need to contribute only partly to the mean value. The pixels are square. This will simplify the mathematics I hope.
I can calculate the distance from the pixelcorners to the central point, from this you can find the pixels enterly inside and enterly outside. The rest needs correction. But how to find this correction.
[edit] thanks to Heath Raftery the problem is solved! [/edit]
the integral of a circle with radius r
As an example: I want to know the average pixelvalue of pixels in this circle. I know it is 0.3425, since 34.25% of the circle has a value of 1 and the rest is 0.
Function to check what part of a pixel is in the circle:
function [ a ] = incirc( x,y,r )
%only handles the top right quadrant of a circle
if x<0||y<0,error('only positive x,y');end
%integral of sqrt(r^2-x^2) dx
F = #(x,r) (1/2)*(x*sqrt(r^2-x^2)+r^2*atan(x/sqrt(r^2-x^2)));
%find corner locations
x=[x-0.5,x+0.5];
y=[y-0.5,y+0.5];
d = sqrt(x.^2+y.^2); %distance to closed and furthest corner
if max(d)<r,a=1;return;end %inside circle
if min(d)>r,a=0;return;end %outside circle
%intersections with edges (r^2 = x^2+y^2)
inters = [sqrt(r^2-y(1)^2),sqrt(r^2-y(2)^2),sqrt(r^2-x(1)^2),sqrt(r^2-x(2)^2)]; %x(1) x(2) y(1) y(2)
%remove imaginary and out of range intersections
inters(imag(inters)~=0)=NaN;
inters(inters<1E-5)=NaN; %to find values that are zero
inters([~((x(1)<inters(1:2))&(inters(1:2)<x(2))),~((y(1)<inters(3:4))&(inters(3:4)<y(2)))])=NaN;
idx = find(~isnan(inters));
if numel(idx)~=2,error('need two intersections of circle with pixel');end
%check area of pixel inside circumference
if all(idx==[1,2]) %2 intersections on y-edge
a=(F(y(2),r)-F(y(1),r)) - x(1); %area
elseif all(idx==[3,4]) %2 intersections on x-edge
a=(F(x(2),r)-F(x(1),r)) - y(1); %area
elseif all(idx==[1,3]) %one intersection on y-edge one on x-edge (left&bottom)
a=(F(inters(1),r)-F(x(1),r))- (y(1)*(inters(1)-x(1)));
elseif all(idx==[2,4]) %one intersection on y-edge one on x-edge (top&right)
a=(inters(2)-x(1))+(F(x(2),r)-F(inters(2),r))-(y(1)*(x(2)-inters(2)));
else
error('geometry')
end
a=real(a);
if a<0||a>1
error('computational error');
end
end
Script to test the function
M = ones(100); %data
M(1:50,:)=0;
pos=[50.2,50];
r = 2;
%calculate what the result should be
h=50-pos(2)+0.5;
A=pi*r^2;
wedge = acos(h/r)/pi;
triangle = h*sqrt(r^2-h^2);
res=(A*wedge-triangle)/A
S=0;N=0;
for i = 1:size(M,1)
for j = 1:size(M,2)
x=abs(j-pos(1));
y=abs(i-pos(2));
n=incirc( x,y,r );
M_(i,j)=n;
S = S+M(i,j)*n;
N = N+n;
end
end
result = S/N
result = 0.3425
You can see the algorithm finds the part of the pixel in the circle.
The question is missing a question, but I'll assume that it's not how to calculate whether pixels are fully inside or outside the circle. That's a relatively simple task. That is, a pixel is fully inside if the furtherest corner of the pixel to the centre is less than a radius away from the centre, and a pixel is fully outside if the closest corner of the pixel to the centre is more than a radius away from the centre.
The question of what proportion of pixels on the circumference fall within the circumference is much trickier. There are two fundamental solutions:
Exact and hard.
Approximate and a bit easier.
In both cases, note the horizontal and vertical symmetry means only the top right quadrant need be considered.
Then, for (1), translate the circle centre to the origin (0, 0) and treat the circumference as the function y(x) = sqrt(r^2 - x^2). Then, the area of an overlapping pixel within the circle is the integral:
integral(y(x) - y0, from x0 to x1, with respect to x)
where y0 is the bottom coordinate of the pixel, x0 is the left coordinate and x1 is the right coordinate.
This integral can be solved exactly with a trigonometric identity and a trigonometric substitution.
For (2), just generate a set of random points within the pixel and count how many of them fall within the circumference. As the set gets larger, the proportion of points that fall within the circumference to the count of all point approaches the proportion of the pixel within the circumference.
You can use inpolygon, to get the indices which lie inside the circle, once you have those indices you can get your pixels and do what you want.
M = rand(100); %data
[nx,ny] = size(M) ;
[X,Y] = meshgrid(1:ny,1:nx) ;
pos=[20,20];
r = 5;
phi=linspace(0,2*pi,100);
imagesc(M);
axis image
hold on
plot(pos(1),pos(2),'rx')
xc = pos(1)+r*sin(phi) ;
yc = pos(2)+r*cos(phi) ;
plot(xc,yc,'-r');
% hold off
%% get indices which are inside the circle
idx = inpolygon(X(:),Y(:),xc,yc) ;
xi = X(idx) ; yi = Y(idx) ;
plot(xi,yi,'.r')
mypixels = M(idx) ;
You can also use rangesearch to get the points lying within the given radius of the circle. As below:
M = rand(100); %data
[nx,ny] = size(M) ;
[X,Y] = meshgrid(1:ny,1:nx) ;
pos=[20,20];
r = 5;
phi=linspace(0,2*pi,100);
imagesc(M);
axis image
hold on
plot(pos(1),pos(2),'rx')
xc = pos(1)+r*sin(phi) ;
yc = pos(2)+r*cos(phi) ;
plot(xc,yc,'-r');
% hold off
%% Use nearest neighbour search
idx = rangesearch([X(:),Y(:)],pos,r) ;
xi = X(idx{1}) ; yi = Y(idx{1}) ;
plot(xi,yi,'.r')
mypixels = M(idx{1}) ;

Placing Circles into a given area

I have a given area (let's say 1000 x 1000), and I want to place circles in this area with the following requirements:
The number of circles is arbitrary, but fixed after it was chosen at the begin of the algorithm. The number should be so that most of the area is covered by the circles.
The circles shall have in general different radii, and the sizes of the radii shall be in a certain interval (e. g. between 20 and 80).
The circles shall not overlap.
I want to implement a code which does this with matlab. So far I have accomplished this code, which contains for simplicity only one value for the radius:
%% Area
perix=1000;
periy=1000;
%Number of circles
numbercircles=100;
radii(1:numbercircles)=70
%% Placing Circles
%first circle
xi=rand*perix; % array for storing x-values of circle centers
yi=radii(1); %array for storing y-values of circle centers
radiusarray=[radii(1)] ; %array for storing radii
plot(sin(linspace(0,2*pi,100))*radii(1)+xi,cos(linspace(0,2*pi,100))*radii(1)+yi);
hold on
axis([0 perix 0 perix])
% Idea:
%* Step 1: Random x coordinate for each circle middle point, y-coordinate at
% the top of the area, y_init=periy, and given radius.
%* Step 2: Lower y coordinate with constant x-coordinate until the distance to
%neighbour spheres is lower than the combined radii of those spheres.
%* Step 3: Move sphere on the x-axis to decrease the distance and further
%decrease the y-value if possible.
for lauf=2:numbercircles;
disp(numbercircles-lauf)
deltaz=10;
%% Step 1
% random x coordinate of sphere
x1=rand*100;
% y coordinate of circle is on the edge of the area and will be
% lower in the following
y1=periy;
Radnew=radii(lauf);
%% Step 2
%distance to other circle
d=min([sqrt((xi-x1).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi+perix)-x1).^2+(yi-y1).^2-(Radnew+radiusarray)) sqrt(((xi-perix)-x1).^2+(yi-y1).^2)-(Radnew+radiusarray)]);
while deltaz > 1e-4
%lower till y1=Radnew or distance to other spheres < 2*Rad
while ((y1>Radnew) & (d > deltaz))
%number=number+1
% lower y1
% if a<2
% deltaz
% end
y1=y1-deltaz;
% recalculate distance to all other spheres
d=min([sqrt((xi-x1).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi+perix)-x1).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi-perix)-x1).^2+(yi-y1).^2)-(Radnew+radiusarray)]);
end;
dmaxakt=d;
%adjust position in x direction and y direction: Increasing
%x coordinate iteratively in small steps
if (y1>Radnew)
xz(1)=x1+deltaz*rand;
if xz(1)>perix
xz(1)=x1-perix;
elseif xz(1)<0
xz(1)=x1+perix;
end;
dz(1)=min([sqrt((xi-xz(1)).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi+perix)-xz(1)).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi-perix)-xz(1)).^2+(yi-y1).^2)-(Radnew+radiusarray)]);
xz(2)=x1-deltaz*rand;
if xz(2)>perix
xz(2)=x1-perix;
elseif xz(1)<0
xz(2)=x1+perix;
end;
dz(2)=min([sqrt((xi-xz(2)).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi+perix)-xz(2)).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi-perix)-xz(2)).^2+(yi-y1).^2)-(Radnew+radiusarray)]);
%determine which distance z is the largest
vmax=find(max(dz)==dz);
%set the x-value to the value which belongs to the largest
%distance
x1=xz(vmax(1));
end;
%calculate new distance
d=min([sqrt((xi-x1).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi+perix)-x1).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi-perix)-x1).^2+(yi-y1).^2)-(Radnew+radiusarray)]);
if ((d>dmaxakt) & (y1>Radnew))
dmaxakt=d;
else
deltaz=deltaz*1e-1;
end;
end;
% if (y1<1e-5)
% y1=rand;
% end;
%last check: test if y-coordinate is still in the area
if (y1<periy-Radnew)
%Assembling the arrays for the circle places
xi=[xi x1];
yi=[yi y1];
radiusarray=[radiusarray Radnew];
end;
%Plotting
%zeit(lauf)=cputime-t;
plot(sin(linspace(0,2*pi,20))*Radnew+x1,cos(linspace(0,2*pi,20))*Radnew+y1);
%plot(sin(linspace(0,2*pi,20))*Rad1+x1+perix,cos(linspace(0,2*pi,20))*Rad1+y1);
%plot(sin(linspace(0,2*pi,20))*Rad1+x1-perix,cos(linspace(0,2*pi,20))*Rad1+y1);
hold on
axis([0 perix 0 perix])
pause(0.0001);
saveas(gcf, 'circle.png')
end;
The code basically assumes an initial x-coordinate and the maximum y-coordinate and lowers the y-coordinate until overlap is detected. Then the x-coordinate and the y-coordinate are modified to achieve high density of the circles.
The problem of this code is, that it is very slow, because the distance of lowering the y-coordinate is decreasing in every while-loop, which means that the time of lowering the spheres can be very long. I would appreciate if somebody could come up with an idea how to increase the speed of this code.
Not sure if this helps, but i checked your code as you posted it with the profiler and it says 98% of the time is saving the .png file
Line Number 111 / saveas(gcf, 'circle.png') / 99 / 47.741s / 98.4%
Do you want a picture everytime a new circle is drawn or just the last one? In the ladder case just put the 'saveas(...)' behind the last end, and caluclation is down to 1% of the time

Shift the concentric circle and coordinate to the right

clc
n=10;
th=(0:360)*pi/180;
h=axes('Position',[0.25,0.25,0.25,0.25]);
hold on
cc='bmmyyyggwr';
for i=1:n
x=(n+1-i)*cos(th);
y=(n+1-i)*sin(th);
plot(x,y);
fill(x,y,cc(i))
axis off
axis equal
end
I plot 10 concentric circles. I want the concentric circle and coordinate keep moving to right along the X-axis, and stay a while during shifting.
I used the plot(x+20,y),but it can't move color. How to make the concentric circles stay for a while during shifting? Really appreciate for any suggestions.
This may do what you want.
Note we're setting xlim and ylim, otherwise the circles would not appear to move at all. In the first loop, we draw the circles, in the second loop, we move them.
clf
n=10;
th=(0:360)*pi/180;
h=axes('Position',[0.25,0.25,0.25,0.25]);
hold on
cc='bmmyyyggwr';
phh = gobjects(2, n);
xlim([-10, 30])
ylim([-10, 10])
axis off
axis equal
for i=1:n
x=(n+1-i)*cos(th);
y=(n+1-i)*sin(th);
phh(1, i)=plot(x,y);
phh(2, i)=fill(x,y,cc(i));
end
for j=1:n
for i=1:n
phh(1, i).XData = phh(1, i).XData + 1;
phh(2, i).XData = phh(2, i).XData + 1;
end
drawnow
pause(1);
end