Skip to content

Commit

Permalink
New function: descale; fix conditional_descale param issues
Browse files Browse the repository at this point in the history
  • Loading branch information
LightArrowsEXE committed May 4, 2020
1 parent 95fae93 commit 70ca210
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 7 deletions.
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
author = 'LightArrowsEXE'

# The short X.Y version
version = '0.0.4'
version = '0.0.5'

# The full version, including alpha/beta/rc tags
release = '0.0.4'
release = '0.0.5'

# -- General configuration ---------------------------------------------------

Expand Down
2 changes: 2 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ Functions
lvsfunc.misc.source
lvsfunc.misc.wipe_row
lvsfunc.scale.conditional_descale
lvsfunc.scale.descale
lvsfunc.scale.smart_descale
lvsfunc.scale.smart_reupscale
lvsfunc.scale.test_descale
Expand Down Expand Up @@ -186,6 +187,7 @@ lvsfunc.scale
.. autosummary::

lvsfunc.scale.conditional_descale
lvsfunc.scale.descale
lvsfunc.scale.smart_descale
lvsfunc.scale.smart_reupscale
lvsfunc.scale.test_descale
Expand Down
80 changes: 77 additions & 3 deletions lvsfunc/scale.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,90 @@
from typing import Callable, List, Optional, Union

import vapoursynth as vs
from vsutil import get_depth, get_w, get_y, join, plane, split
from vsutil import get_depth, get_w, get_y, iterate, join, plane, split

from . import util

core = vs.core


def conditional_descale(clip: vs.VideoNode,
width: Optional[int], height: int = 720,
def descale(clip: vs.VideoNode,
upscaler: Callable[[vs.VideoNode, int, int], vs.VideoNode],
width: Optional[int] = None, height: int = 720,
kernel: str = 'bicubic', brz: float = 0.05,
b: float = 0, c: float = 1 / 2, taps: int = 4,
src_left: float = 0.0,
src_top: float = 0.0) -> vs.VideoNode:
"""
A generic descaling function.
includes support for handling fractional resolutions (although that's still experimental)
If you want to descale to a fractional resolution,
set src_left and src_top and round up the target height.
:param clip: Clip to descale
:param upscaler: Callable function with signature upscaler(clip, width, height) -> vs.VideoNode to be used for reupscaling.
Example for nnedi3_rpow2: `clip, upscaler = nnedi3_rpow2, ...`
:param width: Width to descale to (if None, auto-calculated)
:param height: Height to descale to (Default: 720)
:param kernel: Kernel used to descale (see :py:func:`descale.get_filter`, default: bicubic)
:param brz: Binarizing for the credit mask
:param b: B-param for bicubic kernel (Default: 0)
:param c: C-param for bicubic kernel (Default: 1 / 2)
:param taps: Taps param for lanczos kernel (Default: 4)
:param src_left: Horizontal shifting for fractional resolutions
:param src_top: Vertical shifting for fractional resolutions
:return: Descaled and re-upscaled clip
"""
try:
from descale import get_filter
except ModuleNotFoundError:
raise ModuleNotFoundError("fractional_descale: missing dependency 'descale'")

def _create_credit_mask(clip: vs.VideoNode, descaled_clip: vs.VideoNode,
kernel: str = 'bicubic', brz: float = 0.05,
b: float = 0, c: float = 1/2, taps: int = 4,
src_left: Optional[float] = False,
src_top: Optional[float] = False) -> vs.VideoNode:
src_left = src_left or 0
src_top = src_top or 0

rescaled = util.get_scale_filter(kernel, b=b, c=c, taps=taps)(descaled_clip, clip.width, clip.height,
src_left = src_left, src_top = src_top)
credit_mask = core.std.Expr([clip, rescaled], 'x y - abs').std.Binarize(brz)
credit_mask = iterate(credit_mask, core.std.Maximum, 4)
return iterate(credit_mask, core.std.Inflate, 2)

kernel = kernel.lower()

if width is None:
width = get_w(clip, clip.width / clip.height)

clip_y = get_y(clip)
descaled = get_filter(b, c, taps, kernel)(clip_y, width, height)

# This is done this way to prevent it from doing a needless conversion if params not passed
if src_left is not 0 or src_top is not 0:
descaled = core.resize.Bicubic(descaled, src_left = src_left, src_top = src_top)

upscaled = upscaler(descaled, width=clip.width, height=clip.height)

if src_left is not 0 or src_top is not 0:
upscaled = core.resize.Bicubic(descaled, src_left = -src_left, src_top = -src_top)

credit_mask = _create_credit_mask(clip_y, descaled, kernel, brz, b, c, taps, src_left, src_top)
merged = core.std.MaskedMerge(upscaled, clip_y, credit_mask)
merged = core.std.SetFrameProp(merged, "_descaled", data="True")

if clip.format is vs.GRAY:
return merged
return join([merged, plane(clip, 1), plane(clip, 2)])


def conditional_descale(clip: vs.VideoNode,
upscaler: Callable[[vs.VideoNode, int, int], vs.VideoNode],
width: Optional[int] = None, height: int = 720,
kernel: str = 'bicubic',
b: Union[float, Fraction] = Fraction(0),
c: Union[float, Fraction] = Fraction(1, 2),
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
install_requires = fh.read()

name = "lvsfunc"
version = "0.0.4"
release = "0.0.4"
version = "0.0.5"
release = "0.0.5"

setuptools.setup(
name=name,
Expand Down

0 comments on commit 70ca210

Please sign in to comment.