
    G 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    v/root/GenerationalWealth/GenerationalWealth/venv/lib/python3.13/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$ )zEstimate 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9CS/!++F3!226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ll3$[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                  " X4[        R                  S9n
XzSU2SU24'   XS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                  X5      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   )dtypeNz#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%(99Q<!syy|a/@CS/!99		!;CII;d399+VCS/!yys(%%d+IIrww1v,-q5HHh)<"1"bqb&	"1"bc'
SS"#rr'
IIsBHHa!eQZ012	9$&IIOOA$9D!  yy$$ 	98	9s   -$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    HHNN1!!"1%!!!"%qTBFF6QR5$99BFF;<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:0yE>r   g        )r   wherelog)r_smallr_sqUs       r   r8   -ThinPlateSplineTransform._radial_basis_kernel   s=     !tHHQ#XsD266$-+@$@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   