Skip to content
dnjulek edited this page Jul 9, 2026 · 2 revisions

Edge-directed interpolation — an OpenCL implementation of the vapoursynth-zip CPU EEDI3's numeric core.

EEDI3 reconstructs a missing field by finding, for each interpolated pixel, the best non-crossing warping between the neighbouring lines: a dynamic program minimises a cost built from neighbourhood similarity (alpha), the vertical difference the interpolation creates (beta), the interpolation direction's length (the remaining 1-alpha-beta), and the change in direction from pixel to pixel (gamma).

This plugin exposes two functions sharing one numeric core:

  • EEDI3 — interpolates rows (the classic vertical deinterlacer / doubler).
  • EEDI3H — interpolates columns (the horizontal axis). It runs the identical kernel on a transposed copy, so it is bit-exact to Transpose → EEDI3 → Transpose.

Usage

vszipcl.EEDI3(vnode clip, int field[, bint dh=False, int mdis=20, int nrad=2, float alpha=0.2, float beta=0.25, float gamma=20.0, bint hp=False, int vcheck=2, float vthresh0=32.0, float vthresh1=64.0, float vthresh2=4.0, vnode sclip=None, int device_id=0, int num_streams=1, int[] tune])
vszipcl.EEDI3H(vnode clip, int field[, ... same arguments ...])

Both functions take the same arguments. For EEDI3 the interpolated axis is the height; for EEDI3H it is the width (so the mod-2 / dh-doubling rules apply to width instead of height).

Parameters

  • clip:
    Clip to process. 8/16-bit integer, 16-bit half, or 32-bit float; Gray / YUV / RGB.
  • field: Mode of operation and which field is kept.
    • 0 = same rate, keep bottom field
    • 1 = same rate, keep top field
    • 2 = double rate (alternates each frame), starts with bottom
    • 3 = double rate (alternates each frame), starts with top
  • dh: (Default: False)
    Doubles the size of the input along the interpolated axis (height for EEDI3, width for EEDI3H): each input line is copied to every other output line and the gaps are interpolated. field must be 0 or 1 when dh=True.
  • mdis: (Default: 20, range: 1..40)
    Maximum connection radius (search distance). Larger connects shallower slopes but is slower and more artifact-prone.
  • nrad: (Default: 2, range: 0..3)
    Radius for the neighbourhood-similarity term.
  • alpha / beta / gamma: (Default: 0.2 / 0.25 / 20.0)
    Cost weights. alpha and beta must each be in [0, 1] and alpha + beta ≤ 1; gamma ≥ 0. Larger alpha connects more lines/edges; larger beta connects fewer; the leftover weight favours shorter (more vertical) connections; larger gamma penalises direction changes (smoother field).
  • hp: (Default: False)
    Use half-pel search steps (higher angular resolution, slower). Implemented here, unlike eedi3m where it is a no-op.
  • vcheck: (Default: 2)
    Reliability check on the interpolated result: 0 off, 1 weak, 2 medium, 3 strong. When > 0, inconsistent pixels are blended toward cint (a vertical-cubic value, or the matching sclip pixel if given).
  • vthresh0 / vthresh1 / vthresh2: (Default: 32.0 / 64.0 / 4.0)
    Thresholds for vcheck. Must be > 0 when vcheck > 0.
  • sclip: (Default: None)
    Optional "smooth clip" supplying the cint value for the vcheck blend. Must match the output format and dimensions.
  • device_id / num_streams: see Home.
  • tune: (Default: unset)
    Launch-geometry override — [bx, run, run_hp, lws_floor] (strip width + register-fill lengths). The ship defaults are the measured Ampere values used on every vendor, so you can retune at runtime — especially on AMD / Apple — instead of rebuilding; untuned is byte-identical to the ship build. See Tune for the full table, ranges, and vendor starting points.

Examples

out = core.vszipcl.EEDI3(src, field=1)                       # deinterlace, keep top field
out = core.vszipcl.EEDI3(src, field=1, dh=True)              # double the height (AA base)
out = core.vszipcl.EEDI3(src, field=0, nrad=3, mdis=40)      # stronger (slower) search
out = core.vszipcl.EEDI3H(src, field=1, dh=True)             # double the width

Notes

  • All planes are processed. There is no planes argument; each plane is interpolated with its own geometry.
  • Integer input is processed in a normalized [0, 1] float domain (the same pipeline as float clips), so kept rows are bit-lossless and interpolated rows match the float result requantized. This differs from eedi3m, which processes integer clips in the integer domain — so vszipcl.EEDI3 and eedi3m.EEDI3 differ by ±1 code on a fraction of interpolated pixels on integer clips (invisible; the DP direction decisions still match). On float clips the two match to the float floor except for hp=1.
  • hp works. eedi3m ignores the hp flag; here it performs real half-pel search.
  • Removed arguments (vs eedi3m): ucubic (always cubic), cost3 (always the 3-neighbourhood cost), mclip, opt.

Benchmark

1080p YUV420, fps (higher is better), RTX 3070 Ti — see Benchmarks for method. field=1, mdis=40, nrad=3. The reference is the CPU vszip EEDI3.

EEDI3 (vertical)

Implementation u16 f16 f32
vszipcl (s=1) 76.1 76.3 69.9
vszipcl (s=2) 78.3 77.9 73.6
vszip (CPU) 54.2

EEDI3H (horizontal)

Implementation u16 f16 f32
vszipcl (s=1) 76.2 76.6 70.4
vszipcl (s=2) 79.5 78.7 75.3
vszip (CPU) 56.1

The CPU reference is 32-bit-float only, so u16/f16 are vszipcl-only; on f32 vszipcl is ~1.35× the CPU. The barrier-bound DP means a second stream adds little.

Clone this wiki locally