Warp a Mask with a Transformation#
Apply geometric transforms (affine, perspective) to masks.
Affine transform#
For rotation, scaling, shearing, translation:
import numpy as np
# 2x3 affine matrix (same as OpenCV)
M = np.array([
[0.9, -0.1, 10],
[0.1, 0.9, 20]
], dtype=np.float32)
warped = mask.warp_affine(M, output_imshape=(480, 640))
Perspective transform#
For 3x3 homography matrices:
# 3x3 perspective matrix
H = np.array([
[1.1, 0.1, 5],
[0.05, 1.2, 10],
[0.0001, 0.0002, 1]
], dtype=np.float32)
warped = mask.warp_perspective(H, output_imshape=(480, 640))
From OpenCV#
If you have a transform matrix from OpenCV:
import cv2
# Get affine transform from point correspondences
src_pts = np.array([[0, 0], [100, 0], [0, 100]], dtype=np.float32)
dst_pts = np.array([[10, 10], [110, 20], [5, 115]], dtype=np.float32)
M = cv2.getAffineTransform(src_pts, dst_pts)
warped = mask.warp_affine(M, output_imshape)
# Or perspective from 4 points
H = cv2.getPerspectiveTransform(src_4pts, dst_4pts)
warped = mask.warp_perspective(H, output_imshape)
Resize#
Simple scaling is a special case:
# Resize to specific dimensions
resized = mask.resize((new_height, new_width))
# Or use warp_affine with a scale matrix
scale = 0.5
M = np.array([[scale, 0, 0], [0, scale, 0]], dtype=np.float32)
resized = mask.warp_affine(M, output_imshape)
Decode-warp-encode fallback#
For complex warps not directly supported, decode to array first:
import cv2
# Decode
arr = mask.to_array()
# Warp with OpenCV (use INTER_NEAREST for binary masks)
warped_arr = cv2.warpPerspective(
arr, H, (width, height),
flags=cv2.INTER_NEAREST
)
# Re-encode
warped_mask = RLEMask.from_array(warped_arr)
Performance note#
Direct RLE warping (warp_affine, warp_perspective) avoids
decoding to a dense array. For sparse masks this can be much faster
than the decode-warp-encode approach.