I want N points on a circle, set apart by a Euclidean distance (straight line, not around the circumference) of 50. The radius is determined by the number of points and the distance between consecutive points.
However, when I choose one of the points as a reference and calculate the distances to other points, I do not get any distance values equal to 50.
Below is my code:
N = 100; % number of points
eclddst = 50; % euclidean distance between adjacent points
r = eclddst/(2*sin(pi/N)); % radius of the circle
cord = r*exp((0:1/(N-1):1)*pi*2*1i)'; % coordinates
XCor = real(cord);
YCor = imag(cord);
N_COORD = [XCor YCor];
% taking location 3 as the reference point to check the distance between the points
DSTNT = sqrt( (N_COORD(3,1)-N_COORD(:,1)).^2 + ( N_COORD(3,2)- N_COORD(:,2)).^2)';
The distance values around the third point which I obtain are:
100.959
50.505
0.000
50.505
100.959
151.311
The points adjacent to point 3 should have 50 as their distance value and not 50.505.
Why do I get this error?
Thanks in advance.
Your issue is in the number of points which your formula generates, because of a misleading statement at the link you were following. Note that it was stated:
r = A*exp((0:1/300:1)*pi*2j); % 300 point circle, radius A
However, this will give 301 points not 300. If you plotted this though, you would see only 300 points (much easier to see if you use, say, 4 points). The first and last points are identical since
exp(0*pi*2j) = exp(1*pi*2j) = 1
To get around this, the simplest options are to change 0:1/300:1 to not reach 1, or simply create and remove an extra point as shown here:
N = 100; % number of points
d = 50; % Euclidean distance between adjacent points
% Euclidean distance around circle is essentially side length of N-sided polygon.
% Triangular sector angle within polygon (rads): 2*pi/N
% By bisecting the triangle to get a right-triangle, we can deduce that
% sin((2*pi/N)/2) = (d/2)/r => r = (d/2)/sin(pi/N)
r = (d/2)/sin(pi/N);
% Use linspace as it's clearer than colon array, create N+1 points
% Note that point 1 and point N+1 will be identical!
complexcoords = r*exp(linspace(0,1,N+1)*pi*2*1i).';
% Remove the last point as you put it in an array
coords = [real(complexcoords(1:N)) imag(complexcoords(1:N))];
As a check:
% Euclidean distances from point 3
dists = sqrt((coords(3,1)-coords(:,1)).^2 + (coords(3,2)-coords(:,2)).^2);
dists(1:5)
>> 99.951
50 % Neighbouring points are distance 50!
0
50 % Ditto
99.951
Note that you should be careful using '. This is the complex conjugate transpose, meaning that x + yi becomes x - yi. You won't notice this on a circle centred around 0 and an even number of points, but when you want to transpose something in MATLAB always use .', otherwise you may get some hard to diagnose issues! I have corrected this in my above code.
Doc links: ctranspose/', transpose/.'.
Related
I have plotted a list of corners I've obtained using Harris Corner detection.
Now I need to find the 4 furthers points that will represent the corners of the rectangle
I know I can get the two top and bottom diagonal corners using
max(C);
min(C);
Where C is an n row matrix with a column for x and y like
x y
0 1
2 3
4 5
6 6
But how do I get the other two corners?
I thought I could rotate the matrix and use min and max again, but of course that just returns me a huge n column matrix (and I want a 2 column matrix)
I feel like the answer is obvious, but I'm blanking :(
i don't know how limited is the following method but it worked for an example similar to yours:
% detect possible corners
points = detectHarrisFeatures(BW);
C = points.Location;
% compute par-wise distances between all points
D = pdist2(C,C);
p = zeros(1,4);
% compute maximum distance to find first pair
[m,idx1] = max(D,[],2);
[~,idx2] = max(m);
idx1 = idx1(idx2);
p(1:2) = [idx1, idx2];
% add first pair distance to distance matrix so the next pair will be
% distant from this pair as well, and compute max distance again
D = bsxfun(#plus,D,sum(D([idx1 idx2],:),1));
[m,idx1] = max(D,[],2);
[~,idx2] = max(m);
idx1 = idx1(idx2);
p(3:4) = [idx1, idx2];
% plot
imshow(BW);
hold on;
plot(C(:,1),C(:,2),'g.');
plot(C(p,1),C(p,2),'rx','LineWidth',2);
another option is to use FEX functions like Polygon simplification and Decimate Polygon, and to set the number of desired vertexes to 4.
Another alternative solution, if you dont want to use corner detection:
im=zeros(100);
im(40:70,30:80)=1;
im=imrotate(im,rand*100);
[x,y]=find(im);
x=x+2*randn(size(x));
y=y+2*randn(size(y));
X=[x(:),y(:)];
d=ceil(pdist2(X,X)*10)/10;
[a,b]=find(d==max(d(:)));
xm=x(a);
ym=y(a);
figure,plot(x,y,'ks')
hold on, plot(xm,ym,'ro','MarkerSize',12,'MArkerFaceColor','r')
axis image
How can I efficiently find all pixels (u',v') within a distance x from a given pixel (u,v). Specifically all (u',v') such that sqrt((u-u')^2 +(v-v')^2) <= x
To find all pixels at distance x you can use this indexing trick (for Manhattan distance)
u=10;v=10;
x=3.4;
pixels=img([floor(u-x) ceil(u+x)],[floor(v-x) ceil(v+x)]);
However, note that this will add any pixel that is within the distance, even if its just a piece of the pixel! E.g. (6,6) is inside!
For Euclidean distance, you need to define a circle around the point
[xi,yi]=meshgrid(1:size(img,1),1:size(img,2));
mask=sqrt((xi-u).^2+(yi-v).^2)<x; % or ceil(x)
pixel_values=img(mask);
[pixel_indices_u pixel_indices_v]=find(mask);
u = rand(1e2,1); % Create a 100 random points in the unit square
v = rand(1e2,1); % Create a 100 random points in the unit square
a = 0.3; % Choosen pixel
b = 0.4;
x = 0.1; % radius from the choosen pixel
idx = (sqrt((u-a).^2 +(v-b).^2) <= x); % Create a logical index array
locs = [u(idx) v(idx)]; % Index the locations
This is basically exactly what you describe in the question, with the points being labelled as (u,v) and the "destination point" so to speak labelled with (a,b) as a prime (') denotes the complex conjugate transpose in MATLAB.
Read more on logical indexing in this very insightful answer by Luis Mendo
Assume that I have a vector with 6 distance elements as
D = [10.5 44.8 30.01 37.2 23.4 49.1].
I'm trying to create random pair positions of a given distances, inside a 200 meters circle. Note that the distance D created by using (b - a).*rand(6,1) + a, with a = 10 and b = 50 in Matlab. I do not know how to generate the random pairs with given the distances.
Could anybody help me in generating this kind of scenario?
This is an improvement to Alessiox's answer. It follows same logic, first generate a set of points ([X1 Y1]) that have at least distance D from the main circle border, then generate the second set of points ([X2 Y2]) that have exact distance D from the first set.
cx = 50; cy = -50; cr = 200;
D = [10.5 44.8 30.01 37.2 23.4 49.1]';
n = numel(D);
R1 = rand(n, 1) .* (cr - D);
T1 = rand(n, 1) * 2 * pi;
X1 = cx+R1.*cos(T1);
Y1 = cy+R1.*sin(T1);
T2 = rand(n, 1) * 2 * pi;
X2 = X1+D.*cos(T2);
Y2 = Y1+D.*sin(T2);
You can tackle the problem using a two-steps approach. You can
randomly generate the first point and then you can consider the circle whose center is that point and whose radius is the distance in D
once you did draw the circle, every point lying on that circle will have distance D from the first point previously created and by random selection of one of these candidates you'll have the second point
Let's see with an example: let's say you main circle has radius 200 and its center is (0,0) so we start by declaring some main variables.
MAINCENTER_x=0;
MAINCENTER_y=0;
MAINRADIUS=200;
Let's now consider the first distance, D(1)=10.5 and we now generate the first random point which (along with its paired point - I reckon you don't want one point inside and the other outside of the main circle) must lie inside the main circle
r=D(1); % let's concentrate on the first distance
while true
x=((MAINRADIUS-2*r) - (-MAINRADIUS+2*r))*rand(1,1) + (-MAINRADIUS+2*r);
y=((MAINRADIUS-2*r) - (-MAINRADIUS+2*r))*rand(1,1) + (-MAINRADIUS+2*r);
if x^2+y^2<=(MAINRADIUS-2*r)^2
break;
end
end
and at the end of this loop x and y will be our first point coordinates.
Now we shall generate all its neighbours, thus several candidates to be the second point in the pair. As said before, these candidates will be the points that lie on the circle whose center is (x,y) and whose radius is D(1)=10.5. We can create these candidates as follows:
% declare angular spacing
ang=0:0.01:2*pi;
% build neighbour points
xp=r*cos(ang)+x;
yp=r*sin(ang)+y;
Now xp and yp are two vectors that contain, respectively, the x-coordinates and y-coordinates of our candidates, thus we shall now randomly select one of these
% second point
idx=randsample(1:length(xp),1);
secondPoint_x=xp(idx);
secondPoint_y=yp(idx);
Finally, the pair (x,y) is the first point and the pair (secondPoint_x, secondPoint_y) is our second point. The following plot helps summarizing these steps:
The red circle is the main area (center in (0,0) and radius 200), the red asterisk is the first point (x,y) the blue little circle has center (x,y) and radius 10.5 and finally the black asterisk is the second point of the pair (secondPoint_x, secondPoint_y), randomly extracted amongst the candidates lying on the blue little circle.
You must certainly can repeat the same process for all elements in D or rely on the following code, which does the very same thing without iterating through all the elements in D.
MAINCENTER_x=0;
MAINCENTER_y=0;
MAINRADIUS=200;
D = [10.5 44.8 30.01 37.2 23.4 49.1];
% generate random point coordinates
while true
x=((MAINRADIUS-2*D) - (-MAINRADIUS+2*D)).*rand(1,6) + (-MAINRADIUS+2*D);
y=((MAINRADIUS-2*D) - (-MAINRADIUS+2*D)).*rand(1,6) + (-MAINRADIUS+2*D);
if all(x.^2+y.^2<=(MAINRADIUS-2*D).^2)
break;
end
end
% declare angular spacing
ang=0:0.01:2*pi;
% build neighbour points
xp=bsxfun(#plus, (D'*cos(ang)),x');
yp=bsxfun(#plus, (D'*sin(ang)),y');
% second points
idx=randsample(1:size(xp,2),length(D));
secondPoint_x=diag(xp(1:length(D),idx));
secondPoint_y=diag(yp(1:length(D),idx));
%plot
figure(1);
plot(MAINRADIUS*cos(ang)+MAINCENTER_x,MAINRADIUS*sin(ang)+MAINCENTER_y,'r'); %main circle
hold on; plot(xp',yp'); % neighbours circles
hold on; plot(x,y,'r*'); % first points (red asterisks)
hold on; plot(secondPoint_x,secondPoint_y,'k*'); %second points (black asterisks)
axis equal;
Now x and y (and secondPoint_x and secondPoint_y by extension) will be vector of length 6 (because 6 are the distances) in which the i-th element is the i-th x (or y) component for the first (or second) point.
I have a binary image of a human. In MATLAB, boundary points and the center of the image are also defined, and they are two column matrices. Now I want to draw lines from the center to the boundary points so that I can obtain all points of intersection between these lines and the boundary of the image. How can I do that? Here is the code I have so far:
The code that is written just to get the one intersection point if anyone can help please
clear all
close all
clc
BW = im2bw(imread('C:\fyc-90_1-100.png'));
BW = imfill(BW,'holes');
[Bw m n]=preprocess(BW);
[bord sk pr_sk]=border_skeleton(BW);
boundry=bord;
L = bwlabel(BW);
s = regionprops(L, 'centroid');
centroids = cat(1, s.Centroid);
Step #1 - Generating your line
The first thing you need to do is figure out how to draw your line. To make this simple, let's assume that the centre of the human body is stored as an array of cen = [x1 y1] as you have said. Now, supposing you click anywhere in your image, you get another point linePt = [x2 y2]. Let's assume that both the x and y co-ordinates are the horizontal and vertical components respectively. We can find the slope and intercept of this line, then create points between these two points parameterized by the slope and intercept to generate your line points. One thing I will point out is that if we draw a slope with a vertical line, by definition the slope would be infinity. As such, we need to place in a check to see if we have this situation. If we do, we assume that all of the x points are the same, while y varies. Once you have your slope and intercept, simply create points in between the line. You'll have to choose how many points you want along this line yourself as I have no idea about the resolution of your image, nor how big you want the line to be. We will then store this into a variable called linePoints where the first column consists of x values and the second column consists of y values. In other words:
In other words, do this:
%// Define number of points
numPoints = 1000;
%// Recall the equation of the line: y = mx + b, m = (y2-y1)/(x2-x1)
if abs(cen(1) - linePt(1)) < 0.00001 %// If x points are close
yPts = linspace(cen(2), linePt(2), numPoints); %// y points are the ones that vary
xPts = cen(1)*ones(numPoints, 1); %//Make x points the same to make vertical line
else %// Normal case
slp = (cen(2) - linePt(2)) / cen(1) - linePt(1)); %// Solve for slope (m)
icept = cen(2) - slp*cen(1); %// Solve for intercept (b)
xPts = linspace(cen(1), linePt(1), numPoints); %// Vary the x points
yPts = slp*xPts + icept; %// Solve for the y points
end
linePoints = [xPts(:) yPts(:)]; %// Create point matrix
Step #2 - Finding points of intersection
Supposing you have a 2D array of points [x y] where x denotes the horizontal co-ordinates and y denotes the vertical co-ordinates of your line. We can simply find the distance between all of these points in your boundary with all of your points on the line. Should any of the points be under a certain threshold (like 0.0001 for example), then this indicates an intersection. Note that due to the crux of floating point data, we can't check to see if the distance is 0 due to the step size in between each discrete point in your data.
I'm also going to assume border_skeleton returns points of the same format. This method works without specifying what the centroid is. As such, I don't need to use the centroids in the method I'm proposing. Also, I'm going to assume that your line points are stored in a matrix called linePoints that is of the same type that I just talked about.
In other words, do this:
numBoundaryPoints = size(boundry, 1); %// boundary is misspelled in your code BTW
ptsIntersect = []; %// Store points of intersection here
for idx = 1 : numBoundaryPoints %// For each boundary point...
%//Obtain the i'th boundary point
pt = boundry(:,idx);
%//Get distances - This computes the Euclidean distance
%//between the i'th boundary point and all points along your line
dists = sqrt(sum(bsxfun(#minus, linePoints, pt).^2, 2));
%//Figure out which points intersect and store
ptsIntersect = [ptsIntersect; linePoints(dists < 0.0001, :)];
end
In the end, ptsIntersect will store all of the points along the boundary that intersect with this line. Take note that I have made a lot of assumptions here because you haven't (or seem reluctant to) give any more details than what you've specified in your comments.
Good luck.
My question is related to this link stackoverflow ques
In essence repeating the figure drawn there .. I have a central point ( x , y ) in an image around which I have to draw 4 circles of 1-4 unit radius with 8 angles between them.
In this diagram there are 12 angle bins but I have 8. There is a code solution there but it is for plotting the above figure.
I want to calculate the maximum intensity point in each of the 4 regions of each wedge. Is there any inbuilt function in matlab ? I looked at rose but could'nt understand if it would help me....
I would greatly appreciate if someone could help me how to calculate it in matlab....
Thanks
I put some code below that should be the basic skeleton of what you want to do. But I left an important function unimplemented because I think you will be able to do it and it will help you understand this process better.
% I assume that data_points is an M-by-2 array, where each row corresponds
% to an (x,y) coordinate pair, and M is the number of data points.
data_points = ... ;
% I assume this array stores the intensities at each data point.
intensities = ... ;
% I assume that this stores the total number of gridded polar regions you want
% to find the max intensity in (i.e. 4*(number of cells) in your picture above).
total_num_bins = ... ;
% This will store the max intensities. For places that have no nearby
% data points, the max intensity will remain zero.
max_intensities = zeros(total_num_bins);
% I assume these store the values of the center point.
x = ... ; y = ... ;
% The number of different data points.
num_data_points = length(intensities); % also equals size(data_points,1)
% Now, loop through the data points, decide which polar bin they fall in, and
% update the max intensity of that area if needed.
for ii = 1:num_data_points
% Grab the current point coordinates.
cur_x = data_points[ii,1];
cur_y = data_points[ii,2];
% Convert the current data point to polar coordinates,
% keeping in mind that we are treating (x,y) like the center.
cur_radius = sqrt( (cur_x - x)^2 + (cur_y - y)^2 );
cur_angle = atan2(cur_y - y, cur_x - x)
% You have to write this yourself, but it
% will return an index for the bin that this
% data point falls into, i.e. which of the 4 segments
% of one of the radial cells it falls into.
cur_bin = get_bin_number(cur_radius, cur_angle);
% Check if this data point intensity is larger than
% the current max value for its bin.
if ( intensities(ii) >= max_intensities(cur_bin))
max_intensities(cur_bin) = intensities(ii);
end
end
You will now have to make the function get_bin_number() which takes as its input the angle and radius of the data point away from the center point. It should return just an index between 1 and total_num_bins, because you will be keeping the max intensities in a linear array. So, for example, index number 1 might correspond to the first 1/4 piece of the closest radial cell in the upper right quadrant, index 2 might correspond to the next 1/4 of that same cell, moving counter-clockwise, or something like this. You have to devise your own convention for keeping track of the bins.
A late answer, but I believe an even easier solution would just be to convert your data from (x,y) coordinates to (r,theta) by using (r = sqrt(x.^2 + y.^2), theta = atan(y,x)) then use the hist3 function on the (r,theta) data set to get a radial histogram.
Therefore solution is as follows:
% I assume you have some M-by-2 matrix X that's in the form (x,y)
% Convert (x,y) to (r,theta)
xVect = X(:,1);
yVect = X(:,2);
X = [sqrt(xVect.^2 + yVect.^2), ...%formula for r
atan(yVect,xVect)]; %formula for theta
% 5 is the number of wedges along 'r', your radial axis
% 12 is the number of wedges along 'theta', your theta 'axis'
dist = hist3(X,5,12);
Even if you have solved this, I hope this helps anybody else who wants to create a radial/angular histogram!