ó
    Å“,j¹   ã                   óL   • S SK Jr  S SKrS SKJr  SSKJrJrJ	r	   " S S5      r
g)é    )ÚSelfN)Údistance_matrixé   )Úcheck_nDÚ_deprecate_estimateÚFailedEstimationc                   ó„   • \ rS rSrSrS rS r\S 5       r\	S\
\-  4S j5       rS rS	 rS
 r\S 5       r\S 5       rSrg)ÚThinPlateSplineTransformé	   uÌ	  Thin-plate spline transformation.

Given two matching sets of points, source and destination, this class
estimates the thin-plate spline (TPS) transformation which transforms
each point in source into its destination counterpart.

Attributes
----------
src : (N, 2) array_like
    Coordinates of control points in source image.

References
----------
.. [1] Bookstein, Fred L. "Principal warps: Thin-plate splines and the
       decomposition of deformations," IEEE Transactions on pattern analysis
       and machine intelligence 11.6 (1989): 567â€“585.
       DOI:`10.1109/34.24792`
       https://user.engineering.uiowa.edu/~aip/papers/bookstein-89.pdf

Examples
--------
>>> import skimage as ski

Define source and destination control points such that they simulate
rotating by 90 degrees and generate a meshgrid from them:

>>> src = np.array([[0, 0], [0, 5], [5, 5], [5, 0]])
>>> dst = np.array([[5, 0], [0, 0], [0, 5], [5, 5]])

Estimate the transformation:

>>> tps = ski.transform.ThinPlateSplineTransform.from_estimate(src, dst)

Appyling the transformation to `src` approximates `dst`:

>>> np.round(tps(src), 4)  # doctest: +FLOAT_CMP
array([[5., 0.],
       [0., 0.],
       [0., 5.],
       [5., 5.]])

Create a meshgrid to apply the transformation to:

>>> grid = np.meshgrid(np.arange(5), np.arange(5))
>>> grid[1]
array([[0, 0, 0, 0, 0],
       [1, 1, 1, 1, 1],
       [2, 2, 2, 2, 2],
       [3, 3, 3, 3, 3],
       [4, 4, 4, 4, 4]])

>>> coords = np.vstack([grid[0].ravel(), grid[1].ravel()]).T
>>> transformed = tps(coords)
>>> np.round(transformed[:, 1]).reshape(5, 5).astype(int)
array([[0, 1, 2, 3, 4],
       [0, 1, 2, 3, 4],
       [0, 1, 2, 3, 4],
       [0, 1, 2, 3, 4],
       [0, 1, 2, 3, 4]])

The estimation can fail - for example, if all the input or output points
are the same.  If this happens, you will get a transform that is not
"truthy" - meaning that ``bool(tform)`` is ``False``:

>>> if tps:
...     print("Estimation succeeded.")
Estimation succeeded.

Not so for a degenerate transform with identical points.

>>> bad_src = np.ones((4, 2))
>>> bad_tps = ski.transform.ThinPlateSplineTransform.from_estimate(
...      bad_src, dst)
>>> if not bad_tps:
...     print("Estimation failed.")
Estimation failed.

Trying to use this failed estimation transform result will give a suitable
error:

>>> bad_tps.params  # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
  ...
FailedEstimationAccessError: No attribute "params" for failed estimation ...
c                 ó.   • SU l         S U l        S U l        g )NF©Ú
_estimatedÚ_spline_mappingsÚsrc©Úselfs    Ú³C:\Users\johnn\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\skimage/transform/_thin_plate_splines.pyÚ__init__Ú!ThinPlateSplineTransform.__init__`   s   € ØˆŒØ $ˆÔØˆ�ó    c                 ó
  • U R                   c  Sn[        U5      e[        R                  " U5      nUR                  S:w  d  UR
                  S   S:w  a  Sn[        U5      eU R                  U5      nU R                  X5      nU$ )zâEstimate the transformation from a set of corresponding points.

Parameters
----------
coords : (N, 2) array_like
    x, y coordinates to transform

Returns
-------
transformed_coords: (N, D) array
    Destination coordinates
zOTransformation is undefined, define it by calling `estimate` before applying itr   é   z%Input `coords` must have shape (N, 2))r   Ú
ValueErrorÚnpÚarrayÚndimÚshapeÚ_radial_distanceÚ_spline_function)r   ÚcoordsÚmsgÚradial_distÚtransformed_coordss        r   Ú__call__Ú!ThinPlateSplineTransform.__call__e   s…   € ð × Ñ Ñ(ð%ð ô ˜S“/Ð!Ü—’˜&Ó!ˆà�;‰;˜!Ó˜vŸ|™|¨A™°!Ó3Ø9ˆCÜ˜S“/Ð!à×+Ñ+¨FÓ3ˆØ!×2Ñ2°6ÓGÐà!Ð!r   c                 ó   • [        S5      e)NzNot supported)ÚNotImplementedErrorr   s    r   ÚinverseÚ ThinPlateSplineTransform.inverseƒ   s   € ä! /Ó2Ð2r   Úreturnc                 óp   • U " 5       nUR                  X5      nUc  U$ [        U R                   SU 35      $ )a  Estimate optimal spline mappings between source and destination points.

Parameters
----------
src : (N, 2) array_like
    Control points at source coordinates.
dst : (N, 2) array_like
    Control points at destination coordinates.

Returns
-------
tform : Self or ``FailedEstimation``
    An instance of the transformation if the estimation succeeded.
    Otherwise, we return a special ``FailedEstimation`` object to
    signal a failed estimation. Testing the truth value of the failed
    estimation object will return ``False``. E.g.

    .. code-block:: python

        tform = ThinPlateSplineTransform.from_estimate(...)
        if not tform:
            raise RuntimeError(f"Failed estimation: {tf}")

Notes
-----
The number N of source and destination points must match.
z: )Ú	_estimater   Ú__name__)Úclsr   ÚdstÚtfr!   s        r   Úfrom_estimateÚ&ThinPlateSplineTransform.from_estimate‡   s=   € ñ: ‹UˆØ�l‰l˜3Ó$ˆØ‘[ˆrÐPÔ&6¸#¿,¹,¸ÀrÈ#ÈÐ7OÓ&PÐPr   c                 ól  • [        USSS9  [        USSS9  UR                  S   S:  d  UR                  S   S:  a  Sn[        U5      eUR                  UR                  :w  a'  SUR                   S	UR                   3n[        U5      eXl        UR                  u  pE[	        X5      nU R                  U5      n[        R                  " [        R                  " US
45      U/5      nUS-   n	[        R                  " X™4[        R                  S9n
XzSU2SU24'   XŠSU2SS24'   UR                  U
SS2SU24'   [        R                  " U[        R                  " US
-   U45      /5      n [        R                  R                  X«5      U l        g! [        R                  R                    a     gf = f)z6Try to estimate and return reason if estimation fails.r   r   )Úarg_namer/   r   é   z,Need at least 3 points in in `src` and `dst`z'Shape of `src` and `dst` didn't match, z != r   )ÚdtypeNéýÿÿÿz#Unable to solve for spline mappings)r   r   r   r   r   Ú_radial_basis_kernelr   ÚhstackÚonesÚzerosÚfloat32ÚTÚvstackÚlinalgÚsolver   ÚLinAlgError)r   r   r/   r!   ÚnÚdÚdistÚKÚPÚn_plus_3ÚLÚVs               r   r,   Ú"ThinPlateSplineTransform._estimate¨   s�  € ä��a %Ò(Ü��a %Ò(à�9‰9�Q‰<˜!Ó˜sŸy™y¨™|¨aÓ/Ø@ˆCÜ˜S“/Ð!Ø�9‰9˜Ÿ	™	Ó!Ø;¸C¿I¹I¸;ÀdÈ3Ï9É9È+ÐVˆCÜ˜S“/Ð!àŒØ�y‰y‰ˆä˜sÓ(ˆØ×%Ñ% dÓ+ˆÜ�IŠI”r—w’w  1˜v“¨Ð,Ó-ˆØ�q‘5ˆÜ�HŠH�hÐ)´·±Ñ<ˆØˆ"ˆ1ˆ"ˆbˆqˆbˆ&‰	Øˆ"ˆ1ˆ"ˆb‰cˆ'‰
Ø—S‘Sˆˆ"‰#ˆr�ˆrˆ'‰
Ü�IŠI�sœBŸHšH a¨!¡e¨Q ZÓ0Ð1Ó2ˆð	9Ü$&§I¡I§O¡O°AÓ$9ˆDÔ!ð øô �y‰y×$Ñ$ó 	9Ù8ð	9ús   Å-$F ÆF3Æ2F3c                 óN   • [        XR                  5      nU R                  U5      $ )zCCompute the radial distance between input points and source points.)r   r   r8   )r   r    Údistss      r   r   Ú)ThinPlateSplineTransform._radial_distanceÆ   s!   € ä ¯©Ó1ˆØ×(Ñ(¨Ó/Ð/r   c                 óà   • U R                   R                  S   nU R                  SU nU R                  US nUS   [        R                  " XSS 5      -   [        R                  " X$5      -   nU$ )z3Estimate the spline function in X and Y directions.r   Nr   )r   r   r   r   Údot)r   r    r"   rB   ÚwÚar#   s          r   r   Ú)ThinPlateSplineTransform._spline_functionË   sj   € à�H‰H�N‰N˜1ÑˆØ×!Ñ! " 1Ð%ˆØ×!Ñ! ! "Ð%ˆØ˜q™T¤B§F¢F¨6°Q°R°5Ó$9Ñ9¼B¿FºFÀ;Ó<RÑRÐØ!Ð!r   c           	      ó|   • SnU S-  n[         R                  " U S:H  SU[         R                  " X!-   5      -  5      nU$ )a  Compute the radial basis function for thin-plate splines.

Parameters
----------
r : (4, N) ndarray
    Input array representing the Euclidean distance between each pair of
    two collections of control points.

Returns
-------
U : (4, N) ndarray
    Calculated kernel function U.
g:Œ0âŽyE>r   g        )r   ÚwhereÚlog)ÚrÚ_smallÚr_sqÚUs       r   r8   Ú-ThinPlateSplineTransform._radial_basis_kernelÓ   s=   € ð ˆØ�!‰tˆÜ�HŠH�Q˜#‘X˜s D¬2¯6ª6°$±-Ó+@Ñ$@ÓAˆØˆr   c                 ó(   • U R                  X5      SL $ )a…  Estimate optimal spline mappings between source and destination points.

Parameters
----------
src : (N, 2) array_like
    Control points at source coordinates.
dst : (N, 2) array_like
    Control points at destination coordinates.

Returns
-------
success: bool
    True indicates that the estimation was successful.

Notes
-----
The number N of source and destination points must match.
N)r,   )r   r   r/   s      r   ÚestimateÚ!ThinPlateSplineTransform.estimateç   s   € ð( �~‰~˜cÓ'¨4Ð/Ð/r   r   N)r-   Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   r$   Úpropertyr(   Úclassmethodr   r   r1   r,   r   r   Ústaticmethodr8   r   r\   Ú__static_attributes__© r   r   r
   r
   	   sƒ   † ñTòlò
"ð< ñ3ó ð3ð ðQ¨Ð/?Ñ(?ó Qó ðQò@ò<0ò
"ð ñó ðð& ñ0ó ó0r   r
   )Útypingr   Únumpyr   Úscipy.spatialr   Ú_shared.utilsr   r   r   r
   rf   r   r   Ú<module>rk      s    ðÝ ã Ý )ç KÑ K÷r0ò r0r   