diff --git a/src/fit_ellipse_2d.m b/src/fit_ellipse_2d.m
new file mode 100644
index 0000000000000000000000000000000000000000..26575d6b61e435f7427a7ad7373eaa994a6dbf28
--- /dev/null
+++ b/src/fit_ellipse_2d.m
@@ -0,0 +1,150 @@
+function [ f, Q ] = fit_ellipse_2d( p, method )
+%FIT_ELLIPSE Fit a 2D ellipse to 2D points.
+
+    if nargin < 2
+        method = 'direct';
+    end
+
+    switch( lower( method ) )
+       
+        case 'direct'
+            Q = direct_ellipse_fit( p( :, 1:2 ) );
+        case 'taubin'
+            Q = taubin_ellipse_fit( p( :, 1:2 ) );    
+    end
+    
+    f = quadratic_to_cartesian2( Q );
+    
+    %% Subfunctions
+    
+    function f = quadratic_to_cartesian2( Q )
+    %% Convert to cartesian coordnates for the ellipse.
+    % Return [ x0 y0 a b theta ].
+    % We always have a > b.    
+    % theta in radians measure the angle of the ellipse long axis with the
+    % x axis, in radians, and positive means counter-clockwise.
+    
+    % Formulas from 
+    % https://en.wikipedia.org/wiki/Ellipse#In_Cartesian_coordinates
+    
+        A = Q(1);
+        B = Q(2);
+        C = Q(3);
+        D = Q(4);
+        E = Q(5);
+        F = Q(6);
+        
+        term1 = 2 * ( A * E * E  ...
+            + C * D * D ...
+            - B * D * E ...
+            + ( B * B - 4 * A * C ) * F );
+        term2 = ( A + C );
+        term3 = sqrt( ( A - C ) * ( A - C ) + B * B );
+        term4 = B * B - 4 * A * C;
+        
+        a = - sqrt( term1 * ( term2 + term3 ) ) / term4 ;
+        b = - sqrt( term1 * ( term2 - term3 ) ) / term4 ;
+        
+        x0 = ( 2 * C * D - B * E ) / term4;
+        y0 = ( 2 * A * E - B * D ) / term4;
+        
+        if B ~= 0            
+            theta = atan( 1/B * ( C - A - term3 ) );            
+        elseif A < 0
+            theta = 0;
+        else
+            theta = pi/2;
+        end
+        
+        if b > a
+            btemp = b;
+            b = a;
+            a = btemp;
+            theta = theta + pi/2;
+            if theta > pi
+                theta = theta - pi;
+            end
+        end
+        
+        f = [ x0 y0 a b theta ];
+    end
+    
+    function Q = direct_ellipse_fit(P) 
+    %  Direct ellipse fit, proposed in article
+    %    A. W. Fitzgibbon, M. Pilu, R. B. Fisher
+    %     "Direct Least Squares Fitting of Ellipses"
+    %     IEEE Trans. PAMI, Vol. 21, pages 476-480 (1999)
+    %
+    % Adapted from 
+    % https://fr.mathworks.com/matlabcentral/fileexchange/22684-ellipse-fit-direct-method
+
+        centroid = mean( P );   % the centroid of the data set
+        D1 = [(P(:,1)-centroid(1)).^2, (P(:,1)-centroid(1)).*(P(:,2)-centroid(2)),...
+            (P(:,2)-centroid(2)).^2];
+        D2 = [P(:,1)-centroid(1), P(:,2)-centroid(2), ones(size(P,1),1)];
+        S1 = D1'*D1;
+        S2 = D1'*D2;
+        S3 = D2'*D2;
+        T = -inv(S3)*S2';
+        M = S1 + S2*T;
+        M = [M(3,:)./2; -M(2,:); M(1,:)./2];
+        [evec,eval] = eig(M); %#ok<ASGLU>
+        cond = 4*evec(1,:).*evec(3,:)-evec(2,:).^2;
+        A1 = evec(:,find(cond>0)); %#ok<FNDSB>
+        Q = [A1; T*A1];
+        A4 = Q(4)-2*Q(1)*centroid(1)-Q(2)*centroid(2);
+        A5 = Q(5)-2*Q(3)*centroid(2)-Q(2)*centroid(1);
+        A6 = Q(6)+Q(1)*centroid(1)^2+Q(3)*centroid(2)^2+...
+            Q(2)*centroid(1)*centroid(2)-Q(4)*centroid(1)-Q(5)*centroid(2);
+        Q(4) = A4;  Q(5) = A5;  Q(6) = A6;
+        Q = Q/norm(Q);
+    end
+
+    function Q = taubin_ellipse_fit( P )
+    %   Ellipse fit by Taubin's Method published in
+    %      G. Taubin, "Estimation Of Planar Curves, Surfaces And Nonplanar
+    %                  Space Curves Defined By Implicit Equations, With
+    %                  Applications To Edge And Range Image Segmentation",
+    %      IEEE Trans. PAMI, Vol. 13, pages 1115-1138, (1991)
+    %
+    %     Input:  XY(n,2) is the array of coordinates of n points x(i)=XY(i,1), y(i)=XY(i,2)
+    %
+    %     Output: Q = [a b c d e f]' is the vector of algebraic
+    %             parameters of the fitting ellipse:
+    %             ax^2 + bxy + cy^2 +dx + ey + f = 0
+    %             the vector Q is normed, so that ||A||=1
+    %
+    %     Among fast non-iterative ellipse fitting methods,
+    %     this is perhaps the most accurate and robust
+    %
+    %     Note: this method fits a quadratic curve (conic) to a set of points;
+    %     if points are better approximated by a hyperbola, this fit will
+    %     return a hyperbola. To fit ellipses only, use "Direct Ellipse Fit".
+
+        centroid = mean(P);   % the centroid of the data set
+        Z = [(P(:,1)-centroid(1)).^2, (P(:,1)-centroid(1)).*(P(:,2)-centroid(2)),...
+            (P(:,2)-centroid(2)).^2, P(:,1)-centroid(1), P(:,2)-centroid(2), ones(size(P,1),1)];
+        M = Z'*Z/size(P,1);
+        P = [M(1,1)-M(1,6)^2, M(1,2)-M(1,6)*M(2,6), M(1,3)-M(1,6)*M(3,6), M(1,4), M(1,5);
+            M(1,2)-M(1,6)*M(2,6), M(2,2)-M(2,6)^2, M(2,3)-M(2,6)*M(3,6), M(2,4), M(2,5);
+            M(1,3)-M(1,6)*M(3,6), M(2,3)-M(2,6)*M(3,6), M(3,3)-M(3,6)^2, M(3,4), M(3,5);
+            M(1,4), M(2,4), M(3,4), M(4,4), M(4,5);
+            M(1,5), M(2,5), M(3,5), M(4,5), M(5,5)];
+        Q = [4*M(1,6), 2*M(2,6), 0, 0, 0;
+            2*M(2,6), M(1,6)+M(3,6), 2*M(2,6), 0, 0;
+            0, 2*M(2,6), 4*M(3,6), 0, 0;
+            0, 0, 0, 1, 0;
+            0, 0, 0, 0, 1];
+        [V,D] = eig(P,Q);
+        [Dsort,ID] = sort(diag(D)); %#ok<ASGLU>
+        Q = V(:,ID(1));
+        Q = [Q; -Q(1:3)'*M(1:3,6)];
+        A4 = Q(4)-2*Q(1)*centroid(1)-Q(2)*centroid(2);
+        A5 = Q(5)-2*Q(3)*centroid(2)-Q(2)*centroid(1);
+        A6 = Q(6)+Q(1)*centroid(1)^2+Q(3)*centroid(2)^2+...
+            Q(2)*centroid(1)*centroid(2)-Q(4)*centroid(1)-Q(5)*centroid(2);
+        Q(4) = A4;  Q(5) = A5;  Q(6) = A6;
+        Q = Q/norm(Q);
+    end  %  Taubin
+
+end