Giter Club home page Giter Club logo

least-squares-ellipse-fitting's Introduction

DOI bdhammel

Least Squares fitting of ellipses, python routine

based on the publication Halir, R., Flusser, J.: 'Numerically Stable Direct Least Squares Fitting of Ellipses'

Install

pip install lsq-ellipse

https://pypi.org/project/lsq-ellipse/

Example execution

import numpy as np
from ellipse import LsqEllipse
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse

if __name__ == '__main__':
    # avalible in the `example.py` script in this repo
    X1, X2 = example.make_test_ellipse()

    X = np.array(list(zip(X1, X2)))
    reg = LsqEllipse().fit(X)
    center, width, height, phi = reg.as_parameters()

    print(f'center: {center[0]:.3f}, {center[1]:.3f}')
    print(f'width: {width:.3f}')
    print(f'height: {height:.3f}')
    print(f'phi: {phi:.3f}')

    fig = plt.figure(figsize=(6, 6))
    ax = plt.subplot()
    ax.axis('equal')
    ax.plot(X1, X2, 'ro', zorder=1)
    ellipse = Ellipse(
        xy=center, width=2*width, height=2*height, angle=np.rad2deg(phi),
        edgecolor='b', fc='None', lw=2, label='Fit', zorder=2
    )
    ax.add_patch(ellipse)

    plt.xlabel('$X_1$')
    plt.ylabel('$X_2$')

    plt.legend()
    plt.show()

ellipse fit

Cite this work

@software{ben_hammel_2020_3723294,
  author       = {Ben Hammel and Nick Sullivan-Molina},
  title        = {bdhammel/least-squares-ellipse-fitting: v2.0.0},
  month        = mar,
  year         = 2020,
  publisher    = {Zenodo},
  version      = {v2.0.0},
  doi          = {10.5281/zenodo.3723294},
  url          = {https://doi.org/10.5281/zenodo.3723294}
}

Ben Hammel, & Nick Sullivan-Molina. (2020, March 21). bdhammel/least-squares-ellipse-fitting: v2.0.0 (Version v2.0.0). Zenodo. http://doi.org/10.5281/zenodo.3723294

least-squares-ellipse-fitting's People

Contributors

adler-j avatar bdhammel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

least-squares-ellipse-fitting's Issues

Strange result on this test data

import cv2
import poly_point_isect
import numpy as np

points = [{'x': 622, 'y': 339}, {'x': 677, 'y': 337}, {'x': 792, 'y': 331}, {'x': 873, 'y': 317}, {'x': 900, 'y': 309}, {'x': 918, 'y': 300}, {'x': 926, 'y': 289}, {'x': 926, 'y': 283}, {'x': 902, 'y': 270}]
img = np.zeros((800, 1500, 3), np.uint8)
b, g, r = 0x3E, 0x88, 0xE5  # orange
img[:, :, 0] = b
img[:, :, 1] = g
img[:, :, 2] = r
draw_connected_points(img, points)
points = np.array([[p['x'], p['y']] for p in points])
reg = LsqEllipse().fit(points)
center, width, height, phi = reg.as_parameters()
print(center)
cv2.imshow("test", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

The fitted center is (-78086.55916753855, -4782.9191357491145) which is strange for the input points:
ๅ›พ็‰‡

Finding distance between data point and ellipse

Thanks for your code, it is very helpful.
I am trying to find the distance between data points and the ellipse, so that I can estimate the error. Is there an easy way to do that? Thanks in advance!

fitting bug

The error occurs when I call fit_obj.as_parameters if the given data failed to fit an ellipse. Since len(fit_ellipse_P.coefficients) = 0 in this situation. As a user, I could only add a condition outside, But obviously, you guys could add this condition into the built-in code.

AttributeError:

AttributeError: module 'ellipse' has no attribute 'make_test_ellipse'

Fit with fixed center

Great piece of code! Is it by any chance possible to fit using a fixed center for the ellipse?

Code not on PyPI

Thank you for making this code available open source. It is very useful for my work.

Would you be willing to upload it to PyPI? This would be helpful for me because my package currently contains a copy of ellipses.py and I would rather import it.

I can help create the setup.py and MANIFEST.in files if you'd like.

as_parameters() and compliance with Mathworld parameters definition

Hello,
Many thanks for this great software that has been very useful to me.

Upgrading from 2.0.1 to 2.2.1 I noticed that somehow the axis in which the parameters are returned are inverted.
Digging a bit in the code I noticed that now width and height are inverted with respect to the definition of https://mathworld.wolfram.com/Ellipse.html, resulting in an ellipse with major axis aligned with the x-axis to have phi=90deg

Any reason to do that?

I would have thought the one below to be the the implementation complying with the Mathworld documentation.

Many thanks


class myLsqEllipse(LsqEllipse):
def as_parameters(self):
"""Returns the definition of the fitted ellipse as localized parameters

    Returns
    _______
    center : tuple
        (x0, y0)
    width : float
        Total length (diameter) of horizontal axis.
    height : float
        Total length (diameter) of vertical axis.
    phi : float
        The counterclockwise angle [radians] of rotation from the x-axis to the semimajor axis
    """

    # Eigenvectors are the coefficients of an ellipse in general form
    # the division by 2 is required to account for a slight difference in
    # the equations between (*) and (**)
    # a*x^2 +   b*x*y + c*y^2 +   d*x +   e*y + f = 0  (*)  Eqn 1
    # a*x^2 + 2*b*x*y + c*y^2 + 2*d*x + 2*f*y + g = 0  (**) Eqn 15
    # We'll use (**) to follow their documentation
    a = self.coefficients[0]
    b = self.coefficients[1] / 2.
    c = self.coefficients[2]
    d = self.coefficients[3] / 2.
    f = self.coefficients[4] / 2.
    g = self.coefficients[5]

    # Finding center of ellipse [eqn.19 and 20] from (**)
    x0 = (c*d - b*f) / (b**2 - a*c)
    y0 = (a*f - b*d) / (b**2 - a*c)
    center = (x0, y0)

    # Find the semi-axes lengths [eqn. 21 and 22] from (**)
    numerator = 2 * (a*f**2 + c*d**2 + g*b**2 - 2*b*d*f - a*c*g)
    denominator1 = (b**2 - a*c) * ( np.sqrt((a-c)**2+4*b**2) - (c+a))  # noqa: E201
    denominator2 = (b**2 - a*c) * (-np.sqrt((a-c)**2+4*b**2) - (c+a))
    width = np.sqrt(numerator / denominator1)
    height = np.sqrt(numerator / denominator2)

    # Angle of counterclockwise rotation of major-axis of ellipse to x-axis
    # [eqn. 23] from (**)
    # w/ trig identity eqn 9 form (***)
    if b == 0 and a < c:
        phi = 0.0
    elif b == 0 and a > c:
        phi = np.pi/2
    elif b != 0 and a < c:
        phi = 0.5 * np.arctan(2*b/(a-c))
    elif b != 0 and a > c:
        phi = 0.5 * (np.pi + np.arctan(2*b/(a-c)))
    elif a == c:
        phi = 0.0
    else:
        raise RuntimeError("Unreachable")

    return center, width, height, phi

Wrong angle calculation

Hello,

It seems that the angle calculation is not always correct.
I have this case and angle is -0.13946737246282517
This seems the angle from Y axis instead of the X axis
AngleEllipse
EllipseIn.txt

Documentation/ellipse definition sometimes confusing

Hi,

Nice code, very helpful, thanks for making it public!

I was a little confused by one point in the code, but so far as I could spot, it's only a docstring (minor) issue:

  • In ref (*) (paper) the ellipse is defined as a x^2 + b x y + ..., which are the coefficients returned in the corresponding attribute ellipse.LsqEllipse.coefficients.
  • However, the docstring in that attribute ellipse.LsqEllipse.coefficients points to ref (**) (MathWorld), which defines the ellipse with additional factors: a x^2 + 2 b x y + ..., and is the source of my confusion.

In the method as_parameters, those factors are implemented where needed, but wouldn't it be clearer to:

  • either modify the docstring where it needs to be modified,
  • or incorporate the incriminated factors directly in the fitting routine (and harmonize the notation throughout the code)?

Happy holidays!

Uncertainties calculation

Hello and thank you for your nice package.

Currently I use your package for fitting ellipses and it works perfect but I would like to know if there is way to output the uncertainties of the computed ellipse parameters ? If it's not implemented can you guide me to a paper explaining how to compute them for an ellipse fit.

Thank you in advance

add weights option

could be very useful to add weights to this, so some points could be regarded with less significance than others

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.