Finger peak detection using MATLAB - matlab

I have to create an algorithm with Matlab that, with a image of a hand, can know the form of the hand by the number of raised fingers and the presence or absence of the thumb. So far, the algorithm is almost complete but I don't know what more I can do that could find the peaks that represents the fingers. We tried a lot of things but nothing works. The idea is to find when there is a sudden increasement but as the pixels are never completely aligned, nothing that we tried worked. Someone has any idea? Here is the code so far.
The image that he is reading is this one:
To know if the finger is relevant or not, we already have an idea that might work... but we need to find the fingers first.
clear all
close all
image=imread('mao2.jpg');
YCBCR = rgb2ycbcr(image);
image=YCBCR;
cb = image(:,:,2);
cr = image(:,:,3);
imagek(:,1) = cb(:);
imagek(:,2) = cr(:);
imagek = double(imagek);
[IDX, C] = kmeans(imagek, 2, 'EmptyAction', 'singleton');
s=size(image);
IDX= uint8(IDX);
C2=round(C);
imageNew = zeros(s(1),s(2));
temp = reshape(IDX, [s(1) s(2)]);
for i = 1 : 1 : s(1)
for j = 1 : 1 : s(2)
imageNew(i,j,:) = C2(temp(i,j));
end
end
imageNew=uint8(imageNew);
[m,n]=size(imageNew);
for i=1:1:m
for j = 1:1:n
if(imageNew(i,j)>=127)
pretobranco(i,j)=0;
else
pretobranco(i,j)=1;
end
end
end
I2=imfill(pretobranco);
imshow(I2);
imwrite(I2, 'mao1trab.jpg');
[m,n]=size(I2);
B=edge(I2);
figure
imshow(B);
hold on;
stats=regionprops(I2,'BoundingBox');
rect=rectangle('position', [stats(1).BoundingBox(1), stats(1).BoundingBox(2), stats(1).BoundingBox(3), stats(1).BoundingBox(4)], 'EdgeColor', 'r');
stats(1).BoundingBox(1)
stats(1).BoundingBox(2)
stats(1).BoundingBox(3)
stats(1).BoundingBox(4)
figure
Bound = B( stats(1).BoundingBox(2): stats(1).BoundingBox(2)+stats(1).BoundingBox(4)-1, stats(1).BoundingBox(1):stats(1).BoundingBox(1)+stats(1).BoundingBox(3)-1);
imshow(Bound)
y1 = round(stats(1).BoundingBox(2))
y2 = round(stats(1).BoundingBox(2)+stats(1).BoundingBox(4)-1)
x1 = round(stats(1).BoundingBox(1))
x2 = round(stats(1).BoundingBox(1)+stats(1).BoundingBox(3)-1)
% Bounding box contida em imagem[M, N].
[M,N] = size(Bound)
vertical=0;
horizontal=0;
if M > N
vertical = 1 %imagem vertical
else
horizontal = 1 %imagem horizontal
end
%Find thumb
MaoLeft = 0;
MaoRight = 0;
nPixelsBrancos = 0;
if vertical==1
for i = x1:1:x2
for j= y1:1:y2
if I2(j,i) == 1
nPixelsBrancos = nPixelsBrancos + 1; %Numero de pixels da mão
end
end
end
for i=x1:1:x1+30
for j=y1:1:y2
if I2(j,i) == 1
MaoLeft = MaoLeft + 1; %Number of pixels of the hand between the 30 first colums
end
end
end
for i=x2-30:1:x2
for j=y1:1:y2
if I2(j,1) == 1
MaoRight = MaoRight + 1; %Number of pixels of the hand between the 30 last colums
end
end
end
TaxaBrancoLeft = MaoLeft/nPixelsBrancos
TaxaBrancoRight = MaoRight/nPixelsBrancos
if TaxaBrancoLeft <= (7/100)
if TaxaBrancoRight <= (7/100)
Thumb = 0 %Thumb in both borders is defined as no Thumb.
else
ThumbEsquerdo = 1 %Thumb on left
end
end
if TaxaBrancoRight <= (7/100) && TaxaBrancoLeft >= (7/100)
ThumbDireito = 1 %Thumb on right
end
end
if horizontal==1
for i = x1:1:x2
for j= y1:y2
if I2(i,j) == 1
nPixelsBrancos = nPixelsBrancos + 1; %Numero de pixels da mão
end
end
end
for i=x1:1:x2
for j=y1:1:y1+30
if I2(i,j) == 1
MaoLeft = MaoLeft + 1; %Numero de pixels da mão entre as 30 primeiras colunas
end
end
end
for i=x1:1:x2
for j=y2-30:1:y2
if I2(j,1) == 1
MaoRight = MaoRight + 1; %Numero de pixels da mão entre as 30 ultimas colunas
end
end
end
TaxaBrancoLeft = MaoLeft/nPixelsBrancos
TaxaBrancoRight = MaoRight/nPixelsBrancos
if TaxaBrancoLeft <= (7/100)
if TaxaBrancoRight <= (7/100)
Thumb = 0 %Polegar nas duas bordas. Definimos como sem polegar.
else
ThumbEsquerdo = 1 %Polegar na borda esquerda
end
end
if TaxaBrancoRight <= (7/100) && TaxaBrancoLeft >= (7/100)
ThumbDireito = 1 %Polegar na borda direita
end
end
figure
imshow(I2);
%detecção da centroid
Ibw = im2bw(I2);
Ilabel = bwlabel(Ibw);
stat = regionprops(Ilabel,'centroid');
figure
imshow(I2); hold on;
for x = 1: numel(stat)
plot(stat(x).Centroid(1),stat(x).Centroid(2),'ro');
end
centroid = [stat(x).Centroid(1) stat(x).Centroid(2)] %coordenadas x e y da centroid
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Seemed like an interesting problem, so I gave it a shot. Basically you start with a Sobel filter to find the edges in your image (after slight denoising). Then clean up the resulting lines, use them to separate regions within your binary mask of the hand, use a watershed transform to find the wrist, some distance transforms to find other landmarks, then remove the palm. What you're left with is separate regions for each finger and thumb. You can count those regions easily enough or find which way they are pointing, or whatever you'd like.
imgURL = 'https://encrypted-tbn2.gstatic.com/imgs?q=tbn:ANd9GcRQsqJtlrOnSbJNTnj35Z0uG9BXsecX2AXn1vV0YDKodq-zSuqnnQ';
imgIn=imread(imgURL);
gaussfilt = fspecial('gaussian', 3, .5); % Blur starting image
blurImg = imfilter(double(img(:,:,1)), gaussfilt);
edgeImg = edge(blurImg, 'sobel'); % Use Sobel edge filter to pick out contours of hand + fingers
% Clean up contours
edgeImg = bwmorph(edgeImg, 'close', 1);
edgeImg = bwmorph(edgeImg, 'thin', Inf);
% Clean up rogue spots in corners
edgeImg([2 end-1], 2) = 0;
edgeImg([2 end-1], end-1) = 0;
% Extend lines to edge of image (correct for 'close' operation above
edgeImg([1 end],:) = edgeImg([2 end-1],:);
edgeImg(:, [1 end]) = edgeImg(:, [2 end-1]);
% Remove all but the longest line
regs = regionprops(edgeImg, 'Area', 'PixelIdxList');
regs(vertcat(regs.Area) ~= max(vertcat(regs.Area))) = [];
lineImg = false(size(edgeImg, 1), size(edgeImg, 2));
lineImg(regs.PixelIdxList) = 1;
fillImg = edgeImg;
% Close in wrist
if any(fillImg(1,:))
fillImg(1,:) = 1;
end
if any(fillImg(end,:))
fillImg(end,:) = 1;
end
if any(fillImg(:,1))
fillImg(:,1) = 1;
end
if any(fillImg(:,end))
fillImg(:,end) = 1;
end
fillImg = imfill(fillImg, 'holes');
fillImg([1 end], :) = 0;
fillImg(:, [1 end]) = 0;
fillImg([1 end],:) = fillImg([2 end-1],:);
fillImg(:, [1 end]) = fillImg(:, [2 end-1]);
% Start segmenting out hand + fingers
handBin = fillImg;
% Set lines in above image to 0 to separate closely-spaced fingers
handBin(lineImg) = 0;
% Erode these lines to make fingers a bit more separate
handBin = bwmorph(handBin, 'erode', 1);
% Segment out just hand (remove wrist)
distImg = bwdist(~handBin);
[cDx, cDy] = find(distImg == max(distImg(:)));
midWrist = distImg;
midWrist = max(midWrist(:)) - midWrist;
midWrist(distImg == 0) = Inf;
wristWatershed = watershed(imerode(midWrist, strel('disk', 10)));
whichRegion = wristWatershed(cDx, cDy);
handBin(wristWatershed ~= whichRegion) = 0;
regs = regionprops(handBin, 'Area', 'PixelIdxList');
regs(vertcat(regs.Area) ~= max(vertcat(regs.Area))) = [];
handOnly = zeros(size(handBin, 1), size(handBin, 2));
handOnly(regs.PixelIdxList) = 1;
% Find radius of circle around palm centroid that excludes wrist and splits
% fingers into separate regions.
% This is estimated as D = 1/3 * [(Centroid->Fingertip) + 2*(Centroid->Wrist)]
% Find Centroid-> Wrist distance
dist2w = wristWatershed ~= whichRegion;
dist2w = bwdist(dist2w);
distToWrist = dist2w(cDx, cDy);
% Find Centroid-> Fingertip distance
dist2FE = zeros(size(handOnly, 1), size(handOnly, 2));
dist2FE(cDx, cDy) = 1;
dist2FE = bwdist(dist2FE).*handOnly;
distToFingerEnd = max(dist2FE(:));
circRad = mean([distToFingerEnd, distToWrist, distToWrist]); % Estimage circle diameter
% Draw circle
X = bsxfun(#plus,(1:size(handOnly, 1))',zeros(1,size(handOnly, 2)));
Y = bsxfun(#plus,(1:size(handOnly, 2)),zeros(size(handOnly, 1),1));
B = sqrt(sum(bsxfun(#minus,cat(3,X,Y),reshape([cDx, cDy],1,1,[])).^2,3))<=circRad;
% Cut out binary mask within circle
handOnly(B) = 0;
% Label separate regions, where each now corresponds to a separate digit
fingerCount = bwlabel(handOnly);
% Display overlay image
figure()
imshow(imgIn)
hold on
overlayImg = imshow(label2rgb(fingerCount, 'jet', 'k'));
set(overlayImg, 'AlphaData', 0.5);
hold off
Results:
http://imgur.com/ySn1fPy

Related

Struggling with while loop (computer graphics)

Working on a little project to do with computer graphics. So far I have (I think) everything in order as the code below patches my world to the screen fine.
However, I have a final hurdle to jump: I would like the code to patch for different values of theta. In the code, it is set at 2*pi/4 but I would like to iterate and patch for every angle between 0:pi/4:2*pi. However, when I try to put the code in a for or while loop it doesn't seem to do what I expect, that is, to patch with one angle, then patch with another etc.
Really stuck I have tried a lot of stuff and now I'm just without any ideas. Would really appreciate any help or suggestions.
function world()
% Defining House Vertices
house_verts = [-5, 0, -5;
5, 0, -5;
5, 10, -5;
0,15,-5;
-5,10,-5;
-5,0,5;
5,0,5;
5,10,5;
0,15,5;
-5,10,5];
% Sorting out the homeogenous co-ordinates
ones = [1,1,1,1,1,1,1,1,1,1];
ones=transpose(ones);
house_verts = [house_verts, ones];
house_verts = transpose(house_verts);
% House faces
house_faces = [1,2,3,4,5;
2,7,8,3,3;
6,7,8,9,10;
1,6,10,5,5;
3,4,9,8,8;
4,5,10,9,9;
1,2,7,6,6];
world_pos = [];
% creating a street
street_vector = [1,0,1]; % the direction of the street
orthog_street_vector = [-1,0,1];
for i = 1:15
% current_pos1 and 2 will be the positions of the two houses
% opposite each other on the street
current_pos1 = 30*i*street_vector + 50*orthog_street_vector;
current_pos2 = 30*i*street_vector - 50*orthog_street_vector;
world_pos = [world_pos;current_pos1;current_pos2];
end
% initialising world vertices and faces
world_verts = [];
world_faces = [];
% Populating the street
for i =1:size(world_pos,1)
T = transmatrix(world_pos(i,:)); % a translation matrix
s = [1,1/2 + rand(),1];
S=scalmatrix(s); % a matrix for a random scaling of the height (y-coordinate)
Ry = rotymatrix(rand()*2*pi); % a matrix for a random rotation about the y-axis
A = T*Ry*S; % the compound transformation matrix to take the house into the world
obj_faces = size(world_verts,2) + house_faces; %increments the basic house faces to match the current object
obj_verts = A*house_verts;
world_verts = [world_verts, obj_verts]; % adds the vertices to the world
world_faces = [world_faces; obj_faces]; % adds the faces to the world
end
% initialising aligned vertices
align_verts = [];
% Aligning the vertices to the particular camera at angle theta
for elm = world_verts
x = 350 + 350*cos(2*pi/4);
z = 350 + 350*sin(2*pi/4);
y = 80;
u = [x,y,z];
v = [250,0,250];
d = v - u;
phiy = atan2(d(1),d(3));
phix = -atan2(d(2),sqrt(d(1)^2+d(3)^2));
T = transmatrix([-u(1),-u(2),-u(3)]);
Ry = rotymatrix(phiy);
Rx = rotxmatrix(phix);
A = Rx*Ry*T;
align_verts = [align_verts, A*elm];
end
% initialising projected vertices
proj_verts=[];
% Performing the projection
for elm = align_verts
proj = projmatrix(10);
projverts = proj*elm;
projverts = ((10/projverts(3))*projverts);
proj_verts = [proj_verts,projverts];
end
% Displaying the world
for i = 1:size(world_faces,1)
for j = 1:size(world_faces,2)
x(j) =proj_verts(1,world_faces(i,j));
z(j) = proj_verts(2,world_faces(i,j));
end
patch(x,z,'w')
end
end
function T = transmatrix(p)
T = [1 0 0 p(1) ; 0 1 0 p(2) ; 0 0 1 p(3) ; 0 0 0 1];
end
function S = scalmatrix(s)
S = [s(1) 0 0 0 ; 0 s(2) 0 0 ; 0 0 s(3) 0 ; 0 0 0 1];
end
function Ry = rotymatrix(theta)
Ry = [cos(theta), 0, -sin(theta),0;
0,1,0,0;
sin(theta),0,cos(theta),0;
0,0,0,1];
end
function Rx = rotxmatrix(phi)
Rx = [1, 0, 0, 0;
0, cos(phi), -sin(phi), 0;
0, sin(phi), cos(phi), 0;
0, 0, 0, 1];
end
function P = projmatrix(f)
P = [1,0,0,0
0,1,0,0
0,0,1,0
0,0,1/f,0];
end
Updated code: managed to get the loop to work but now there is some bug i don't understand when it does a full rotation again any help would be great.
function world()
% Defining House Vertices
house_verts = [-5, 0, -5;
5, 0, -5;
5, 10, -5;
0,15,-5;
-5,10,-5;
-5,0,5;
5,0,5;
5,10,5;
0,15,5;
-5,10,5];
% Sorting out the homeogenous co-ordinates
ones = [1,1,1,1,1,1,1,1,1,1];
ones=transpose(ones);
house_verts = [house_verts, ones];
house_verts = transpose(house_verts);
% House faces
house_faces = [1,2,3,4,5;
2,7,8,3,3;
6,7,8,9,10;
1,6,10,5,5;
3,4,9,8,8;
4,5,10,9,9;
1,2,7,6,6];
world_pos = [];
% creating a street
street_vector = [1,0,1]; % the direction of the street
orthog_street_vector = [-1,0,1];
for i = 1:15
% current_pos1 and 2 will be the positions of the two houses
% opposite each other on the street
current_pos1 = 30*i*street_vector + 50*orthog_street_vector;
current_pos2 = 30*i*street_vector - 50*orthog_street_vector;
world_pos = [world_pos;current_pos1;current_pos2];
end
% initialising world vertices and faces
world_verts = [];
world_faces = [];
% Populating the street
for i =1:size(world_pos,1)
T = transmatrix(world_pos(i,:)); % a translation matrix
s = [1,1/2 + rand(),1];
S=scalmatrix(s); % a matrix for a random scaling of the height (y-coordinate)
Ry = rotymatrix(rand()*2*pi); % a matrix for a random rotation about the y-axis
A = T*Ry*S; % the compound transformation matrix to take the house into the world
obj_faces = size(world_verts,2) + house_faces; %increments the basic house faces to match the current object
obj_verts = A*house_verts;
world_verts = [world_verts, obj_verts]; % adds the vertices to the world
world_faces = [world_faces; obj_faces]; % adds the faces to the world
end
% initialising aligned vertices
align_verts = [];
% initialising projected vertices
proj_verts=[];
% Aligning the vertices to the particular camera at angle theta
theta = 0;
t = 0;
while t < 100
proj_verts=[];
align_verts = [];
for elm = world_verts
x = 300 + 300*cos(theta);
z = 300 + 300*sin(theta);
y = 80;
u = [x,y,z];
v = [200,0,200];
d = v - u;
phiy = atan2(d(1),d(3));
phix = -atan2(d(2),sqrt(d(1)^2+d(3)^2));
T = transmatrix([-u(1),-u(2),-u(3)]);
Ry = rotymatrix(phiy);
Rx = rotxmatrix(phix);
A = Rx*Ry*T;
align_verts = [align_verts, A*elm];
end
% Performing the projection
for elm = align_verts
proj = projmatrix(6);
projverts = proj*elm;
projverts = ((6/projverts(3))*projverts);
proj_verts = [proj_verts,projverts];
end
% Displaying the world
for i = 1:size(world_faces,1)
for j = 1:size(world_faces,2)
x(j) = proj_verts(1,world_faces(i,j));
z(j) = proj_verts(2,world_faces(i,j));
end
patch(x,z,'w')
pbaspect([1,1,1]); % adjusts the aspect ratio of the figure
end
title('Projected Space', 'fontsize', 16, 'interpreter', 'latex')
xlabel('$x$', 'fontsize', 16, 'interpreter', 'latex')
ylabel('$z$', 'fontsize', 16, 'interpreter', 'latex')
zlabel('$y$', 'fontsize', 16, 'interpreter', 'latex')
axis([-5,5,-5,2,0,5]) % sets the axes limits
view(0,89)
pause(0.0000001)
theta = theta + 0.01;
clf
end
end
function T = transmatrix(p)
T = [1 0 0 p(1) ; 0 1 0 p(2) ; 0 0 1 p(3) ; 0 0 0 1];
end
function S = scalmatrix(s)
S = [s(1) 0 0 0 ; 0 s(2) 0 0 ; 0 0 s(3) 0 ; 0 0 0 1];
end
function Ry = rotymatrix(theta)
Ry = [cos(theta), 0, -sin(theta),0;
0,1,0,0;
sin(theta),0,cos(theta),0;
0,0,0,1];
end
function Rx = rotxmatrix(phi)
Rx = [1, 0, 0, 0;
0, cos(phi), -sin(phi), 0;
0, sin(phi), cos(phi), 0;
0, 0, 0, 1];
end
function P = projmatrix(f)
P = [1,0,0,0
0,1,0,0
0,0,1,0
0,0,1/f,0];
end

How to find Orientation of axis of contour in matlab?

I want to find Orientation, MajorAxisLengthand MinorAxisLength of contour which is plotted with below code.
clear
[x1 , x2] = meshgrid(linspace(-10,10,100),linspace(-10,10,100));
mu = [1,3];
sigm = [2,0;0,2];
xx_size = length(mu);
tem_matrix = ones(size(x1));
x_mesh= cell(1,xx_size);
for i = 1 : xx_size
x_mesh{i} = tem_matrix * mu(i);
end
x_mesh= {x1,x2};
temp_mesh = [];
for i = 1 : xx_size
temp_mesh = [temp_mesh x_mesh{i}(:)];
end
Z = mvnpdf(temp_mesh,mu,sigm);
z_plat = reshape(Z,size(x1));
figure;contour(x1, x2, z_plat,3, 'LineWidth', 2,'color','m');
% regionprops(z_plat,'Centroid','Orientation','MajorAxisLength','MinorAxisLength');
In my opinion, I may have to use regionprops command but I don't know how to do this. I want to find direction of axis of contour and plot something like this
How can I do this task? Thanks very much for your help
Rather than trying to process the graphical output of contour, I would instead recommend using contourc to compute the ContourMatrix and then use the x/y points to estimate the major and minor axes lengths as well as the orientation (for this I used this file exchange submission)
That would look something like the following. Note that I have modified the inputs to contourc as the first two inputs should be the vector form and not the output of meshgrid.
% Compute the three contours for your data
contourmatrix = contourc(linspace(-10,10,100), linspace(-10,10,100), z_plat, 3);
% Create a "pointer" to keep track of where we are in the output
start = 1;
count = 1;
% Now loop through each contour
while start < size(contourmatrix, 2)
value = contourmatrix(1, start);
nPoints = contourmatrix(2, start);
contour_points = contourmatrix(:, start + (1:nPoints));
% Now fit an ellipse using the file exchange
ellipsedata(count) = fit_ellipse(contour_points(1,:), contour_points(2,:));
% Increment the start pointer
start = start + nPoints + 1;
count = count + 1;
end
orientations = [ellipsedata.phi];
% 0 0 0
major_length = [ellipsedata.long_axis];
% 4.7175 3.3380 2.1539
minor_length = [ellipsedata.short_axis];
% 4.7172 3.3378 2.1532
As you can see, the contours are actually basically circles and therefore the orientation is zero and the major and minor axis lengths are almost equal. The reason that they look like ellipses in your post is because your x and y axes are scaled differently. To fix this, you can call axis equal
figure;contour(x1, x2, z_plat,3, 'LineWidth', 2,'color','m');
axis equal
Thank you #Suever. It help me to do my idea.
I add some line to code:
clear
[X1 , X2] = meshgrid(linspace(-10,10,100),linspace(-10,10,100));
mu = [-1,0];
a = [3,2;1,4];
a = a * a';
sigm = a;
xx_size = length(mu);
tem_matrix = ones(size(X1));
x_mesh= cell(1,xx_size);
for i = 1 : xx_size
x_mesh{i} = tem_matrix * mu(i);
end
x_mesh= {X1,X2};
temp_mesh = [];
for i = 1 : xx_size
temp_mesh = [temp_mesh x_mesh{i}(:)];
end
Z = mvnpdf(temp_mesh,mu,sigm);
z_plat = reshape(Z,size(X1));
figure;contour(X1, X2, z_plat,3, 'LineWidth', 2,'color','m');
hold on;
% Compute the three contours for your data
contourmatrix = contourc(linspace(-10,10,100), linspace(-10,10,100), z_plat, 3);
% Create a "pointer" to keep track of where we are in the output
start = 1;
count = 1;
% Now loop through each contour
while start < size(contourmatrix, 2)
value = contourmatrix(1, start);
nPoints = contourmatrix(2, start);
contour_points = contourmatrix(:, start + (1:nPoints));
% Now fit an ellipse using the file exchange
ellipsedata(count) = fit_ellipse(contour_points(1,:), contour_points(2,:));
% Increment the start pointer
start = start + nPoints + 1;
count = count + 1;
end
orientations = [ellipsedata.phi];
major_length = [ellipsedata.long_axis];
minor_length = [ellipsedata.short_axis];
tet = orientations(1);
x1 = mu(1);
y1 = mu(2);
a = sin(tet) * sqrt(major_length(1));
b = cos(tet) * sqrt(major_length(1));
x2 = x1 + a;
y2 = y1 + b;
line([x1, x2], [y1, y2],'linewidth',2);
tet = ( pi/2 + orientations(1) );
a = sin(tet) * sqrt(minor_length(1));
b = cos(tet) * sqrt(minor_length(1));
x2 = x1 + a;
y2 = y1 + b;
line([x1, x2], [y1, y2],'linewidth',2);

MATLAB 3D lines are invisible

Hello I'am suffered from a problem
As you can see I want a draw 3D graph.
Problem is when I draw sphere lines are invisible.
Here is simple version of my source
clear all; close all; clc
n=1;
n_inner_drone=3;
n_outter_drone=2;
length=100;
initial_d = zeros(1,n);
inner_x = zeros(n_inner_drone,n);
inner_y = zeros(n_inner_drone,n);
inner_z = zeros(n_inner_drone,n);
outter_x = zeros(n_outter_drone,n);
outter_y = zeros(n_outter_drone,n);
outter_z = zeros(n_outter_drone,n);
radius= length;
disp('test');
%%%%%%%%%%%%%%%%%%%%%% Sphere
% figure()
% [x, y, z] = sphere;
% h = surfl(x*length, y*length, z*length);
% hSurf = surf(X,Y,Z,'EdgeColor','none','LineStyle','none','FaceLighting','phong');
% set(h, 'FaceAlpha', 0.05)
% surf(x*length, y*length, z*length,
% shading interp
hold on
%%%%%%%%%%%%%%%%%%%%%%%%%
for i=1:n_inner_drone
k=1;
while 1
x_temp= randi([-length, length], 1, 1);
y_temp= randi([-length, length], 1, 1);
z_temp= randi([-length, length], 1, 1);
dist = sqrt(x_temp^2 + y_temp^2 + z_temp^2);
if dist<radius
if i==1
initial_d(k) = dist;
end
inner_x(i,k) = x_temp;
inner_y(i,k) = y_temp;
inner_z(i,k) = z_temp;
k = k+1;
end
if k == n+1, break, end
end
end
ideal_direction_length = ones(1,n);
ideal_direction_length = ideal_direction_length * length;
ideal_direction_length = ideal_direction_length - initial_d;
k=1;
random_x = inner_x(1,:);
random_y = inner_y(1,:);
random_z = inner_z(1,:);
random_moving_distance = zeros(1,n);
moving_distance = 0;
trigger = 0;
while 1
if trigger == 0
direction = randi([1, 6], 1, 1);
trigger = 1;
end
if direction == 1
random_x(k) = random_x(k) + 1;
elseif direction == 2
random_x(k) = random_x(k) - 1;
elseif direction == 3
random_y(k) = random_y(k) + 1;
elseif direction == 4
random_y(k) = random_y(k) - 1;
elseif direction == 5
random_z(k) = random_z(k) + 1;
elseif direction == 6
random_z(k) = random_z(k) - 1;
end
dist = sqrt(random_x(k)^2 + random_y(k)^2 + random_z(k)^2);
moving_distance = moving_distance+1;
%%%%%%%%%% Line
plot3(random_x(n),random_y(n),random_z(n),'k+')
%%%%%%%%%%%%%%%
if dist>radius
random_moving_distance(k) = moving_distance;
k = k+1;
moving_distance = 0;
trigger = 0;
end
if k == n+1, break, end
end
plot3(inner_x(1,n),inner_y(1,n),inner_z(1,n),'r*')
for k=2:n_inner_drone
plot3(inner_x(k,n),inner_y(k,n),inner_z(k,n),'b*')
end
for k=1:n_outter_drone
plot3(outter_x(k,n),outter_y(k,n),outter_z(k,n),'k*')
end
At the first, I suspected I worngly draw lines, but without sphere I can see lines as fig2.
Those anyone who knows about this problem.
Please answer to me and I will very appericiate about it.
Thanks for reading.
I think it is because:
plot3(gravity_x(n),gravity_y(n),gravity_z(n))
is not a line. Its a single point.
plot3(gravity_x(n:n+1),gravity_y(n:n+1),gravity_z(n:n+1))
is a line.

Matlab - Failures of function to detect collisions between line segments and circle

Many questions exist already covering how to detect collisions between a line segment and a circle.
In my code, I am using Matlab's linecirc function, then comparing the intersection points it returns with the ends of my line segments, to check that the points are within the line (linecirc assumes an infinite line, which I don't have/want).
Copying and adding some sprintf calls to the linecirc function shows that it is calculating points as intended. These seem to be being lost by my function.
My code is below:
function cutCount = getCutCountHex(R_g, centre)
clf;
cutCount = 0;
% Generate a hex grid
Dg = R_g*2;
L_b = 62;
range = L_b*8;
dx = Dg*cosd(30);
dy = 3*R_g;
xMax = ceil(range/dx); yMax = ceil(range/dy);
d1 = #(xc, yc) [dx*xc dy*yc];
d2 = #(xc, yc) [dx*(xc+0.5) dy*(yc+0.5)];
centres = zeros((xMax*yMax),2);
count = 1;
for yc = 0:yMax-1
for xc = 0:xMax-1
centres(count,:) = d1(xc, yc);
count = count + 1;
centres(count, :) = d2(xc, yc);
count = count + 1;
end
end
for i=1:size(centres,1)
centres(i,:) = centres(i,:) - [xMax/2 * dx, yMax/2 * dy];
end
hold on
axis equal
% Get counter for intersected lines
[VertexX, VertexY] = voronoi(centres(:,1), centres(:,2));
numLines = size(VertexX, 2);
for lc = 1:numLines
segStartPt = [VertexX(1,lc) VertexY(1,lc)];
segEndPt = [VertexX(2,lc) VertexY(2,lc)];
slope = (segEndPt(2) - segStartPt(2))/(segEndPt(1) - segStartPt(1));
intercept = segEndPt(2) - (slope*segEndPt(1));
testSlope = isinf(slope);
if (testSlope(1)==1)
% Pass the x-axis intercept instead
intercept = segStartPt(1);
end
[xInterceptionPoints, yInterceptionPoints] = ...
linecirc(slope, intercept, centre(1), centre(2), L_b);
testArr = isnan(xInterceptionPoints);
if (testArr(1) == 0) % Line intersects. Line segment may not.
interceptionPoint1 = [xInterceptionPoints(1), yInterceptionPoints(1)];
interceptionPoint2 = [xInterceptionPoints(2), yInterceptionPoints(2)];
% Test if first intersection is on the line segment
p1OnSeg = onSeg(segStartPt, segEndPt, interceptionPoint1);
p2OnSeg = onSeg(segStartPt, segEndPt, interceptionPoint2);
if (p1OnSeg == 1)
cutCount = cutCount + 1;
scatter(interceptionPoint1(1), interceptionPoint1(2), 60, 'MarkerFaceColor', 'r', 'MarkerEdgeColor', 'k');
end
% Test if second intersection point is on the line segment
if (interceptionPoint1(1) ~= interceptionPoint2(1) || interceptionPoint1(2) ~= interceptionPoint2(2)) % Don't double count touching points
if (p2OnSeg == 1)
cutCount = cutCount + 1;
scatter(interceptionPoint2(1), interceptionPoint2(2), 60, 'MarkerFaceColor', 'r', 'MarkerEdgeColor', 'k');
end
end
end
end
% Plot circle
viscircles(centre, L_b, 'EdgeColor', 'b');
H = voronoi(centres(:,1), centres(:,2));
for i = 1:size(H)
set(H(i), 'Color', 'g');
end
end
function boolVal = onSeg(segStart, segEnd, testPoint)
bvX = isBetweenOrEq(segStart(1), segEnd(1), testPoint(1));
bvY = isBetweenOrEq(segStart(2), segEnd(2), testPoint(2));
if (bvX == 1 && bvY == 1)
boolVal = 1;
else
boolVal = 0;
end
end
function boolVal = isBetweenOrEq(end1, end2, test)
if ((test <= end1 && test >= end2) || (test >= end1 && test <= end2))
boolVal = 1;
else
boolVal = 0;
end
end
It creates a hexagonal grid, then calculates the number of crossings between a circle drawn with a fixed radius (62 in this case) and a specified centre.
The scatter calls show the locations that the function counts.
Implementing sprintf calls within the if(p1OnSeg == 1) block indicates that my function has chosen fictitious intersection points (although it then deals with them correctly)
if (interceptionPoint1(1) > -26 && interceptionPoint1(1) < -25)
sprintf('p1 = [%f, %f]. Vx = [%f, %f], Vy = [%f, %f].\nxint = [%f, %f], yint = [%f, %f]',...
interceptionPoint1(1), interceptionPoint1(2), VertexX(1,lc), VertexX(2,lc), VertexY(1,lc), VertexY(2,lc),...
xInterceptionPoints(1), xInterceptionPoints(2), yInterceptionPoints(1), yInterceptionPoints(2))
end
Outputs
p1 = [-25.980762, 0.000000]. Vx = [-25.980762, -25.980762], Vy = [-15.000000, 15.000000].
xint = [-25.980762, -25.980762], yint = [0.000000, 0.000000]
A picture shows the strange points.
Sorry for the very long question but - why are these being detected. They don't lie on the circle (displaying values within a mylinecirc function detects the intersections at around (-25, 55) and (-25, -55) or so (as an infinite line would expect).
Moving the circle can remove these points, but sometimes this leads to other problems with detection. What's the deal?
Edit: Rotating my grid pattern created by [Vx, Vy] = voronoi(...) and then removing points with very large values (ie those going close to infinity etc) appears to have fixed this problem. The removal of 'large' value points seems to be necessary to avoid NaN values appearing in 'slope' and 'intercept'. My guess is this is related to a possible slight inclination due to rotation, coupled with then overflow of the expected intercept.
Example code added is below. I also edited in Jan de Gier's code, but that made no difference to the problem and so is not changed in the question code.
%Rotate slightly
RotAngle = 8;
RotMat = [cosd(RotAngle), -sind(RotAngle); sind(RotAngle), cosd(RotAngle)];
for i=1:size(centres,1)
centres(i,:) = centres(i,:) - [floor(xMax/2) * dx, floor(yMax/2) * dy]; %Translation
centres(i,:) = ( RotMat * centres(i,:)' ); %Rotation
end
% Get counter for intersected lines
[VertexX, VertexY] = voronoi(centres(:,1), centres(:,2));
% Filter vertices
numLines = size(VertexX, 2);
newVx = [];
newVy = [];
for lc = 1:numLines
testVec = [VertexX(:,lc) VertexY(:,lc)];
if ~any(abs(testVec) > range*1.5)
newVx = [newVx; VertexX(:,lc)'];
newVy = [newVy; VertexY(:,lc)'];
end
end
VertexX = newVx';
VertexY = newVy';
numLines = size(VertexX, 2);
Still appreciating answers or suggestions to clear up why this is/was occuring.
Example values that cause this are getCutCountHex(30, [0,0]) and ...(35, [0,0])
I cant reproduce your problem, but the thing I did notice is that your onSeg() function might be wrong: it returns true if the testpoint lies in the rectangle with two of the four corner points being segStart and segEnd.
A function that returns true iff a point is on (or more accurate: close enough to) the line segment (segStart,segEnd) could be:
function boolVal = onSeg(segStart, segEnd, testPoint)
tolerance = .5;
AB = sqrt((segEnd(1)-segStart(1))*(segEnd(1)-segStart(1))+(segEnd(2)-segStart(2))*(segEnd(2)-segStart(2)));
AP = sqrt((testPoint(1)-segEnd(1))*(testPoint(1)-segEnd(1))+(testPoint(2)-segEnd(2))*(testPoint(2)-segEnd(2)));
PB = sqrt((segStart(1)-testPoint(1))*(segStart(1)-testPoint(1))+(segStart(2)-testPoint(2))*(segStart(2)-testPoint(2)));
boolVal = abs(AB - (AP + PB)) < tolerance;
end
an approach that I found in one of the anwers here: Find if point lays on line segment. I hope that solves your problem.

generate a matrix image after having all the balck pixel's coordinates with MatLab

I have an Image, converted into binary, i got all the black pixel's coordinates.
The 'matrix' contains the x and y coordinates arranged by columns.
Now i Need to make a Simulation, to see if my Programme works.
I have to generate an Matrix Image with my results.
im=imread('square.jpg');
imshow(im); c=im2bw(im); figure; imshow(c);
dim = size(c) % size of the image
x = [];
y = [];
xdif = [];
newx = [];
matrix = [];
for i = 1:dim(1)
for j = 1:dim(2)
if c(i,j)==0;
x = [x i];
y = [y j];
end
end
end
% show black pixel's coordinates
p = [x;y];
%number of pixels
nr = length(x)
dimp = size(p);
xval = p(1,:);
yval = p(2,:);
j=1;
i=1;
for z = 1:dimp(2)-1
xdif = xval(z+1)-xval(z);
ff=find(xdif > 0);
if ff == 1
i = 1;
else
i=i+1;
end
newx(i,j)= xval(z);
newy(i,j)= yval(z);
if ff == 1
j= j+1;
end
end
xsize = size(newx);
ysize = size(newy);
matrix_size = xsize(2)+ysize(2)
xinc = 1;
yinc = 1;
x=1;
for ct = 1:1:matrix_size/2
x;
matrix(:,x) = newx(:,xinc);
matrix(:,x+1) = newy(:,yinc);
matrix;
xinc = xinc+1;
yinc = yinc+1;
x=x+3;
end
matrix
this is my Programme, now i need to make a simulation, by generating an image with my coordinates.
how can i do that?
thank's