I\'m looking to fit a plane to a set of ~ 6-10k 3D points. I\'m looking to do this as fast as possible, and accuracy is not the highest concern (frankly the plane can be off
In computer vision a standard way is to use RANSAC or MSAC, in your case;
http://en.wikipedia.org/wiki/RANSAC
It looks like griddata might be what you want. The link has an example in it.
If this doesn't work, maybe check out gridfit on the MATLAB File Exchange. It's made to match a more general case than griddata
.
You probably don't want to be rolling your own surface fitting, as there's several well-documented tools out there.
Take the example from griddata
:
x = % some values
y = % some values
z = % function values to fit to
ti = % this range should probably be greater than or equal to your x,y test values
[xq,yq] = meshgrid(ti,ti);
zq = griddata(x,y,z,xq,yq,'linear'); % NOTE: linear will fit to a plane!
Plot the gridded data along with the scattered data.
mesh(xq,yq,zq), hold
plot3(x,y,z,'o'), hold off
You may try the consolidator by John D'Errico. It aggregates the points within a given tolerance, this will allow to reduce the amount of data and increase the speed. You can also check John's gridfit function which is usually faster and more flexible than griddata
Use the standard plane equation Ax + By + Cz + D = 0
, and write the equation as a matrix multiplication. P
is your unknown 4x1 [A;B;C;D]
g = [x y z 1]; % represent a point as an augmented row vector
g*P = 0; % this point is on the plane
Now expand this to all your actual points, an Nx4 matrix G
. The result is no longer exactly 0, it's the error you're trying to minimize.
G*P = E; % E is a Nx1 vector
So what you want is the closest vector to the null-space of G, which can be found from the SVD. Let's test:
% Generate some test data
A = 2;
B = 3;
C = 2.5;
D = -1;
G = 10*rand(100, 2); % x and y test points
% compute z from plane, add noise (zero-mean!)
G(:,3) = -(A*G(:,1) + B*G(:,2) + D) / C + 0.1*randn(100,1);
G(:,4) = ones(100,1); % augment your matrix
[u s v] = svd(G, 0);
P = v(:,4); % Last column is your plane equation
OK, remember that P can vary by a scalar. So just to show that we match:
scalar = 2*P./P(1);
P./scalar
ans = 2.0000 3.0038 2.5037 -0.9997