jaded-encoding-thaumaturgy / lvsfunc Goto Github PK
View Code? Open in Web Editor NEWlvsfunc, a collection of LightArrowsEXE's VapourSynth functions and wrappers
Home Page: https://lvsfunc.readthedocs.io/
License: MIT License
lvsfunc, a collection of LightArrowsEXE's VapourSynth functions and wrappers
Home Page: https://lvsfunc.readthedocs.io/
License: MIT License
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)
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 see: HomeOfVapourSynthEvolution/VapourSynth-BM3D#27
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,
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.
ivtc_credits
to pulldown_credits
(will remain as alias to give people time to update)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.
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'
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'
Branch from #130
Original comment: #130 (comment)
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!
The function currently has a tendency to refuse to release the ivtc'd clip and the relevant files, causing an error and forcing users to refresh their previewer.
Originally posted by @Setsugennoao in #139 (comment)
https://lvsfunc.encode.moe/en/latest/submodules/scale.html#
Could let me know why remove this?
about ssim_downsample which one would you currently recommend using
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)
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:
Write/update the following functions:
Deprecate the following functions:
To be updated.
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```
See #121
Some things I think can be done to improve lvsfunc.comparison.diff
after hearing some user feedback:
return_frames=True
These aren't hard requirements, but potential improvements to be made at a later date.
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.
range_mask
takes only the luma plane here so radc
becomes useless to ask.
https://github.com/Irrational-Encoding-Wizardry/lvsfunc/blob/afbc5664f35372110fcb24e943b2f056b3e6bb51/lvsfunc/mask.py#L82
However, it affects the luma plane output and it seems to relate to #54 because range_mask
doesn't work as it should.
Both masks are made from luma only.
Maybe this is intended (idk), but I thought it was odd.
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:
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.
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),
This will probably require a few adjustments to the way I'm checking for var res/formats.
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:
~~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.
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.
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.
As you can see in the comparison, output are different when rad > 1.
rfs but with fading, so that scenefiltering mid scene becomes less of a temporally inconsistent mess and pain unless you write a lot of fade_filter lines which is ugly as sin
context here: https://discord.com/channels/856381934052704266/856383302097043497/946352375206146048
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.