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)
- Track motion across frames (feature tracking or optical flow)
- Estimate global camera movement (e.g. translation, rotation)
- Smooth the trajectory over time (low‐pass filtering)
- 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 |