Fill convex area between 3D points in Matlab - matlab

I have a collection of 3D points in Matlab
PY=0.5000 0 0.5000;
0.5000 0.1250 0.3750;
0.5000 0.2500 0.2500;
0.5000 0.3750 0.1250;
0.6250 0 0.3750;
0.6250 0.1250 0.2500;
0.6250 0.2500 0.1250;
0.6250 0.3750 0;
0.7500 0 0.2500;
0.7500 0.1250 0.1250;
0.7500 0.2500 0];
These points are parts of the unit simplex
close all
patch([0 0 1],[0 1 0],[1 0 0],[0.8 0.8 0.8]);
axis equal
axis([0 1 0 1 0 1])
view(120,30)
hold on
scatter3(PY(:,1), PY(:,2), PY(:,3))
Question: I would like to fill the convex region that one gets by connecting these points. I'm unable to do that. Could you help?
This is what I tried
1) CHPY=convhull(PY(:,1),PY(:,2),PY(:,3) );
which gives me as error
Error computing the convex hull. The points may be coplanar or collinear.
2)
T = delaunayTriangulation(PY);
K = convexHull(T);
which gives me as error
Error using delaunayTriangulation/convexHull
The triangulation is empty.

Related

MATLAB fitcsvm svm boundary equation does not separate data

I am trying to classify binary data using fitcsvm, but when I plot the boundry equation, it does not sit close to the data.
Here is the code that I used to generate the model
Theme
%creating inputs for the model
xTable = [responseData_Intensity.Intensity responseData_Intensity.ActiveForce_kg_];
y = responseData_Intensity.FeltSVM;
%-------------------------------------------------------SVM MODEL
SVMModel = fitcsvm(xTable,y);
%------------------------------------------PLOTTING THE MODEL WITH DATA
figureSVM = figure;
hold on
figTitle = strcat(participantList(participantNumber),'-',parameter,'-Maximal Margin Line');
title(figTitle);
in = responseData_Intensity.Intensity; fr = responseData_Intensity.ActiveForce_Kg_;
gscatter(in,fr,responseData_Intensity.FeltSVM,'rb');
syms x
eqn = slope*x+yIntercept == 0;
xIntercept = double(solve(eqn)); % X values where y=0
xlabel('Inensity Tested');
ylabel('Force (kg)');
plot(in(SVMModel.IsSupportVector), fr(SVMModel.IsSupportVector), 'ko', 'MarkerSize',10);
plot(in, -SVMModel.Beta(1)/SVMModel.Beta(2)*in - (SVMModel.Bias)/SVMModel.Beta(2))
legend('Not Felt','Felt','Support Vector','Classifier');
These are the values for
xTable and y
xTable =
0.5000 0.5500
0.4000 0.6167
0.3000 0.4000
0.2000 0.3500
0.1000 0.6833
0.2000 0.6333
0.1000 0.4833
0 0.6500
0.5000 0.6167
0.4000 0.5333
0.3000 0.7333
0.2000 0.7000
0.1000 0.7000
0.2000 0.6833
0.1000 0.7833
0.1000 0.6500
0.2000 0.6333
0.1000 0.8167
0 1.1333
0 0.8500
y =
1
1
1
1
-1
1
-1
-1
1
1
1
1
-1
1
1
-1
1
-1
1
1
and the resulting plot
which seems off because it is so far removed from the data and the support vectors. The zoomed in data is here:
From all the other example I've seen the line should divide the data in between the two identifiers? I may be getting some things mixed up, so any help would be very much appreciated!
Figured out the answer, I needed to normalize the data, once that is done the boundary equation separatest the data nicely!

Distance Transform Behaviors Differently Between Matlab and OpenCV

I am currently translating code from Matlab to OpenCV but found the distance transform function behaviors differently between Matlab and OpenCV.
Take the simple matrix as an example
bw =
0 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
Matlab version distance transform assigns a number that is the distance between that pixel and the nearest nonzero pixel of BW, which makes sense and I got
1.4142 1.0000 1.4142 2.2361 3.1623
1.0000 0 1.0000 2.0000 2.2361
1.4142 1.0000 1.4142 1.0000 1.4142
2.2361 2.0000 1.0000 0 1.0000
3.1623 2.2361 1.4142 1.0000 1.4142
In OpenCV, I choose the DIST_L2 (the simple euclidean distance). it gives me
1.3692 0.9550 1.3692 2.3242 3.2792
0.9550 0 0.9550 1.9100 2.3242
1.3692 0.9550 1.3692 2.3242 1.3692
2.3242 1.9100 0.9550 0 0.9550
3.2792 2.3242 1.3692 0.9550 1.3692
I don't understand why and it doesn't make sense to me. I realized that OpenCV compute the pixel with nearest zero pixel, so I already inverted the input matrix.
maskSize – Size of the distance transform mask. It can be 3, 5, or CV_DIST_MASK_PRECISE (the latter option is only supported by the first function).
It looks like OpenCV version distance transform is doing some normalization using maskSize. Set it to 0 (Even the documentation didn't mention it) and it solves the issue.

Summing cumulative area under curves of overapping triangles

I have two matrices for several triangles:
x =
2.0000 5.0000 10.0000
8.0000 10.0000 12.0000
12.0000 24.0000 26.0000
22.0000 25.0000 28.0000
23.0000 26.0000 25.0000
23.5000 27.0000 27.5000
20.0000 23.0000 27.0000
21.0000 24.0000 27.0000
24.0000 25.0000 27.0000
24.0000 26.0000 27.0000
24.0000 28.0000 29.0000
19.0000 22.0000 25.0000
18.0000 21.0000 23.0000
y =
0 1.0000 0
0 0.8000 0
0 0.6000 0
0 0.8000 0
0 0.8000 0
0 0.8000 0
0 1.0000 0
0 1.0000 0
0 1.0000 0
0 1.0000 0
0 1.0000 0
0 1.0000 0
0 1.0000 0
one line is one triangle. Columns are x and y positions of each point of the triangles.
So, I plot all these triangles and I need to sum the cumulative area under the curve of the triangles.
I try to use the area function, but I couldn't find how to sum their areas.
EDIT: I need to plot the sum of the areas on a red line in the same graphics. So I don't want a number like 20 cm²... I would like something like that:
I suggest that you interpolate to create all your individual triangles and then add the results. First you will need to augment your x and y matrices with the beginning (the origin) and end points like so:
m = 30; %// This is your max point, maybe set it using max(x(:))?
X = [zeros(size(x,1),1), x, ones(size(x,1),1)*m];
Y = [zeros(size(y,1),1), y, zeros(size(y,1),1)];
then perform all the interpolations (I'll sum as I go):
xi = 0:0.1:m;
A = zeros(1,size(xi,2)); %// initialization
for row = 1:size(x,1)
A = A + interp1(X(row,:), Y(row,:), xi);
end
and finally plot:
plot(x,y,'k')
hold on
plot(xi,A,'r','linewidth',2)
using your example data this gives:

Assigning Different Colors to a Plot / Scatter

So I have a vector called C1_Vector that has been previously filled with different shades of 1 RGB color ([0 0.5 1]), blue. So there are many different vectors within the C1_Vector
ex:
C1_Vector = ([0 0.5 1], [0 0.45 0.98], [0 0.49 1.01], etc.)
I want to each one of my points, in s1, to correspond to a different color. This is what I've been playing around with, and struggling with. Can someone help me with this syntax?
plot(s1(1,:),s1(2,:),'.', 'color', C1_Vector );
where,
s1 =
3.0000 3.0000 3.0000 1.5000 1.5000 1.5000 0 -1.5000
1.5000 0 -1.5000 1.5000 0 -1.5000 0 3.0000
Using the scatter function makes it quite easy as long as you provide the same number of color vectors than element to plot.
Basically for each pair of points to display the function assign it the corresponding color in the color matrix provided, which is M x 3 where M is the number of points.
Therefore for the demo I added colors to C1_Vector so that it contains as many elements as s1.
C1_Vector = [0 0.5 1; 0 0.45 0.98; 0 0.49 1.01;1 0 1; rand(1,3); 0 1 0; 0 1 1;rand(1,3)];
s1 = [3.0000 3.0000 3.0000 1.5000 1.5000 1.5000 0 -1.5000;
1.5000 0 -1.5000 1.5000 0 -1.5000 0 3.0000];
scatter(s1(1,:),s1(2,:),[],C1_Vector,'filled')
grid on
Output:
Is that what you meant?

Blockdiagonal variation grid

I have the feeling I am missing something intuitive in my solution for generating a partially varied block-diagonal grid. In any case, I would like to get rid of the loop in my function (for the sake of challenge...)
Given tuples of parameters, number of intervals and percentage variation:
params = [100 0.5 1
24 1 0.9];
nint = 1;
perc = 0.1;
The desired output should be:
pspacegrid(params,perc,nint)
ans =
90.0000 0.5000 1.0000
100.0000 0.5000 1.0000
110.0000 0.5000 1.0000
100.0000 0.4500 1.0000
100.0000 0.5000 1.0000
100.0000 0.5500 1.0000
100.0000 0.5000 0.9000
100.0000 0.5000 1.0000
100.0000 0.5000 1.1000
21.6000 1.0000 0.9000
24.0000 1.0000 0.9000
26.4000 1.0000 0.9000
24.0000 0.9000 0.9000
24.0000 1.0000 0.9000
24.0000 1.1000 0.9000
24.0000 1.0000 0.8100
24.0000 1.0000 0.9000
24.0000 1.0000 0.9900
where you can see that the variation occurs at the values expressed by this mask:
mask =
1 0 0
1 0 0
1 0 0
0 1 0
0 1 0
0 1 0
0 0 1
0 0 1
0 0 1
1 0 0
1 0 0
1 0 0
0 1 0
0 1 0
0 1 0
0 0 1
0 0 1
0 0 1
The function pspacegrid() is:
function out = pspacegrid(params, perc, nint)
% PSPACEGRID Generates a parameter space grid for sensitivity analysis
% Size and number of variation steps
sz = size(params);
nsteps = nint*2+1;
% Preallocate output
out = reshape(permute(repmat(params,[1,1,nsteps*sz(2)]),[3,1,2]),[],sz(2));
% Mask to index positions where to place interpolated
[tmp{1:sz(2)}] = deal(true(nsteps,1));
mask = repmat(logical(blkdiag(tmp{:})),sz(1),1);
zi = cell(sz(1),1);
% LOOP per each parameter tuple
for r = 1:sz(1)
% Columns, rows, rows to interpolate and lower/upper parameter values
x = 1:sz(2);
y = [1; nint*2+1];
yi = (1:nint*2+1)';
z = [params(r,:)*(1-perc); params(r,:)*(1+perc)];
% Interpolated parameters
zi{r} = interp2(x,y,z, x, yi);
end
out(mask) = cat(1,zi{:});
I think I got it, building off your pre-loop code:
params = [100 0.5 1
24 1 0.9];
nint = 1;
perc = 0.1;
sz = size(params);
nsteps = nint*2+1;
% Preallocate output
out = reshape(permute(repmat(params,[1,1,nsteps*sz(2)]),[3,1,2]),[],sz(2));
%Map of the percentage moves
[tmp{1:sz(2)}] = deal(linspace(-perc,perc,nint*2+1)');
mask = repmat(blkdiag(tmp{:}),sz(1),1) + 1; %Add one so we can just multiply at the end
mask.*out
So instead of making your mask replicate the ones I made it replicate the percentage moves each element makes which is a repeating pattern, the basic element is made like this:
linspace(-perc,perc,nint*2+1)'
Then it's as simple as adding 1 to the whole thing and multiplying by your out matrix
I tested it as follows:
me = mask.*out;
you = pspacegrid(params, perc, nint);
check = me - you < 0.0001;
mean(check(:))
Seemed to work when I fiddled with the inputs. However I did get an error with your function, I had to change true(...) to ones(...). This might be because I'm running it online which probably uses Octave rather than Matlab.