GithubHelp home page GithubHelp logo

jaded-encoding-thaumaturgy / lvsfunc Goto Github PK

View Code? Open in Web Editor NEW
51.0 11.0 11.0 1.31 MB

lvsfunc, a collection of LightArrowsEXE's VapourSynth functions and wrappers

Home Page: https://lvsfunc.readthedocs.io/

License: MIT License

Python 100.00%
vapoursynth video-encoding anime fansubbing vapoursynth-functions vapoursynth-plugins python python-library python3

lvsfunc's People

Contributors

alucardsama04 avatar deadnews avatar dependabot[bot] avatar fichtefoll avatar ichunjo avatar kageru avatar kgrabs avatar lightarrowsexe avatar motbob avatar mukunku avatar orangechannel avatar petzku avatar po5 avatar setsugennoao avatar tomato39 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lvsfunc's Issues

Optimizing nnedi3_clamp

  • No more copying chroma
  • Slight Expr optimization by replacing the multiplication and boolean operations with an exclusive or
  • Huge eedi3 speedup when opencl=False
  • Removes extra std.Transpose calls (+ supports 32 bit and loses the vsTAAMBK dependency in the process)
def nneedi3_clamp(clip: vs.VideoNode, strength: int = 1,
                  mask: Optional[vs.VideoNode] = None, ret_mask: bool = False,
                  show_mask: bool = False,
                  opencl: bool = False) -> vs.VideoNode:
    """
    A function that clamps eedi3 to nnedi3 for the purpose of reducing eedi3 artifacts.
    This should fix every issue created by eedi3. For example: https://i.imgur.com/hYVhetS.jpg
    Original function written by Zastin, modified by LightArrowsEXE.
    Dependencies:
    * kagefunc (optional: retinex edgemask)
    * vapoursynth-retinex (optional: retinex edgemask)
    * vapoursynth-tcanny (optional: retinex edgemask)
    * vapoursynth-eedi3
    * vapoursynth-nnedi3 or znedi3
    * vapoursynth-nnedi3cl (optional: opencl)
    :param clip:                Input clip
    :param strength:            Set threshold strength (Default: 1)
    :param mask:                Clip to use for custom mask (Default: None)
    :param ret_mask:            Replace default mask with a retinex edgemask (Default: False)
    :param show_mask:           Return mask instead of clip (Default: False)
    :param opencl:              OpenCL acceleration (Default: False)
    :return:                    Antialiased clip
    """
    
    if clip.format is None:
        raise ValueError("nneedi3_clamp: 'Variable-format clips not supported'")
    
    clip_y = get_y(clip)
    
    bits = clip.format.bits_per_sample - 8
    thr = strength * (1 >> bits) if clip.format.sample_type==vs.INTEGER else strength/219
    expr = 'x z - y z - xor y x y {0} + min y {0} - max ?'.format(thr)
    
    if mask is None:
        if ret_mask:
            try:
                import kagefunc as kgf
            except ModuleNotFoundError:
                raise ModuleNotFoundError("nnedi3_clamp: missing dependency 'kagefunc'")
            mask = kgf.retinex_edgemask(clip_y, 1).std.Binarize()
        else:
            mask = clip_y.std.Prewitt().std.Binarize().std.Maximum().std.Convolution([1] * 9)
    
    nnedi3_args = dict(nsize=3, nns=3, qual=1)
    eedi3_args = dict(alpha=0.25, beta=0.5, gamma=40, nrad=2, mdis=20)
    
    clip_tra = core.std.Transpose(clip_y)
    
    if opencl:
        nnedi3 = core.nnedi3cl.NNEDI3CL
        strong = core.eedi3m.EEDI3CL(clip_tra, 0, True, **eedi3_args)
        strong = core.resize.Spline36(strong, height=clip.width, src_top=0.5)
        strong = core.std.Transpose(strong)
        strong = core.eedi3m.EEDI3CL(strong, 0, True, **eedi3_args)
        strong = core.resize.Spline36(strong, height=clip.height, src_top=0.5)
    else:
        nnedi3 = core.nnedi3.nnedi3
        strong = core.eedi3m.EEDI3(clip_tra, 0, True, mclip=mask.std.Transpose(), **eedi3_args)
        strong = core.resize.Spline36(strong, height=clip.width, src_top=0.5)
        strong = core.std.Transpose(strong)
        strong = core.eedi3m.EEDI3(strong, 0, True, mclip=mask, **eedi3_args)
        strong = core.resize.Spline36(strong, height=clip.height, src_top=0.5)
    
    weak = nnedi3(clip_tra, 0, True, **nnedi3_args)
    weak = core.resize.Spline36(weak, height=clip.width, src_top=0.5)
    weak = core.std.Transpose(weak)
    weak = nnedi3(weak, 0, True, **nnedi3_args)
    weak = core.resize.Spline36(weak, height=clip.height, src_top=0.5)
    
    aa = core.std.Expr([strong, weak, clip_y], expr)
    
    merged = clip_y.std.MaskedMerge(aa, mask)

    if show_mask:
        return mask
    return merged if clip.format.color_family == vs.GRAY else core.std.ShufflePlanes([merged, clip], [0, 1, 2], vs.YUV)

find_scene_changes: display error

from vapoursynth import core
from lvsfunc.render import find_scene_changes


clip1 = core.ffms2.Source('video1.mkv')
clip2 = core.ffms2.Source('video2.mkv')

find_scene_changes(nced1)
find_scene_changes(nced2)
>>>python script.py
Detecting scene changes... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0/2160 0.00% 0.00 fps -:--:--
Traceback (most recent call last):
  File "g:\script.py", line 9, in <module>
    find_scene_changes(nced1)
  File "C:\Users\Varde\AppData\Roaming\Python\Python39\site-packages\lvsfunc\render.py", line 262, in find_scene_changes
    clip_async_render(clip, callback=_cb)
  File "C:\Users\Varde\AppData\Roaming\Python\Python39\site-packages\lvsfunc\render.py", line 178, in clip_async_render
    p.start()
  File "C:\Users\Varde\AppData\Roaming\Python\Python39\site-packages\rich\progress.py", line 644, in start
    self.live.start(refresh=True)
  File "C:\Users\Varde\AppData\Roaming\Python\Python39\site-packages\rich\live.py", line 113, in start
    self.console.set_live(self)
  File "C:\Users\Varde\AppData\Roaming\Python\Python39\site-packages\rich\console.py", line 780, in set_live
    raise errors.LiveError("Only one live display may be active at once")
rich.errors.LiveError: Only one live display may be active at once
Core freed but 6 filter instance(s) still exis

Tested with last pip version

Please make it available in a single .py file again

For the people who use portable VapourSynth it is much easier to use a single .py file. Messing with pip is rather a horror with embedded (portable) python.

If possible please make a single lvsfunc.py (like it was earlier) for the people, who use portable versions.

Thank you in advance,

Checklist for v0.4.3

v0.4.3 Checklist

These are all the things I want to finish before I push for a v0.4.3 release.
This list is not final, and things may be added at any point.

General

Write/update

  • Double-check all default values, use sane defaults that give the best generic solution
  • Rename ivtc_credits to pulldown_credits (will remain as alias to give people time to update)
  • Fix incorrect option being picked by pick_remograin/repair (convo)
  • #130 (@Setsugennoao)

Deprecate

Support

I'd like feature requests or updates to be added to this issue if there's no other relevant issue already. What would you like to see in v0.4.3?

To be updated.

vsaa required to use lvsfunc.misc.source?

It appears that due to how the current __init__.py is setup, attempting to use lvsfunc.misc.source causes scripts to fail when vsaa is not installed.

Can we split up the imports so that vsaa is only imported when its used?

Example stacktrace:

2022-09-05 20:51:02.243: INFO: QSS file successfully loaded.
2022-09-05 20:51:02.243: INFO: Found version patches to be applied.
2022-09-05 20:51:02.243: INFO: Found application patches to be applied.
2022-09-05 20:51:02.404: ERROR: No module named 'vsaa'
2022-09-05 20:51:02.405: ERROR: Traceback (most recent call last):
  File "script.vpy", line 4, in <module>
    import lvsfunc as lvs
  File "/usr/lib/python3.10/site-packages/lvsfunc/__init__.py", line 12, in <module>
    from . import (
  File "/usr/lib/python3.10/site-packages/lvsfunc/aa.py", line 9, in <module>
    import vsaa
ModuleNotFoundError: No module named 'vsaa'

export_images

  • imwri does not work by default needs imgformat passed
  • example has missing "
  • example has hq lq swapped

mask.py get_mask seems to be broken

https://lvsfunc.encode.moe/en/latest/submodules/mask.html#lvsfunc.mask.BoundingBox states
ref (VideoNode) – Reference clip for format, resolution, and length.
but looking at the code
https://github.com/Irrational-Encoding-Wizardry/lvsfunc/blob/34660f524a121824011d2c3d33fc3ba8f556f2f9/lvsfunc/mask.py#L350
especially
mask: vs.VideoNode = core.std.BlankClip(ref, color=white, length=1, format=mask_fmt.id)
https://github.com/Irrational-Encoding-Wizardry/lvsfunc/blob/34660f524a121824011d2c3d33fc3ba8f556f2f9/lvsfunc/mask.py#L367
seem wrong since the BlankClip only returns one frame, from the looks of it 'length=1' is the issue.
so something like
mask_d = lvs.mask.BoundingBox((0, 785), (665, 294)).get_mask(clip)
only returns a clip with one frame not clip.num_frames.
so the solution should be to delete ', length=1'

descaler is invoked even when it is not used

I don't know if it is a bug or a feature but the descaler library is invoked, when I wanted to use the edgefixer function. If libdescale.dll is not loaded before calling import lvsfunc VapourSynth throws a missing namespace error referring to line 899 in lvsfunc.py, where descaler is defined. If it is loaded before the import command, the error disappears and the script just runs fine.

As far as I understand descaler is not required for edgefixer...

VapourSynth version: R49-RC1
OS: Win 10 x64

BTW: what is the difference between MonoS's edgefixer and sekrit's one (https://github.com/sekrit-twc/EdgeFixer)?

Thank you very much in advance!

Implement BM3DCUDA

https://github.com/WolframRhodium/VapourSynth-BM3DCUDA

The cuda implementation is quite fast:
Linux 5.12.6: 3900X, GTX 1080, Nv 465.31, cuda 11.3.0-2

clip = core.std.BlankClip(width=1920, height=1080, format=vs.YUV444PS, color=[0.5,0,0], length=1000)
gpu = core.bm3dcuda.BM3D(clip, fast=True).set_output()

Output 1000 frames in 11.08 seconds (90.22 fps)

clip = core.std.BlankClip(width=1920, height=1080, format=vs.YUV444PS, color=[0.5,0,0], length=1000)
gpu = core.bm3dcuda.BM3D(clip, fast=False).set_output()

Output 1000 frames in 42.47 seconds (23.55 fps)

replace_ranges: Error when rfsing image source

This is a multi issue, since it also led to me finding a small issue with source.

Anyway, from Vodes:
image

Setting exclusive=True fixed this issue. Will create a PR later to try and fix this behaviour.

Checklist for v0.4.0

These are all the things I want to finish before I push for a v0.4.0 release.
This list is not final, and things may be added at any point.

General:

  • Resolve all currently open PRs and issues (#60, #65, #66, #70, #74)
  • Update all functions to use 3.10 annotations and typehints
  • Update all functions to use relevant decorators wherever possible
  • Update all AVS ports (request) This will be reserved for a future version.

Write/update the following functions:

  • #84
  • Anime IVTC port (likely Kongarou's rewrite) (Kogarou stalled 😠)
  • shift_tint -> general detint function (Potential Tweak rewrite instead in a later version?)
  • new detail mask
  • update source (Too complex for lvsfunc, might make a separate module at some point)
  • New unsharpening function

Deprecate the following functions:

  • dehalo.deemphasize
  • deinterlace.dir_deshimmer
  • deinterlace.dir_unsharp
  • scale.test_descale

To be updated.

upscaled_sraa not working with parameter rep AND h

scaled = lvf.upscaled_sraa(contrasharp, 2, 13, 1080)
Python exception: Repair: Input clips must have the same format

Traceback (most recent call last):
File "src\cython\vapoursynth.pyx", line 1927, in vapoursynth.vpy_evaluateScript
File "src\cython\vapoursynth.pyx", line 1928, in vapoursynth.vpy_evaluateScript
File "F:\VPS\ENCO EN COURS\Island\island01.vpy", line 39, in 
scaled = lvf.upscaled_sraa(contrasharp, 2, None, 1080)
File "C:\Users\Varde\AppData\Local\Programs\Python\Python37\Lib\lvsfunc.py", line 342, in upscaled_sraa
return core.resize.Spline36(aa_y, w, h) if rep is None else core.resize.Spline36(aa_y, w, h).rgvs.Repair(clip, rep)
File "src\cython\vapoursynth.pyx", line 1833, in vapoursynth.Function.__call__
vapoursynth.Error: Repair: Input clips must have the same format```

diff: Improvements checklist

Some things I think can be done to improve lvsfunc.comparison.diff after hearing some user feedback:

  • Return ranges when possible instead of just single frames with return_frames=True
  • Some kind of output file if specified that can be referenced later (and ideally will not get overwritten) Was handled in #40, and there it was determined it'd be better to just return the frames (which it does right now).
  • Param to create a bookmark file, or to add to an existing bookmark file maybe? Likewise, by outputting the list of frame ranges, the user can write this themselves.
  • If vspreview/vsedit at one point allows for it, maybe somehow overwrite the frame number you can jump to to only display the frame numbers of the actual frames taken (instead of going sequentially from 0-1000 for example like it would normally). This would make copy-pasting values a lot easier. Unlikely to ever happen, so just marking this as done.

These aren't hard requirements, but potential improvements to be made at a later date.

Avisynth port updates

A lot of Avisynth ports are very old, and the filters ported have since been updated to be faster, more precise, and offer more functionality. This issue has been made to take a look at all the ports within lvsfunc that could use re-porting. This issue will be updated at a later date once I find time to look through the module and find what is and isn't an AVS port. Any help with listing them is appreciated.

Functions that require updating:
[ ] - masked_dha (?)

To be updated.

Old function adoption list/requests

This issue will mark the list of older functions I plan on adopting as well as requested filters.
These will mainly be unmaintained functions from old *funcs or random gists.
I'm not necessarily planning to rewrite most of them, but I do plan on making sure they're at least R55 compliant, and will hopefully remain compliant with future VapourSynth API changes.

This is also the place to go to to request AVS ports.

Currently eyeing the following functions:

  • Zastin's morpho deband function (Not publicised outside of discord, or if it was it's lost)
  • BasedAA (Need to figure out why it breaks on certain setups before further plans are made) Added, see commit.
  • RemoveDirt (again because it looks interesting...)
  • The various ivtc/dec_txt functions, and hopefully turn them into a singular function instead of a bunch of separate ones.
  • g41fun's masked_dha Added, see #76.
  • Zastin's texture mask (requested)
  • Other random stuff I come across that look interesting, even if not entirely functional.

Since lvsfunc is meant to be a general stop for most generic function needs, I'm always open for more requests, so if there's any older functions you feel could use adopting, please don't hesitate to leave a comment with a link here.

Consider using the lambda

https://github.com/Irrational-Encoding-Wizardry/lvsfunc/blob/16c20a94443796adccbcf6feb926da8dea54bfb9/lvsfunc/mask.py#L70
If you import any function:

from lvsfunc import rfs
File "lvsfunc/__init__.py", line 12, in 
from . import (aa, comparison, deblock, dehalo, dehardsub, deinterlace,
File "lvsfunc/comparison.py", line 21, in 
from .dehardsub import hardsub_mask
File "lvsfunc/dehardsub.py", line 13, in 
from .mask import DeferredMask
File "lvsfunc/mask.py", line 70, in 
vs.VideoNode] = core.bilateral.Bilateral,
File "src/cython/vapoursynth.pyx", line 2385, in vapoursynth._CoreProxy.__getattr__
File "src/cython/vapoursynth.pyx", line 2228, in vapoursynth.Core.__getattr__
AttributeError: No attribute with the name bilateral exists. Did you mistype a plugin namespace?

Consider using the lambda:

vs.VideoNode] = lambda clip, ref, sigma : core.bilateral.Bilateral(clip, ref, sigma),

autodb_dpir: A new autodeblocker tool using DPIR

Issue to keep track of changes I would still like to see. This new feature is available on the autodeblock branch.

Current docstring and parameters:

def autodb_dpir(clip: vs.VideoNode, edgevalue: int = 24,
                strs: Sequence[float] = (30, 50, 75),
                thrs: Sequence[Tuple[float, float, float]] = [(1.5, 2.0, 2.0), (3.0, 4.5, 4.5), (5.5, 7.0, 7.0)],
                matrix: Optional[Matrix] = None,
                cuda: bool = True, device_index: int = 0,
                ) -> vs.VideoNode:
    """
    A rewrite of fvsfunc.AutoDeblock that uses vspdir instead of dfttest to deblock.

    This function checks for differences between a frame and an edgemask with some processing done on it,
    and for differences between the current frame and the next frame.
    For frames where both thresholds are exceeded, it will perform deblocking at a specified strength.
    This will ideally be frames that show big temporal *and* spatial inconsistencies.

    Thresholds and calculations are added to the frameprops to use as reference when setting the thresholds.

    Keep in mind that vsdpir is not perfect; it may cause weird, black dots to appear sometimes.
    If that happens, you can perform a denoise on the original clip (maybe even using vsdpir's denoising mode)
    and grab the brightest pixels from your two clips. That should return a perfectly fine clip.

    Thanks Vardë, louis, setsugen_no_ao!

    Dependencies:

    * vs-dpir
    * rgsf

    :param clip:            Input clip
    :param edgevalue:       Remove edges from the edgemask that exceed this threshold (higher means more edges removed)
    :param strs:            A list of DPIR strength values (higher means stronger deblocking).
                            You can pass any arbitrary number of values here.
                            The amount of values in strs and thrs need to be equal.
                            Note that the current highest vsdpir can go as of writing is ``strength=75``
    :param thrs:            A list of thresholds, written as [(EdgeValRef, NextFrameDiff, PrevFrameDiff)].
                            You can pass any arbitrary number of values here.
                            The amount of values in strs and thrs need to be equal.
    :param matrix:          Enum for the matrix of the input clip. See ``types.Matrix`` for more info.
                            If `None`, gets matrix from the "_Matrix" prop of the clip
    :param cuda:            Device type used for deblocking. Uses CUDA if True, else CPU
    :param device_index:    The 'device_index' + 1º device of type device type in the system

    :return:                Deblocked clip
    """

As this issue was created a bit late, I will only include issues we have yet to properly figure out. Comments/suggestions are welcome. Please mention any and all issues with the function either here or in the #lvsfunc channel on our Discord server.

To-do:

  • Figure out what kind of threshold to use

~~At the time of writing, it does a conversion to and from 8bit values. The easiest method would be allowing a range of [0, 1], as that is what is returned in the frameprops, and is ultimately what is being used for the actual calculations. However, I feel this isn't as palatable as regular numbers are. I am currently considering a [0, 100] range. Would like more thoughts and opinions on this before really making a call. ~~ Sticking with 8bit-esque values for the time being. May change later.

  • Figure out a good set of default values

The current default values seem decent for my use-cases, but I have only really tested it on two specific sources. More user feedback would be appreciated here. No response, so staying with this until I find time to revisit it.

  • See if we can somehow move the meat of the function to ModifyFrame functionality

Frame evals are much slower to run and initialise than simple frame modifications, but I am not familiar enough with how to write a function use ModifyFrame properly. ModifyFrame seems to cause memory problems, likely due to different memory allocation in ModifyFrame than FrameEval that messes up by forcing every instance of DPIR to be initialised or something? Either way, not feasible currently.

For these issues, PRs/comments are most appreciated.

dpir: `_ChromaLocation` property gets removed

For some reason, when running DPIR, the _ChromaLocation property gets yeeted. I have not yet verified whether this is the case for more props. A simple temporary workaround will be introduced in a commit in a bit, but we should find a more permanent solution.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.