3D rotation of a sphere around a fixed point in Matlab - matlab

I have a sphere centered on the origin of the axes. I use the rotate3d function to allow its rotation. However, when I rotate it, it seems to move in the space with having a fixed point for the rotation. I would like to fix the origin as rotation center. How can I achieve it?
Here is my code:
function ex
global state;
fh = figure('Menu','none','Toolbar','none','Units','characters',...
'Renderer','OpenGL');
hPanAni = uipanel('parent',fh,'Units','characters','Position',...
[22.6 10.4 53 23],'title','Controls','FontSize',11,...
'FontAngle','italic','FontWeight','bold');
hIniAni = uicontrol(hPanAni,'Style','pushbutton','Units','normalized',...
'Position',[0.14 0.75 0.5 0.12],'String','Spin',...
'FontSize',10,'Callback',#hIniAniCallback);
hFinAni = uicontrol(hPanAni,'Style','pushbutton','Units','normalized',...
'Position',[0.14 0.5 0.5 0.12],'String','Stop',...
'FontSize',10,'Callback',#hFinAniCallback);
hResetAni = uicontrol(hPanAni,'Style','pushbutton','Units','normalized',...
'Position',[0.14 0.25 0.5 0.12],'String','Reset',...
'FontSize',10,'Callback',#hResetAniCallback);
hPantSim = uipanel('Parent',fh,'Units','characters',...
'Position',[107.87 8 157.447 42],'BorderType','none','title',...
'Screen','FontSize',11,'FontAngle','italic',...
'FontWeight','bold');
hPantSimInt = uipanel('Parent',hPantSim,'Units','normalized','Position',...
[0 0 1 1],'BorderType','line','BackgroundColor','k');
axes('units','normalized','position',[0,0,1,1],'Parent',...
hPantSimInt);
stars = rand(60,2);
scatter(stars(:,1),stars(:,2),6,'y','Marker','+');
axis off;
ah4 = axes('Parent',hPantSimInt,'Units','normalized','Position',...
[0 0 1 1],'Color','none','Visible','off','DataAspectRatio',...
[1 1 1],'NextPlot','add');
T1 = 0:pi/1000:2*pi;
Fin = numel(T1);
if (Fin>1000)
Incr = floor(Fin/1000);
else
Incr = 1;
end
Y = zeros(numel(T1),3);
Y(:,1) = 7000*cos(T1);
Y(:,2) = 7000*sin(T1);
R_esf = 6378;
[x_esf,y_esf,z_esf] = sphere(50);
x_esf = R_esf*x_esf;
y_esf = R_esf*y_esf;
z_esf = R_esf*z_esf;
props.FaceColor= 'texture';
props.EdgeColor = 'none';
props.Parent = ah4;
surface(x_esf,y_esf,z_esf,props);
handles.psat = line('parent',ah4,'XData',Y(1,1), 'YData',Y(1,2),...
'ZData',Y(1,3),'Marker','o', 'MarkerSize',10,'MarkerFaceColor','b');
line([0 1.5*R_esf],[0 0],[0 0],'LineWidth',3,'Color','g');
line([0 0],[0 1.5*R_esf],[0 0],'LineWidth',3,'Color','g');
line([0 0],[0 0],[0 1.5*R_esf],'LineWidth',3,'Color','g');
pbaspect([1 1 1]);
axis vis3d;
rotate3d(ah4);
view([atan2(Y(1,2),Y(1,1)),0]);
az = 0;
k = 2;
ind_ini = 0;
state = 0;
function hIniAniCallback(hObject,evt)
tic;
if (ind_ini == 1)
return;
end
ind_ini = 1;
state = 0;
while (k<=Fin)
set(handles.psat,'XData',Y(k,1),'YData',Y(k,2),'ZData',Y(k,3));
pause(0.002);
if (k == Fin)
toc;
end
k = k + Incr;
if (state == 1)
state = 0;
break;
end
end
end
function hFinAniCallback(hObject,evt)
ind_ini = 0;
state = 1;
end
function hResetAniCallback(hObject,evt)
set([handles.psat],'Visible','off');
ind_ini = 0;
state = 1;
az = 0;
k = 2;
handles.psat = line('parent',ah4,'XData',Y(1,1), 'YData',Y(1,2),...
'ZData',Y(1,3),'Marker','o', 'MarkerSize',10,'MarkerFaceColor','b');
end
end

The problem is that the 3d rotation is done with respect to the center of your axes, and not with respect to the origin. After you add the green lines along the axes, the limits of the x,y,z axes is automatically changed, the center of sphere is no longer positioned in the center of the figure. Add the following line after drawing all the lines:
ax_limits = 2*[-R_esf R_esf];
set (ah4, 'xlim', ax_limits, 'ylim', ax_limits, 'zlim', ax_limits)
The '2' factor is just to prevent the sphere from filling your axes tightly. You can set it to whatever value you need.

Related

How do I eliminate points outside the contour lines?

I have the code that generate a plot which has points plotted both inside and outside the contour line. I want to eliminate the points outside the outermost contour line. I'm using gaussian copula function.
plot(givenData(:,1),givenData(:,2),'b.','MarkerSize',3);
givenData is a 5000x2 matrix and I want only those values that lie inside the outer contour line to be plotted.
plot i'm getting
plot i want to generate
i want to eliminate the points lying outside the red contour which are shown as geen dots.
function [xgrid,ygrid,Z] = biVariateContourPlotsGMMCopula(givenData,gmmObject,~,numMeshPoints,x_dim,y_dim)
d = 2;
if nargin < 5
x_dim = 1;
y_dim = 2;
end
if x_dim == y_dim
hist(givenData(:,x_dim),10);
return;
end
numMeshPoints = min(numMeshPoints,256);
givenData = givenData(:,[x_dim y_dim]);
alpha = gmmObject.alpha;
mu = gmmObject.mu(:,[x_dim y_dim]);
sigma = gmmObject.sigma([x_dim y_dim],[x_dim y_dim],:) + 0.005*repmat(eye(d),[1 1 numel(alpha)]);
gmmObject = gmdistribution(mu,sigma,alpha);
bin_num = 256;
for j = 1:2
l_limit = min(gmmObject.mu(:,j))-3*(max(gmmObject.Sigma(j,j,:))^0.5);
u_limit = max(gmmObject.mu(:,j))+3*(max(gmmObject.Sigma(j,j,:))^0.5);
xmesh_inverse_space{j} = (l_limit:(u_limit-l_limit)/(bin_num-1):u_limit);
end
[~,pdensity{i},xmesh{i}]=kde(currentVar,numMeshPoints);
pdensity{i}(pdensity{i}<0) = 0;
cdensity{i} = cumsum(pdensity{i});
cdensity{i} = (cdensity{i}-min(cdensity{i}))/(max(cdensity{i})-min(cdensity{i})); % scaling the cdensity value to be between [0 1]
end
[xgrid,ygrid] = meshgrid(xmesh{1}(2:end-1),xmesh{2}(2:end-1));
for k = 1:d
marginalLogLikelihood_grid{k} = log(pdensity{k}(2:end-1)+eps);
marginalCDFValues_grid{k} = cdensity{k}(2:end-1);
end
[marg1,marg2] = meshgrid(marginalLogLikelihood_grid{1},marginalLogLikelihood_grid{2});
[xg,yg] = meshgrid(marginalCDFValues_grid{1},marginalCDFValues_grid{2});
inputMatrix = [reshape(xg,numel(xg),1) reshape(yg,numel(yg),1)];
copulaLogLikelihoodVals = gmmCopulaPDF(inputMatrix,gmmObject,xmesh_inverse_space);
Z = reshape(copulaLogLikelihoodVals,size(marg1,1),size(marg1,2));
Z = Z+marg1+marg2;
Z = exp(Z);
plot(givenData(:,1),givenData(:,2),'b.','MarkerSize',3);hold
contour(xgrid,ygrid,Z,40,'EdgeColor',[1 0 0]);
axis tight;

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

Problems with performing image translation in MATLAB

I'm trying to do image translation using MATLAB, and the image doesn't move at all. My code is:
myPic = imread('pic.jpg');
x = 250;
y = 375;
trans = affine2d([1 0 0; 0 1 0; x y 1]);
outputPic = imwarp(myPic, trans);
imshow(myPic)
axis on
figure()
imshow(outputPic)
axis on
isequal(myPic,outputPic) %evaluates to 1!!!
When I do the same for a rotation affine matrix, it worked. Why doesn't this work?
here's what happens when I print both pics:
In order for this to work, you'll need to define an 'OutputView' parameter.
This parameter sets the size and location of the output image in world coordinate system, using imref2d function.
Example:
myPic = imread('peppers.png');
x = 250;
y = 375;
%defines transformations
trans = affine2d([1 0 0; 0 1 0; x y 1]);
eyeTrans= affine2d([1 0 0; 0 1 0; 0 0 1]);
%initializes imref2d object
outView = imref2d([size(myPic,1)+y,size(myPic,2)+x]);
outputPic1 = imwarp(I,trans,'OutputView',outView)
outputPic2 = imwarp(I,eyeTrans,'OutputView',outView)
%display result
figure,
subplot(1,2,1); imshow(outputPic2); title('original')
subplot(1,2,2); imshow(outputPic1); title('translated')
Result:

Finger peak detection using 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

Code for a multicolumn legend in Matlab

I have designed an application called CLegend, which allows to build a multicolumn legend, whose code is
function CLegend(hax,numcol,Ley)
%# Inputs
% hax : handle of the axes object to which belongs the legend
% numcol: number of columns for the legend
% Ley: text strings (labels) for the legend
set(hax,'Units','normalized','Position',[0.1 0.1 0.8 0.8]);
set(hax,'Units','characters');
posAx = get(hax,'Position');
insAx = get(hax,'TightInset');
[legend_h,object_h] = legend(hax,Ley,'Units','characters','Location',...
'South','Orientation','vertical');
posl = get(legend_h,'Position');
numlines = length(Ley);
if (numlines<numcol)
numcol = numlines;
end
numpercolumn = ceil(numlines/numcol);
if (mod(numlines,numpercolumn) == 0)
numcol = numlines/numpercolumn;
end
l = zeros(1,numlines);
a = zeros(1,numlines);
h = zeros(1,4);
for j=1:numlines
h = get(object_h(j),'Extent');
l(j) = h(3);
a(j) = h(4);
set(object_h(j),'Units','characters');
end
lmax = posl(3)*max(l);
hmax = posl(4)*max(a);
hLine = object_h(numlines+1);
xdata = get(hLine, 'xdata');
dx = xdata(2)-xdata(1);
di = 2;
sheight = hmax;
height = hmax*numpercolumn-sheight/2;
line_width = dx*posl(3);
spacer = xdata(1)*posl(3);
delta1 = spacer + line_width + spacer + lmax;
delta2 = line_width + spacer + lmax + spacer;
delta3 = lmax + spacer + line_width + spacer;
factx = 1/(posl(3)*numcol);
facty = 1/(hmax*numpercolumn);
width_l = numcol*delta1;
set(legend_h, 'Position', [posAx(1) + 0.5*(posAx(3)-width_l) posl(2) ...
width_l numpercolumn*hmax]);
col_ind = -1;
row_ind = -1;
j = 0;
for i=1:numlines,
if strcmpi(orient,'horizontal'),
if mod(i,numcol)==1,
row_ind = row_ind+1;
end
col_ind = mod(i,numcol)-1;
if col_ind == -1,
col_ind = numcol-1;
end
else
if numpercolumn==1 || mod(i,numpercolumn)==1,
col_ind = col_ind+1;
end
row_ind = mod(i,numpercolumn)-1;
if row_ind == -1,
row_ind = numpercolumn-1;
end
end
if (i==1)
linenum = i+numlines;
else
linenum = linenum+di;
end
labelnum = i;
set(object_h(linenum), 'ydata',facty*[height-row_ind*sheight ...
height-row_ind*sheight]);
set(object_h(linenum), 'xdata', factx*[spacer + j*delta2 ...
spacer + j*delta2 + line_width]);
set(object_h(linenum+1), 'ydata',facty*(height-row_ind*sheight));
set(object_h(linenum+1), 'xdata', factx*(spacer+line_width/2));
set(object_h(labelnum), 'Position', [j*delta3+spacer*2+line_width ...
height-row_ind*sheight]);
if (mod(i,numpercolumn)== 0)
j = j + 1;
end
end
opl = get(legend_h,'OuterPosition');
set(hax, 'Position',[posAx(1) posAx(2)+opl(4) posAx(3) posAx(4)-opl(4)]);
set(legend_h, 'OuterPosition',[opl(1) (posAx(2)-insAx(2))/2 opl(3) opl(4)]);
set([hax,legend_h],'Units','normalized');
end
I have problems with it. I have tried it with a more complicated code but similar to this one that appears below.
function qq
fh = figure('Units','characters');
GrapWin = uipanel ('Parent',fh,'Units','characters','title','Graphic',...
'Position',[135 5 120 40]);
haxes = axes('Parent',GrapWin,'Units','normalized','Position',[0.1 0.1 0.8 0.8]);
PanVD = uipanel('Parent',fh,'Units','characters','Position',[55 5 30 10],...
'title','Dependent Variable');
VDlh = uicontrol('Parent',PanVD,'Style','listbox','Units',...
'normalized','Position',[0 0 1 1],'String',{'X','Y','Z'},'Value',1,...
'Callback',#VDLhCallback);
T = 0:pi/100:2*pi;
X = sin(T);
xlabel(haxes,'Time');
title(haxes,'Sine Function');
plot(haxes,T,X);
CLegend(haxes,3,{'Var X'});
function VDLhCallback (src,evt)
value = get(VDlh,'Value');
switch value
case 1
title(haxes,'Sine Function');
plot(haxes,T,X);
CLegend(haxes,3,{'Var X'});
case 2
title(haxes,'Cosine Function');
Y = cos(T);
plot(haxes,T,Y);
CLegend(haxes,3,{'Var Y'});
case 3
Z = tan(T);
title(haxes,'Tangent Function');
plot(haxes,T,Z);
CLegend(haxes,3,{'Var Z'});
end
end
end
It happens something that I do not understand because the first time that CLegend is called the legend appears not centered (respect to axes) but the following callings through the listbox options it does is centered.
Other problem that occurs is that if I delete the command line
set(haxes,'Units','normalized')
then, although the legend is centered, the axes appear with a reduced size.
I also have found that the first time Clegend is calles, the position of the axes (variable posAx) is different from the following callings (in which posAx is always the same).
I have thought that when the units were changed, the position of the object was not changed but this problem arises doubts inside my mind.
In the Figure Properties documentation, it is said of Unit
This property affects the CurrentPoint and Position properties. If you
change the value of Units, it is good practice to return it to its
default value after completing your computation so as not to affect
other functions that assume Units is the default value.
Can it explain your problems?
After a lot of proofs, I have found that my problem was the resizing of the figure. The first time CLegend was called the figure window had its original size. The following calls of CLegend happened with the figure windows maximized.