PyEFD
An Python/NumPy implementation of a method for approximating a contour with a Fourier series, as described in [1].
EFD representations of an MNIST [2] digit. Shows progressive improvement of approximation by order of Fourier series.
Installation
$ pip install pyefd
Usage
Given a closed contour of a shape, generated by e.g. scikit-image or OpenCV, this package can fit a Fourier series approximating the shape of the contour.
General usage examples
This section describes the general usage patterns of pyefd.
from pyefd import elliptic_fourier_descriptors
coeffs = elliptic_fourier_descriptors(contour, order=10)
The coefficients returned are the \(a_n\), \(b_n\), \(c_n\) and \(d_n\) of the following Fourier series representation of the shape.
The coefficients returned can be normalized so that they are rotation and size-invariant. This can be achieved by calling:
from pyefd import elliptic_fourier_descriptors
coeffs = elliptic_fourier_descriptors(contour, order=10, normalize=True)
Normalization can also be done afterwards:
from pyefd import normalize_efd
coeffs = normalize_efd(coeffs)
OpenCV example
If you are using OpenCV to generate contours, this example
shows how to connect it to pyefd.
import cv2
import numpy
from pyefd import elliptic_fourier_descriptors
# Find the contours of a binary image using OpenCV.
contours, hierarchy = cv2.findContours(
im, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Iterate through all contours found and store each contour's
# elliptical Fourier descriptor's coefficients.
coeffs = []
for cnt in contours:
# Find the coefficients of all contours
coeffs.append(elliptic_fourier_descriptors(
numpy.squeeze(cnt), order=10))
Using EFD as features
To use EFD as features, one can write a small wrapper function:
def efd_feature(contour):
coeffs = elliptic_fourier_descriptors(
contour, order=10, normalize=True)
return coeffs.flatten()[3:]
If the coefficients are normalized, then coeffs[0, 0] = 1.0,
coeffs[0, 1] = 0.0 and coeffs[0, 2] = 0.0, so they can be disregarded when using
the elliptic Fourier descriptors as features.
See [1] for more technical details.
Testing
Run tests with:
$ python setup.py test
or with Pytest:
$ py.test tests.py
The tests includes a single image from the MNIST dataset of handwritten digits ([2]) as a contour to use for testing.
References
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
1.4.1 (2020-09-28)
Added
Added
CHANGELOG.md
Changed
Change CI from Azure Devops to Github Actions
1.4.0 (2019-07-27)
Changed
Merged PR #4: Vectorized contour reconstruction function
1.3.0 (2019-06-18)
Changed
Merged PR #2: Numpy vectorized efd
Moved from Travis CI to Azure Pipelines
Replaced rst with markdown
1.2.0 (2018-06-14)
Changed
Updated setup.py
Updated numpy requirement
Added
Added Pipfile
Ran Black on code
Testing on 3.6
1.1.0 (2018-06-13)
Added
New example for OpenCV
Updated documentation
1.0.0 (2016-04-19)
Changed
Deemed stable enough for version 1.0 release
Added
Created documentation.
0.1.2 (2016-02-29)
Changed
Testing with pytest instead of nosetests.
Added
Added Coveralls use.
0.1.1 (2016-02-17)
Fixed
Fixed MANIFEST
Added
Added LICENSE file that was missing.
0.1.0 (2016-02-09)
Added
Initial release
API
A Python implementation of the method described in [3] and [4] for calculating Fourier coefficients for characterizing closed contours.
References
F. P. Kuhl and C. R. Giardina, “Elliptic Fourier Features of a Closed Contour,” Computer Vision, Graphics and Image Processing, Vol. 18, pp. 236-258, 1982.
Oivind Due Trier, Anil K. Jain and Torfinn Taxt, “Feature Extraction Methods for Character Recognition - A Survey”, Pattern Recognition Vol. 29, No.4, pp. 641-662, 1996
Created by hbldh <henrik.blidh@nedomkull.com> on 2016-01-30.
- pyefd.calculate_dc_coefficients(contour)[source]
Calculate the \(A_0\) and \(C_0\) coefficients of the elliptic Fourier series.
- Parameters:
contour (numpy.ndarray) – A contour array of size
[M x 2].- Returns:
The \(A_0\) and \(C_0\) coefficients.
- Return type:
tuple
- pyefd.elliptic_fourier_descriptors(contour, order=10, normalize=False, return_transformation=False)[source]
Calculate elliptical Fourier descriptors for a contour.
- Parameters:
contour (numpy.ndarray) – A contour array of size
[M x 2].order (int) – The order of Fourier coefficients to calculate.
normalize (bool) – If the coefficients should be normalized; see references for details.
return_transformation (bool) – If the normalization parametres should be returned. Default is
False.
- Returns:
A
[order x 4]array of Fourier coefficients and optionally the transformation parametresscale,psi_1(rotation) andtheta_1(phase)- Return type:
:
numpy.ndarrayor (numpy.ndarray, (float, float, float))
- pyefd.normalize_efd(coeffs, size_invariant=True, return_transformation=False)[source]
Normalizes an array of Fourier coefficients.
- Parameters:
coeffs (numpy.ndarray) – A
[n x 4]Fourier coefficient array.size_invariant (bool) – If size invariance normalizing should be done as well. Default is
True.return_transformation (bool) – If the normalization parametres should be returned. Default is
False.
- Returns:
The normalized
[n x 4]Fourier coefficient array and optionally the transformation parametresscale, \(psi_1\) (rotation) and \(theta_1\) (phase)- Return type:
numpy.ndarrayor (numpy.ndarray, (float, float, float))
- pyefd.plot_efd(coeffs, locus=(0.0, 0.0), image=None, contour=None, n=300)[source]
Plot a
[2 x (N / 2)]grid of successive truncations of the series.Note
Requires matplotlib!