142 lines
5.4 KiB
Python
142 lines
5.4 KiB
Python
"""
|
|
===================================
|
|
Types of homographies
|
|
===================================
|
|
|
|
`Homographies <https://en.wikipedia.org/wiki/Homography>`_
|
|
are transformations of a Euclidean space that preserve the alignment of points.
|
|
Specific cases of homographies correspond to the conservation of more
|
|
properties, such as parallelism (affine transformation), shape (similar
|
|
transformation) or distances (Euclidean transformation).
|
|
|
|
Homographies on a 2D Euclidean space (i.e., for 2D grayscale or multichannel
|
|
images) are defined by a 3x3 matrix. All types of homographies can be defined
|
|
by passing either the transformation matrix, or the parameters of the simpler
|
|
transformations (rotation, scaling, ...) which compose the full transformation.
|
|
|
|
The different types of homographies available in scikit-image are
|
|
shown here, by increasing order of complexity (i.e. by reducing the number of
|
|
constraints). While we focus here on the mathematical properties of
|
|
transformations, tutorial
|
|
:ref:`sphx_glr_auto_examples_transform_plot_geometric.py` explains how to use
|
|
such transformations for various tasks such as image warping or parameter
|
|
estimation.
|
|
"""
|
|
import math
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
|
|
from skimage import data
|
|
from skimage import transform
|
|
from skimage import img_as_float
|
|
|
|
######################################################################
|
|
# Euclidean (rigid) transformation
|
|
# =================================
|
|
#
|
|
# A `Euclidean transformation <https://en.wikipedia.org/wiki/Rigid_transformation>`_,
|
|
# also called rigid transformation, preserves the Euclidean distance between
|
|
# pairs of points. It can be described as a rotation about the origin
|
|
# followed by a translation.
|
|
|
|
tform = transform.EuclideanTransform(
|
|
rotation=np.pi / 12.,
|
|
translation = (100, -20)
|
|
)
|
|
print(tform.params)
|
|
|
|
######################################################################
|
|
# Now let's apply this transformation to an image. Because we are trying
|
|
# to reconstruct the *image* after transformation, it is not useful to see
|
|
# where a *coordinate* from the input image ends up in the output, which is
|
|
# what the transform gives us. Instead, for every pixel (coordinate) in the
|
|
# output image, we want to figure out where in the input image it comes from.
|
|
# Therefore, we need to use the inverse of ``tform``, rather than ``tform``
|
|
# directly.
|
|
|
|
img = img_as_float(data.chelsea())
|
|
tf_img = transform.warp(img, tform.inverse)
|
|
fig, ax = plt.subplots()
|
|
ax.imshow(tf_img)
|
|
_ = ax.set_title('Euclidean transformation')
|
|
|
|
######################################################################
|
|
# For a rotation around the center of the image, one can
|
|
# compose a translation to change the origin, a rotation, and finally
|
|
# the inverse of the first translation.
|
|
|
|
rotation = transform.EuclideanTransform(rotation=np.pi/3)
|
|
shift = transform.EuclideanTransform(translation=-np.array(img.shape[:2]) / 2)
|
|
# Compose transforms by multiplying their matrices
|
|
matrix = np.linalg.inv(shift.params) @ rotation.params @ shift.params
|
|
tform = transform.EuclideanTransform(matrix)
|
|
tf_img = transform.warp(img, tform.inverse)
|
|
fig, ax = plt.subplots()
|
|
_ = ax.imshow(tf_img)
|
|
|
|
######################################################################
|
|
# Similarity transformation
|
|
# =================================
|
|
#
|
|
# A `similarity transformation <https://en.wikipedia.org/wiki/Similarity_(geometry)>`_
|
|
# preserves the shape of objects. It combines scaling, translation and rotation.
|
|
|
|
tform = transform.SimilarityTransform(
|
|
scale=0.5,
|
|
rotation=np.pi/12,
|
|
translation=(100, 50))
|
|
print(tform.params)
|
|
tf_img = transform.warp(img, tform.inverse)
|
|
fig, ax = plt.subplots()
|
|
ax.imshow(tf_img)
|
|
_ = ax.set_title('Similarity transformation')
|
|
|
|
######################################################################
|
|
# Affine transformation
|
|
# =================================
|
|
#
|
|
# An `affine transformation <https://en.wikipedia.org/wiki/Affine_transformation>`_
|
|
# preserves lines (hence the alignment of objects), as well as parallelism
|
|
# between lines. It can be decomposed into a similarity transform and a
|
|
# `shear transformation <https://en.wikipedia.org/wiki/Shear_mapping>`_.
|
|
|
|
tform = transform.AffineTransform(
|
|
shear=np.pi/6,
|
|
)
|
|
print(tform.params)
|
|
tf_img = transform.warp(img, tform.inverse)
|
|
fig, ax = plt.subplots()
|
|
ax.imshow(tf_img)
|
|
_ = ax.set_title('Affine transformation')
|
|
|
|
|
|
######################################################################
|
|
# Projective transformation (homographies)
|
|
# ========================================
|
|
#
|
|
# A `homography <https://en.wikipedia.org/wiki/Homography>`_, also called
|
|
# projective transformation, preserves lines but not necessarily
|
|
# parallelism.
|
|
|
|
matrix = np.array([[1, -0.5, 100],
|
|
[0.1, 0.9, 50],
|
|
[0.0015, 0.0015, 1]])
|
|
tform = transform.ProjectiveTransform(matrix=matrix)
|
|
tf_img = transform.warp(img, tform.inverse)
|
|
fig, ax = plt.subplots()
|
|
ax.imshow(tf_img)
|
|
ax.set_title('Projective transformation')
|
|
# sphinx_gallery_thumbnail_number = 5
|
|
|
|
plt.show()
|
|
######################################################################
|
|
# See also
|
|
# ========================================
|
|
#
|
|
# * :ref:`sphx_glr_auto_examples_transform_plot_geometric.py` for composing
|
|
# transformations or estimating their parameters
|
|
# * :ref:`sphx_glr_auto_examples_transform_plot_rescale.py` for simple
|
|
# rescaling and resizing operations
|
|
# * :func:`skimage.transform.rotate` for rotating an image around its center
|
|
#
|