Skip to content
Snippets Groups Projects
EllipsoidFit.py 1.25 KiB
Newer Older
  • Learn to ignore specific revisions
  • import numpy as np
    
    def ellipsoidFit(X, dtype=np.float32):
    
        X = np.array(X)
        N = X.shape[0]
    
        mu = np.mean(X, axis=0)
    
        for i in range(N):
            X[i,:] = X[i,:] - mu
    
        if N < 9:
            raise ValueError('Need at least 9 points to fit an ellipsoid')
    
        x = X[:,0]
        y = X[:,1]
        z = X[:,2]
    
        A = np.empty((N,9), dtype=dtype)
    
        A[:,0] = x**2 + y**2 - 2*z*z
        A[:,1] = x**2 + z**2 - 2*y*y
        A[:,2] = 2*x*y
        A[:,3] = 2*x*z
        A[:,4] = 2*y*z
        A[:,5] = 2*x
        A[:,6] = 2*y
        A[:,7] = 2*z
        A[:,8] = 1
    
        b = x**2 + y**2 + z**2
    
        u = np.linalg.solve(np.matmul(A.T, A), np.matmul(A.T, b))
    
        v = np.zeros(10)
    
        v[0] = u[0] + u[1] - 1
        v[1] = u[0] - 2*u[1] - 1
        v[2] = u[1] - 2*u[0] - 1
        v[3] = u[2]
        v[4] = u[3]
        v[5] = u[4]
        v[6] = u[5]
        v[7] = u[6]
        v[8] = u[7]
        v[9] = u[8]
    
        B = np.empty((4,4), dtype=dtype);
        B = np.array([[v[0], v[3], v[4], v[6]],
                      [v[3], v[1], v[5], v[7]],
                      [v[4], v[5], v[2], v[8]],
                      [v[6], v[7], v[8], v[9]]])
    
        center = np.linalg.solve(-B[:3,:3], B[:3,3])
    
        center = center + mu
    
        evals, evecs = np.linalg.eig(B[:3,:3]*(1./v[9]))
    
        radii = np.sqrt(1./ abs(evals))
    
        return v[:6]*(1./v[9]), radii, center