3434 _range = range
3535
3636
37- def elliptic_fourier_descriptors (contour , order = 10 , normalize = False ):
37+ def elliptic_fourier_descriptors (
38+ contour , order = 10 , normalize = False , return_transformation = False
39+ ):
3840 """Calculate elliptical Fourier descriptors for a contour.
3941
4042 :param numpy.ndarray contour: A contour array of size ``[M x 2]``.
4143 :param int order: The order of Fourier coefficients to calculate.
4244 :param bool normalize: If the coefficients should be normalized;
4345 see references for details.
44- :return: A ``[order x 4]`` array of Fourier coefficients.
45- :rtype: :py:class:`numpy.ndarray`
46+ :param bool return_transformation: If the normalization parametres should be returned.
47+ Default is ``False``.
48+ :return: A ``[order x 4]`` array of Fourier coefficients and optionally the
49+ transformation parametres ``scale``, ``psi_1`` (rotation) and ``theta_1`` (phase)
50+ :rtype: ::py:class:`numpy.ndarray` or (:py:class:`numpy.ndarray`, (float, float, float))
4651
4752 """
4853 dxy = np .diff (contour , axis = 0 )
4954 dt = np .sqrt ((dxy ** 2 ).sum (axis = 1 ))
50- t = np .concatenate ([([0. ]), np .cumsum (dt )])
55+ t = np .concatenate ([([0.0 ]), np .cumsum (dt )])
5156 T = t [- 1 ]
5257
5358 phi = (2 * np .pi * t ) / T
@@ -74,21 +79,24 @@ def elliptic_fourier_descriptors(contour, order=10, normalize=False):
7479 )
7580
7681 if normalize :
77- coeffs = normalize_efd (coeffs )
82+ coeffs = normalize_efd (coeffs , return_transformation = return_transformation )
7883
7984 return coeffs
8085
8186
82- def normalize_efd (coeffs , size_invariant = True ):
87+ def normalize_efd (coeffs , size_invariant = True , return_transformation = False ):
8388 """Normalizes an array of Fourier coefficients.
8489
8590 See [#a]_ and [#b]_ for details.
8691
8792 :param numpy.ndarray coeffs: A ``[n x 4]`` Fourier coefficient array.
8893 :param bool size_invariant: If size invariance normalizing should be done as well.
8994 Default is ``True``.
90- :return: The normalized ``[n x 4]`` Fourier coefficient array.
91- :rtype: :py:class:`numpy.ndarray`
95+ :param bool return_transformation: If the normalization parametres should be returned.
96+ Default is ``False``.
97+ :return: The normalized ``[n x 4]`` Fourier coefficient array and optionally the
98+ transformation parametres ``scale``, :math:`psi_1` (rotation) and :math:`theta_1` (phase)
99+ :rtype: :py:class:`numpy.ndarray` or (:py:class:`numpy.ndarray`, (float, float, float))
92100
93101 """
94102 # Make the coefficients have a zero phase shift from
@@ -136,11 +144,15 @@ def normalize_efd(coeffs, size_invariant=True):
136144 )
137145 ).flatten ()
138146
147+ size = coeffs [0 , 0 ]
139148 if size_invariant :
140149 # Obtain size-invariance by normalizing.
141- coeffs /= np .abs (coeffs [ 0 , 0 ] )
150+ coeffs /= np .abs (size )
142151
143- return coeffs
152+ if return_transformation :
153+ return coeffs , (size , psi_1 , theta_1 )
154+ else :
155+ return coeffs
144156
145157
146158def calculate_dc_coefficients (contour ):
@@ -153,7 +165,7 @@ def calculate_dc_coefficients(contour):
153165 """
154166 dxy = np .diff (contour , axis = 0 )
155167 dt = np .sqrt ((dxy ** 2 ).sum (axis = 1 ))
156- t = np .concatenate ([([0. ]), np .cumsum (dt )])
168+ t = np .concatenate ([([0.0 ]), np .cumsum (dt )])
157169 T = t [- 1 ]
158170
159171 xi = np .cumsum (dxy [:, 0 ]) - (dxy [:, 0 ] / dt ) * t [1 :]
@@ -199,7 +211,7 @@ def reconstruct_contour(coeffs, locus=(0, 0), num_points=300):
199211 return reconstruction
200212
201213
202- def plot_efd (coeffs , locus = (0. , 0. ), image = None , contour = None , n = 300 ):
214+ def plot_efd (coeffs , locus = (0.0 , 0.0 ), image = None , contour = None , n = 300 ):
203215 """Plot a ``[2 x (N / 2)]`` grid of successive truncations of the series.
204216
205217 .. note::
0 commit comments