Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Image Transformation

Image deformations, also called transformations in the computer vision literature (see Szeliski1), fall into the categories shown below:

2d-planar-transformations
Figure: Categories of 2D planar transformations from Szeliski.

Each category preserves a different, nested set of geometric properties — every property a more restrictive category preserves is also preserved by every category to its left:

PropertyTranslationEuclideanSimilarityAffineProjective
Straight lines stay straightYesYesYesYesYes
Parallel lines stay parallelYesYesYesYesNo
Angles preservedYesYesYesNoNo
Lengths/distances preservedYesYesNoNoNo
Absolute orientation preserved (no rotation)YesNoNoNoNo

Pure Translation (Rigid Body Motion)

As the simplest of the categories above — no change in shape or size — dictk.imaging.translate shifts every pixel by a fixed displacement. This example shifts the image by dx=-60 pixels in x and dy=+80 pixels in y, representing rigid body motion where the material moves without deforming.

import dictk
from dictk.imaging import translate, write_image

photo = dictk.astronaut(300, 300)
write_image(photo, "astronaut_translate_original.png")

translated = translate(photo, dx=-60, dy=80)
write_image(translated, "astronaut_translate_rigid_body.png")
Saved: astronaut_translate_original.png, astronaut_translate_rigid_body.png
TranslationImage
Originaloriginal
dx=-60, dy=+80rigid body translation

Pure Rotation

A 30° counterclockwise rotation, another rigid body motion that preserves distances and angles. dictk.imaging.rotate pivots on the image's top-left corner (0, 0), consistent with stretch and translate's pivot choice in this codebase — unlike the more typical "object spins in place" rotation about the center, most content swings away from that fixed corner, similar to a door on a hinge.

import dictk
from dictk.imaging import rotate, write_image

photo = dictk.astronaut(300, 300)
write_image(photo, "astronaut_rotate_original.png")

rotated = rotate(photo, 30.0)
write_image(rotated, "astronaut_rotate_30deg.png")
Saved: astronaut_rotate_original.png, astronaut_rotate_30deg.png
RotationImage
Originaloriginal
30° (origin-pivoted)30 degree rotation

X-Axis Stretch (Extension)

As a concrete example of the similarity category above, dictk.imaging.stretch applies a uniaxial stretch along the x-axis: the image's top-left corner (x=0, y=0) stays fixed, and content grows away from it, using backward mapping with bilinear interpolation so the result has no gaps (unlike naively moving each source pixel forward, which can leave holes). The two stretches below range from a small, realistic deformation (5%, similar in magnitude to a modest tensile strain in a materials test) up to a much larger one (50%).

import dictk
from dictk.imaging import stretch, write_image

photo = dictk.astronaut(300, 300)
write_image(photo, "astronaut_stretch_original.png")

stretch_5pct = stretch(photo, factor_x=1.05)
write_image(stretch_5pct, "astronaut_stretch_x_5pct.png")

stretch_50pct = stretch(photo, factor_x=1.50)
write_image(stretch_50pct, "astronaut_stretch_x_50pct.png")
Saved: astronaut_stretch_original.png, astronaut_stretch_x_5pct.png, astronaut_stretch_x_50pct.png
StretchImage
Originaloriginal
5% (factor_x=1.05)5% x-axis stretch
50% (factor_x=1.50)50% x-axis stretch

Y-Axis Stretch (Compression)

The same dictk.imaging.stretch function compresses along the y-axis with factor_y < 1.0. Pivoting on the origin means the top edge (y=0) stays fixed while content shrinks toward it, leaving a black margin along the bottom — the mirror image of the x-axis stretch case, where growth away from the origin never leaves a gap.

import dictk
from dictk.imaging import stretch, write_image

photo = dictk.astronaut(300, 300)
write_image(photo, "astronaut_compress_original.png")

compress_neg5pct = stretch(photo, factor_y=0.95)
write_image(compress_neg5pct, "astronaut_compress_y_neg5pct.png")

compress_neg50pct = stretch(photo, factor_y=0.50)
write_image(compress_neg50pct, "astronaut_compress_y_neg50pct.png")
Saved: astronaut_compress_original.png, astronaut_compress_y_neg5pct.png, astronaut_compress_y_neg50pct.png
CompressionImage
Originaloriginal
-5% (factor_y=0.95)-5% y-axis compression
-50% (factor_y=0.50)-50% y-axis compression

Simple Shear

A shear deformation with γ = 0.5, where horizontal planes slide relative to each other by an amount proportional to their y-coordinate — the higher up a row of pixels, the further it shifts sideways. dictk.imaging.shear pivots on the image's top-left corner (0, 0), consistent with the other transform functions in this codebase.

import dictk
from dictk.imaging import shear, write_image

photo = dictk.astronaut(300, 300)
write_image(photo, "astronaut_shear_original.png")

sheared = shear(photo, shear_x=0.5)
write_image(sheared, "astronaut_shear_x_0.5.png")
Saved: astronaut_shear_original.png, astronaut_shear_x_0.5.png
ShearImage
Originaloriginal
γ = 0.5 (shear_x=0.5)simple shear

Complex Deformation

Combines rotation (15°) with anisotropic stretching (1.3x in x, 0.8x in y) — realistic loading scenarios where materials experience multiple simultaneous deformation modes, typically the hardest case for correlation algorithms. dictk.imaging.complex_deform composes the two into a single deformation gradient (stretch applied first, then rotation) and applies it in one backward-mapping pass, so the result isn't blurred by interpolating twice as calling stretch and then rotate separately would.

import dictk
from dictk.imaging import complex_deform, write_image

photo = dictk.astronaut(300, 300)
write_image(photo, "astronaut_complex_original.png")

combined = complex_deform(photo, factor_x=1.3, factor_y=0.8, angle=15.0)
write_image(combined, "astronaut_complex_deform.png")
Saved: astronaut_complex_original.png, astronaut_complex_deform.png
Composed DeformationImage
Originaloriginal
factor_x=1.3, factor_y=0.8, angle=15°composed deformation

Crack Dislocation

A vertical crack splits the image at x = width/2: the left half shifts down 4 pixels and the right half shifts up 4 pixels, producing a displacement field that jumps discontinuously across the crack line — unlike every other example on this page, which deforms smoothly. Standard DIC assumes smooth displacements and cannot capture this jump; cases like this motivate the Heaviside finite-element formulation.

import dictk
from dictk.imaging import crack_dislocation, write_image

photo = dictk.astronaut(300, 300)
write_image(photo, "astronaut_crack_plain_original.png")

cracked_plain = crack_dislocation(photo, offset=4.0)
write_image(cracked_plain, "astronaut_crack_plain_dislocation.png")
Saved: astronaut_crack_plain_original.png, astronaut_crack_plain_dislocation.png
Crack DislocationImage
Originaloriginal
offset=4 pixelscrack dislocation

References


  1. Szeliski R. Computer vision: algorithms and applications, 2nd Edition, Springer Nature; 2022 Jan 3. download (43 MB)