Fit plane to N dimensional points in MATLAB - matlab

I have a set of N points in k dimensions as a matrix of size N X k.
How can I find the best fitting line through these points? The line will be a plane (hyerpplane) in k dimensions. It will have k coefficients and one bias term.
Existing functions like fit seem to be usable only for points in 2 or 3 dimension.

You can fit a hyperplane (or any lower dimensional affine space) to a set of D dimensional data using Principal Component Analysis. Here's an example of fitting a plane to a set of 3D data. This is explained in more detail in the MATLAB documentation but I tried to construct the simplest example I could.
% generate some random correlated data
D = 3;
mu = zeros(1,D);
sqrt_sig = randn(D);
sigma = sqrt_sig'*sqrt_sig;
% generate 50 points in a D x 50 matrix
X = mvnrnd(mu, sigma, 50)';
% perform PCA
coeff = pca(X');
% The last principal component is normal to the best fit plane and plane goes through mean of X
a = coeff(:,D);
b = -mean(X,2)'*a;
% plane defined by a'*x + b = 0
dist = abs(a'*X+b) / norm(a);
mse = mean(dist.^2)
Edit: Added example plot of results for D = 3. I take advantage of the orthogonality of the other principal components here. Ignore the code if you want it's just to demonstrate that the plane does in fact fit the data pretty well.
% plot in 3D
X0 = bsxfun(#minus,X,mean(X,2));
b1 = coeff(:,1); b2 = coeff(:,2);
y1 = b1'*X0; y2 = b2'*X0;
y1_min = min(y1); y1_max = max(y1);
y1_span = y1_max - y1_min;
y2_min = min(y2); y2_max = max(y2);
y2_span = y2_max - y2_min;
pad = 0.2;
y1_min = y1_min - pad*y1_span;
y1_max = y1_max + pad*y1_span;
y2_min = y2_min - pad*y2_span;
y2_max = y2_max + pad*y2_span;
[y1_m,y2_m] = meshgrid(linspace(y1_min,y1_max,5), linspace(y2_min,y2_max,5));
grid = bsxfun(#plus, bsxfun(#times,y1_m(:)',b1) + bsxfun(#times,y2_m(:)',b2), mean(X,2));
x = reshape(grid(1,:),size(y1_m));
y = reshape(grid(2,:),size(y1_m));
z = reshape(grid(3,:),size(y1_m));
figure(1); clf(1);
surf(x,y,z,'FaceColor','black','FaceAlpha',0.3,'EdgeAlpha',0.6);
hold on;
plot3(X(1,:),X(2,:),X(3,:),' .');
axis equal;
axis vis3d;
Edit2: When I say "principal component" I'm being a bit sloppy (or just plain wrong) with the wording. I'm actually referring to the orthogonal basis vectors that the principal components are expressed in.

Here's a simpler solution, that just uses MATLAB's \ operator. We start with defining a plane in k dimensions:
% 0 = a + x(1) * b(1) + x(2) * b(2) + ... + x(k) * 1
k = 8;
a = randn(1);
b = randn(k-1,1);
(note that we assume b(k)=1, you can always multiply the plane parameters by any value without changing the plane).
Next we generate N random points within this plane:
N = 1000;
x = rand(N,k-1);
x(:,k) = -(a + x * b);
...sorry, it's not the best way to generate random points on the plane, but it's good enough for the demonstration here. Add noise to the points:
x = x + 0.05*randn(size(x));
To find the parameters of the plane, we solve the system of equations
% a + x(1:k-1) * b == -x(k)
in the least-squares sense. a and b are the unknowns there. We can rewrite the left-hand side as [1,x(1:k-1)] * [a;b]. If we have a matrix equation M*p=v we can solve for p by writing p=M\v:
p = [ones(N,1),x(:,1:k-1)]\(-x(:,k));
disp(['ground truth: [a,b,1] = ',mat2str([a,b',1],3)]);
disp(['estimated : [a,b,1] = ',mat2str([p',1],3)]);
This gives as output:
ground truth: [a,b,1] = [-1.35 -1.44 -1.48 1.17 0.226 -0.214 0.234 -1.59 1]
estimated : [a,b,1] = [-1.41 -1.38 -1.43 1.14 0.219 -0.195 0.221 -1.54 1]
The less noise or the more points in the dataset, the smaller the error will be of course!

Related

Finding the values of a scalar function on a 3D grid which correspond to the direction of slowest increase

I have some scalar function F(x,y,z) defined on a grid in 3D space, and there is a minimum of F somewhere in the array. Example code to generate such a function, and locate the coordinates of the minimum, is given below:
x = linspace(-10,80,100);
y = linspace(-20,5,100);
z = linspace(-10,10,100);
[X,Y,Z] = meshgrid(x,y,z);
F = some_scalar_function(X, Y, Z);
% Find the minimum of the function on the grid
[minval,ind] = min(F(:));
[ii,jj,kk] = ind2sub(size(F),ind);
xmin = x(jj);
ymin = y(ii);
zmin = z(kk);
figure;isosurface(X,Y,Z,F,minval+100)
% Some sample scalar function (assume it is given on the grid, and the analytic form not known)
function F = some_scalar_function(X, Y, Z)
F = (X-6).^2 + 10*(Y+2).^2 + 10*Z.^2 + 5*X.*Y;
end
I would like to obtain a vector of F values from the grid along some new direction (let's call it r) which corresponds to the direction of slowest increase of the function F, i.e starting from the minimum and "walking" outwards. I would also like to obtain the corresponding values of the coordinate r as well. I have tried to explain what I mean in the figure below:
Taking a path along any direction other than r should lead to a steeper increase in F, and is therefore not the correct route. Can anyone show how this can be done in Matlab? Thanks!
EDIT
After the comments from rahnema1 and Ander Biguri, I have run the command
[Gmag,Gazimuth,Gelevation] = imgradient3(F);
Taking a look at a plane through z=0, the function F(x,y,z=0) itself looks like the following:
and the outputs from imgradient3() look like this (again, only a single plane from the resulting full 3D arrays):
How can I obtain the line cut corresponding to path of slowest increase as a function of r from these? (still bearing in mind they are 3D arrays, and the direction is not necessarily constrained to the z=0 plane).
Consider a sphere that its center is the position of the minimum point of F.
For each point on the surface of the sphere compute the shortest path to the center point. use imerode to find the surface of the sphere and use shortestpathtree to compute the tree of shortest paths.
Gradient magnitude is set as the difficulty of path traversal. Use imgradient3 to calculate the gradient magnitude.
The path between the surface point with the minimum distance to the center , path1, is considered the direction of slowest increase of the function F.
But path1 is the half of the path. Other half ,path2, is computed by eliminating the sub-tree that contains the first surface point and again computing the shortest path tree using the resulting graph. The function im2col3 is defined for converting the 3D array to graph data structure.
Here is the non tested code:
% im2col for 3D image
function col = im2col3 (im)
col = zeros(prod(size(im)-2), 26);
n = 1;
for kk = 1:3
for jj = 1:3
for ii = 1:3
if ~(ii == 2 && jj == 2 && kk == 2)
col(:, n) = reshape(im(ii:end-(3-ii), jj:end-(3-jj), kk:end-(3-kk)),[],1);
n = n + 1;
end
end
end
end
end
% gradient magnitude
[Gmag,~,~] = imgradient3(F);
% convert array to graph
idx = reshape(1:numel(F), size(F));
t = im2col3(idx);
w = Gmag(t);
s = repmat(reshape(idx(2:end-1,2:end-1,2:end-1),[],1), size(t, 2));
G = graph(s, t, w);
% form the sphere
[~, sphere_center] = min(F(:));
[r, c, z] = ind2sub(size(F), sphere_center);
sphere_radius_2 = min([r c z]) ^ 2;
sphere_logical = ((1:size(F, 1)).'- r) .^ 2 ...
+ ((1:size(F, 2))- c) .^ 2 ...
+ (reshape(1:size(F, 3), 1, 1, [])- z) .^ 2 ...
< sphere_radius_2;
se = strel('cube',3);
sphere_surface = xor(imerode(sphere_logical, se), sphere_logical);
sphere_nodes = idx(sphere_surface);
% compute the half of the path
[T, D] = shortestpathtree(G, sphere_center, sphere_nodes,'OutputForm','cell');
[mn1, im1] = min(D);
path1 = T{im1};
% eliminate the sub-tree
subtree_root = path1(2);
subtree_nodes = bfsearch(T, subtree_root);
G1 = rmnodes (G, subtree_nodes);
sphere_nodes = setdiff (sphere_nodes, subtree_nodes);
% computing other half
[T1, D1] = shortestpathtree(G1, sphere_center, sphere_nodes,'OutputForm','cell');
[mn2, im2] = min(D1);
path2 = T1{im2};

eigenvalue decomposition of structure tensor in matlab

I have a synthetic image. I want to do eigenvalue decomposition of local structure tensor (LST) of it for some edge detection purposes. I used the eigenvaluesl1 , l2 and eigenvectors e1 ,e2 of LST to generate an adaptive ellipse for each pixel of image. Unfortunately I get unequal eigenvalues l1 , l2 and so unequal semi-axes length of ellipse for homogeneous regions of my figure:
However I get good response for a simple test image:
I don't know what is wrong in my code:
function [H,e1,e2,l1,l2] = LST_eig(I,sigma1,rw)
% LST_eig - compute the structure tensor and its eigen
% value decomposition
%
% H = LST_eig(I,sigma1,rw);
%
% sigma1 is pre smoothing width (in pixels).
% rw is filter bandwidth radius for tensor smoothing (in pixels).
%
n = size(I,1);
m = size(I,2);
if nargin<2
sigma1 = 0.5;
end
if nargin<3
rw = 0.001;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% pre smoothing
J = imgaussfilt(I,sigma1);
% compute gradient using Sobel operator
Sch = [-3 0 3;-10 0 10;-3 0 3];
%h = fspecial('sobel');
gx = imfilter(J,Sch,'replicate');
gy = imfilter(J,Sch','replicate');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% compute tensors
gx2 = gx.^2;
gy2 = gy.^2;
gxy = gx.*gy;
% smooth
gx2_sm = imgaussfilt(gx2,rw); %rw/sqrt(2*log(2))
gy2_sm = imgaussfilt(gy2,rw);
gxy_sm = imgaussfilt(gxy,rw);
H = zeros(n,m,2,2);
H(:,:,1,1) = gx2_sm;
H(:,:,2,2) = gy2_sm;
H(:,:,1,2) = gxy_sm;
H(:,:,2,1) = gxy_sm;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% eigen decomposition
l1 = zeros(n,m);
l2 = zeros(n,m);
e1 = zeros(n,m,2);
e2 = zeros(n,m,2);
for i = 1:n
for j = 1:m
Hmat = zeros(2);
Hmat(:,:) = H(i,j,:,:);
[V,D] = eigs(Hmat);
D = abs(D);
l1(i,j) = D(1,1); % eigen values
l2(i,j) = D(2,2);
e1(i,j,:) = V(:,1); % eigen vectors
e2(i,j,:) = V(:,2);
end
end
Any help is appreciated.
This is my ellipse drawing code:
% determining ellipse parameteres from eigen value decomposition of LST
M = input('Enter the maximum allowed semi-major axes length: ');
I = input('Enter the input data: ');
row = size(I,1);
col = size(I,2);
a = zeros(row,col);
b = zeros(row,col);
cos_phi = zeros(row,col);
sin_phi = zeros(row,col);
for m = 1:row
for n = 1:col
a(m,n) = (l2(m,n)+eps)/(l1(m,n)+l2(m,n)+2*eps)*M;
b(m,n) = (l1(m,n)+eps)/(l1(m,n)+l2(m,n)+2*eps)*M;
cos_phi1 = e1(m,n,1);
sin_phi1 = e1(m,n,2);
len = hypot(cos_phi1,sin_phi1);
cos_phi(m,n) = cos_phi1/len;
sin_phi(m,n) = sin_phi1/len;
end
end
%% plot elliptic structuring elements using parametric equation and superimpose on the image
figure; imagesc(I); colorbar; hold on
t = linspace(0,2*pi,50);
for i = 10:10:row-10
for j = 10:10:col-10
x0 = j;
y0 = i;
x = a(i,j)/2*cos(t)*cos_phi(i,j)-b(i,j)/2*sin(t)*sin_phi(i,j)+x0;
y = a(i,j)/2*cos(t)*sin_phi(i,j)+b(i,j)/2*sin(t)*cos_phi(i,j)+y0;
plot(x,y,'r','linewidth',1);
hold on
end
end
This my new result with the Gaussian derivative kernel:
This is the new plot with axis equal:
I created a test image similar to yours (probably less complicated) as follows:
pos = yy([400,500]) + 100 * sin(xx(400)/400*2*pi);
img = gaussianlineclip(pos+50,7) + gaussianlineclip(pos-50,7);
I = double(stretch(img));
(This requires DIPimage to run)
Then ran your LST_eig on it (sigma1=1 and rw=3) and your code to draw ellipses (no change to either, except adding axis equal), and got this result:
I suspect some non-uniformity in some of the blue areas of your image, which cause very small gradients to appear. The problem with the definition of the ellipses as you use them is that, for sufficiently oriented patterns, you'll get a line even if that pattern is imperceptible. You can get around this by defining your ellipse axes lengths as follows:
a = repmat(M,size(l2)); % longest axis is always the same
b = M ./ (l2+1); % shortest axis is shorter the more important the largest eigenvalue is
The smallest eigenvalue l1 is high in regions with strong gradients but no clear direction. The above does not take this into account. One option could be to make a depend on both energy and anisotropy measures, and b depend only on energy:
T = 1000; % some threshold
r = M ./ max(l1+l2-T,1); % circle radius, smaller for higher energy
d = (l2-l1) ./ (l1+l2+eps); % anisotropy measure in range [0,1]
a = M*d + r.*(1-d); % use `M` length for high anisotropy, use `r` length for high isotropy (circle)
b = r; % use `r` width always
This way, the whole ellipse shrinks if there are strong gradients but no clear direction, whereas it stays large and circular when there are only weak or no gradients. The threshold T depends on image intensities, adjust as needed.
You should probably also consider taking the square root of the eigenvalues, as they correspond to the variance.
Some suggestions:
You can write
a = (l2+eps)./(l1+l2+2*eps) * M;
b = (l1+eps)./(l1+l2+2*eps) * M;
cos_phi = e1(:,:,1);
sin_phi = e1(:,:,2);
without a loop. Note that e1 is normalized by definition, there is no need to normalize it again.
Use Gaussian gradients instead of Gaussian smoothing followed by Sobel or Schaar filters. See here for some MATLAB implementation details.
Use eig, not eigs, when you need all eigenvalues. Especially for such a small matrix, there is no advantage to using eigs. eig seems to produce more consistent results. There is no need to take the absolute value of the eigenvalues (D = abs(D)), as they are non-negative by definition.
Your default value of rw = 0.001 is way too small, a sigma of that size has no effect on the image. The goal of this smoothing is to average gradients in a local neighborhood. I used rw=3 with good results.
Use DIPimage. There is a structuretensor function, Gaussian gradients, and a lot more useful stuff. The 3.0 version (still in development) is a major rewrite that improves significantly on dealing with vector- and matrix-valued images. I can write all of your LST_eig as follows:
I = dip_image(I);
g = gradient(I, sigma1);
H = gaussf(g*g.', rw);
[e,l] = eig(H);
% Equivalences with your outputs:
l1 = l{2};
l2 = l{1};
e1 = e{2,:};
e2 = e{1,:};

How do I plot linear decision boundary in matlab

plotted two different dataset
I have 2 different dataset that have different mu and sigma, and X vector such as [1.8; 1.8]. And also I know probability of each classes that P(ω1)= P(ω2) = 1/2
I want to ploting linear decision boundary between these two dataset but I don't have any idea have to do. My code is down below, here
X = [1.8; 1.8];
u1 = [1;1]; u2 = [3;3];
s1 = [1 0;0 1]; s2 = [1 0;0 1];
Pr1 = 1/2;
Pr2 = 1/2;
r = mvnrnd(u1,s1,500);
plot(r(:,1), r(:,2), '+r');
hold on
r = mvnrnd(u2,s2,500);
plot(r(:,1), r(:,2), '+b');
hold on
grid on
W1 = (u1')/(s1(1,1))^2;
W10 = (u1'*u1)/(-2*s1(1,1)) + log(Pr1);
g1 = W1'.*X + W10;
W2 = (u2')/(s2(1,1))^2;
W20 = (u2'*u2)/(-2*s2(1,1)) + log(Pr2);
g2 = W2'.*X + W20;
Is there someone who can give any idea to me please?
The trick is to calculate two points of the decision boundary you want to plot.
W1_W2 = W2 - W1; % vector from W1 to W2
W1_W2_average = (W2 + W1)/2; % point in the middle between W1 and W2
W1_W2_orthogonal = [-W1_W2(2) W1_W2(1)]; % vector orthogonal to W1_W2
points = [W1_W2_average - 2*W1_W2_orthogonal; W1_W2_average + 2*W1_W2_orthogonal]; % Two points on the line you want to plot
plot(points(:, 1), points(:, 2)); %plot the line
Note that I am not very familiar with classification problems. I might have forgotten some terms in the calculation of the decision boundary.
I solved decision problem, in detailed
First I defined parametric function with parameters x1 and x2 such as
g = #(x1,x2)
then in order to plotting decision boundary realized that g1-g2 = 0 equation such as
e = #(x1,x2) (W1*[x1;x2] + w10 - W2*[x1;x2] - w20)
ezplot(g, [-xlim xlim -ylim ylim])
and done

Equally spaced points in a contour

I have a set of 2D points (not ordered) forming a closed contour, and I would like to resample them to 14 equally spaced points. It is a contour of a kidney on an image. Any ideas?
One intuitive approach (IMO) is to create an independent variable for both x and y. Base it on arc length, and interpolate on it.
% close the contour, temporarily
xc = [x(:); x(1)];
yc = [y(:); y(1)];
% current spacing may not be equally spaced
dx = diff(xc);
dy = diff(yc);
% distances between consecutive coordiates
dS = sqrt(dx.^2+dy.^2);
dS = [0; dS]; % including start point
% arc length, going along (around) snake
d = cumsum(dS); % here is your independent variable
perim = d(end);
Now you have an independent variable and you can interpolate to create N segments:
N = 14;
ds = perim / N;
dSi = ds*(0:N).'; %' your NEW independent variable, equally spaced
dSi(end) = dSi(end)-.005; % appease interp1
xi = interp1(d,xc,dSi);
yi = interp1(d,yc,dSi);
xi(end)=[]; yi(end)=[];
Try it using imfreehand:
figure, imshow('cameraman.tif');
h = imfreehand(gca);
xy = h.getPosition; x = xy(:,1); y = xy(:,2);
% run the above solution ...
Say your contour is defined by independent vector x and dependent vector y.
You can get your resampled x vector using linspace:
new_x = linspace(min(x),max(x),14); %14 to get 14 equally spaced points
Then use interp1 to get new_y values at each new_x point:
new_y = interp1(x,y,new_x);
There are a few interpolation methods to choose from - default is linear. See interp1 help for more info.

Creating a matrix containing a filled ellipse based on a non-contiguous outline

I'm trying to create a matrix of 0 values, with 1 values filling a ellipse shape. My ellipse was generated using minVolEllipse.m (Link 1) which returns a matrix of the ellipse equation in the 'center form' and the center of the ellipse. I then use a snippet of code from Ellipse_plot.m (from the aforementioned link) to parameterize the vector into major/minor axes, generate a parametric equation, and generate a matrix of transformed coordinates. You can see their code to see how this is done. The result is a matrix that has index locations for points along the ellipse. It does not encompass every value along the outline of the ellipse unless I set the number of grid points, N, to a ridiculously high value.
When I use the MATLAB plot or patch commands I see exactly the result I'm looking for. However, I want this represented as a matrix of 0 values with 1s where patch 'fills in' the blanks. It is apparent that MATLAB has this functionality, but I have yet to find the code to execute it. What I am looking for is similar to how bwfill of the image processing toolbox works (Link 2). bwfill does not work for me because my ellipse is not contiguous, so the function returns a matrix filled completely with 1 values.
Hopefully I have outlined the problem well enough, if not please comment and I can edit the post to clarify.
EDIT:
I have devised a strategy using the 2-D X vector from Ellipse_plot.m as an input to EllipseDirectFit.m (Link 3). This function returns the coefficients for the ellipse function ax^2+bxy+cy^2+dx+dy+f=0. Using these coefficients I calculate the angle between the x-axis and the major axis of the ellipse. This angle, along with the center and major/minor axes are passed into ellipseMatrix.m (Link 4), which returns a filled matrix. Unfortunately, the matrix appears to be out of rotation from what I want. Here is the portion of my code:
N = 20; %Number of grid points in ellipse
ellipsepoints = clusterpoints(clusterpoints(:,1)==i,2:3)';
[A,C] = minVolEllipse(ellipsepoints,0.001,N);
%%%%%%%%%%%%%%
%
%Adapted from:
% Ellipse_plot.m
% Nima Moshtagh
% nima#seas.upenn.edu
% University of Pennsylvania
% Feb 1, 2007
% Updated: Feb 3, 2007
%%%%%%%%%%%%%%
%
%
% "singular value decomposition" to extract the orientation and the
% axes of the ellipsoid
%------------------------------------
[U D V] = svd(A);
%
% get the major and minor axes
%------------------------------------
a = 1/sqrt(D(1,1))
b = 1/sqrt(D(2,2))
%theta values
theta = [0:1/N:2*pi+1/N];
%
% Parametric equation of the ellipse
%----------------------------------------
state(1,:) = a*cos(theta);
state(2,:) = b*sin(theta);
%
% Coordinate transform
%----------------------------------------
X = V * state;
X(1,:) = X(1,:) + C(1);
X(2,:) = X(2,:) + C(2);
% Output: Elip_Eq = [a b c d e f]' is the vector of algebraic
% parameters of the fitting ellipse:
Elip_Eq = EllipseDirectFit(X')
% http://mathworld.wolfram.com/Ellipse.html gives the equation for finding the angle theta (teta).
% The coefficients from EllipseDirectFit are rescaled to match what is expected in the wolfram link.
Elip_Eq(2) = Elip_Eq(2)/2;
Elip_Eq(4) = Elip_Eq(4)/2;
Elip_Eq(5) = Elip_Eq(5)/2;
if Elip_Eq(2)==0
if Elip_Eq(1) < Elip_Eq(3)
teta = 0;
else
teta = (1/2)*pi;
endif
else
tetap = (1/2)*acot((Elip_Eq(1)-Elip_Eq(3))/(Elip_Eq(2)));
if Elip_Eq(1) < Elip_Eq(3)
teta = tetap;
else
teta = (pi/2)+tetap;
endif
endif
blank_mask = zeros([height width]);
if teta < 0
teta = pi+teta;
endif
%I may need to switch a and b, depending on which is larger (so that the fist is the major axis)
filled_mask1 = ellipseMatrix(C(2),C(1),b,a,teta,blank_mask,1);
EDIT 2:
As a response to the suggestion from #BenVoigt, I have written a for-loop solution to the problem, here:
N = 20; %Number of grid points in ellipse
ellipsepoints = clusterpoints(clusterpoints(:,1)==i,2:3)';
[A,C] = minVolEllipse(ellipsepoints,0.001,N);
filled_mask = zeros([height width]);
for y=0:1:height
for x=0:1:width
point = ([x;y]-C)'*A*([x;y]-C);
if point < 1
filled_mask(y,x) = 1;
endif
endfor
endfor
Although this is technically a solution to the problem, I am interested in a non-iterative solution. I'm running this script over many large images, and need it to be very fast and parallel.
EDIT 3:
Thanks #mathematical.coffee for this solution:
[X,Y] = meshgrid(0:width,0:height);
fill_mask=arrayfun(#(x,y) ([x;y]-C)'*A*([x;y]-C),X,Y) < 1;
However, I believe there is yet a better way to do this. Here is a for-loop implementation that I did that runs faster than both above attempts:
ellip_mask = zeros([height width]);
[U D V] = svd(A);
a = 1/sqrt(D(1,1));
b = 1/sqrt(D(2,2));
maxab = ceil(max(a,b));
xstart = round(max(C(1)-maxab,1));
xend = round(min(C(1)+maxab,width));
ystart = round(max(C(2)-maxab,1));
yend = round(min(C(2)+maxab,height));
for y = ystart:1:yend
for x = xstart:1:xend
point = ([x;y]-C)'*A*([x;y]-C);
if point < 1
ellip_mask(y,x) = 1;
endif
endfor
endfor
Is there a way to accomplish this goal (the total image size is still [width height]) without this for-loop? The reason this is faster is because I don't have to iterate over the entire image to determine if my point is within the ellipse. Instead, I can simply iterate over a square region that is the length of the center +/- the largest principle axis.
Expanding the matrix multiply, which is an elliptic norm, gives a fairly simply vectorized expression:
[X,Y] = meshgrid(0:width,0:height);
X = X - C(1);
Y = Y - C(2);
fill_mask = X.^2 * A(1,1) + X.*Y * (A(1,2) + A(2,1)) + Y.^2 * A(2,2) < 1;
This is what I intended by my original comment.