
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "auto_examples/transform/plot_geometric.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_auto_examples_transform_plot_geometric.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_auto_examples_transform_plot_geometric.py:


===============================
Using geometric transformations
===============================

In this example, we will see how to use geometric transformations in the context
of image processing.

.. GENERATED FROM PYTHON SOURCE LINES 9-17

.. code-block:: Python


    import math
    import numpy as np
    import matplotlib.pyplot as plt

    from skimage import data
    from skimage import transform








.. GENERATED FROM PYTHON SOURCE LINES 18-30

Basics
======

Several different geometric transformation types are supported: similarity,
affine, projective and polynomial. For a tutorial on the available types of
transformations, see :ref:`sphx_glr_auto_examples_transform_plot_transform_types.py`.

Geometric transformations can either be created using the explicit
parameters (e.g. scale, shear, rotation and translation) or the
transformation matrix.

First we create a transformation using explicit parameters:

.. GENERATED FROM PYTHON SOURCE LINES 30-34

.. code-block:: Python


    tform = transform.SimilarityTransform(scale=1, rotation=math.pi / 2, translation=(0, 1))
    print(tform.params)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    [[ 6.123234e-17 -1.000000e+00  0.000000e+00]
     [ 1.000000e+00  6.123234e-17  1.000000e+00]
     [ 0.000000e+00  0.000000e+00  1.000000e+00]]




.. GENERATED FROM PYTHON SOURCE LINES 35-37

Alternatively you can define a transformation by the transformation matrix
itself:

.. GENERATED FROM PYTHON SOURCE LINES 37-42

.. code-block:: Python


    matrix = tform.params.copy()
    matrix[1, 2] = 2
    tform2 = transform.SimilarityTransform(matrix)








.. GENERATED FROM PYTHON SOURCE LINES 43-46

These transformation objects can then be used to apply forward and inverse
coordinate transformations between the source and destination coordinate
systems:

.. GENERATED FROM PYTHON SOURCE LINES 46-51

.. code-block:: Python


    coord = [1, 0]
    print(tform2(coord))
    print(tform2.inverse(tform(coord)))





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    [[6.123234e-17 3.000000e+00]]
    [[ 0.000000e+00 -6.123234e-17]]




.. GENERATED FROM PYTHON SOURCE LINES 52-56

Image warping
=============

Geometric transformations can also be used to warp images:

.. GENERATED FROM PYTHON SOURCE LINES 56-77

.. code-block:: Python


    text = data.text()

    tform = transform.SimilarityTransform(
        scale=1, rotation=math.pi / 4, translation=(text.shape[0] / 2, -100)
    )

    rotated = transform.warp(text, tform)
    back_rotated = transform.warp(rotated, tform.inverse)

    fig, ax = plt.subplots(nrows=3)

    ax[0].imshow(text, cmap=plt.cm.gray)
    ax[1].imshow(rotated, cmap=plt.cm.gray)
    ax[2].imshow(back_rotated, cmap=plt.cm.gray)

    for a in ax:
        a.axis('off')

    plt.tight_layout()




.. image-sg:: /auto_examples/transform/images/sphx_glr_plot_geometric_001.png
   :alt: plot geometric
   :srcset: /auto_examples/transform/images/sphx_glr_plot_geometric_001.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 78-95

Parameter estimation
====================

In addition to the basic functionality mentioned above you can also
generate a transform by estimating the parameters of a geometric
transformation using the least squares method.

This can amongst other things be used for image registration or
rectification, where you have a set of control points or
homologous/corresponding points in two images.

Let's assume we want to recognize letters on a photograph which was not
taken from the front but at a certain angle. In the simplest case of a
plane paper surface the letters are projectively distorted. Simple matching
algorithms would not be able to match such symbols. One solution to this
problem would be to warp the image so that the distortion is removed and
then apply a matching algorithm:

.. GENERATED FROM PYTHON SOURCE LINES 95-103

.. code-block:: Python


    text = data.text()

    src = np.array([[0, 0], [0, 50], [300, 50], [300, 0]])
    dst = np.array([[155, 15], [65, 40], [260, 130], [360, 95]])

    tform3 = transform.ProjectiveTransform.from_estimate(src, dst)








.. GENERATED FROM PYTHON SOURCE LINES 104-119

.. note::

   For many transform types, including the ``ProjectiveTransform``, it is
   possible for the estimation to fail.  If this is the case,
   ``from_estimate`` returns a special object of type ``FailedEstimation``.
   This object describes the reason for the failure and can be tested for.
   The following is a typical pattern to handle failed estimations
   explicitly:

   .. code-block:: python

      if not tform3:  # If result is *falsey*, we have a failed estimation.
          raise RuntimeError(f'Failed estimation: {tform3}')

   See :ref:`failed-estimation` below for more details.

.. GENERATED FROM PYTHON SOURCE LINES 119-134

.. code-block:: Python


    warped = transform.warp(text, tform3, output_shape=(50, 300))

    fig, ax = plt.subplots(nrows=2, figsize=(8, 3))

    ax[0].imshow(text, cmap=plt.cm.gray)
    ax[0].plot(dst[:, 0], dst[:, 1], '.r')
    ax[1].imshow(warped, cmap=plt.cm.gray)

    for a in ax:
        a.axis('off')

    plt.tight_layout()
    plt.show()




.. image-sg:: /auto_examples/transform/images/sphx_glr_plot_geometric_002.png
   :alt: plot geometric
   :srcset: /auto_examples/transform/images/sphx_glr_plot_geometric_002.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 135-145

The above estimation relies on accurate knowledge of the location of points
and an accurate selection of their correspondence. If point locations have
an uncertainty associated with them, then weighting can be provided so that
the resulting transform prioritises an accurate fit to those points with the
highest weighting.
An alternative approach called the
`RANSAC algorithm <https://en.wikipedia.org/wiki/Random_sample_consensus>`_
is useful when the correspondence points are not perfectly accurate.
See the :ref:`sphx_glr_auto_examples_transform_plot_matching.py` tutorial
for an in-depth description of how to use this approach in scikit-image.

.. GENERATED FROM PYTHON SOURCE LINES 147-159

.. _failed-estimation:

Failed estimation
====================

There are situations where transform classes can fail to estimate a valid
transformation, and we recommend that you always check for this possible
case.

If estimation succeeds, the result you get back will be a valid estimated
transform.  You can check if you have a valid transform by truth testing.
E.g., the estimation from the previous section ``tform3`` is valid and *truthy*:

.. GENERATED FROM PYTHON SOURCE LINES 159-162

.. code-block:: Python


    bool(tform3)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    True



.. GENERATED FROM PYTHON SOURCE LINES 163-166

However, if estimation failed, the ``from_estimate`` method returns a
special object of type ``FailedEstimation``.  Here is an example of a failed
estimation, where all the input points are the same:

.. GENERATED FROM PYTHON SOURCE LINES 166-172

.. code-block:: Python


    # Repeat last point 4 times, for four identical points.
    bad_src = np.tile(src[-1, :], (4, 1))
    bad_tform = transform.ProjectiveTransform.from_estimate(bad_src, dst)
    bad_tform





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    /usr/lib/python3/dist-packages/numpy/_core/numeric.py:476: RuntimeWarning:

    invalid value encountered in cast


    FailedEstimation('ProjectiveTransform: Scaling generated NaN values')



.. GENERATED FROM PYTHON SOURCE LINES 173-174

This object type is *falsey*---meaning that:

.. GENERATED FROM PYTHON SOURCE LINES 174-177

.. code-block:: Python


    bool(bad_tform)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    False



.. GENERATED FROM PYTHON SOURCE LINES 178-179

You can access the raw message string of the failure with

.. GENERATED FROM PYTHON SOURCE LINES 179-182

.. code-block:: Python


    str(bad_tform)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    'ProjectiveTransform: Scaling generated NaN values'



.. GENERATED FROM PYTHON SOURCE LINES 183-195

We recommend that you put in a routine check to confirm the estimation
succeeded:

.. code-block:: python

   if not bad_tform:
       raise RuntimeError(f'Failed estimation: {bad_tform}')

Of course, there may be times, where you did not check the *truthiness* of
the estimation, and you nevertheless try to use the returned estimate.  In
this case, you'll get a :class:`~.FailedEstimationAccessError`---a custom
subclass of a :class:`AttributeError`.


.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 0.693 seconds)


.. _sphx_glr_download_auto_examples_transform_plot_geometric.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: plot_geometric.ipynb <plot_geometric.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: plot_geometric.py <plot_geometric.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: plot_geometric.zip <plot_geometric.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
