.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/03_affine/02_rotation_animation.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code or to run this example in your browser via Binder. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_03_affine_02_rotation_animation.py: Rotation Animation ================== We use the rotate module to rotate a 2D image. .. GENERATED FROM PYTHON SOURCE LINES 13-15 Imports ------- .. GENERATED FROM PYTHON SOURCE LINES 15-24 .. code-block:: Python import numpy as np import matplotlib.pyplot as plt from matplotlib import animation from splineops.affine.affine import rotate from splineops.resize.resize import resize from urllib.request import urlopen from PIL import Image .. GENERATED FROM PYTHON SOURCE LINES 26-32 Load and Preprocess the Image ----------------------------- Load a Kodak image, convert it to grayscale, normalize it, and then resize it by a factor of (0.5, 0.5). After that, scale its intensity back to [0, 255] before rotation. .. GENERATED FROM PYTHON SOURCE LINES 32-75 .. code-block:: Python # Load the image url = 'https://r0k.us/graphics/kodak/kodak/kodim07.png' with urlopen(url, timeout=10) as resp: img = Image.open(resp) data = np.array(img, dtype=np.float64) # Convert to grayscale using a standard formula data_gray = ( data[:, :, 0] * 0.2989 + data[:, :, 1] * 0.5870 + data[:, :, 2] * 0.1140 ) # Show the original grayscale image plt.figure(figsize=(5, 5)) plt.imshow(data_gray, cmap="gray", vmin=0, vmax=255) plt.title("Original grayscale image") plt.axis("off") plt.tight_layout() plt.show() # Normalize the grayscale image to [0,1] data_normalized = data_gray / 255.0 # Define zoom factors for resizing zoom_factors = (0.3, 0.3) interp_method = "cubic" # Resize the image using spline interpolation (this returns image in [0,1]) image_resized = resize( data_normalized, zoom_factors=zoom_factors, method=interp_method ) # Bring the resized image back to [0,255] image_resized = (image_resized * 255.0).astype(np.float32) # Use the center of the resized image as the custom center of rotation custom_center = (image_resized.shape[0] // 2, image_resized.shape[1] // 2) radius = min(image_resized.shape) // 2 .. image-sg:: /auto_examples/03_affine/images/sphx_glr_02_rotation_animation_001.png :alt: Original grayscale image :srcset: /auto_examples/03_affine/images/sphx_glr_02_rotation_animation_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 76-80 Create an Animation ------------------- Create the animation of the image being rotated from 0 to 360 degrees. Explore the effect of the spline degree. .. GENERATED FROM PYTHON SOURCE LINES 80-166 .. code-block:: Python ROTATION_STEP_DEG = 5 INTERVAL_MS = 250 def rotate_and_mask(image, angle, degree, center, radius): rotated = rotate(image, angle=angle, degree=degree, center=center) rows, cols = rotated.shape rr, cc = np.ogrid[:rows, :cols] mask = (rr - center[0])**2 + (cc - center[1])**2 <= radius**2 # We'll return both the rotated image and the mask so we can use the mask as alpha. return rotated, mask def create_combined_animation(image, center, radius): """ Build a 3-panel rotation demo that shows spline degrees 0, 1 and 3. Parameters ---------- image : 2D np.ndarray Grayscale image in the range [0, 255]. center : tuple[int, int] (row, col) coordinates of the rotation centre. radius : int Pixel radius of the circular area we want to keep visible. """ # ------------------------------------------------------------------ # 1. Figure and axes # ------------------------------------------------------------------ fig, axes = plt.subplots( nrows=3, ncols=1, figsize=(4, 12), # a bit narrower than (6, 18) constrained_layout=True, ) degrees = [0, 1, 3] # Pre‑compute the square that bounds the circle x0, x1 = center[1] - radius, center[1] + radius y0, y1 = center[0] - radius, center[0] + radius # note y inverted later for ax, d in zip(axes, degrees): ax.set_title(f"Spline degree {d}", fontsize=12, pad=8) ax.set_xlim(x0, x1) ax.set_ylim(y1, y0) # invert y so (0,0) is top‑left ax.set_aspect("equal") ax.axis("off") # ------------------------------------------------------------------ # 2. Empty image artists (one per axis) # ------------------------------------------------------------------ image_artists = [ ax.imshow( np.zeros_like(image), # full‑sized buffer (fastest, no re‑alloc) cmap="gray", vmin=0, vmax=255, ) for ax in axes ] # ------------------------------------------------------------------ # 3. Animation driver # ------------------------------------------------------------------ rotation_step = ROTATION_STEP_DEG # ° per frame interval_ms = INTERVAL_MS # interval in ms total_frames = 360 // rotation_step # one full revolution def animate(frame): angle = frame * rotation_step for artist, deg in zip(image_artists, degrees): rotated, mask = rotate_and_mask( image, angle=angle, degree=deg, center=center, radius=radius, ) artist.set_data(rotated) artist.set_alpha(mask.astype(float)) return image_artists return animation.FuncAnimation( fig, animate, frames=total_frames, interval=interval_ms, blit=True, ) # Create the animation ani = create_combined_animation(image_resized, center=custom_center, radius=radius) .. container:: sphx-glr-animation .. raw:: html .. GENERATED FROM PYTHON SOURCE LINES 167-172 Export the Animation -------------------- Writes into: /_static/animations/ Does nothing when the file is run normally by users. .. GENERATED FROM PYTHON SOURCE LINES 172-181 .. code-block:: Python from splineops.utils.sphinx import export_animation_mp4_and_html export_animation_mp4_and_html( ani, stem="rotation_animation", interval_ms=INTERVAL_MS, dpi=80, force=True, ) .. rst-class:: sphx-glr-script-out .. code-block:: none (PosixPath('/home/runner/work/splineops/splineops/docs/_build/_generated_static/animations/rotation_animation.mp4'), PosixPath('/home/runner/work/splineops/splineops/docs/_build/_generated_static/animations/rotation_animation.html')) .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 39.288 seconds) .. _sphx_glr_download_auto_examples_03_affine_02_rotation_animation.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: binder-badge .. image:: images/binder_badge_logo.svg :target: https://mybinder.org/v2/gh/splineops/splineops.github.io/main?urlpath=lab/tree/notebooks_binder/auto_examples/03_affine/02_rotation_animation.ipynb :alt: Launch binder :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: 02_rotation_animation.ipynb <02_rotation_animation.ipynb>` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: 02_rotation_animation.py <02_rotation_animation.py>` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: 02_rotation_animation.zip <02_rotation_animation.zip>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_