Descale analysis tools for VapourSynth
Project description
nativeres
nativeres is a set of descale analysis tools for VapourSynth.
It combines and supersedes the following tools:
- Original getscaler by cN3rd https://gist.github.com/cN3rd/51077b6abf45b684bf9a3c657d859b43
- Original getnative by Infiziert90 https://github.com/Infiziert90/getnative
- GetFnative by YomikoR https://github.com/YomikoR/GetFnative
- getfscaler https://github.com/Jaded-Encoding-Thaumaturgy/getscaler
The package provides:
- A CLI for frame analysis
- A Python API for VapourSynth scripts and tooling
- An optional VSView plugin
What it does
nativeres helps answer three common descale questions:
getnative: What native resolution was this frame likely upscaled from?getscaler: Which scaler most likely produced this upscale?getfreq: Does the frame's frequency distribution show likely scaling artifacts or native-resolution clues?
Installation
# Install the package with `pip`
pip install nativeres
# Or with `uv`
uv tool install nativeres
VSView plugin
This repository also contains a VSView plugin package.
pip install nativeres[plugin]
# Or with uv
uv tool install nativeres[plugin]
The plugin registers as a VSView tool panel and tool dock under Native Resolution.
Usage can be found in the plugin README.
Usage
CLI
nativeres accepts regular media files, images, and VapourSynth scripts (.vpy / .py). For scripts, the first VapourSynth output is used.
-
Displays a plot to determine the native resolution height for the frame 15000 with the Bilinear kernel:
nativeres getnative file.m2ts --frame 15000 --dim-mode height --kernel bilinear
Right-click the plot to open the context menu, where you can reset zoom and copy or export the plot as
PNG,SVG,JSON, orCSV. -
Displays a table showing the errors of the inverse scalers at height 800 for frame 15000.
nativeres getscaler file.m2ts 800 --frame 15000 --dim-mode height
-
Compute and display a DCT-based frequency plot for the selected frame.
nativeres getfreq file.m2ts --frame 15000
The frequency plot uses the same right-click context menu for reset zoom plus copy/export actions.
Python
from nativeres import getnative
from vskernels import Bilinear
clip = ... # Your VapourSynth clip
results = getnative(
clip,
frame_num=15000,
dimensions=((clip.width, h) for h in range(540, 901)),
kernel=Bilinear(),
)
best = min(results, key=lambda result: result.error)
print(best.dim.height, best.error)
CLI Reference
Main help:
getnative help:
getscaler help:
getfreq help:
Python API
function getnative
getnative(
clip: VideoNode,
frame_num: int,
dimensions: Iterable[tuple[float, float]],
kernel: ComplexKernelLike,
crop: tuple[LeftCrop, RightCrop, TopCrop, BottomCrop] | None = None,
shift: tuple[TopShift, LeftShift] = (0, 0),
metric_mode: MetricMode = 'MAE',
borders_aware: bool | int | tuple[LeftCrop, RightCrop, TopCrop, BottomCrop] = 8,
progress_cb: Callable[[int, int], None] | None = None,
func: FuncExcept | None = None,
**kwargs: Any
) -> list[GetNativeResult]
Determine the best (fractional) native resolution for a selected frame.
This checks a list of candidate resolutions by descaling the selected frame using kernel and comparing the result to the source frame using metric_mode.
Args:
clip: Source clip.frame_num: Frame index inclipto evaluate.dimensions: Iterable of candidate resolutions to test. Each item may be a(width, height)tuple.kernel: Kernel used to perform each descale attempt.crop: Optional crop to apply before descaling. Aspect ratio is preserved.shift: Optional pixel shift applied during descaling:(top_shift, left_shift).metric_mode: Error metric to use:"MSE","MAE", or"RMSE".borders_aware: Amount (or crop tuple) to ignore at image borders to avoid edge noise when computing the metric.progress_cb: Optional progress callback called asprogress_cb(current, total).func: Function returned for custom error handling.kwargs: Additional arguments passed to the Rescale class.
Returns:
A list of GetNativeResult items. Each item contains the tested fractional resolution (dim) and its associated error.
function getscaler
getscaler(
clip: VideoNode,
frame_num: int,
width: float,
height: float,
kernels: ComplexKernelLike | Sequence[ComplexKernelLike],
base_width: int | None = None,
base_height: int | None = None,
crop: tuple[LeftCrop, RightCrop, TopCrop, BottomCrop] | None = None,
shift: tuple[TopShift, LeftShift] = (0, 0),
metric_mode: MetricMode = 'MAE',
mask: MaskLike | None = None,
borders_aware: bool | int | tuple[LeftCrop, RightCrop, TopCrop, BottomCrop] = 8,
func: FuncExcept | None = None,
**kwargs: Any
) → list[GetScalerResult]
Find the best inverse scaler (kernel) for a given frame of a clip.
Each supplied kernel is tested by descaling the selected frame to the provided (width, height) and computing an error metric.
Args:
clip: Source clip.frame_num: Frame index inclipto evaluate.width: Width to be descaled to. If passed as a float, a fractional descale is performed.height: Height to be descaled to. If passed as a float, a fractional descale is performed.kernels: A single kernel or a sequence of kernels to evaluate.base_width: Optional integer height to contain the clip within.base_height: Optional integer width to contain the clip within.crop: Optional crop to apply before descaling. Aspect ratio is preserved.shift: Pixel shifts applied during descaling:(top_shift, left_shift).metric_mode: Error metric to use:"MSE","MAE", or"RMSE".mask: Optional edge-detection mask to reduce noise influence on the metric.borders_aware: Amount (or crop tuple) to ignore at image borders to avoid edge noise when computing the metric.func: Function returned for custom error handling.kwargs: Additional arguments passed to the Rescale class.
Returns:
A list of GetScalerResult items. Each item contains the evaluated kernel and its associated error.
function get_descale_error
get_descale_error(
clip: VideoNode,
frame_num: int,
width: float,
height: float,
kernel: ComplexKernelLike,
base_width: int | None = None,
base_height: int | None = None,
crop: tuple[LeftCrop, RightCrop, TopCrop, BottomCrop] | None = None,
shift: tuple[TopShift, LeftShift] = (0, 0),
metric_mode: MetricMode = 'MAE',
mask: MaskLike | None = None,
borders_aware: bool | int | tuple[LeftCrop, RightCrop, TopCrop, BottomCrop] = 8,
func: FuncExcept | None = None,
**kwargs: Any
) → float
Compute the descale error for a selected frame using a specific kernel.
Args:
clip: Source clip.frame_num: Frame index inclipto evaluate.width: Width to be descaled to. If passed as a float, a fractional descale is performed.height: Height to be descaled to. If passed as a float, a fractional descale is performed.kernel: Kernel used for the descale operation.base_width: Optional integer height to contain the clip within.base_height: Optional integer width to contain the clip within.crop: Optional crop to apply before descaling. Aspect ratio is preserved.shift: Pixel shifts applied during descaling:(top_shift, left_shift).metric_mode: Error metric to use:"MSE","MAE", or"RMSE".mask: Optional edge-detection mask to reduce noise influence on the metric.borders_aware: Amount (or crop tuple) to ignore at image borders to avoid edge noise when computing the metric.func: Function returned for custom error handling.kwargs: Additional arguments passed to the Rescale class.
Returns:
The computed error as a float. Lower values indicate a better descale match.
function get_dct_distribution
get_dct_distribution(
clip: VideoNode,
frame_num: int,
cull_rate: float = 3.0,
func: FuncExcept | None = None
) → tuple[NpFloatArray1D, NpFloatArray1D]
Calculate DCT frequency distribution for both horizontal and vertical dimensions of a selected frame.
Args:
clip: Source clip.frame_num: Frame index inclipto analyze.cull_rate: Cull rate for DCT coefficients.func: Function returned for custom error handling.
Returns: A tuple of (dct_h, dct_v).
class GetNativeResult
Result for getnative, pairing a fractional resolution with an error metric.
class GetScalerResult
Result for getscaler, pairing a kernel with its error.
class ResolutionFrac
Fractional resolution expressed as floating-point width and height.
Notes
- You should always visually verify the results on multiple frames before committing to a descale setup.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nativeres-0.1.0.tar.gz.
File metadata
- Download URL: nativeres-0.1.0.tar.gz
- Upload date:
- Size: 33.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eaab3f142e5f387167385144c8959d75416e53993c9c85f5844aa7d1b4f0328d
|
|
| MD5 |
03489d8e301f21330875d340db705ca4
|
|
| BLAKE2b-256 |
136c0778746e495397e879a344c58e17f987fbac2aa80873c609c5d3c41795ff
|
Provenance
The following attestation bundles were made for nativeres-0.1.0.tar.gz:
Publisher:
pypipublish.yml on Jaded-Encoding-Thaumaturgy/nativeres
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nativeres-0.1.0.tar.gz -
Subject digest:
eaab3f142e5f387167385144c8959d75416e53993c9c85f5844aa7d1b4f0328d - Sigstore transparency entry: 1108514956
- Sigstore integration time:
-
Permalink:
Jaded-Encoding-Thaumaturgy/nativeres@a980e61b2e0588c12c31baf8dfb5acceaefdfe60 -
Branch / Tag:
refs/tags/nativeres/v0.1.0 - Owner: https://github.com/Jaded-Encoding-Thaumaturgy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypipublish.yml@a980e61b2e0588c12c31baf8dfb5acceaefdfe60 -
Trigger Event:
release
-
Statement type:
File details
Details for the file nativeres-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nativeres-0.1.0-py3-none-any.whl
- Upload date:
- Size: 23.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e7d6c9bb7cd486721f552fd87d6b77327c300ab042b3c675af97ef95e509eaee
|
|
| MD5 |
546deb22d99c4f11afd6429609705c7d
|
|
| BLAKE2b-256 |
9a425642b19b79c196e076f0618c75678d0208df6ac9de814d2c1aa1c98cc41a
|
Provenance
The following attestation bundles were made for nativeres-0.1.0-py3-none-any.whl:
Publisher:
pypipublish.yml on Jaded-Encoding-Thaumaturgy/nativeres
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nativeres-0.1.0-py3-none-any.whl -
Subject digest:
e7d6c9bb7cd486721f552fd87d6b77327c300ab042b3c675af97ef95e509eaee - Sigstore transparency entry: 1108514969
- Sigstore integration time:
-
Permalink:
Jaded-Encoding-Thaumaturgy/nativeres@a980e61b2e0588c12c31baf8dfb5acceaefdfe60 -
Branch / Tag:
refs/tags/nativeres/v0.1.0 - Owner: https://github.com/Jaded-Encoding-Thaumaturgy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypipublish.yml@a980e61b2e0588c12c31baf8dfb5acceaefdfe60 -
Trigger Event:
release
-
Statement type: