data fitting an ellipse in 3D space

倾然丶 夕夏残阳落幕 提交于 2019-12-02 05:24:55

This answer is not a direct fit in 3D, it instead involves first a rotation of the data so that the plane of the points coincides with the xy plane, then a fit to the data in 2D.

% input: data, a N x 3 array with one set of Cartesian coords per row

% remove the center of mass
CM = mean(data);
datap = data - ones(size(data,1),1)*CM;


% now rotate all points into the xy plane ...
% start by finding the plane:

[u s v]=svd(datap);

% rotate the data into the principal axes frame:

datap = datap*v;


% fit the equation for an ellipse to the rotated points

x= [0.25 0.07 0.037 0 0]'; % initial parameters    
options=1;
xopt = fmins(@fellipse,x,options,[],datap) % set the distance minimum as the target function

This is the function fellipse, based on the function provided:

function [merit]= fellipse(x,data) % x is the initial parameters, data stores the datapoints

a = x(1);
b = x(2);
alpha = x(3);    
z = x(4:5);

R = [cos(alpha), sin(alpha), 0; -sin(alpha), cos(alpha), 0; 0, 0, 1];
data = data*R; 

merit = 0;

[dim1, dim2]=size(data);
for i=1:dim1
    dist=@(phi)sum( ( [a*cos(phi);b*sin(phi)] + z - data(i,1:2)').^2 ); 
    phi=fminbnd(dist,0,2*pi);
    merit = merit+dist(phi);
end

end

Also, note again that this can be turned into a fit directly in 3D, but this answer is just as good if you can assume the data points lie approx. in a 2D plane. The current solution is likely much more efficient then a solution in 3D with additional parameters.

Hopefully the code is self-explanatory. I recommend looking at the link included in the OP, it explains the purpose of the loop over phi.

And this is how you can inspect the result of the fit:

a = xopt(1);
b = xopt(2);
alpha = xopt(3);
z = [xopt(4:5) ; 0]';

phi = linspace(0,2*pi,100)';
simdat = [a*cos(phi) b*sin(phi) zeros(size(phi))];
R = [cos(alpha), -sin(alpha), 0; sin(alpha), cos(alpha), 0; 0, 0, 1];
simdat = simdat*R  + ones(size(simdat,1), 1)*z ; 


figure, hold on
plot3(datap(:,1),datap(:,2),datap(:,3),'o')
plot3(simdat(:,1),simdat(:,2),zeros(size(simdat,1),1),'r-')

Edit

The following is a 3D approach. It does not appear to be very robust as it is quite sensitive to the choice of starting parameters. Some improvements may be necessary.

CM = mean(data);
datap = data - ones(size(data,1),1)*CM;
xopt = [  0.07 0.25 1 -0.408976 0.610120 0 0  0]';
options=1;
xopt = fmins(@fellipse3d,xopt,options,[],datap) % set the distance minimum as the target function

The function fellipse3d is

function [merit]= fellipse3d(x,data) % x is the initial parameters, data stores the datapoints

a = abs(x(1));
b = abs(x(2));
alpha = x(3);
beta = x(4);
gamma = x(5);
z = x(6:8)';

[dim1, dim2]=size(data);

R1 = [cos(alpha), sin(alpha), 0; -sin(alpha), cos(alpha), 0; 0, 0, 1];
R2 = [1, 0, 0; 0, cos(beta), sin(beta); 0, -sin(beta), cos(beta)];
R3 = [cos(gamma), sin(gamma), 0; -sin(gamma), cos(gamma), 0; 0, 0, 1];
R = R3*R2*R1;

data = (data - z(ones(dim1,1),:))*R; 

merit = 0;
for i=1:dim1
    dist=@(phi)sum( ([a*cos(phi);b*sin(phi);0]  - data(i,:)').^2 ); 
    phi=fminbnd(dist,0,2*pi);
    merit = merit+dist(phi);
end
end

You can visualize the results with

a = xopt(1);
b = xopt(2);
alpha = -xopt(3);
beta = -xopt(4);
gamma = -xopt(5);
z = xopt(6:8)' + CM;

dim1 = 100;
phi = linspace(0,2*pi,dim1)';

simdat = [a*cos(phi) b*sin(phi) zeros(size(phi))];

R1 = [cos(alpha), sin(alpha), 0; ...
     -sin(alpha), cos(alpha), 0; ... 
        0, 0, 1];

R2 = [1, 0, 0;  ...
      0, cos(beta), sin(beta);  ...
      0, -sin(beta), cos(beta)];

R3 = [cos(gamma), sin(gamma), 0;  ...
      -sin(gamma), cos(gamma), 0;  ...
           0, 0, 1];

R = R1*R2*R3;

simdat = simdat*R + z(ones(dim1,1),:); 

figure, hold on
plot3(data(:,1),data(:,2),data(:,3),'o')
plot3(simdat(:,1),simdat(:,2),simdat(:,3),'r-')
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!