0
# Video Analysis and Object Tracking
1
2
OpenCV provides powerful capabilities for analyzing motion in video sequences, tracking objects across frames, and modeling temporal dynamics. These tools enable applications ranging from surveillance and activity recognition to augmented reality and autonomous navigation.
3
4
## Capabilities
5
6
### Optical Flow
7
8
Optical flow algorithms estimate the motion of pixels or features between consecutive frames, providing dense or sparse motion vectors that describe scene dynamics.
9
10
#### Lucas-Kanade Sparse Optical Flow
11
12
```python { .api }
13
next_pts, status, err = cv2.calcOpticalFlowPyrLK(
14
prevImg, nextImg, prevPts, nextPts,
15
winSize=None, maxLevel=None, criteria=None,
16
flags=None, minEigThreshold=None
17
)
18
```
19
20
Calculates sparse optical flow using the iterative Lucas-Kanade method with pyramids. Tracks a sparse set of feature points from one frame to the next.
21
22
**Parameters:**
23
- `prevImg`: First 8-bit input image (grayscale)
24
- `nextImg`: Second input image of the same size and type
25
- `prevPts`: Vector of 2D points for which flow needs to be found (Nx1x2 or Nx2 array)
26
- `nextPts`: Output vector of 2D points (with single-precision floating-point coordinates)
27
- `winSize`: Size of the search window at each pyramid level (default: (21, 21))
28
- `maxLevel`: 0-based maximal pyramid level number (default: 3)
29
- `criteria`: Termination criteria for iterative search (default: 30 iterations or 0.01 epsilon)
30
- `flags`: Operation flags (e.g., cv2.OPTFLOW_USE_INITIAL_FLOW, cv2.OPTFLOW_LK_GET_MIN_EIGENVALS)
31
- `minEigThreshold`: Minimum eigenvalue threshold for feature selection (default: 1e-4)
32
33
**Returns:**
34
- `next_pts`: Calculated new positions of input features in second image
35
- `status`: Status vector (1 if flow found, 0 otherwise)
36
- `err`: Error vector containing the difference between patches around original and moved points
37
38
**Example:**
39
```python
40
# Detect good features to track
41
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
42
prev_pts = cv2.goodFeaturesToTrack(prev_gray, maxCorners=100, qualityLevel=0.3, minDistance=7)
43
44
# Calculate optical flow
45
next_gray = cv2.cvtColor(next_frame, cv2.COLOR_BGR2GRAY)
46
next_pts, status, err = cv2.calcOpticalFlowPyrLK(prev_gray, next_gray, prev_pts, None)
47
48
# Select good points
49
good_new = next_pts[status == 1]
50
good_old = prev_pts[status == 1]
51
```
52
53
#### Farneback Dense Optical Flow
54
55
```python { .api }
56
flow = cv2.calcOpticalFlowFarneback(
57
prev, next, flow, pyr_scale, levels, winsize,
58
iterations, poly_n, poly_sigma, flags
59
)
60
```
61
62
Computes dense optical flow using the Gunnar Farneback's algorithm. Produces a flow field for every pixel in the image.
63
64
**Parameters:**
65
- `prev`: First 8-bit single-channel input image
66
- `next`: Second input image of the same size and type
67
- `flow`: Computed flow image (same size as prev, 2-channel float)
68
- `pyr_scale`: Pyramid scale (< 1), typical value: 0.5 (each layer is half the size)
69
- `levels`: Number of pyramid layers including the initial image
70
- `winsize`: Averaging window size (larger = more robust to noise but more blurred)
71
- `iterations`: Number of iterations at each pyramid level
72
- `poly_n`: Size of pixel neighborhood used for polynomial expansion (typically 5 or 7)
73
- `poly_sigma`: Standard deviation for Gaussian used to smooth derivatives (typically 1.1 or 1.5)
74
- `flags`: Operation flags (cv2.OPTFLOW_USE_INITIAL_FLOW, cv2.OPTFLOW_FARNEBACK_GAUSSIAN)
75
76
**Returns:**
77
- `flow`: 2-channel array containing horizontal (dx) and vertical (dy) flow vectors
78
79
**Example:**
80
```python
81
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
82
next_gray = cv2.cvtColor(next_frame, cv2.COLOR_BGR2GRAY)
83
84
flow = cv2.calcOpticalFlowFarneback(
85
prev_gray, next_gray, None,
86
pyr_scale=0.5, levels=3, winsize=15,
87
iterations=3, poly_n=5, poly_sigma=1.2, flags=0
88
)
89
90
# Visualize flow with HSV color encoding
91
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
92
hsv = np.zeros((flow.shape[0], flow.shape[1], 3), dtype=np.uint8)
93
hsv[..., 0] = ang * 180 / np.pi / 2
94
hsv[..., 1] = 255
95
hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
96
flow_rgb = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
97
```
98
99
#### Optical Flow Pyramid
100
101
```python { .api }
102
pyramid = cv2.buildOpticalFlowPyramid(
103
img, winSize, maxLevel,
104
withDerivatives=True, pyrBorder=None,
105
derivBorder=None, tryReuseInputImage=True
106
)
107
```
108
109
Constructs a pyramid which can be used as input for subsequent optical flow calculations. Pre-building pyramids improves performance when tracking multiple features.
110
111
**Parameters:**
112
- `img`: 8-bit input image
113
- `winSize`: Window size for optical flow
114
- `maxLevel`: 0-based maximal pyramid level number
115
- `withDerivatives`: Flag to specify whether to precompute gradients
116
- `pyrBorder`: Border mode for pyramid layers (default: cv2.BORDER_REFLECT_101)
117
- `derivBorder`: Border mode for derivatives (default: cv2.BORDER_CONSTANT)
118
- `tryReuseInputImage`: Optimization flag to reuse input image
119
120
**Returns:**
121
- `pyramid`: Output pyramid list
122
123
**Example:**
124
```python
125
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
126
pyramid = cv2.buildOpticalFlowPyramid(
127
gray, winSize=(21, 21), maxLevel=3,
128
withDerivatives=True
129
)
130
```
131
132
#### Optical Flow File I/O
133
134
```python { .api }
135
flow = cv2.readOpticalFlow(path)
136
```
137
138
Read optical flow from a .flo file.
139
140
**Parameters:**
141
- `path` (str): Path to the file to be loaded
142
143
**Returns:**
144
- `flow`: Optical flow field as CV_32FC2 matrix (2-channel float). First channel corresponds to the flow in the horizontal direction (u), second - vertical (v)
145
146
**Example:**
147
```python
148
# Read optical flow from file
149
flow = cv2.readOpticalFlow('flow.flo')
150
print(f'Flow shape: {flow.shape}') # (height, width, 2)
151
152
# Extract horizontal and vertical components
153
flow_x = flow[..., 0] # u component
154
flow_y = flow[..., 1] # v component
155
```
156
157
---
158
159
```python { .api }
160
success = cv2.writeOpticalFlow(path, flow)
161
```
162
163
Write optical flow to a .flo file on disk.
164
165
**Parameters:**
166
- `path` (str): Path to the file to be written
167
- `flow`: Flow field to be stored. Must be CV_32FC2 (2-channel float). First channel corresponds to the flow in the horizontal direction (u), second - vertical (v)
168
169
**Returns:**
170
- `success` (bool): True on success, False otherwise
171
172
**Example:**
173
```python
174
# Calculate optical flow
175
flow = cv2.calcOpticalFlowFarneback(prev_gray, next_gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)
176
177
# Save to file
178
success = cv2.writeOpticalFlow('flow.flo', flow)
179
if success:
180
print('Flow saved successfully')
181
182
# Later, read it back
183
loaded_flow = cv2.readOpticalFlow('flow.flo')
184
```
185
186
### Background Subtraction
187
188
Background subtraction algorithms model the static background and identify moving foreground objects, essential for surveillance and object detection in static camera scenarios.
189
190
#### MOG2 Background Subtractor
191
192
```python { .api }
193
cv2.BackgroundSubtractorMOG2
194
```
195
196
Gaussian Mixture-based Background/Foreground Segmentation Algorithm. An improved adaptive algorithm that models each pixel as a mixture of Gaussians and selects appropriate components to represent the background.
197
198
**Key Methods:**
199
- `apply(image, fgmask=None, learningRate=-1)`: Compute foreground mask
200
- `getBackgroundImage(backgroundImage=None)`: Compute background image
201
- `setHistory(history)`: Set number of frames in history
202
- `setVarThreshold(threshold)`: Set variance threshold for pixel-model matching
203
- `setDetectShadows(detect)`: Enable/disable shadow detection
204
205
**Example:**
206
```python
207
bg_subtractor = cv2.createBackgroundSubtractorMOG2(
208
history=500, varThreshold=16, detectShadows=True
209
)
210
211
while True:
212
ret, frame = cap.read()
213
if not ret:
214
break
215
216
fg_mask = bg_subtractor.apply(frame)
217
218
# Optional: get background image
219
bg_image = bg_subtractor.getBackgroundImage()
220
```
221
222
#### KNN Background Subtractor
223
224
```python { .api }
225
cv2.BackgroundSubtractorKNN
226
```
227
228
K-nearest neighbors based Background/Foreground Segmentation Algorithm. Uses k-nearest neighbors to classify pixels as background or foreground.
229
230
**Key Methods:**
231
- `apply(image, fgmask=None, learningRate=-1)`: Compute foreground mask
232
- `getBackgroundImage(backgroundImage=None)`: Compute background image
233
- `setHistory(history)`: Set number of frames in history
234
- `setDist2Threshold(threshold)`: Set threshold on squared distance
235
- `setDetectShadows(detect)`: Enable/disable shadow detection
236
237
**Example:**
238
```python
239
bg_subtractor = cv2.createBackgroundSubtractorKNN(
240
history=500, dist2Threshold=400.0, detectShadows=True
241
)
242
243
fg_mask = bg_subtractor.apply(frame, learningRate=0.01)
244
```
245
246
#### Creating Background Subtractors
247
248
```python { .api }
249
bg_subtractor = cv2.createBackgroundSubtractorMOG2(
250
history=500, varThreshold=16, detectShadows=True
251
)
252
```
253
254
Creates a MOG2 background subtractor.
255
256
**Parameters:**
257
- `history`: Length of history (number of frames)
258
- `varThreshold`: Threshold on squared Mahalanobis distance between pixel and model
259
- `detectShadows`: If True, algorithm detects and marks shadows (slower but more accurate)
260
261
**Returns:**
262
- Background subtractor object
263
264
```python { .api }
265
bg_subtractor = cv2.createBackgroundSubtractorKNN(
266
history=500, dist2Threshold=400.0, detectShadows=True
267
)
268
```
269
270
Creates a KNN background subtractor.
271
272
**Parameters:**
273
- `history`: Length of history
274
- `dist2Threshold`: Threshold on squared distance between pixel and sample
275
- `detectShadows`: If True, algorithm detects and marks shadows
276
277
**Returns:**
278
- Background subtractor object
279
280
**Comparison Example:**
281
```python
282
# MOG2 - better for complex scenarios, detects shadows
283
mog2 = cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=16, detectShadows=True)
284
285
# KNN - faster, good for simpler scenarios
286
knn = cv2.createBackgroundSubtractorKNN(history=500, dist2Threshold=400, detectShadows=False)
287
288
# Apply both and compare
289
fg_mask_mog2 = mog2.apply(frame)
290
fg_mask_knn = knn.apply(frame)
291
```
292
293
### Mean Shift Tracking
294
295
Mean shift algorithms iteratively move a search window toward regions of higher density, useful for tracking objects based on color histograms or appearance models.
296
297
#### Mean Shift
298
299
```python { .api }
300
retval, window = cv2.meanShift(
301
probImage, window, criteria
302
)
303
```
304
305
Finds the object center using mean shift algorithm. The algorithm shifts a window to the location with maximum probability density.
306
307
**Parameters:**
308
- `probImage`: Back projection of the object histogram (probability map)
309
- `window`: Initial search window (x, y, width, height)
310
- `criteria`: Stop criteria (type, max iterations, epsilon)
311
312
**Returns:**
313
- `retval`: Number of iterations performed
314
- `window`: Converged window position (x, y, width, height)
315
316
**Example:**
317
```python
318
# Setup the initial tracking window
319
x, y, w, h = 300, 200, 100, 150
320
track_window = (x, y, w, h)
321
322
# Calculate histogram of ROI
323
roi = frame[y:y+h, x:x+w]
324
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
325
mask = cv2.inRange(hsv_roi, np.array((0., 60., 32.)), np.array((180., 255., 255.)))
326
roi_hist = cv2.calcHist([hsv_roi], [0], mask, [180], [0, 180])
327
cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)
328
329
# Tracking loop
330
while True:
331
ret, frame = cap.read()
332
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
333
dst = cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)
334
335
# Apply meanshift
336
ret, track_window = cv2.meanShift(dst, track_window,
337
(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1))
338
339
x, y, w, h = track_window
340
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
341
```
342
343
#### CamShift (Continuously Adaptive Mean Shift)
344
345
```python { .api }
346
rotated_rect, window = cv2.CamShift(
347
probImage, window, criteria
348
)
349
```
350
351
Continuously Adaptive Mean Shift algorithm. An extension of mean shift that adapts the size and orientation of the search window based on the zeroth moment.
352
353
**Parameters:**
354
- `probImage`: Back projection of the object histogram
355
- `window`: Initial search window (x, y, width, height)
356
- `criteria`: Stop criteria for iterative algorithm
357
358
**Returns:**
359
- `rotated_rect`: Rotated rectangle containing position, size, and angle ((x, y), (width, height), angle)
360
- `window`: Converged window position (x, y, width, height)
361
362
**Example:**
363
```python
364
# Similar setup as meanShift
365
track_window = (x, y, w, h)
366
367
# Tracking loop
368
while True:
369
ret, frame = cap.read()
370
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
371
dst = cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)
372
373
# Apply CamShift
374
ret, track_window = cv2.CamShift(dst, track_window,
375
(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1))
376
377
# Draw rotated rectangle
378
pts = cv2.boxPoints(ret)
379
pts = np.int0(pts)
380
cv2.polylines(frame, [pts], True, (0, 255, 0), 2)
381
```
382
383
### Object Tracking
384
385
OpenCV provides multiple tracking algorithms with different trade-offs between speed and accuracy. Modern trackers can handle occlusions, scale changes, and appearance variations.
386
387
#### Tracker Base Class
388
389
```python { .api }
390
cv2.Tracker
391
```
392
393
Base class for visual object tracking algorithms (legacy API). Provides a common interface for all tracker implementations.
394
395
**Common Methods:**
396
- `init(image, boundingBox)`: Initialize tracker with image and bounding box
397
- `update(image)`: Update tracker state with new frame
398
- `empty()`: Check if tracker is empty
399
- `clear()`: Clear internal state
400
401
#### DaSiamRPN Tracker
402
403
```python { .api }
404
cv2.TrackerDaSiamRPN
405
```
406
407
Distractor-aware Siamese Region Proposal Network tracker. State-of-the-art deep learning tracker with high accuracy, particularly robust to distractors and appearance changes.
408
409
**Creation:**
410
```python
411
tracker = cv2.TrackerDaSiamRPN_create()
412
```
413
414
**Example:**
415
```python
416
# Initialize tracker
417
tracker = cv2.TrackerDaSiamRPN_create()
418
bbox = cv2.selectROI('Select Object', frame, fromCenter=False)
419
tracker.init(frame, bbox)
420
421
# Tracking loop
422
while True:
423
ret, frame = cap.read()
424
success, bbox = tracker.update(frame)
425
426
if success:
427
x, y, w, h = [int(v) for v in bbox]
428
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
429
```
430
431
#### MIL Tracker
432
433
```python { .api }
434
cv2.TrackerMIL
435
```
436
437
Multiple Instance Learning tracker. Uses an online learning approach that updates the appearance model during tracking. Good balance between accuracy and speed.
438
439
**Creation:**
440
```python
441
tracker = cv2.TrackerMIL_create()
442
```
443
444
**Characteristics:**
445
- Good tracking performance
446
- Handles partial occlusions well
447
- Moderate computational cost
448
- Suitable for real-time applications
449
450
#### KCF Tracker
451
452
```python { .api }
453
cv2.TrackerKCF
454
```
455
456
Kernelized Correlation Filters tracker. Fast and efficient tracker using correlation filters in Fourier domain. Good for objects with limited appearance variation.
457
458
**Creation:**
459
```python
460
tracker = cv2.TrackerKCF_create()
461
```
462
463
**Characteristics:**
464
- Very fast
465
- Good accuracy for rigid objects
466
- Struggles with fast motion and scale changes
467
- Excellent for real-time tracking
468
469
#### CSRT Tracker
470
471
```python { .api }
472
cv2.TrackerCSRT
473
```
474
475
Discriminative Correlation Filter tracker with Channel and Spatial Reliability (CSRT). More accurate than KCF but slower, uses spatial reliability maps.
476
477
**Creation:**
478
```python
479
tracker = cv2.TrackerCSRT_create()
480
```
481
482
**Characteristics:**
483
- High accuracy
484
- Handles non-rectangular objects
485
- Slower than KCF
486
- Good for complex objects
487
488
#### GOTURN Tracker
489
490
```python { .api }
491
cv2.TrackerGOTURN
492
```
493
494
Generic Object Tracking Using Regression Networks. Deep learning-based tracker trained offline on large datasets. Requires Caffe model files.
495
496
**Creation:**
497
```python
498
tracker = cv2.TrackerGOTURN_create()
499
```
500
501
**Characteristics:**
502
- Deep learning-based
503
- Very robust to appearance changes
504
- Requires model files
505
- Faster than DaSiamRPN
506
507
#### Multi-Tracker Example
508
509
```python
510
# Create multiple trackers for different objects
511
trackers = cv2.MultiTracker_create()
512
513
# Add trackers for each object
514
for bbox in bboxes:
515
tracker = cv2.TrackerKCF_create()
516
trackers.add(tracker, frame, bbox)
517
518
# Update all trackers
519
while True:
520
ret, frame = cap.read()
521
success, boxes = trackers.update(frame)
522
523
for i, box in enumerate(boxes):
524
x, y, w, h = [int(v) for v in box]
525
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
526
```
527
528
### Kalman Filter
529
530
The Kalman filter provides optimal state estimation for linear dynamic systems, widely used for predicting object positions and reducing measurement noise in tracking applications.
531
532
```python { .api }
533
cv2.KalmanFilter(dynamParams, measureParams, controlParams=0, type=CV_32F)
534
```
535
536
Kalman filter implementation for state estimation and prediction. Models system dynamics and measurement process to optimally estimate hidden states.
537
538
**Parameters:**
539
- `dynamParams`: Dimensionality of the state vector
540
- `measureParams`: Dimensionality of the measurement vector
541
- `controlParams`: Dimensionality of the control vector (default: 0)
542
- `type`: Data type (CV_32F or CV_64F)
543
544
**Key Attributes:**
545
- `statePre`: Predicted state (x'(k))
546
- `statePost`: Corrected state (x(k))
547
- `transitionMatrix`: State transition matrix (A)
548
- `measurementMatrix`: Measurement matrix (H)
549
- `processNoiseCov`: Process noise covariance matrix (Q)
550
- `measurementNoiseCov`: Measurement noise covariance matrix (R)
551
- `errorCovPre`: Priori error estimate covariance matrix (P'(k))
552
- `errorCovPost`: Posteriori error estimate covariance matrix (P(k))
553
- `gain`: Kalman gain matrix (K(k))
554
555
**Key Methods:**
556
- `predict(control=None)`: Computes predicted state
557
- `correct(measurement)`: Updates state with measurement
558
559
**Example - Tracking a Moving Point:**
560
```python
561
# Create Kalman filter for 2D point tracking
562
# State: [x, y, dx, dy], Measurement: [x, y]
563
kalman = cv2.KalmanFilter(4, 2)
564
565
# Transition matrix (constant velocity model)
566
kalman.transitionMatrix = np.array([
567
[1, 0, 1, 0], # x = x + dx
568
[0, 1, 0, 1], # y = y + dy
569
[0, 0, 1, 0], # dx = dx
570
[0, 0, 0, 1] # dy = dy
571
], dtype=np.float32)
572
573
# Measurement matrix
574
kalman.measurementMatrix = np.array([
575
[1, 0, 0, 0],
576
[0, 1, 0, 0]
577
], dtype=np.float32)
578
579
# Process and measurement noise
580
kalman.processNoiseCov = np.eye(4, dtype=np.float32) * 0.03
581
kalman.measurementNoiseCov = np.eye(2, dtype=np.float32) * 0.1
582
583
# Initialize state
584
kalman.statePost = np.array([[x], [y], [0], [0]], dtype=np.float32)
585
586
# Tracking loop
587
while True:
588
# Predict
589
prediction = kalman.predict()
590
pred_x, pred_y = int(prediction[0]), int(prediction[1])
591
592
# Get measurement (e.g., from detection)
593
measurement = np.array([[measured_x], [measured_y]], dtype=np.float32)
594
595
# Update
596
kalman.correct(measurement)
597
598
# Use prediction for display
599
cv2.circle(frame, (pred_x, pred_y), 5, (0, 255, 0), -1)
600
```
601
602
**Example - Tracking with Missing Measurements:**
603
```python
604
# When no measurement is available
605
if object_detected:
606
measurement = np.array([[x], [y]], dtype=np.float32)
607
kalman.correct(measurement)
608
609
# Always predict (even without measurement)
610
prediction = kalman.predict()
611
estimated_position = (int(prediction[0]), int(prediction[1]))
612
```
613
614
### Motion Analysis
615
616
Advanced motion analysis tools for estimating geometric transformations and aligning images based on motion models.
617
618
#### Enhanced Correlation Coefficient (ECC) Transform
619
620
```python { .api }
621
retval, warp_matrix = cv2.findTransformECC(
622
templateImage, inputImage,
623
warpMatrix, motionType,
624
criteria=None, inputMask=None,
625
gaussFiltSize=5
626
)
627
```
628
629
Finds the geometric transformation between two images by maximizing the Enhanced Correlation Coefficient. Useful for image alignment and registration.
630
631
**Parameters:**
632
- `templateImage`: Reference image (single-channel 8-bit or 32-bit float)
633
- `inputImage`: Image to align (same type and size as template)
634
- `warpMatrix`: Initial transformation matrix (2x3 for affine/euclidean, 3x3 for homography)
635
- `motionType`: Type of transformation (MOTION_TRANSLATION, MOTION_EUCLIDEAN, MOTION_AFFINE, MOTION_HOMOGRAPHY)
636
- `criteria`: Termination criteria (max iterations and epsilon)
637
- `inputMask`: Optional mask for template image
638
- `gaussFiltSize`: Size of Gaussian filter for smoothing (1 = no smoothing)
639
640
**Returns:**
641
- `retval`: Final correlation coefficient
642
- `warp_matrix`: Estimated transformation matrix
643
644
**Motion Types:**
645
- `cv2.MOTION_TRANSLATION`: Only translation (2 parameters)
646
- `cv2.MOTION_EUCLIDEAN`: Rotation + translation (3 parameters)
647
- `cv2.MOTION_AFFINE`: Affine transformation (6 parameters)
648
- `cv2.MOTION_HOMOGRAPHY`: Perspective transformation (8 parameters)
649
650
**Example - Image Stabilization:**
651
```python
652
# Reference frame
653
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
654
655
# Initialize transformation matrix
656
warp_matrix = np.eye(2, 3, dtype=np.float32)
657
658
# Current frame
659
curr_gray = cv2.cvtColor(curr_frame, cv2.COLOR_BGR2GRAY)
660
661
# Define termination criteria
662
criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 50, 0.001)
663
664
# Find transformation
665
try:
666
cc, warp_matrix = cv2.findTransformECC(
667
prev_gray, curr_gray, warp_matrix,
668
cv2.MOTION_EUCLIDEAN, criteria
669
)
670
671
# Apply transformation to stabilize
672
stabilized = cv2.warpAffine(
673
curr_frame, warp_matrix,
674
(curr_frame.shape[1], curr_frame.shape[0]),
675
flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP
676
)
677
except cv2.error:
678
print("ECC optimization failed")
679
```
680
681
**Example - Video Alignment:**
682
```python
683
# Align sequence of frames to first frame
684
first_frame = cv2.cvtColor(frames[0], cv2.COLOR_BGR2GRAY)
685
aligned_frames = [frames[0]]
686
687
for frame in frames[1:]:
688
curr_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
689
690
# Use affine transformation for better alignment
691
warp_matrix = np.eye(2, 3, dtype=np.float32)
692
693
try:
694
_, warp_matrix = cv2.findTransformECC(
695
first_frame, curr_gray, warp_matrix,
696
cv2.MOTION_AFFINE,
697
criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 100, 1e-5)
698
)
699
700
aligned = cv2.warpAffine(
701
frame, warp_matrix,
702
(frame.shape[1], frame.shape[0])
703
)
704
aligned_frames.append(aligned)
705
except:
706
aligned_frames.append(frame) # Use original if alignment fails
707
```
708
709
## See Also
710
711
- [Image Processing](image-processing.md) - Filtering and transformations used in video preprocessing
712
- [Feature Detection](feature-detection.md) - Corner and feature detection for tracking
713
- [Object Detection](object-detection.md) - Detecting objects in video frames
714
- [Camera Calibration](camera-calibration.md) - Camera calibration for accurate motion estimation
715