Video Stabilisation - iffatAGheyas/computer-vision-handbook GitHub Wiki

🎥 Video Stabilization

Video stabilization removes unwanted camera shake or jitter from a video, making it appear smoother and more professional.

Think of it as a virtual tripod—keeping the subject steady even if the camera moves.


📦 Where It’s Used

  • Action cameras (e.g., GoPro)
  • Drones
  • Mobile phone videos
  • Surveillance footage

🔍 How It Works (Conceptually)

  1. Track motion across frames (feature tracking or optical flow)
  2. Estimate global camera movement (e.g. translation, rotation)
  3. Smooth the trajectory over time (low‐pass filtering)
  4. Apply correction transforms to each frame

✅ Step-by-Step Pipeline

Step Task OpenCV Tool
1 Detect motion between frames Optical Flow / Feature Matching
2 Estimate transformation (e.g. affine) cv2.estimateAffinePartial2D()
3 Accumulate and smooth trajectory NumPy math
4 Apply inverse transform to stabilise cv2.warpAffine()

🧪 Code: Basic Video Stabilization (Translation Only)

This version:

  • Uses goodFeaturesToTrack for feature detection
  • Estimates affine transforms (translation + rotation)
  • Stabilises via accumulated motion smoothing
import cv2
import numpy as np

cap = cv2.VideoCapture("baby.mp4")
ret, prev = cap.read()
prev_gray = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY)

transforms = []
fourcc = cv2.VideoWriter_fourcc(*"XVID")
fps    = int(cap.get(cv2.CAP_PROP_FPS))
w      = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h      = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
out    = cv2.VideoWriter("stabilized.avi", fourcc, fps, (w, h))

while True:
    ret, curr = cap.read()
    if not ret:
        break

    curr_gray = cv2.cvtColor(curr, cv2.COLOR_BGR2GRAY)

    # 1. Feature tracking
    prev_pts = cv2.goodFeaturesToTrack(
        prev_gray, maxCorners=200,
        qualityLevel=0.01, minDistance=30, blockSize=3
    )
    curr_pts, status, _ = cv2.calcOpticalFlowPyrLK(
        prev_gray, curr_gray, prev_pts, None
    )

    # 2. Estimate affine transform
    m, _ = cv2.estimateAffinePartial2D(
        prev_pts[status == 1],
        curr_pts[status == 1]
    )

    # 3. Extract translation components and accumulate
    dx = m[0, 2]
    dy = m[1, 2]
    transforms.append((dx, dy))

    # 4. Build inverse transform matrix
    m_inv = np.vstack([m, [0, 0, 1]])  # to 3×3
    m_inv[0:2, 2] *= -1                # reverse translation
    m_inv = m_inv[0:2, :]

    # 5. Apply to stabilise
    stabilized = cv2.warpAffine(curr, m_inv, (w, h))

    out.write(stabilized)
    cv2.imshow("Stabilized Video", stabilized)
    if cv2.waitKey(10) & 0xFF == 27:
        break

    prev_gray = curr_gray.copy()

cap.release()
out.release()
cv2.destroyAllWindows()

🔍 Output

  • Input video: shaky or jittery
  • Output video: stored as stabilized.avi, noticeably smoother

Summary

Step Purpose
Feature Tracking Find matching points in each frame
Estimate Transform Determine how the camera moved
Inverse Warp Shift frame to compensate motion
Write Output Save the stabilized video