Chapter 14 · VSR / Frame Interpolation / Video Inpainting¶
Chapter 13 established the fundamental concepts of video enhancement: temporal consistency, optical flow, alignment.
This chapter looks at concrete models: BasicVSR++, RVRT, RIFE/FILM, video stabilization.
These models ground the concepts of Chapter 13, each with different engineering trade-offs.
14.0 Scope and prerequisites¶
From a model-design perspective, video enhancement has one fundamental constraint beyond images: the time dimension. Not only must the same object be sharp in adjacent frames, it must "line up" with itself at the pixel level, or the result visually flickers, jitters, and texture-pops. Chapter 13 already discussed how this temporal consistency is defined, why optical flow and alignment are necessary, and why bidirectional propagation is more stable than unidirectional. This chapter assumes these basics are in mind and focuses on how concrete models turn those concepts into trainable, deployable networks.
After reading you should be able to answer the following questions:
- In video super-resolution (VSR), what are the trade-offs among sliding-window, recurrent, and bidirectional structures?
- What failure modes are BasicVSR++'s "second-order propagation" and "flow-guided deformable alignment" specifically solving?
- After VRT / RVRT brought Transformers into VSR, what did they buy versus BasicVSR++, and what did they pay?
- Why does video frame interpolation (VFI) not directly reuse general optical-flow models, but instead train a dedicated IFNet that estimates "intermediate frame to both endpoints"?
- Why does video deblurring enjoy the structural advantage of "sharp copies in adjacent frames"?
- Why is old-film restoration, a craft-heavy task, handled by a multi-step pipeline rather than a single model?
Reading note: most code fragments in this chapter are skeletons (stubs) that cannot be trained directly; the goal is to spell out the architecture's key data flows. Full implementations can be found in mmagic (formerly mmediting, OpenMMLab's low-level vision toolbox) and the official repos of each project.
Abbreviations on first appearance. As in Chapter 1, the first time each abbreviation appears we give a full name in parentheses and a one-line definition:
- VSR (Video Super-Resolution): taking low-resolution video to high resolution while meeting both spatial sharpness and temporal consistency
- VFI (Video Frame Interpolation): synthesizing intermediate frames between two given frames, taking low-frame-rate video to high frame rate
- EDVR (Enhanced Deformable Video Restoration, 2019): the first sliding-window VSR using deformable conv for alignment; the NTIRE 2019 challenge winner at CVPR Workshops
- TDAN (Temporally Deformable Alignment Network): early VSR using deformable conv as an "implicit optical flow" for alignment
- BasicVSR (2021): the first VSR baseline to make bidirectional recurrence + explicit optical flow alignment a SOTA combination
- IconVSR: the "info-fused" variant from the same BasicVSR paper, which extracts multi-frame information into keyframes for subsequent propagation
- BasicVSR++ (2022): BasicVSR's upgrade, adding second-order propagation and flow-guided deformable alignment
- VRT (Video Restoration Transformer, 2022): brings window Transformers into VSR, with attention along the time axis
- RVRT (Recurrent Video Restoration Transformer, 2023): the recurrent version of VRT, replacing part of the long-range attention with recurrence to control compute
- DCN (Deformable Convolutional Network): a convolution where every kernel sampling position carries a learnable offset, letting the conv "aim at" irregular positions
- RIFE (Real-time Intermediate Flow Estimation, 2022): a VFI method that directly estimates "intermediate frame to both endpoints" flow
- IFNet (Intermediate Flow Network): the sub-network in RIFE dedicated to predicting intermediate-frame flow
- FILM (Frame Interpolation for Large Motion, Google 2022): a VFI method built on multi-scale recursive flow estimation, strong on large displacement
- AMT (All-pairs Multi-field Transforms, 2023): adds attention on top of RIFE; more robust to occlusion
- MIMO-UNet (Multi-Input Multi-Output UNet): a video deblurring architecture that processes independently at different resolutions and then fuses
- ProPainter (ICCV 2023): current SOTA video inpainting method; inpaints flow first, then frames
- E2FGVI (End-to-end Flow-Guided Video Inpainting, CVPR 2022): end-to-end flow-guided video inpainting
- GOP (Group of Pictures): in video coding, a group of frames starting from one I-frame and forming an independent decoding unit
- REDS (Realistic and Dynamic Scenes): the standard VSR dataset from NTIRE 2019, 270 training + 30 test clips
- VMAF (Video Multi-Method Assessment Fusion): the video-quality metric Netflix released in 2016, fusing several sub-metrics, trained on real human ratings
- FVD (Fréchet Video Distance): a distribution-distance metric that extends FID to video, commonly used for generative video
- tOF / tLPIPS: temporal versions of optical-flow consistency / LPIPS consistency, measuring alignment and perceptual difference between adjacent frames
- NAFNet (Nonlinear Activation Free Network, 2022): a minimal low-level vision network that replaces nonlinearity with gating multiplications
- GoPro: the de facto video-deblurring dataset; uses a 240 fps high-speed camera to average multiple frames into a synthesized "blurred frame" with the original frame as ground truth
More abbreviations are introduced inline as they appear.
14.1 Structure of this chapter¶
The four sub-tasks below are independent in video enhancement but mutually depend on one another in practice. VSR and deblurring both focus on "each frame being sharper," frame interpolation focuses on "more frames," video inpainting focuses on "content completion," and stabilization focuses on "geometric stability between frames." A real video enhancement pipeline typically chains several of them together in some order.
14.2-14.5 Video super-resolution (VSR): BasicVSR → BasicVSR++ → RVRT
14.6 Frame interpolation (VFI): RIFE, FILM, AMT
14.7 Video deblurring
14.8 Video inpainting
14.9 Video stabilization
14.10-14.11 Engineering combinations and evaluation
Each task gets one representative model plus a few engineering points. This chapter does not aim to cover every method - only the main threads that are still being used in production environments in 2024-2026.
14.2 The evolution of video super-resolution (VSR)¶
The VSR evolution path is similar to image SR but two years later:
2017 VESPCN - first end-to-end VSR
2018 TDAN - implicit alignment (DCN)
2019 EDVR - sliding window + DCN alignment
2020 RBPN - recurrent + multi-frame compensation
2021 BasicVSR - bidirectional recurrent + explicit optical flow alignment
2022 BasicVSR++ - second-order propagation + flow-guided DCN
2022 VRT - temporal Transformer
2023 RVRT - efficient recurrent Transformer
BasicVSR++ is the de facto standard for 2022-2024 - simple, strong, fast. Detailed below.
Three VSR architectures compared¶
Compressing the timeline above into structure, you can see that VSR models mainly choose among three "temporal aggregation modes," each corresponding to a particular engineering trade-off:
- Sliding window (EDVR-style): to output one frame, independently take N frames around it (typical N = 5 or 7), align them to the center frame, and fuse. Pros: simple structure, direct training, naturally supports random access. Costs: no explicit feature reuse between adjacent output frames, so long-range temporal information has to be stacked by enlarging the window.
- Recurrent (the forward direction of BasicVSR): maintain a hidden state \(h_t\) that updates along the time direction; each frame computes a new \(h_t\) from \(h_{t-1}\) and the current frame's features. Pros: long-range information is packed into the hidden state, VRAM-friendly, compute-efficient. Costs: a unidirectional RNN cannot see future frames, with a ceiling on detail recovery when motion is in the reverse direction.
- Bidirectional (BasicVSR / BasicVSR++): run two RNNs in parallel, forward and backward, and at each time step fuse the two hidden states. Pros: any frame has access to both past and future information; best long-range temporal consistency. Costs: must have the whole clip (or a sufficiently long buffer) to run; real-time settings are limited.
The diagram below shows all three modes in one place, noting carefully the direction of arrows and where aggregation happens:
graph TB
subgraph SW[Sliding window: EDVR style]
SW1[t-2] --> SWA[align + fuse]
SW2[t-1] --> SWA
SW3[t center] --> SWA
SW4[t+1] --> SWA
SW5[t+2] --> SWA
SWA --> SWO[output frame t]
end
subgraph RC[Recurrent unidirectional: BasicVSR forward]
RC1[frame t-2] --> RCH1[h_t-2]
RCH1 --> RCH2[h_t-1]
RC2[frame t-1] --> RCH2
RCH2 --> RCH3[h_t]
RC3[frame t] --> RCH3
RCH3 --> RCO[output frame t]
end
subgraph BD[Bidirectional: BasicVSR / BasicVSR++]
BD1[frame t] --> BDF[forward h^f_t]
BD1 --> BDB[backward h^b_t]
BDFprev[h^f_t-1] --> BDF
BDBnext[h^b_t+1] --> BDB
BDF --> BDM[fuse]
BDB --> BDM
BDM --> BDO[output frame t]
end
style SWO fill:#e3f2fd
style RCO fill:#fff3e0
style BDO fill:#e8f5e9
Selection rules in engineering:
- Offline video files with sensitivity to a quality ceiling (restoration, editing, transcoding enhancement) → bidirectional.
- Real-time streams (livestreaming, video conferencing, AR pass-through): must be causal recurrent (only history allowed); bidirectional is not available.
- Image sequences with weak scene continuity (e.g. batch-enhancement of slides): sliding window is more robust than RNN, because the hidden state gets polluted at scene cuts.
These three modes are not mutually exclusive: BasicVSR++'s overall structure is essentially "bidirectional + second-order propagation + DCN-corrected flow," while the later RVRT mixes "recurrence + cross-frame attention." Architectural differences mainly determine VRAM footprint, latency, future-frame dependency, and cross-scene robustness.
14.3 BasicVSR++ in detail¶
Chan et al. proposed BasicVSR++ in 2022, a representative of the bidirectional recurrent architecture from Chapter 13, Section 13.8. Its design choices remain the first-pick baseline for most 2024-2026 VSR products (offline video transcoding enhancement, long-video post-processing), because the structure is simple, training is stable, and inference VRAM is predictable.
Overall structure¶
Feature extraction
LR frames ─────────────→ feature maps F_t
│
↓
┌─────────────────────┴─────────────────────┐
│ │
▼ Forward propagation ▼ Backward propagation
h^f_1 ─→ h^f_2 ─→ ... ─→ h^f_T h^b_T ─→ h^b_{T-1} ─→ ... ─→ h^b_1
Each step aligns the previous hidden state with optical flow
│ │
└─────────────────────┬─────────────────────┘
↓
Aggregation (concat + conv)
│
↓
Upsample (PixelShuffle)
│
↓
HR frames
Key innovation 1: second-order propagation¶
A plain bidirectional RNN uses only the previous step at each step:
BasicVSR++ uses second-order:
Why does this help?
- First-order: \(h_{t-1}\) is warped from \(h_{t-2}\), which was warped from earlier ones; optical flow errors accumulate along the way
- Second-order: directly access \(h_{t-2}\), bypassing the accumulated error of \(h_{t-1}\)
- Corrects local errors of the optical flow
Key innovation 2: Flow-Guided Deformable Alignment¶
Combines optical flow with deformable convolution. Before reading the code, let us spell out the data flow. "Flow-guided" means first warp the previous hidden state into the current frame's viewpoint using optical flow, then let the DCN refine the warped features locally; the DCN offsets are not learned from zero but are a small correction on top of the flow.
The diagram below traces the chain of "warp + occlusion mask + DCN refinement":
graph LR
HPrev[previous hidden state h_t-1] --> Warp[backward warp<br/>resample with flow f_t-1 → t]
Flow[flow f_t-1 → t<br/>estimated by SPyNet] --> Warp
Ft[current frame features F_t] --> OffsetNet[offset prediction network<br/>input warped_h + F_t + flow]
Warp --> OffsetNet
Flow --> OffsetNet
OffsetNet --> Sum[offset = flow + learned correction]
Flow --> Sum
Sum --> DCN[Deformable Conv<br/>sample h_t-1 at corrected positions]
HPrev --> DCN
DCN --> Mask[occlusion mask<br/>weaken contribution in occluded areas]
Ft --> Mask
Mask --> Out[aligned features<br/>passed to recurrent unit]
style Warp fill:#fff3e0
style DCN fill:#e3f2fd
style Mask fill:#ffebee
The occlusion mask is usually learned implicitly as an extra DCN channel, or computed directly from the forward-backward consistency error of the flow (large error → treat as occlusion, downweighting the warped features).
Why "flow + DCN" is more robust than flow alone:
- Use optical flow to give the deformable convolution an initial sampling position, effectively injecting physical meaning into the DCN
- Let the DCN learn a correction to the flow; when the flow is one or two pixels off, the DCN can still pull it back
- In fast-motion / partial-occlusion settings, pure flow warping produces obvious ghosting; DCN's multi-point sampling mitigates this
class FlowGuidedDCN(nn.Module):
"""Flow-guided deformable alignment (BasicVSR++)."""
def __init__(self, channels: int, num_groups: int = 8):
super().__init__()
# Predict the DCN offset correction (relative to optical flow)
self.offset_conv = nn.Conv2d(
channels * 2 + 2, # h_prev + features + flow
num_groups * 2 * 9, # 9 sampling points × 2 dims × num_groups
3, padding=1,
)
# The actual deformable conv (using torchvision's DeformConv2d here)
from torchvision.ops import DeformConv2d
self.dcn = DeformConv2d(channels, channels, 3, padding=1, groups=num_groups)
def forward(self, h_prev, features_t, flow):
"""
h_prev: previous hidden state (B, C, H, W)
features_t: current frame features (B, C, H, W)
flow: optical flow (B, 2, H, W)
"""
# 1. Use flow to first warp h_prev to the current viewpoint
warped_h = warp_with_flow(h_prev, flow)
# 2. Network predicts DCN offset (correction)
x = torch.cat([warped_h, features_t, flow], dim=1)
offsets = self.offset_conv(x)
# offsets shape: (B, num_groups * 2 * 9, H, W)
# 3. Add the optical flow as the offset baseline (important!)
# Make the DCN start from the flow's position; what it learns is the correction
offsets = offsets + flow.repeat(1, offsets.shape[1] // 2, 1, 1)
# 4. DCN samples at the corrected positions
return self.dcn(h_prev, offsets)
Advantages of the flow + DCN combination: optical flow provides physical meaning, DCN provides local correction capability, more stable than pure flow on fast-moving / partial-occlusion scenes. Put this mechanism inside the second-order propagation and the effects compound: second-order reduces accumulated flow error, flow-guided DCN reduces single-step flow error, and the temporal consistency over a clip improves substantially.
Training BasicVSR++¶
- Datasets: REDS (240 video clips) + Vimeo-90K + self-synthesized degraded pairs
- Degradation: MM-CelebA-style video degradation + REDS-standard motion blur and compression
- Loss: primarily Charbonnier reconstruction loss (on every output frame). Temporal consistency emerges naturally from the architectural inductive bias of bidirectional propagation + flow-guided alignment, rather than from an explicit temporal loss term
- Training duration: 1.6M steps on 8× A100, about 10 days
Performance¶
On REDS4 4× VSR, PSNR is ~32.4 dB, clearly higher than EDVR (31.1) and BasicVSR (31.4). At the same time it stays real-time, about 30 ms per frame on an A100.
14.4 Training data for VSR¶
Data requirements for VSR are higher than for image SR:
| Dataset | Number of videos | Resolution | Use |
|---|---|---|---|
| REDS | 270 (train) + 30 (test) | 720P | General VSR standard |
| Vimeo-90K | 64,612 7-frame clips | 448×256 | Frame interpolation + VSR |
| Vid4 | 4 clips | 720P | Test |
| UDM10 | 10 clips | 1080P | Test |
| YouHQ40 | 40 4K clips | 4K | Real high-quality |
Video degradation synthesis¶
def synthesize_video_pair(hr_video):
"""Synthesize an LR training pair from an HR video."""
# 1. Temporally consistent degradation (same parameters across the clip)
blur_kernel = sample_blur_kernel() # fixed for one clip
noise_sigma = sample_noise_sigma() # fixed for one clip
lr_frames = []
for hr_frame in hr_video:
x = apply_blur(hr_frame, blur_kernel)
x = downsample(x, scale=4)
x = add_noise(x, noise_sigma)
lr_frames.append(x)
lr_video = torch.stack(lr_frames)
# 2. Video-specific degradation (whole clip together)
lr_video = h264_compression(lr_video, bitrate=random.uniform(500, 5000))
return lr_video
Note: degradation parameters are fixed for one clip. This is where it differs from images: if each frame uses different degradation parameters, the model learns a "different degradation every frame" distribution, and at inference time it actually amplifies the tiny inter-frame degradation differences into temporal flicker.
14.5 VRT and RVRT: Video Restoration Transformer¶
Liang et al. proposed VRT in 2022 and improved it to RVRT in 2023. This line brings Transformers into VSR; the corresponding idea is "drop the serial dependency of the RNN's hidden state and let all frames see each other through attention." Its prominence comes from two facts: it beats BasicVSR++ on SOTA benchmarks by about 0.5 dB; its implementation complexity and VRAM pressure are also notably higher.
Core idea¶
Drop the recurrent RNN and directly use self-attention to aggregate across frames:
Compute¶
Naive multi-frame attention has complexity that explodes - attention over 5 frames of \(H \times W\) is \((5HW)^2\), 25× more than a single-frame \((HW)^2\). VRT's engineering work splits attention along two axes:
- Window spatial attention: first run self-attention within local windows of each frame (continuing the Swin 7×7 or 8×8 windows), reducing spatial complexity from \((HW)^2\) to \(HW \cdot w^2\) where \(w\) is the window edge.
- Temporal-axis attention: treat the T tokens at the same spatial position as a sequence and attend over them; length drops from \(T \cdot HW\) to \(T\).
RVRT, building on VRT, adds another layer of "recurrence": chunk the whole clip into segments, use VRT-style attention within each segment, and use a recurrent connection between segments to pass hidden state, further compressing compute. The design is effectively a compromise between "fully recurrent (BasicVSR++)" and "fully attention (VRT)."
VRT vs BasicVSR++¶
| Dimension | BasicVSR++ | VRT/RVRT |
|---|---|---|
| Performance | Strong | Stronger (PSNR +0.5 dB) |
| Speed | Fast | Slow (2-3×) |
| Memory | Medium | Large (attention) |
| Real-time | Possible | Difficult |
| Implementation complexity | Simple | Complex |
Engineering practice in 2026:
- Offline high-quality enhancement: RVRT or VRT
- Real-time / near real-time: BasicVSR++
- On-device: BasicVSR or lighter
14.6 Frame interpolation (VFI)¶
Frame interpolation is another video task: taking a low frame-rate video to a high frame rate (24 fps → 60 fps, 60 fps → 240 fps).
Task definition¶
Given two adjacent frames \(F_t\) and \(F_{t+1}\), generate the intermediate frame \(F_{t+0.5}\).
Note the two different contexts of "intermediate frame":
- At inference: there is no intermediate frame in the user's video, this is the difficulty of the task
- At training: the standard practice is to take three consecutive frames from a high-FPS video (e.g. 240 fps GoPro), use the first and third as input and the second as ground truth supervision, so at training time, ground truth exists
RIFE (2022)¶
Huang et al.'s RIFE (Real-time Intermediate Flow Estimation) is the current de facto standard for frame interpolation. Core innovations:
- Does not explicitly estimate forward/backward optical flow; directly estimates the optical flow from the intermediate frame to both ends
- A single IFNet outputs both \(F_{0.5 \to 0}\) and \(F_{0.5 \to 1}\)
- Use these two flows to warp \(F_0\) and \(F_1\) respectively, fuse to obtain \(F_{0.5}\)
Why not directly reuse a general flow model like RAFT or FlowNet? The answer is that what VFI really needs is "intermediate frame to both endpoints" flow (\(F_{0.5 \to 0}\) and \(F_{0.5 \to 1}\)), whereas a general flow model gives you "frame-to-next-frame" (\(F_{0 \to 1}\)). Inverting the former from the latter requires a back-projection, and that step introduces large amounts of occlusion, holes, and sub-pixel error. RIFE's approach is to train a network that directly outputs \(F_{0.5 \to \{0, 1\}}\), skipping the back-projection.
The diagram below traces RIFE's bidirectional flow estimation + weighted fusion data flow:
graph LR
F0[frame F_0] --> IFNet[IFNet<br/>predicts bidirectional flow from intermediate frame to both ends]
F1[frame F_1] --> IFNet
IFNet --> Fto0[flow F_0.5 → 0]
IFNet --> Fto1[flow F_0.5 → 1]
IFNet --> Mask[fusion mask M ∈ 0,1]
F0 --> Warp0[backward warp]
Fto0 --> Warp0
F1 --> Warp1[backward warp]
Fto1 --> Warp1
Warp0 --> Blend[M ⊙ warp0<br/>+ 1-M ⊙ warp1]
Warp1 --> Blend
Mask --> Blend
Blend --> Refine[FusionNet refinement<br/>fix occluded regions]
F0 --> Refine
F1 --> Refine
Refine --> Mid[intermediate frame F_0.5]
style IFNet fill:#e3f2fd
style Blend fill:#fff3e0
style Mid fill:#e8f5e9
In this diagram the mask is a byproduct of IFNet; its physical meaning is "should this pixel in the intermediate frame come more from F_0 or from F_1?" In disocclusion regions (newly appearing objects) and occlusion boundaries, the mask leans toward one end; in regions visible from both sides, the mask is close to 0.5. FusionNet is a refinement network dedicated to filling holes where "both ends are occluded so warping fails."
class RIFEStub(nn.Module):
"""Simplified RIFE skeleton."""
def __init__(self):
super().__init__()
self.ifnet = IFNet() # outputs flow from intermediate frame to both ends
self.fusion_net = FusionNet() # fuses warp results
def forward(self, f0: torch.Tensor, f1: torch.Tensor) -> torch.Tensor:
"""
f0, f1: two adjacent frames (B, 3, H, W)
returns: intermediate frame f_0.5
"""
# 1. Estimate flow from intermediate frame to both ends
flow_to_0, flow_to_1, mask = self.ifnet(f0, f1)
# 2. Warp the two end frames with the flows
warped_0 = warp_with_flow(f0, flow_to_0)
warped_1 = warp_with_flow(f1, flow_to_1)
# 3. Mask-weighted fusion
f_mid = mask * warped_0 + (1 - mask) * warped_1
# 4. (Optional) final refinement with a refine network
f_mid = self.fusion_net(f_mid, f0, f1)
return f_mid
Advantages of RIFE¶
- Fast: the original RIFE runs at 30 FPS on 1080P
- Simple: a single network end-to-end
- Extensible: recursive calls give \(4\times\), \(8\times\) frame-rate boosts
FILM (Google, 2022)¶
Reda et al.'s FILM uses a different idea: multi-scale optical flow estimation + progressive synthesis:
- Does not depend on single-step optical flow estimation
- Recursively refines at multiple resolutions
- More robust to large displacement (severe-motion scenes)
In practice:
- Slow motion (ordinary video): RIFE and FILM are close
- Fast motion (sports, dance): FILM beats RIFE
AMT (2023)¶
A more recent SOTA: builds on RIFE by adding attention modules; especially strong on occlusion scenes.
Failure modes of frame interpolation¶
- Large displacement: object motion exceeds receptive field, ghosting in the interpolated result
- New objects appearing (disocclusion): the adjacent frames have no information about this object, cannot interpolate
- Semi-transparent objects: the optical flow assumption fails (glass, smoke)
- Repetitive textures: optical flow easily matches the wrong location (fences)
14.7 Video deblurring¶
The difference between video deblurring and image deblurring: adjacent frames provide a sharp reference. This is the most structural advantage that video tasks have over image tasks, and every video deblurring model essentially exploits it.
Key observation¶
Blur in video is often intermittent: one frame is blurred (instant of motion), the next is sharp (motion stopped). Exploiting this property substantially improves deblurring quality. Two typical situations:
- Motion blur from long exposure happens only in the few frames where an object moves fast; the next frame, once the object slows or stops, is sharp
- Handheld camera shake is high-frequency, the blur kernel direction changes every frame, and the sharp regions of adjacent frames tend to lie in different places
The direct engineering implication: video deblurring cannot do per-frame deconvolution like image deblurring; it must do inter-frame alignment and "borrow" sharp pixels from adjacent frames. That brings us back to the optical-flow / DCN alignment toolkit of Chapter 13.
EDVR¶
EDVR is not only the de facto classic for VSR but also a representative for video deblurring:
- Sliding window (5 or 7 frames)
- DCN alignment
- Spatio-temporal attention fusion
MIMO-UNet (multi-input multi-output)¶
Independently process at different resolutions and then fuse, covering blur at multiple scales.
Data: GoPro dataset¶
The standard benchmark for video deblurring: shoot with a high-speed camera (240 fps), average several adjacent frames to obtain a "blurred frame," with the original frame as ground truth.
14.8 Video inpainting / restoration¶
Video restoration includes two categories:
- Video inpainting: complete occluded or removed regions
- Old film restoration: remove scratches, flicker, missing frames
Video Inpainting¶
Given a video and a mask (per-frame annotations of regions to fill), output the inpainted video.
Representative methods: E2FGVI (End-to-end Flow-Guided Video Inpainting, CVPR 2022), ProPainter (ICCV 2023)
Core idea:
- Use optical flow to find the "corresponding pixels" of the mask region in other frames
- Aggregate that information into the current frame
- Use a transformer to fuse spatio-temporally
ProPainter's key improvement: a recurrent flow completion module that first inpaints the optical flow (the flow within the mask region is also missing, because there are no original pixels there from which to estimate flow), then uses the inpainted flow to guide frame inpainting. This step is critical: without inpainted flow, long-range temporal alignment is simply impossible, and when removing a person or object from an entire clip you get the failure mode where "the inpainted filler drifts across frames."
Old film restoration¶
Old film degradation has several special modes:
- Scratches: lines at random positions
- Flicker: whole-frame brightness/contrast jitter
- Missing frames: some frames are entirely missing
- Color decay: cyan/red shift
Engineering pipeline:
Step 1: Scratch removal (use the corresponding positions in adjacent frames)
Step 2: Flicker stabilization (correct inter-frame brightness)
Step 3: Missing frame inpainting (RIFE-class interpolation)
Step 4: Color recovery (Lab space statistical correction + learned color recovery)
Step 5: Enhancement (VSR + frame interpolation to 60 fps)
Representative projects:
- DeepRemaster (Iizuka & Simo-Serra 2019): old-film colorization + restoration
- Bringing Old Films Back to Life (Wan et al. 2022): full film restoration pipeline
14.9 Video stabilization¶
Shake comes from camera motion (handheld phones, action cameras). Distinguishing it from real motion is the difficulty.
Classical methods¶
- Use optical flow / feature point tracking to estimate the camera's global motion
- Smooth this global motion trajectory
- Use the smoothed trajectory to inverse-warp every frame
Original: camera shake + real scene motion
↓
Trajectory estimation + smoothing
↓
Re-warp: smoothed camera + real scene motion
Modern methods¶
- Stabnet (learned stabilization)
- Built into Google's Pixel Camera (each phone vendor has its own scheme)
- Some phones use IMU data as an auxiliary signal (gyroscope is more accurate than image-based optical flow)
The crop problem¶
Stabilization inevitably crops the edges: after warping the camera, the edges of the frame leave blank space. A typical trade-off:
- Strong stabilization: more cropping (smaller field of view)
- Weak stabilization: less cropping (field of view preserved)
14.10 Engineering combinations of video enhancement¶
Real products are usually not a single model but a pipeline:
Example: phone video post-processing (vlog enhancement)¶
Original 1080P 30fps video
↓ Stabilization (StabNet)
↓ Denoising (BasicVSR family)
↓ Frame interpolation (RIFE) → 60 fps
↓ Super-resolution (BasicVSR++) → 4K
↓ Color correction (LUT-based)
4K 60 fps enhanced video
Each step may use a different model; the whole thing runs at about 5-10× real time on a GPU (5-10 seconds = 1 second of video).
Example: livestream video enhancement¶
Strict real-time requirement (< 33ms/frame):
Original 720P 30fps live stream
↓ Lightweight denoising (small NAFNet, < 5ms)
↓ On-device super-resolution (distilled ESRGAN-Lite, < 20ms) → 1080P
↓ Color LUT (< 1ms)
1080P 30fps enhanced stream
Cannot use diffusion, cannot use heavy transformers, cannot use sliding windows (too slow); only ultra-lightweight CNNs.
Example: old film restoration (offline)¶
Real-time is not required; quality first:
Original 480P 24fps black-and-white old film
↓ Scratch removal (DeepRemaster)
↓ Flicker stabilization
↓ Colorization (DeepRemaster + manual adjustment)
↓ Restoration (Bringing Old Films Back to Life)
↓ Frame interpolation (RIFE) → 48 fps
↓ Super-resolution (Real-ESRGAN per-frame + temporal-consistency post-processing)
2K 48fps colorized restored version
14.11 Evaluating video enhancement models¶
Reviewing Chapter 13, Section 13.10, with a few concrete metrics added:
| Metric | Type | Tool |
|---|---|---|
| PSNR / SSIM | Single-frame | Standard |
| LPIPS | Single-frame perceptual | Standard |
| tOF | Temporal optical-flow consistency | Self-implemented |
| tLPIPS | Temporal perceptual consistency | Self-implemented |
| VMAF | Video quality assessment | Open-sourced by Netflix |
| FVD (Fréchet Video Distance) | Distribution distance | For generative video |
VMAF¶
Netflix's video quality metric introduced in 2016, fusing several sub-metrics (VIF, ADM, motion score), with training data from real human ratings. The standard for video quality in production.
# Invoke VMAF (with ffmpeg)
import subprocess
def compute_vmaf(reference_video, distorted_video):
"""Compute the VMAF score with ffmpeg + libvmaf."""
cmd = [
'ffmpeg', '-i', distorted_video, '-i', reference_video,
'-lavfi', 'libvmaf=log_path=vmaf.json:log_fmt=json',
'-f', 'null', '-'
]
subprocess.run(cmd)
# Parse vmaf.json
import json
with open('vmaf.json') as f:
result = json.load(f)
return result['pooled_metrics']['vmaf']['mean']
14.12 Summary¶
- VSR evolution: sliding window (EDVR) → bidirectional Recurrent (BasicVSR++) → Transformer (RVRT)
- BasicVSR++ is the de facto standard in 2024: bidirectional recurrent + second-order propagation + flow-guided DCN
- VSR has high data requirements: degradation parameters are fixed for one clip during synthesis to avoid introducing inconsistency
- The three giants of frame interpolation (VFI): RIFE (fast), FILM (strong on large displacement), AMT (strong on occlusion)
- Video deblurring exploits sharp copies in adjacent frames, an advantage image deblurring does not have
- Video restoration: old films are the classic scenario; engineering is a multi-step pipeline rather than a single model
- Video stabilization hinges on distinguishing camera shake from real motion
- The production pipeline is a combination: not a single model, but a chain of stabilization + denoising + interpolation + SR
- Real-time enhancement is strictly constrained: < 33ms/frame allows only lightweight CNNs
- VMAF is the de facto standard for production video quality assessment
This completes Part IV's two video chapters. Part V moves into engineering deployment—the previous parts covered models themselves, this part covers how to push models into production (quantization, TensorRT, CoreML, mobile, tile).
Next chapter Inference Optimization → quantization, TensorRT, CoreML, torch.compile, dynamic resolution, tile inference.