scenechange

Scene change detection plugin for VapourSynth.

View on GitHub

scenechange

Python versions PyPI - Version GitHub tag (with filter) License GitHub commits since latest release (by SemVer including pre-releases) QA Tests Coverage Status Dependabot Documentation Status mypy uv pytest Ruff Downloads Stargazers pre-commit Prettier

@Tatsh Buy Me A Coffee Libera.Chat Mastodon Follow Patreon

Scene change detection plugin for VapourSynth.

The project builds two VapourSynth plugins:

The vapoursynth-scenechange Python package bundles both compiled plugins together with a small wrapper (scenechange.TemporalSoften) that stitches them into a single function call.

Building and installing

Requirements:

Configure, build, and install:

cmake -S . -B build -G Ninja
cmake --build build
cmake --install build

By default the plugins install to the directory reported by pkg-config --variable=pluginsdir vapoursynth, falling back to ${CMAKE_INSTALL_FULL_LIBDIR}/vapoursynth when the pkg-config variable is unset. Override the location with -DVAPOURSYNTH_PLUGINS_DIR=/path/to/plugins at configure time.

Python package

Prebuilt wheels that bundle both plugins are published to PyPI, so most users do not need to build anything from source:

pip install vapoursynth-scenechange

The wheel installs the compiled plugins as package data (for example site-packages/scenechange/libscenechange.so) alongside the scenechange Python module, and declares vapoursynth as a dependency. Building the plugins from source with CMake (above) is only needed for development or for platforms without a published wheel. See Python wrapper for usage.

Usage

scd.Detect

clip = core.scd.Detect(clip, thresh, interval_h, interval_v, log)

Detect scene changes and attach _SceneChangePrev and _SceneChangeNext properties to the clip.

scd.ApplyLog

clip = core.scd.ApplyLog(clip, log)

Apply _SceneChangePrev and _SceneChangeNext properties to the clip from a log previously produced by scd.Detect.

Supported colour families are GRAY (8-bit and 16-bit) and YUV (8-bit, 9-bit, 10-bit, and 16-bit).

focus2.TemporalSoften2

clip = core.focus2.TemporalSoften2(clip, radius, luma_threshold, chroma_threshold,
                                   scenechange, mode)

YUV or Gray example:

import vapoursynth as vs

core = vs.Core()
core.std.LoadPlugin('/path/to/libscenechange.so')
core.std.LoadPlugin('/path/to/libtemporalsoften2.so')

clip = core.scd.Detect(clip, thresh=20)
clip = core.focus2.TemporalSoften2(clip)

RGB example (scene detection requires GRAY8, so the properties must be copied back):

def copy_sc(n, f):
    fout = f[0].copy()
    fout.props._SceneChange = f[1].props._SceneChange[0]
    return fout


tmp = core.resize.Point(clip, format=vs.GRAY8)
tmp = core.scd.Detect(tmp, thresh=20)
clip = core.std.ModifyFrame([clip, tmp], copy_sc)
clip = core.focus2.TemporalSoften2(clip)

Python wrapper

The TemporalSoften class in the scenechange package collapses the boilerplate above into a single call and handles the RGB property-copy step automatically. Its static load_plugins method loads the bundled plugins into the core, so no manual LoadPlugin paths are required:

import vapoursynth as vs
from scenechange import TemporalSoften

core = vs.core
TemporalSoften.load_plugins(core)
clip = TemporalSoften(core).soften(clip, luma_threshold=4)

Credits

Original plugins by Oka Motofumi (chikuzen.mo at gmail dot com).