View Full Version : Oyster, placebo compression artifacts buster
feisty2
3rd May 2016, 12:06
readme and more
https://github.com/IFeelBloated/Oyster
How this thing works:
certain component of the signal (something other than noise or blankness) would require either high resolution in time domain or frequency domain, but not both (uncertainty principle).
videos are non-stationary signals obviously, so ideal Fourier transform (something like DFTTest(sbsize=10000000000000001, tbsize=10000000000000001)) won't work, transform like that has a high frequency resolution but very poor time resolution, and leads to catastrophic results on components carrying lots of time features (sharp edges, delicate details, etc.), ringings, edges blurred out, and shit like that.
so, short time Fourier transform (something like DFTTest(sbsize=3, tbsize=3)), well, this kind of transform has a relatively higher time resolution but poor frequency resolution, and yeah, you know what kind of shit is about to happen next (washed-out, posterized, etc.), and lim(window size -> 0) gives the completely untransformed data! (frequency resolution -> 0)
anyways, it all comes down to one word, "resolution", you need higher resolution to get better quality, and BM3D, state of the art denoiser enhances frequency resolution by matching similar macroblocks. once a group of similar blocks have been matched, the group of signals go (mostly) stationary as similar blocks share similar copies of frequency distribution, and that's good news, and now go large-window-sized Fourier transform and get a high frequency resolution. and no worries about all that time resolution stuff cuz stationary signal simply has no time feature.
so why do we need more, I mean, BM3D sounds definitely awesome, the thing is, BM3D maximizes frequency resolution by re-positioning (block matching) the video signal, and after all these smart and well designed procedures, signal goes MOSTLY stationary but apparently not COMPLETELY stationary so there's still loss of time feature, BM3D manages to minimize that, but couldn't cancel that out completely, and then you notice that loss of sharpness on edges and delicate details and that's why NLMeans, a time domain filter should step in and clean the mess, and about MDeGrain? well, BM3D simply isn't aggressive enough to compression artifacts, you need something brutal and fierce to wipe the shit away first regardless of detail loss, and then recover the lost details and that's why MDeGrain stays around.
MDeGrain -> BM3D -> NLMeans, it just gets more and more delicate each time and details are restored gradually, and artifacts gets its ass kicked
log:
r4:
strict sanity check in every single function, a lot more user friendly and should be ok to work like any typical module now
added some temporal padding to KNLMeansCL
re-licensed to LGPL v3.0
trivial modifications to the doc
.gitignore
r3
algorithmic update, so quality boost
r2.1
removed global core cuz Myrsloik said it was a horrible idea, simple "import Oyster" works now
new function Search
rewrote Basic
trivial modifications to Final
removed SATD, SAD works better on compression artifacts
removed TrueMotion
jackoneill
3rd May 2016, 13:00
Who is that?
feisty2
3rd May 2016, 14:33
Who is that?
what?
you mean the sample clip?
Kylie Minogue - Come Into My World
one of the best music videos like ever
AzraelNewtype
4th May 2016, 00:22
Waifu2x(dunno why but it looks kinda cartoonized somehow)
Because waifu2x is a neural network scaler trained to upscale cartoons, not live action? Its ability to fight compression artifacts (typically jpeg artifacts) is in service of that goal, not general purpose cleaning.
feisty2
4th May 2016, 00:24
Because waifu2x is a neural network scaler trained to upscale cartoons, not live action? Its ability to fight compression artifacts (typically jpeg artifacts) is in service of that goal, not general purpose cleaning.
it has a photo mode indeed, but still...
no luck with that
BakaProxy
4th May 2016, 02:12
#3DWaifusExist
Verstuurd vanaf mijn SM-A500FU met Tapatalk
feisty2
4th May 2016, 03:49
#3DWaifusExist
Verstuurd vanaf mijn SM-A500FU met Tapatalk
Please do tell, where
BakaProxy
4th May 2016, 12:46
Please do tell, where
They're called real people
Verstuurd vanaf mijn SM-A500FU met Tapatalk
feisty2
4th May 2016, 13:10
They're called real people
Verstuurd vanaf mijn SM-A500FU met Tapatalk
okay, not funny.
thought an inter-waifu2x was out. (waifu2x is intra)
feisty2
9th May 2016, 07:56
r2.1
removed global core cuz Myrsloik said it was a horrible idea, simple "import Oyster" works now
new function Search
rewrote Basic
trivial modifications to Final
removed SATD, SAD works better on compression artifacts
removed TrueMotion
RazorBurn
11th May 2016, 08:02
Got error on r2.1
Failed to evaluate the script:
Python exception: Crop: cropped area extends beyond frame dimensions
Traceback (most recent call last):
File "src\cython\vapoursynth.pyx", line 1491, in vapoursynth.vpy_evaluateScript (src\cython\vapoursynth.c:26897)
File "C:/Temp/StaxRip Temp/SampleClip_temp/SampleClip.vpy", line 11, in <module>
ref = Oyster.Basic(y,vec)
File "C:\Apps\Python\lib\site-packages\Oyster.py", line 171, in Basic
_mask = helpers.genblockmask (ShufflePlanes (src, 0, vs.GRAY))
File "C:\Apps\Python\lib\site-packages\Oyster.py", line 70, in genblockmask
clip = CropAbs (clip, src.width, src.height, 0, 0)
File "src\cython\vapoursynth.pyx", line 1383, in vapoursynth.Function.__call__ (src\cython\vapoursynth.c:25204)
vapoursynth.Error: Crop: cropped area extends beyond frame dimensions
My Code
import vapoursynth as vs
core = vs.get_core()
import mvsfunc
import edi_rpow2 as edi
import mvmulti
import Oyster
clip = core.lsmas.LibavSMASHSource(r"D:\Installers\Multimedia\Video Test Samples\SampleClip.mp4")
clp = mvsfunc.ToRGB(input = clip, depth=32)
y = core.std.ShufflePlanes(clp,0,vs.GRAY)
vec = Oyster.Search(y)
ref = Oyster.Basic(y,vec)
y = Oyster.Final(y,ref,vec)
clip = core.std.ShufflePlanes([y,clp], [0,1,2], vs.YUV)
clip.set_output()
feisty2
12th May 2016, 14:18
Got error on r2.1
clp = mvsfunc.ToRGB(input = clip, depth=32)
y = core.std.ShufflePlanes(clp,0,vs.GRAY)
...
???
and what's the resolution of your clip?
feisty2
3rd July 2016, 17:24
r3
algorithmic update, so quality boost
feisty2
5th July 2016, 16:58
so, bad news here.
been hours and I tried like a million sets of parameters to investigate if there's any chance of quality-speed tradeoff, and, failed to get rid of the abysmal performance even tho had reached the bottom line of almost, everything.
I lowered the precision down to uint8_t, and picked jackoneill's heavily asm optimized mvtools
I used fast profile on V-BM3D
I ditched Oyster.Super, made pel 1, lowest value possible, switched vector searching algorithm from exhaustive to hex
I disabled the varying search window of NLMeans, and fixed that to 4, constant
and, the performance went from 0.00fps up to 0.11fps on 720x480 GRAY, but, I mean, that's still outrageously SLOOOW..
guys, I really tried, but... yeah, and I'm out of ideas of performance boost..
Mystery Keeper
5th July 2016, 17:46
feisty2, 'tis okay. There was a time when I had to ditch simple anime anti-aliasing because it was too slow on my ancient PC. Eventually we'll have enough power to put your script into good use.
feisty2
6th July 2016, 12:23
feisty2, 'tis okay. There was a time when I had to ditch simple anime anti-aliasing because it was too slow on my ancient PC. Eventually we'll have enough power to put your script into good use.
I actually think there will be a huge performance boost if someone could make a GPU version of BM3D...
and I wrote the underlying mechanism at #1, hopefully not some kind of "utterly bizarre misunderstanding"
lansing
7th July 2016, 00:31
Is this 64bit only? The required mvtool plugin only has a 64bit version
feisty2
7th July 2016, 06:47
Is this 64bit only? The required mvtool plugin only has a 64bit version
uhmm, I could compile an x86 binary if you need that, this thing consumes A LOT OF ram, so that probably won't work anyway, you got that 4GB upper limit on x86 programs
Tell me about that, I was testing if I had all the dependencies right with a 1080p source and ran OOM on my 16GB Ram machine. :(
feisty2
8th July 2016, 08:09
Tell me about that, I was testing if I had all the dependencies right with a 1080p source and ran OOM on my 16GB Ram machine. :(
I got 16G also and didn't do any 1080p test, that's just way too heavy to my crappy i7-4790k, guess you'll need Xeon E5 or maybe Xeon E7 to go for a 1080p test, the highest resolution test I did is 720p, and it ran for an hour or so to just reconstruct one single frame
and also you will have to vspipe intermediate clips (basic estimation, etc) to your hard drive to avoid OOM on 720p
basically, something like this
ref = Oyster.Basic (clp, Oyster.Super (clp))
clp = Oyster.Destaircase (clp, ref, block_step=2)
clp = Oyster.Deringing (clp, ref, block_step=2)
goes like
ref = Oyster.Basic (clp, Oyster.Super (clp))
ref.set_output()
#vspipe xxx.vpy ref.rgb
ref = core.raws.Source ("ref.rgb")
clp = Oyster.Destaircase (clp, ref, block_step=2)
clp.set_output()
#vspipe xxx.vpy clp.rgb
ref = core.raws.Source ("ref.rgb")
clp = core.raws.Source ("clp.rgb")
clp = Oyster.Deringing (clp, ref, block_step=2)
clp.set_output()
#vspipe xxx.vpy whatever.rgb
lansing
8th July 2016, 21:34
uhmm, I could compile an x86 binary if you need that, this thing consumes A LOT OF ram, so that probably won't work anyway, you got that 4GB upper limit on x86 programs
well I think that's a bad idea then, my machine has only 16G RAM and my video is 1080
raffriff42
9th July 2016, 02:29
I haven't looked at your code, but if it does a lot of temporal filtering, this can be a big time and memory hog, since filters upstream of a temporal filter get called repeatedly (unless they are cached, but in your case the cache is exhausted quickly). This problem really blows up with multiple temporal filters. The same frame could be processed with the same filter dozens of times. You can see this by inserting temporary WriteFile(current_frame) statements. You should be able to save time and memory by splitting the process into parts, with lossless intermediate files, so expensive operations early in the chain only need to get executed once per frame.
feisty2
19th August 2016, 15:56
r4:
strict sanity check in every single function, a lot more user friendly and should be ok to work like any typical module now
added some temporal padding to KNLMeansCL
re-licensed to LGPL v3.0
trivial modifications to the doc
.gitignore
WolframRhodium
22nd August 2016, 14:44
lWhy not use BM3D in cutoff?
And what's your reason for changing from gauss_resample to DFTTest? Maybe because DFTTest is a spatial-temporal filter(while gauss_resample is just a spatial filter) so that it works theoretically better in most cases?
feisty2
22nd August 2016, 16:20
lWhy not use BM3D in cutoff?
And what's your reason for changing from gauss_resample to DFTTest? Maybe because DFTTest is a spatial-temporal filter(while gauss_resample is just a spatial filter) so that it works theoretically better in most cases?
there's no "cutoff" parameter in Oyster, I assume your were talking about "lowpass"
"lowpass" works as a noise dumper, it separates components with possibility to carry certain noise from components with no noise at all.
and no, DFTTest here is completely spatial(tbsize=0), I picked it because wiener filter (https://en.wikipedia.org/wiki/Wiener_filter)works better than Gaussian blur on noise separation
WolframRhodium
23rd August 2016, 00:26
there's no "cutoff" parameter in Oyster, I assume your were talking about "lowpass"
"lowpass" works as a noise dumper, it separates components with possibility to carry certain noise from components with no noise at all.
and no, DFTTest here is completely spatial(tbsize=0), I picked it because wiener filter (https://en.wikipedia.org/wiki/Wiener_filter)works better than Gaussian blur on noise separation
oh that is freq_merge, I confuse it with your other script...
Then you mean using DFTTest in things like freq_merge and gaussian blur in cutoff?
groucho86
24th August 2016, 18:08
Hey feisty2 , I'm not sure if this is a graphics card issue, lack of RAM or something else.
My source file is ProRes 422HQ.
I'm trying to run the following code:
import vapoursynth as vs
import havsfunc as haf
import mvsfunc as mvf
import mvmulti
import Oyster
core = vs.get_core()
core.std.LoadPlugin("/usr/local/lib/libmvtoolssf.dylib")
core.std.LoadPlugin("/usr/local/lib/libfmtconv.dylib")
core.std.LoadPlugin("/usr/local/lib/libscenechange.dylib")
core.std.LoadPlugin("/usr/local/lib/libtemporalsoften2.dylib")
core.std.LoadPlugin("/usr/local/lib/libffms2.4.dylib")
clip = core.lsmas.LibavSMASHSource(source="/Volumes/OFFLINE/prores422hq.mov")
clip = mvf.ToRGB(input = clip, depth=32)
y = core.std.ShufflePlanes(clip,0,vs.GRAY)
ref = Oyster.Basic(y, Oyster.Super (y))
y = Oyster.Deblocking(y, ref, block_step=2)
y = Oyster.Deringing(clip, ref, sigma=24.0, h=10.8, block_step=2)
clip = core.std.ShufflePlanes([y,clip], [0,1,2], vs.YUV)
clip.set_output()
VapourSynth Editor returns the following error:
Failed to evaluate the script:
Python exception: knlm.KNLMeansCL: fatal error!
(clCreateImage(d.mem_in[0]): CL_IMAGE_FORMAT_NOT_SUPPORTED)
Traceback (most recent call last):
File "src/cython/vapoursynth.pyx", line 1491, in vapoursynth.vpy_evaluateScript (build/temp.macosx-10.9-x86_64-3.5/pyrex/vapoursynth.c:26897)
File "/Volumes/VG_SHUTTLE04/oyster01.vpy", line 23, in <module>
y = Oyster.Deblocking(y, ref, block_step=2)
File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/Oyster.py", line 448, in Deblocking
lowpass, color, matrix)
File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/Oyster.py", line 193, in deblocking
cleansed = helpers.nlmeans(ref, radius, block_size, 4, h, ref, color)
File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/Oyster.py", line 45, in nlmeans
nlm = KNLMeansCL(pad, d=d, a=a, s=s, h=h, cmode=color, wref=1.0, rclip=rclip)
File "src/cython/vapoursynth.pyx", line 1383, in vapoursynth.Function.__call__ (build/temp.macosx-10.9-x86_64-3.5/pyrex/vapoursynth.c:25204)
vapoursynth.Error: knlm.KNLMeansCL: fatal error!
(clCreateImage(d.mem_in[0]): CL_IMAGE_FORMAT_NOT_SUPPORTED)
My graphics card is an ATI Radeon HD 5770. Not entirely sure if it's supported. I tried downgrading KNLMeansCL to 0.6.11 but the issue persists.
Thank you for your help!
feisty2
24th August 2016, 18:15
Hey feisty2 , I'm not sure if this is a graphics card issue, lack of RAM or something else.
My source file is ProRes 422HQ.
I'm trying to run the following code:
import vapoursynth as vs
import havsfunc as haf
import mvsfunc as mvf
import mvmulti
import Oyster
core = vs.get_core()
core.std.LoadPlugin("/usr/local/lib/libmvtoolssf.dylib")
core.std.LoadPlugin("/usr/local/lib/libfmtconv.dylib")
core.std.LoadPlugin("/usr/local/lib/libscenechange.dylib")
core.std.LoadPlugin("/usr/local/lib/libtemporalsoften2.dylib")
core.std.LoadPlugin("/usr/local/lib/libffms2.4.dylib")
clip = core.lsmas.LibavSMASHSource(source="/Volumes/OFFLINE/prores422hq.mov")
clip = mvf.ToRGB(input = clip, depth=32)
y = core.std.ShufflePlanes(clip,0,vs.GRAY)
ref = Oyster.Basic(y, Oyster.Super (y))
y = Oyster.Deblocking(y, ref, block_step=2)
y = Oyster.Deringing(clip, ref, sigma=24.0, h=10.8, block_step=2)
clip = core.std.ShufflePlanes([y,clip], [0,1,2], vs.YUV)
clip.set_output()
VapourSynth Editor returns the following error:
Failed to evaluate the script:
Python exception: knlm.KNLMeansCL: fatal error!
(clCreateImage(d.mem_in[0]): CL_IMAGE_FORMAT_NOT_SUPPORTED)
Traceback (most recent call last):
File "src/cython/vapoursynth.pyx", line 1491, in vapoursynth.vpy_evaluateScript (build/temp.macosx-10.9-x86_64-3.5/pyrex/vapoursynth.c:26897)
File "/Volumes/VG_SHUTTLE04/oyster01.vpy", line 23, in <module>
y = Oyster.Deblocking(y, ref, block_step=2)
File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/Oyster.py", line 448, in Deblocking
lowpass, color, matrix)
File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/Oyster.py", line 193, in deblocking
cleansed = helpers.nlmeans(ref, radius, block_size, 4, h, ref, color)
File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/Oyster.py", line 45, in nlmeans
nlm = KNLMeansCL(pad, d=d, a=a, s=s, h=h, cmode=color, wref=1.0, rclip=rclip)
File "src/cython/vapoursynth.pyx", line 1383, in vapoursynth.Function.__call__ (build/temp.macosx-10.9-x86_64-3.5/pyrex/vapoursynth.c:25204)
vapoursynth.Error: knlm.KNLMeansCL: fatal error!
(clCreateImage(d.mem_in[0]): CL_IMAGE_FORMAT_NOT_SUPPORTED)
My graphics card is an ATI Radeon HD 5770. Not entirely sure if it's supported. I tried downgrading KNLMeansCL to 0.6.11 but the issue persists.
Thank you for your help!
are you sure that you need this on ProRes422HQ which is already pretty close to lossless compression...
ProRes422HQ does not produce compression artifacts :)
groucho86
24th August 2016, 18:26
...If only it were true ProRes 422HQ!
This is for a documentary. I'm dealing with a variety of non-conformed archival elements (Getty, AP, youtube videos, etc.)
My first step usually involves media managing (to ProRes) the assets with 1 second handles using either Resolve or Premiere (maintaining original frame size and frame rate).
From there I use Vapoursynth to convert everything to 1080p23.976.
feisty2
24th August 2016, 18:39
...If only it were true ProRes 422HQ!
This is for a documentary. I'm dealing with a variety of non-conformed archival elements (Getty, AP, youtube videos, etc.)
My first step usually involves media managing (to ProRes) the assets with 1 second handles using either Resolve or Premiere (maintaining original frame size and frame rate).
From there I use Vapoursynth to convert everything to 1080p23.976.
okay, first you must not convert it to RGB if it's not native RGB or YCbCr 4:4:4
DO NOT upsample your video to YUV 4:4:4 or RGB before processing if it's not natively full-sampled, just pass Y as a gray clip and merge the result with UV from the source clip, low-res chroma will jeopardize the correctness of weight calculation (fatal, especially to NLMeans).
do
clip = core.fmtc.bitdepth(clip,bits=32,fulls=False,fulld=True)
instead of
clip = mvf.ToRGB(input = clip, depth=32)
and Radeon HD 5770 is a bit too low-end for Oyster, try something at least like GTX970 or better graphic cards.
edit: I think you forgot to correct maybe something during the copy-paste
try
clip = core.lsmas.LibavSMASHSource(source="/Volumes/OFFLINE/prores422hq.mov")
clip = core.fmtc.bitdepth(clip,bits=32,fulls=False,fulld=True)
y = core.std.ShufflePlanes(clip,0,vs.GRAY)
ref = Oyster.Basic(y, Oyster.Super (y))
y = Oyster.Deblocking(y, ref, block_step=2)
y = Oyster.Deringing(y, ref, sigma=24.0, h=10.8, block_step=2)
clip = core.std.ShufflePlanes([y,clip], [0,1,2], vs.YUV)
clip.set_output()
feisty2
24th August 2016, 18:46
and also take a look at #20 (http://forum.doom9.org/showthread.php?p=1773252#post1773252)if you're then running out of memory..
groucho86
24th August 2016, 19:35
Thank you for your detailed response and for the syntax-example to properly pass Y (I was looking for such an example on the forum and probably copy-pasted from someone who was doing it wrong...)
The "CL_IMAGE_FORMAT_NOT_SUPPORTED" error persists. Not quite sure when I'll be able to test with a better graphics card. When I do, I'll be sure to post the results.
Thanks!
dipje
5th November 2016, 13:32
@groucho86 Are you running that HD5770 with the 'beta' Crimson test drivers for legacy cards instead of the old fashioned 'AMD Catalyst' ?. OpenCL is broken for legacy cards in the Crimson driver so you need the regular Catalyst drivers
groucho86
7th November 2016, 22:18
@groucho86 Are you running that HD5770 with the 'beta' Crimson test drivers for legacy cards instead of the old fashioned 'AMD Catalyst' ?. OpenCL is broken for legacy cards in the Crimson driver so you need the regular Catalyst drivers
Interesting. I wasn't even aware there were test drivers available. This was the default drivers that (I assume) come with Mac OS 10.9.5.
dipje
8th November 2016, 02:31
Hmm, I was assuming Windows. No clue how drivers and/or opencl work in macos
cork_OS
29th November 2016, 20:36
Deringing samples are very impressive!
feisty2
9th January 2017, 08:28
r5:
redid the basic estimation and brought a new parameter "short_time"
short_time
with short_time = True, starts motion estimation at the block size of 8x8 and gradually refines it to 2x2 (optimized for maximum spatial resolution), short_time = False starts motion estimation at 16x16 and gradually refines it to 4x4 (optimized for maximum frequency resolution). short_time = True is meant for Deringing and short_time = False is for Destaircase and Deblocking
edit:typo
feisty2
6th February 2017, 14:18
r6:
redesigned motion estimation when short_time = False (adaptive block size from 128x128 to 4x4)
bebs
12th February 2017, 22:18
Hello,
I tried to use Oyster on a de-interlaced PAL clip (768x576), and it failed with :
Failed to evaluate the script:
Python exception: BlankClip: color value out of range
Traceback (most recent call last):
File "src\cython\vapoursynth.pyx", line 1712, in vapoursynth.vpy_evaluateScript (src\cython\vapoursynth.c:34991)
File "C:/Video/Ori/Capture OK/WES-2003/WES 2003.vpy", line 167, in
y= Oyster.Destaircase(src, ref)
File "C:\Program Files\Python36\lib\site-packages\Oyster.py", line 383, in Destaircase
thr, elast, lowpass, matrix)
File "C:\Program Files\Python36\lib\site-packages\Oyster.py", line 173, in destaircase
mask = core.GenBlockMask(core.ShufflePlanes(src, 0, vs.GRAY))
File "C:\Program Files\Python36\lib\site-packages\Oyster.py", line 89, in GenBlockMask
clip = self.BlankClip(src, 24, 24, color=0.0)
File "src\cython\vapoursynth.pyx", line 1604, in vapoursynth.Function.__call__ (src\cython\vapoursynth.c:33131)
vapoursynth.Error: BlankClip: color value out of range
My script is :
VidBN = core.fmtc.bitdepth(VidBN,bits=32,fulls=False,fulld=True)
y = core.std.ShufflePlanes(VidBN,0,vs.GRAY)
ref = Oyster.Basic(y, Oyster.Super (y))
y= Oyster.Destaircase(y, ref)
VidBN = core.std.ShufflePlanes([y,VidBN], [0,1,2], vs.YUV)
VidBN.set_output()
What's the problem ?
feisty2
13th February 2017, 08:27
I tried to use Oyster on a de-interlaced PAL clip (768x576)
PAL should be 720(or probably something less than 720)x576, apply Oyster BEFORE resizing.
http://i.imgur.com/Sc36zcD.png
and I can't reproduce the error, are you using an outdated version of vaporsynth?
Jindadil007
14th February 2017, 07:13
Fiesty: Would appreciate if you could update correct sequence to run your scripts. I am using like this :
QTGMC > Vine > VBm3d > Oyster (For Deblocking) > Encode with (Plum is very slow therefore sticking with Finesharp alongwith VBm3d script)
Source : 720*480 DVD9. 29.970 fps
Thanks !!!
feisty2
14th February 2017, 07:47
qtgmc -> vine -> oyster -> v-bm3d -> finesharp
Jindadil007
14th February 2017, 08:18
qtgmc -> vine -> oyster -> v-bm3d -> finesharp
Thanks dear...:thanks:
Jindadil007
14th February 2017, 19:26
This is super slow @ 0.00158 fps...it took 20 minutes to process 2 frames ... can't we run it faster ? This is my script :
ref_f = Oyster.Basic(y, Oyster.Super (y), short_time=False)
ref_s = Oyster.Basic(y, Oyster.Super (y), short_time=True)
y = Oyster.Deblocking(y, ref_f, block_step=2)
y = Oyster.Deringing(y, ref_s, sigma=24.0, h=10.8, block_step=2)
feisty2
15th February 2017, 06:11
Oyster.Super (y) -> None
block_step=2 -> block_step=6
lower "pel" to 2, "radius" to 3
feisty2
15th February 2017, 12:27
and also you HAVE TO create intermediate raw files for your process chain.
it will probably be hundreds times faster unless you have 1TB of RAM or so
Jindadil007
15th February 2017, 13:10
and also you HAVE TO create intermediate raw files for your process chain.
it will probably be hundreds times faster unless you have 1TB of RAM or so
Many Thanks...I am testing it on 16GB DDR4 ... Basic Script is pretty fast...This serves my purpose...
feisty2
15th February 2017, 13:28
Many Thanks...I am testing it on 16GB DDR4 ... Would check with new radius and block values as suggested by you... Would update after testing...
if you wanna stick to
ref_f = Oyster.Basic(y, Oyster.Super (y), short_time=False)
ref_s = Oyster.Basic(y, Oyster.Super (y), short_time=True)
y = Oyster.Deblocking(y, ref_f, block_step=2)
y = Oyster.Deringing(y, ref_s, sigma=24.0, h=10.8, block_step=2)
and don't wanna spend eternity waiting...
you have no other choice but to split the script up.
script 1:
y = ....
clip = Oyster.Super (y)
clip.set_output()
vspipe script1.vpy super.raw -p
script 2:
super = core.raws.Source("super.raw", ...)
ref_f = Oyster.Basic(y, super, short_time=False)
ref_f.set_output()
vspipe script2.vpy ref_f.raw -p
script 3:
super = core.raws.Source("super.raw", ...)
ref_s = Oyster.Basic(y, super, short_time=True)
ref_s.set_output()
vspipe script3.vpy ref_s.raw -p
del super.raw
script 4:
ref_f = core.raws.Source("ref_f.raw", ...)
y = Oyster.Deblocking(y, ref_f, block_step=2)
y.set_output()
vspipe script4.vpy deblocked.raw -p
del ref_f.raw
script 5:
y = core.raws.Source("deblocked.raw", ...)
ref_s = core.raws.Source("ref_s.raw", ...)
y = Oyster.Deringing(y, ref_s, sigma=24.0, h=10.8, block_step=2)
y.set_output()
vspipe script5.vpy final.raw -p
del ref_s.raw
del deblocked.raw
Jindadil007
15th February 2017, 13:56
if you wanna stick to and don't wanna spend eternity waiting...you have no other choice but to split the script up.
Thanks for a detailed explanation... Would surely try it that way... Currently I am sticking to :
y = Oyster.Basic(y, super=None, radius=6, pel=4, sad=2000.0, short_time=False)
Once I check output video quality then I would test the way you have suggested...
Jindadil007
16th February 2017, 13:17
Thanks for a detailed explanation... Would surely try it that way... Currently I am sticking to :
y = Oyster.Basic(y, super=None, radius=6, pel=4, sad=2000.0, short_time=False)
Once I check output video quality then I would test the way you have suggested...
Hi feisty...With the Oyster Basic script, Video gets darkened a bit...Black gets intensified...is it natural with Oyster ?
feisty2
16th February 2017, 13:38
Post your full script
Jindadil007
16th February 2017, 13:40
Post your full script
import vapoursynth as vs
import adjust
import Vine
import Oyster
import mvmulti
import finesharp
import havsfunc as haf
import mvsfunc as mvf
core = vs.get_core()
core.max_cache_size = 12000
video = core.lsmas.LWLibavSource(r'C:\DVD\Sample\Vine.mkv')
video = core.fmtc.bitdepth(video,bits=32,fulls=False,fulld=True)
y = core.std.ShufflePlanes(video,0,vs.GRAY)
y = Oyster.Basic(y, super=None, radius=6, pel=4, sad=2000.0, short_time=False)
video = core.std.ShufflePlanes([y,video], [0,1,2], vs.YUV)
video = core.fmtc.bitdepth(video,bits=8,fulls=False,fulld=True)
video.set_output()
feisty2
16th February 2017, 13:44
Read the documentation of fmtconv then you'll know the answer, Oyster has nothing to do with your problem
Key words: fulls fulld
Jindadil007
16th February 2017, 13:55
Read the documentation of fmtconv then you'll know the answer, Oyster has nothing to do with your problem
Key words: fulls fulld
Many Thanks...Read the documentation...Changed fulld to TV Range=False and it did the trick...:thanks:
Cary Knoop
20th February 2017, 07:02
Hello,
I tried to use Oyster on a de-interlaced PAL clip (768x576), and it failed with :
Failed to evaluate the script:
Python exception: BlankClip: color value out of range
Traceback (most recent call last):
File "src\cython\vapoursynth.pyx", line 1712, in vapoursynth.vpy_evaluateScript (src\cython\vapoursynth.c:34991)
File "C:/Video/Ori/Capture OK/WES-2003/WES 2003.vpy", line 167, in
y= Oyster.Destaircase(src, ref)
File "C:\Program Files\Python36\lib\site-packages\Oyster.py", line 383, in Destaircase
thr, elast, lowpass, matrix)
File "C:\Program Files\Python36\lib\site-packages\Oyster.py", line 173, in destaircase
mask = core.GenBlockMask(core.ShufflePlanes(src, 0, vs.GRAY))
File "C:\Program Files\Python36\lib\site-packages\Oyster.py", line 89, in GenBlockMask
clip = self.BlankClip(src, 24, 24, color=0.0)
File "src\cython\vapoursynth.pyx", line 1604, in vapoursynth.Function.__call__ (src\cython\vapoursynth.c:33131)
vapoursynth.Error: BlankClip: color value out of range
I just encountered exactly the same error. Any hint as to what might be the problem?
Oyster is called in the following way:
clip = core.fmtc.bitdepth(c, bits=32, fulls=False, fulld=False)
y = core.std.ShufflePlanes(clip, 0, vs.GRAY)
ref = Oyster.Basic(y, Oyster.Super(y))
y = Oyster.Deblocking(y, ref, block_step=2)
y = Oyster.Deringing(y, ref, sigma=24.0, h=10.8, block_step=2)
clip = core.std.ShufflePlanes([y, clip], [0, 1, 2], vs.YUV)
feisty2
22nd February 2017, 09:01
I just encountered exactly the same error. Any hint as to what might be the problem?
Oyster is called in the following way:
clip = core.fmtc.bitdepth(c, bits=32, fulls=False, fulld=False)
y = core.std.ShufflePlanes(clip, 0, vs.GRAY)
ref = Oyster.Basic(y, Oyster.Super(y))
y = Oyster.Deblocking(y, ref, block_step=2)
y = Oyster.Deringing(y, ref, sigma=24.0, h=10.8, block_step=2)
clip = core.std.ShufflePlanes([y, clip], [0, 1, 2], vs.YUV)
I got 2 things to say here,
1. before the next release of KNLMeansCL, please manually change line 67 to
nlm = self.KNLMeansCL(pad, d=d, a=a, s=s, h=h * math.sqrt(3), channels="YUV" if color else "Y", wref=1.0, rclip=rclip)
to fix a bug introduced in v1.0 (https://forum.doom9.org/showpost.php?p=1797511&postcount=1134)
2. what version of vaporsynth are you using? (the latest one?), will it work if you comment out "Oyster.Deringing"?
Are_
22nd February 2017, 10:35
Using VapourSynth and Oyster at current git.
Deblocking, Deringin, Destaircase, anything triggers this bug.
Even this script raises an error:
import vapoursynth as vs
core = vs.get_core()
clip = core.std.BlankClip(format=vs.GRAYS, color=0.0)
clip.set_output()
And I'm not sure anything should be wrong there.
Also documentation being so scarce on BlankClip does not help either.
So welp, I'm pretty sure the bug is in VapourSynth, maybe I will fill a bug if I gather the strength to do it. :/
EDIT: Hohum, same problem with vapoursynth-36, now I'm not sure anymore about anything.
jackoneill
22nd February 2017, 11:52
Using VapourSynth and Oyster at current git.
Deblocking, Deringin, Destaircase, anything triggers this bug.
Even this script raises an error:
import vapoursynth as vs
core = vs.get_core()
clip = core.std.BlankClip(format=vs.GRAYS, color=0.0)
clip.set_output()
And I'm not sure anything should be wrong there.
Also documentation being so scarce on BlankClip does not help either.
So welp, I'm pretty sure the bug is in VapourSynth, maybe I will fill a bug if I gather the strength to do it. :/
EDIT: Hohum, same problem with vapoursynth-36, now I'm not sure anymore about anything.
What's missing from the documentation? I can fix that.
feisty2
22nd February 2017, 11:59
Using VapourSynth and Oyster at current git.
Deblocking, Deringin, Destaircase, anything triggers this bug.
Even this script raises an error:
import vapoursynth as vs
core = vs.get_core()
clip = core.std.BlankClip(format=vs.GRAYS, color=0.0)
clip.set_output()
And I'm not sure anything should be wrong there.
Also documentation being so scarce on BlankClip does not help either.
So welp, I'm pretty sure the bug is in VapourSynth, maybe I will fill a bug if I gather the strength to do it. :/
EDIT: Hohum, same problem with vapoursynth-36, now I'm not sure anymore about anything.
http://i.imgur.com/nWnCbCG.png
that's weird cuz I couldn't reproduce the error..
maybe just a bug exclusive to Linux vaporsynth?
Are_
22nd February 2017, 12:17
What's missing from the documentation? I can fix that.
Well, I expected color to be a float from the documentation, but the error got me confused about the actual allowed range for it. Maybe saying something like it mapping to the format range and if chroma in float formats maps to -0.5 too. If bugs didn't exist this will be not a problem, though.
Are_
22nd February 2017, 12:19
that's weird cuz I couldn't reproduce the error..
maybe just a bug exclusive to Linux vaporsynth?
Then it looks like this was a bug introduced in R36 for posix targets https://github.com/vapoursynth/vapoursynth/issues/290
Cary Knoop
24th February 2017, 02:45
I got 2 things to say here,
1. before the next release of KNLMeansCL, please manually change line 67 to
nlm = self.KNLMeansCL(pad, d=d, a=a, s=s, h=h * math.sqrt(3), channels="YUV" if color else "Y", wref=1.0, rclip=rclip)
to fix a bug introduced in v1.0 (https://forum.doom9.org/showpost.php?p=1797511&postcount=1134)
2. what version of vaporsynth are you using? (the latest one?), will it work if you comment out "Oyster.Deringing"?
Sorry for the late reply.
The error was found on Windows using:
Vapoursynth: R36
KNLMeansCL. 1.01
Jindadil007
25th February 2017, 09:15
Sorry for the late reply.
The error was found on Windows using:
Vapoursynth: R36
KNLMeansCL. 1.01
KNLMeansCL. 1.01 has a bug...Use version 0.7.7
feisty2
25th February 2017, 14:43
Sorry for the late reply.
The error was found on Windows using:
Vapoursynth: R36
KNLMeansCL. 1.01
I think that's a vaporsynth bug and there's really nothing I can do..
https://github.com/vapoursynth/vapoursynth/issues/290
Cary Knoop
25th February 2017, 18:03
KNLMeansCL. 1.01 has a bug...Use version 0.7.7
Which bug are you referring to?
I did not see any open bugs on GitHub.
Are_
25th February 2017, 18:15
h parameter is scaled differently, to have the same strength in 1.0.x you had in 0.7.x series you need to do h * math.sqrt(3) as feisty2 pointed out. The author knows about it and it will be solved in next release, probably.
Cary Knoop
25th February 2017, 20:04
h parameter is scaled differently, to have the same strength in 1.0.x you had in 0.7.x series you need to do h * math.sqrt(3) as feisty2 pointed out. The author knows about it and it will be solved in next release, probably.
The author should probably express his intent so others can anticipate, if it stays that way many scripts would have to be updated, if it is going to change then it is probably best to wait for 1.02.
Are_
25th February 2017, 20:09
He expressed it in his main thread, it's a bug introduced in 1.x.x series and will be fixed, eventually. :(
Tormaid
18th January 2018, 19:45
This script (taken from the "examples" section on the github page) is consistently crashing Vaporusynth for me. I'm running R42.1 and using the most up-to-date versions of all of the prerequisite filters and scripts, as far as I am aware. The one I'm not 100% sure about is the version of libfftw3-3.dll I got from this site (http://www.fftw.org/install/windows.html).
import vapoursynth as vs
import Oyster
core = vs.get_core()
v = core.ffms2.Source(r"clip.mp4")
v = core.fmtc.bitdepth(v, bits=32)
y = core.std.ShufflePlanes(v, 0, vs.GRAY)
sup = Oyster.Super(y)
ref_f = Oyster.Basic(y, sup, short_time=False)
ref_s = Oyster.Basic(y, sup, short_time=True)
y = Oyster.Destaircase(y, ref_f, sigma=24.0, block_step=2)
y = Oyster.Deringing(y, ref_s, sigma=24.0, h=9.6, block_step=2)
y.set_output()
It crashes whether I'm opening it in vsedit or directly using vspipe.
Edit: I've tested it on two different computers, both running Windows 10, and had the same results.
leon
1st February 2018, 01:47
When I try to import Oyster I get this error:
Traceback (most recent call last):
File "src\cython\vapoursynth.pyx", line 1841, in vapoursynth.vpy_evaluateScript
File "C:/Users/.../Desktop/Untitled.vpy", line 3, in
import Oyster
File "C:\Users\...\AppData\Local\Programs\Python\Python36\lib\site-packages\Oyster.py", line 3, in
import mvmulti
ModuleNotFoundError: No module named 'mvmulti'
What am I doing wrong ?
WolframRhodium
1st February 2018, 02:10
When I try to import Oyster I get this error:
Traceback (most recent call last):
File "src\cython\vapoursynth.pyx", line 1841, in vapoursynth.vpy_evaluateScript
File "C:/Users/Admin/Desktop/Untitled.vpy", line 3, in
import Oyster
File "C:\Users\Admin\AppData\Local\Programs\Python\Python36\lib\site-packages\Oyster.py", line 3, in
import mvmulti
ModuleNotFoundError: No module named 'mvmulti'
What am I doing wrong ?
https://github.com/IFeelBloated/vapoursynth-mvtools-sf/blob/master/src/mvmulti.py
leon
1st February 2018, 04:09
https://github.com/IFeelBloated/vapoursynth-mvtools-sf/blob/master/src/mvmulti.py
I'd tried that before posting but oddly it didn't work(maybe wrong folder).
It works now :thanks:
Max_143
6th February 2018, 15:07
vapoursynth-nnedi3-v11-win64.7z and nnedi3_weights.bin
I took here https://github.com/dubhater/vapoursynth-nnedi3
Script
sup = Oyster.Super(y)
ref_f = Oyster.Basic(y, sup, short_time=False)
ref_s = Oyster.Basic(y, sup, short_time=True)
y = Oyster.Destaircase(y, ref_f, sigma=24.0, block_step=2)
y = Oyster.Deringing(y, ref_s, sigma=24.0, h=9.6, block_step=2)
y.set_output()
I get an error
Failed to evaluate the script:
Python exception: nnedi3: 'D:/Instal/Video/Vapoursynth/Instal/python-3.6.4-embed-amd64/vapoursynth64/plugins/nnedi3_weights.bin' has the wrong size. Expected 13574928 bytes, got 41011 bytes.
Traceback (most recent call last):
File "src\cython\vapoursynth.pyx", line 1847, in vapoursynth.vpy_evaluateScript
File "D:/Klipy/Obrabotka/VsPipe/2/vs2.vpy", line 44, in
sup = Oyster.Super(y)
File "D:\Instal\Video\Vapoursynth\Instal\python-3.6.4-embed-amd64\Oyster.py", line 230, in Super
clip = internal.super(core, src, pel)
File "D:\Instal\Video\Vapoursynth\Instal\python-3.6.4-embed-amd64\Oyster.py", line 108, in super
clip = core.Transpose(core.NNEDI(core.Transpose(core.NNEDI(src, **nnedi_args)), **nnedi_args))
File "src\cython\vapoursynth.pyx", line 1739, in vapoursynth.Function.__call__
vapoursynth.Error: nnedi3: 'D:/Instal/Video/Vapoursynth/Instal/python-3.6.4-embed-amd64/vapoursynth64/plugins/nnedi3_weights.bin' has the wrong size. Expected 13574928 bytes, got 41011 bytes.
I need another file nnedi3_weights.bin or error in another?
(Windows 7 x64)
P.S.
thanks, figured out)
Cary Knoop
2nd September 2018, 04:52
This script is excellent, the default settings are great as well but I made some compromises for speed.
On a deinterlaced PAL video I am using this:
ref_s = Oyster.Basic(y, short_time=True, pel=4)
y = Oyster.Deringing(y, ref_s, radius=3, sigma=24.0, h=8, block_step=6)
It's slow, I get about 3 fps on using 45GB of memory.
Would be interesting to see if the Threadripper 2 can improve speed.
Using a Threadripper 1950X with 64GB of memory and a 1080TI GPU.
To improve speed could a GPU implementation of bm3d be of help? Especially when having multiple GPUs.
https://github.com/JeffOwOSun/gpu-bm3d
zorr
7th February 2019, 00:36
been hours and I tried like a million sets of parameters to investigate if there's any chance of quality-speed tradeoff, and, failed to get rid of the abysmal performance
...
I'm out of ideas of performance boost..
and also you HAVE TO create intermediate raw files for your process chain.
it will probably be hundreds times faster unless you have 1TB of RAM or so
I sped up one of my Avisynth processes by creating intermediate files for each phase (QTGMC -> SMDegrain -> other filters). It speeds up processing tremendously especially when using temporal filters. In theory the frames could be cached but perhaps there just isn't enough memory or maybe the caches are just too small.
Just wondering if doing that for the sub-processes inside Oyster functions would also give speedup. So for example Deblocking could make files between core.NLMeans and core.BMBasic etc. It would of course make calling the filters convoluted, you'd have to pass in a phase number and some extra input files and do the processing in multiple scripts. But I think it might be worth investigating if any speedup is possible that way.
asarian
6th March 2019, 01:11
Holy crap! This Oyster thing is wickedly good! :) Here's a sample from an old DVD of mine, called Old Enough (https://1drv.ms/u/s!AhSxhQ9g_mrMlgx9eSJeXQifBgvR). On the left is the restored image, on the right the original. Notice how extremely well the MPEG 'smudginess' has disappeared! (Look around the hair, for instance)
Oyster is not the fastest filter in the book, though. :)
asarian
6th March 2019, 06:42
I sped up one of my Avisynth processes by creating intermediate files for each phase (QTGMC -> SMDegrain -> other filters).
What kind of intermediate file-size are we talking about here? I tried a 'Super' intermediate pass, but ran out of hard disk space (Sic!) at several hundred G (for a 720x480p source).
zorr
6th March 2019, 10:55
What kind of intermediate file-size are we talking about here? I tried a 'Super' intermediate pass, but ran out of hard disk space (Sic!) at several hundred G (for a 720x480p source).
Im my case it was all 8bit and the clips were not that long. Super will need much more because it's 4x the resolution (assuming pel=4) and in 32bits per component. If you run out of hd space then maybe try to do the processing in segments. Also using a compressed (but still lossless) intermediate file such as FFV1 will help.
asarian
6th March 2019, 11:07
Im my case it was all 8bit and the clips were not that long. Super will need much more because it's 4x the resolution (assuming pel=4) and in 32bits per component. If you run out of hd space then maybe try to do the processing in segments. Also using a compressed (but still lossless) intermediate file such as FFV1 will help.
My 720x480p source was a full-length movie. :) So, a compressed output is good idea. :thanks:
poisondeathray
6th March 2019, 15:59
Holy crap! This Oyster thing is wickedly good! :) Here's a sample from an old DVD of mine, called Old Enough (https://1drv.ms/u/s!AhSxhQ9g_mrMlgx9eSJeXQifBgvR). On the left is the restored image, on the right the original. Notice how extremely well the MPEG 'smudginess' has disappeared! (Look around the hair, for instance)
Oyster is not the fastest filter in the book, though. :)
It does look impressive
One thing that stands out is the left cheek blemish - it looks over enhanced. Was that temporally consistent on other frames ? (or are you still waiting for it to finish processing other frames? :devil: :) )
asarian
7th March 2019, 02:10
It does look impressive
One thing that stands out is the left cheek blemish - it looks over enhanced. Was that temporally consistent on other frames ? (or are you still waiting for it to finish processing other frames? :devil: :) )
That left-cheek blemish was actually a small glitch, it seems, in the original video (only lasting 2 frames). So, good thing Oyster got rid of it. :)
As for still waiting, my poor i7 6700K is going to take 54 hours to complete the job. :scared:
Revan654
31st March 2019, 19:46
I've been trying to get Oyster to work, I always run into either Subsampling not support, which I can easily get around, But it's the whole Blocksize issue. I've tried many source but always run into the same issue. Anyone know what else needs to be added to get this to work?
Python exception: Analyze: the block size must be 4x4, 8x4, 8x8, 16x2, 16x8, 16x16, 32x16, or 32x32.
Example of the Script:
clip = core.fmtc.bitdepth( clip, bits = 32 )
clip = core.fmtc.resample( clip, css = "444" )
ref_s = Oyster.Basic(clip, short_time=True)
clip = Oyster.Deringing(clip, ref_s, block_step=2)
jackoneill
31st March 2019, 21:57
I've been trying to get Oyster to work, I always run into either Subsampling not support, which I can easily get around, But it's the whole Blocksize issue. I've tried many source but always run into the same issue. Anyone know what else needs to be added to get this to work?
Python exception: Analyze: the block size must be 4x4, 8x4, 8x8, 16x2, 16x8, 16x16, 32x16, or 32x32.
Example of the Script:
clip = core.fmtc.bitdepth( clip, bits = 32 )
clip = core.fmtc.resample( clip, css = "444" )
ref_s = Oyster.Basic(clip, short_time=True)
clip = Oyster.Deringing(clip, ref_s, block_step=2)
You have an old copy of MVTools or MVToolsSF. Update them to the latest and that error should go away.
SoupRKnowva
31st May 2020, 02:52
I have a question about doing the process in a series of steps rather than all in one go.
When i run my script and set the output as the results of Oyster.Basic(), using "vspipe exmaple.vpy example_basic.rgb", when i import it again on the second part with core.raws.Source("example_basic.rgb"), I get an error "TypeError: Oyster.Destaircase: the sample type of ref has to be single precision!"
At first i thought the autoloader was using the wrong mvtools, so i removed the non _sf version. Same problem. I tried using example.raw instead of example.rgb, thinking maybe vspipe or the importer were doing something weird. same problem.
But if i feel the output of Basic() straight into Oyster.Destaircase, without saving it out, it works just fine.
Is there something I am missing with writing the file with vspipe or with the import with raws.source()?
feisty2
31st May 2020, 06:52
as the error suggested, the input must be of fp32 sample type, you have to specify the sample type in core.raws.Source
Cary Knoop
7th July 2020, 07:08
Oyster is great but the performance is highly impractical.
Using a GPU-based BM3D implementation would put this slowly into the world of practicality (Optimizing KNLMeans for CUDA instead of CL would probably help as well).
Any updates on a BM3D implementation in CUDA?
Cary Knoop
18th July 2020, 20:36
What is function of sstring in Oyster.py?
43 def FreqMerge(self, low, hi, sbsize, sstring):
44 hif = self.MakeDiff(hi, self.DFTTest(hi, sbsize=sbsize, sstring=sstring, **dfttest_args))
45 clip = self.MergeDiff(self.DFTTest(low, sbsize=sbsize, sstring=sstring, **dfttest_args), hif)
Does this perhaps refer to an older version of DFTTest?
feisty2
19th July 2020, 02:01
things have been updated in the GitHub repo
Cary Knoop
19th July 2020, 02:37
things have been updated in the GitHub repo
Got it, thanks!
Emulgator
23rd January 2023, 10:18
2023, Oyster in VapourSynth R61:
I would welcome a helping tip towards replacement of depreciated function calls
I tried, but I am a VS noob, and I would welcome a full documentation...
I have hacked at Oyster.py but I get "SyntaxError: Invalid syntax for"
core = import core
Split in 2 parts (forum 16000 chars limit)
from vapoursynth import core
import math
fmtc_args = dict(fulls=True, fulld=True)
msuper_args = dict(hpad=0, vpad=0, sharp=2, levels=0)
manalyze_args = dict(search=3, truemotion=False, trymany=True, levels=0, badrange=-24, divide=0, dct=0)
mrecalculate_args = dict(truemotion=False, search=3, smooth=1, divide=0, dct=0)
mdegrain_args = dict(thscd1=16711680.0, thscd2=255.0)
nnedi_args = dict(field=1, dh=True, nns=4, qual=2, etype=1, nsize=0)
dfttest_args = dict(smode=0, sosize=0, tbsize=1, tosize=0, tmode=0)
class core:
def __init__(self):
self.core = vs.core()
self.MSuper = self.core.mvsf.Super
self.MAnalyze = self.core.mvsf.Analyze
self.MRecalculate = self.core.mvsf.Recalculate
self.MDegrain = self.core.mvsf.Degrain
self.RGB2OPP = self.core.bm3d.RGB2OPP
self.OPP2RGB = self.core.bm3d.OPP2RGB
self.BMBasic = self.core.bm3d.VBasic
self.BMFinal = self.core.bm3d.VFinal
self.Aggregate = self.core.bm3d.VAggregate
self.DFTTest = self.core.dfttest.DFTTest
self.KNLMeansCL = self.core.knlm.KNLMeansCL
self.NNEDI = self.core.nnedi3.nnedi3
self.Resample = self.core.fmtc.resample
self.Expr = self.core.std.Expr
self.MakeDiff = self.core.std.MakeDiff
self.MergeDiff = self.core.std.MergeDiff
self.Crop = self.core.std.CropRel
self.CropAbs = self.core.std.CropAbs
self.Transpose = self.core.std.Transpose
self.BlankClip = self.core.std.BlankClip
self.AddBorders = self.core.std.AddBorders
self.StackHorizontal = self.core.std.StackHorizontal
self.StackVertical = self.core.std.StackVertical
self.MaskedMerge = self.core.std.MaskedMerge
self.ShufflePlanes = self.core.std.ShufflePlanes
self.SetFieldBased = self.core.std.SetFieldBased
def FreqMerge(self, low, hi, sbsize, slocation):
hif = self.MakeDiff(hi, self.DFTTest(hi, sbsize=sbsize, slocation=slocation, **dfttest_args))
clip = self.MergeDiff(self.DFTTest(low, sbsize=sbsize, slocation=slocation, **dfttest_args), hif)
return clip
def Pad(self, src, left, right, top, bottom):
w = src.width
h = src.height
clip = self.Resample(src, w+left+right, h+top+bottom, -left, -top, w+left+right, h+top+bottom, kernel="point", **fmtc_args)
return clip
def NLMeans(self, src, d, a, s, h, rclip, color):
def duplicate(src):
if d > 0:
blank = self.Expr(src[0], "0.0") * d
clip = blank + src + blank
else:
clip = src
return clip
pad = self.AddBorders(src, a+s, a+s, a+s, a+s)
pad = duplicate(pad)
if rclip is not None:
rclip = self.AddBorders(rclip, a+s, a+s, a+s, a+s)
rclip = duplicate(rclip)
nlm = self.KNLMeansCL(pad, d=d, a=a, s=s, h=h, channels="YUV" if color else "Y", wref=1.0, rclip=rclip)
clip = self.Crop(nlm, a+s, a+s, a+s, a+s)
return clip[d:clip.num_frames - d]
def ThrMerge(self, flt, src, ref=None, thr=0.0009765625, elast=None):
ref = src if ref is None else ref
elast = thr / 2 if elast is None else elast
BExp = ["x {thr} {elast} + z - 2 {elast} * / * y {elast} z + {thr} - 2 {elast} * / * +".format(thr=thr, elast=elast)]
BDif = self.Expr(src, "0.0")
PDif = self.Expr([flt, src], "x y - 0.0 max")
PRef = self.Expr([flt, ref], "x y - 0.0 max")
PBLD = self.Expr([PDif, BDif, PRef], BExp)
NDif = self.Expr([flt, src], "y x - 0.0 max")
NRef = self.Expr([flt, ref], "y x - 0.0 max")
NBLD = self.Expr([NDif, BDif, NRef], BExp)
BLDD = self.MakeDiff(PBLD, NBLD)
BLD = self.MergeDiff(src, BLDD)
UDN = self.Expr([flt, ref, BLD], ["x y - abs {thr} {elast} - > z x ?".format(thr=thr, elast=elast)])
clip = self.Expr([flt, ref, UDN, src], ["x y - abs {thr} {elast} + < z a ?".format(thr=thr, elast=elast)])
return clip
def GenBlockMask(self, src):
clip = self.BlankClip(src, 24, 24, color=0.0)
clip = self.AddBorders(clip, 4, 4, 4, 4, color=1.0)
clip = self.StackHorizontal([clip, clip, clip, clip])
clip = self.StackVertical([clip, clip, clip, clip])
clip = self.Resample(clip, 32, 32, kernel="point", **fmtc_args)
clip = self.Expr(clip, ["x 0.0 > 1.0 0.0 ?"])
clip = self.StackHorizontal([clip, clip, clip, clip, clip, clip, clip, clip])
clip = self.StackVertical([clip, clip, clip, clip, clip, clip])
clip = self.StackHorizontal([clip, clip, clip, clip, clip, clip])
clip = self.StackVertical([clip, clip, clip, clip, clip])
clip = self.StackHorizontal([clip, clip, clip, clip, clip, clip])
clip = self.StackVertical([clip, clip, clip, clip, clip])
clip = self.CropAbs(clip, src.width, src.height, 0, 0)
return clip
class internal:
def super(core, src, pel):
src = core.Pad(src, 128, 128, 128, 128)
clip = core.Transpose(core.NNEDI(core.Transpose(core.NNEDI(src, **nnedi_args)), **nnedi_args))
if pel == 4:
clip = core.Transpose(core.NNEDI(core.Transpose(core.NNEDI(clip, **nnedi_args)), **nnedi_args))
return clip
def basic(core, src, super, radius, pel, sad, short_time, color):
plane = 4 if color else 0
src = core.Pad(src, 128, 128, 128, 128)
supersoft = core.MSuper(src, pelclip=super, rfilter=4, pel=pel, chroma=color, **msuper_args)
supersharp = core.MSuper(src, pelclip=super, rfilter=2, pel=pel, chroma=color, **msuper_args)
if short_time:
constant = 0.0001989762736579584832432989326
me_sad = [constant * math.pow(sad, 2.0) * math.log(1.0 + 1.0 / (constant * sad))]
me_sad += [sad]
vmulti = core.MAnalyze(supersoft, radius=radius, chroma=color, overlap=4, blksize=8, **manalyze_args)
vmulti = core.MRecalculate(supersoft, vmulti, chroma=color, overlap=2, blksize=4, thsad=me_sad[0], **mrecalculate_args)
vmulti = core.MRecalculate(supersoft, vmulti, chroma=color, overlap=1, blksize=2, thsad=me_sad[1], **mrecalculate_args)
else:
constant = 0.0000139144247313257680589719533
me_sad = constant * math.pow(sad, 2.0) * math.log(1.0 + 1.0 / (constant * sad))
vmulti = core.MAnalyze(supersoft, radius=radius, chroma=color, overlap=64, blksize=128, **manalyze_args)
vmulti = core.MRecalculate(supersoft, vmulti, chroma=color, overlap=32, blksize=64, thsad=me_sad, **mrecalculate_args)
vmulti = core.MRecalculate(supersoft, vmulti, chroma=color, overlap=16, blksize=32, thsad=me_sad, **mrecalculate_args)
vmulti = core.MRecalculate(supersoft, vmulti, chroma=color, overlap=8, blksize=16, thsad=me_sad, **mrecalculate_args)
vmulti = core.MRecalculate(supersoft, vmulti, chroma=color, overlap=4, blksize=8, thsad=me_sad, **mrecalculate_args)
vmulti = core.MRecalculate(supersoft, vmulti, chroma=color, overlap=2, blksize=4, thsad=me_sad, **mrecalculate_args)
clip = core.MDegrain(src, supersharp, vmulti, thsad=sad, plane=plane, **mdegrain_args)
clip = core.Crop(clip, 128, 128, 128, 128)
return clip
def deringing(core, src, ref, radius, h, sigma, \
mse, hard_thr, block_size, block_step, group_size, bm_range, bm_step, ps_num, ps_range, ps_step, \
lowpass, color, matrix):
c1 = 0.1134141984932795312503328847998
c2 = 2.8623043756241389436528021745239
strength = [h]
strength += [h * math.pow(c1 * h, c2) * math.log(1.0 + 1.0 / math.pow(c1 * h, c2))]
strength += [None]
def loop(flt, init, src, n):
strength[2] = n * strength[0] / 4 + strength[1] * (1 - n / 4)
window = int(32 / math.pow(2, n))
flt = init if n == 4 else flt
dif = core.MakeDiff(src, flt)
dif = core.NLMeans(dif, 0, window, 1, strength[2], flt, color)
fnl = core.MergeDiff(flt, dif)
n -= 1
return fnl if n == -1 else loop(fnl, init, src, n)
ref = core.FreqMerge(src, ref, block_size // 2 * 2 + 1, lowpass)
dif = core.MakeDiff(src, ref)
dif = core.BMBasic(dif, ref, radius=radius, th_mse=mse[0], hard_thr=hard_thr, sigma=sigma, \
block_size=block_size, block_step=block_step, group_size=group_size, bm_range=bm_range, bm_step=bm_step, \
ps_num=ps_num, ps_range=ps_range, ps_step=ps_step, matrix=matrix)
dif = core.Aggregate(dif, radius, 1)
ref = core.MergeDiff(ref, dif)
refined = loop(None, ref, src, 4)
bm3d = core.BMFinal(refined, ref, radius=radius, th_mse=mse[1], sigma=sigma, \
block_size=block_size, block_step=block_step, group_size=group_size, bm_range=bm_range, bm_step=bm_step, \
ps_num=ps_num, ps_range=ps_range, ps_step=ps_step, matrix=matrix)
bm3d = core.Aggregate(bm3d, radius, 1)
bm3d = core.FreqMerge(refined, bm3d, block_size // 2 * 2 + 1, lowpass)
clip = loop(None, bm3d, refined, 4)
return clip
def destaircase(core, src, ref, radius, sigma, \
mse, hard_thr, block_size, block_step, group_size, bm_range, bm_step, ps_num, ps_range, ps_step, \
thr, elast, lowpass, matrix):
mask = core.GenBlockMask(core.ShufflePlanes(src, 0, vs.GRAY))
ref = core.FreqMerge(src, ref, block_size // 2 * 2 + 1, lowpass)
ref = core.ThrMerge(src, ref, thr=thr, elast=elast)
dif = core.MakeDiff(src, ref)
dif = core.BMBasic(dif, ref, radius=radius, th_mse=mse[0], hard_thr=hard_thr, sigma=sigma, \
block_size=block_size, block_step=block_step, group_size=group_size, bm_range=bm_range, bm_step=bm_step, \
ps_num=ps_num, ps_range=ps_range, ps_step=ps_step, matrix=matrix)
dif = core.Aggregate(dif, radius, 1)
ref = core.MergeDiff(ref, dif)
dif = core.MakeDiff(src, ref)
dif = core.BMFinal(dif, ref, radius=radius, th_mse=mse[1], sigma=sigma, \
block_size=block_size, block_step=block_step, group_size=group_size, bm_range=bm_range, bm_step=bm_step, \
ps_num=ps_num, ps_range=ps_range, ps_step=ps_step, matrix=matrix)
dif = core.Aggregate(dif, radius, 1)
ref = core.MergeDiff(ref, dif)
clip = core.MaskedMerge(src, ref, mask, first_plane=True)
return clip
def deblocking(core, src, ref, radius, h, sigma, \
mse, hard_thr, block_size, block_step, group_size, bm_range, bm_step, ps_num, ps_range, ps_step, \
lowpass, color, matrix):
mask = core.GenBlockMask(core.ShufflePlanes(src, 0, vs.GRAY))
cleansed = core.NLMeans(ref, radius, block_size, math.ceil(block_size / 2), h, ref, color)
dif = core.MakeDiff(ref, cleansed)
dif = core.BMBasic(dif, cleansed, radius=radius, th_mse=mse[0], hard_thr=hard_thr, sigma=sigma, \
block_size=block_size, block_step=block_step, group_size=group_size, bm_range=bm_range, bm_step=bm_step, \
ps_num=ps_num, ps_range=ps_range, ps_step=ps_step, matrix=matrix)
dif = core.Aggregate(dif, radius, 1)
cleansed = core.MergeDiff(cleansed, dif)
dif = core.MakeDiff(ref, cleansed)
dif = core.BMFinal(dif, cleansed, radius=radius, th_mse=mse[1], sigma=sigma, \
block_size=block_size, block_step=block_step, group_size=group_size, bm_range=bm_range, bm_step=bm_step, \
ps_num=ps_num, ps_range=ps_range, ps_step=ps_step, matrix=matrix)
dif = core.Aggregate(dif, radius, 1)
cleansed = core.MergeDiff(cleansed, dif)
ref = core.FreqMerge(cleansed, ref, block_size // 2 * 2 + 1, lowpass)
src = core.FreqMerge(cleansed, src, block_size // 2 * 2 + 1, lowpass)
clip = core.MaskedMerge(src, ref, mask, first_plane=True)
return clip
Emulgator
23rd January 2023, 10:20
def Super(src, pel=4):
if not isinstance(src, vs.VideoNode):
raise TypeError("Oyster.Super: src has to be a video clip!")
elif src.format.sample_type != vs.FLOAT or src.format.bits_per_sample < 32:
raise TypeError("Oyster.Super: the sample type of src has to be single precision!")
elif src.format.subsampling_w > 0 or src.format.subsampling_h > 0:
raise RuntimeError("Oyster.Super: subsampled stuff not supported!")
if not isinstance(pel, int):
raise TypeError("Oyster.Super: pel has to be an integer!")
elif pel != 2 and pel != 4:
raise RuntimeError("Oyster.Super: pel has to be 2 or 4!")
core = import core
src = core.SetFieldBased(src, 0)
colorspace = src.format.color_family
if colorspace == vs.RGB:
src = core.RGB2OPP(src, 1)
clip = internal.super(core, src, pel)
del core
return clip
def Basic(src, super=None, radius=6, pel=4, sad=2000.0, short_time=False):
if not isinstance(src, vs.VideoNode):
raise TypeError("Oyster.Basic: src has to be a video clip!")
elif src.format.sample_type != vs.FLOAT or src.format.bits_per_sample < 32:
raise TypeError("Oyster.Basic: the sample type of src has to be single precision!")
elif src.format.subsampling_w > 0 or src.format.subsampling_h > 0:
raise RuntimeError("Oyster.Basic: subsampled stuff not supported!")
if not isinstance(super, vs.VideoNode) and super is not None:
raise TypeError("Oyster.Basic: super has to be a video clip or None!")
elif super is not None:
if super.format.sample_type != vs.FLOAT or super.format.bits_per_sample < 32 or super.format.subsampling_w > 0 or super.format.subsampling_h > 0:
raise RuntimeError("Oyster.Basic: corrupted super clip!")
if not isinstance(radius, int):
raise TypeError("Oyster.Basic: radius has to be an integer!")
elif radius < 1:
raise RuntimeError("Oyster.Basic: radius has to be greater than 0!")
if not isinstance(pel, int):
raise TypeError("Oyster.Basic: pel has to be an integer!")
elif pel != 1 and pel != 2 and pel != 4:
raise RuntimeError("Oyster.Basic: pel has to be 1, 2 or 4!")
if not isinstance(sad, float) and not isinstance(sad, int):
raise TypeError("Oyster.Basic: sad has to be a real number!")
elif sad <= 0.0:
raise RuntimeError("Oyster.Basic: sad has to be greater than 0!")
if not isinstance(short_time, bool):
raise TypeError("Oyster.Basic: short_time has to be boolean!")
core = import core
color = True
rgb = False
colorspace = src.format.color_family
if colorspace == vs.RGB:
src = core.RGB2OPP(src, 1)
rgb = True
if colorspace == vs.GRAY:
color = False
src = core.SetFieldBased(src, 0)
super = core.SetFieldBased(super, 0) if super is not None else None
clip = internal.basic(core, src, super, radius, pel, sad, short_time, color)
clip = core.OPP2RGB(clip, 1) if rgb else clip
del core
return clip
def Deringing(src, ref, radius=6, h=6.4, sigma=16.0, \
mse=[None, None], hard_thr=3.2, block_size=8, block_step=1, group_size=32, bm_range=24, bm_step=1, ps_num=2, ps_range=8, ps_step=1, \
lowpass=None):
if not isinstance(src, vs.VideoNode):
raise TypeError("Oyster.Deringing: src has to be a video clip!")
elif src.format.sample_type != vs.FLOAT or src.format.bits_per_sample < 32:
raise TypeError("Oyster.Deringing: the sample type of src has to be single precision!")
elif src.format.subsampling_w > 0 or src.format.subsampling_h > 0:
raise RuntimeError("Oyster.Deringing: subsampled stuff not supported!")
if not isinstance(ref, vs.VideoNode):
raise TypeError("Oyster.Deringing: ref has to be a video clip!")
elif ref.format.sample_type != vs.FLOAT or ref.format.bits_per_sample < 32:
raise TypeError("Oyster.Deringing: the sample type of ref has to be single precision!")
elif ref.format.subsampling_w > 0 or ref.format.subsampling_h > 0:
raise RuntimeError("Oyster.Deringing: subsampled stuff not supported!")
if not isinstance(radius, int):
raise TypeError("Oyster.Deringing: radius has to be an integer!")
elif radius < 1:
raise RuntimeError("Oyster.Deringing: radius has to be greater than 0!")
if not isinstance(h, float) and not isinstance(h, int):
raise TypeError("Oyster.Deringing: h has to be a real number!")
elif h <= 0:
raise RuntimeError("Oyster.Deringing: h has to be greater than 0!")
if not isinstance(mse, list):
raise TypeError("Oyster.Deringing: mse parameter has to be an array!")
elif len(mse) != 2:
raise RuntimeError("Oyster.Deringing: mse parameter has to contain 2 elements exactly!")
for i in range(2):
if not isinstance(mse[i], float) and not isinstance(mse[i], int) and mse[i] is not None:
raise TypeError("Oyster.Deringing: elements in mse must be real numbers or None!")
if not isinstance(lowpass, list) and lowpass is not None:
raise TypeError("Oyster.Deringing: lowpass has to be a list or None!")
core = import core
rgb = False
color = True
mse[0] = sigma * 160.0 + 1200.0 if mse[0] is None else mse[0]
mse[1] = sigma * 120.0 + 800.0 if mse[1] is None else mse[1]
lowpass = [0.0,sigma, 0.48,1024.0, 1.0,1024.0] if lowpass is None else lowpass
matrix = None
colorspace = src.format.color_family
if colorspace == vs.RGB:
rgb = True
matrix = 100
src = core.RGB2OPP(src, 1)
ref = core.RGB2OPP(ref, 1)
if colorspace == vs.GRAY:
color = False
src = core.SetFieldBased(src, 0)
ref = core.SetFieldBased(ref, 0)
clip = internal.deringing(core, src, ref, radius, h, sigma, \
mse, hard_thr, block_size, block_step, group_size, bm_range, bm_step, ps_num, ps_range, ps_step, \
lowpass, color, matrix)
clip = core.OPP2RGB(clip, 1) if rgb else clip
del core
return clip
def Destaircase(src, ref, radius=6, sigma=16.0, \
mse=[None, None], hard_thr=3.2, block_size=8, block_step=1, group_size=32, bm_range=24, bm_step=1, ps_num=2, ps_range=8, ps_step=1, \
thr=0.03125, elast=0.015625, lowpass=None):
if not isinstance(src, vs.VideoNode):
raise TypeError("Oyster.Destaircase: src has to be a video clip!")
elif src.format.sample_type != vs.FLOAT or src.format.bits_per_sample < 32:
raise TypeError("Oyster.Destaircase: the sample type of src has to be single precision!")
elif src.format.subsampling_w > 0 or src.format.subsampling_h > 0:
raise RuntimeError("Oyster.Destaircase: subsampled stuff not supported!")
if not isinstance(ref, vs.VideoNode):
raise TypeError("Oyster.Destaircase: ref has to be a video clip!")
elif ref.format.sample_type != vs.FLOAT or ref.format.bits_per_sample < 32:
raise TypeError("Oyster.Destaircase: the sample type of ref has to be single precision!")
elif ref.format.subsampling_w > 0 or ref.format.subsampling_h > 0:
raise RuntimeError("Oyster.Destaircase: subsampled stuff not supported!")
if not isinstance(radius, int):
raise TypeError("Oyster.Destaircase: radius has to be an integer!")
elif radius < 1:
raise RuntimeError("Oyster.Destaircase: radius has to be greater than 0!")
if not isinstance(mse, list):
raise TypeError("Oyster.Destaircase: mse parameter has to be an array!")
elif len(mse) != 2:
raise RuntimeError("Oyster.Destaircase: mse parameter has to contain 2 elements exactly!")
for i in range(2):
if not isinstance(mse[i], float) and not isinstance(mse[i], int) and mse[i] is not None:
raise TypeError("Oyster.Destaircase: elements in mse must be real numbers or None!")
if not isinstance(thr, float) and not isinstance(thr, int):
raise TypeError("Oyster.Destaircase: thr has to be a real number!")
elif thr < 0 or thr > 1:
raise RuntimeError("Oyster.Destaircase: thr has to fall in [0, 1]!")
if not isinstance(elast, float) and not isinstance(elast, int):
raise TypeError("Oyster.Destaircase: elast has to be a real number!")
elif elast < 0 or elast > thr:
raise RuntimeError("Oyster.Destaircase: elast has to fall in [0, thr]!")
if not isinstance(lowpass, list) and lowpass is not None:
raise TypeError("Oyster.Destaircase: lowpass has to be a list or None!")
core = import core
rgb = False
mse[0] = sigma * 160.0 + 1200.0 if mse[0] is None else mse[0]
mse[1] = sigma * 120.0 + 800.0 if mse[1] is None else mse[1]
lowpass = [0.0,sigma, 0.48,1024.0, 1.0,1024.0] if lowpass is None else lowpass
matrix = None
colorspace = src.format.color_family
if colorspace == vs.RGB:
rgb = True
matrix = 100
src = core.RGB2OPP(src, 1)
ref = core.RGB2OPP(ref, 1)
src = core.SetFieldBased(src, 0)
ref = core.SetFieldBased(ref, 0)
clip = internal.destaircase(core, src, ref, radius, sigma, \
mse, hard_thr, block_size, block_step, group_size, bm_range, bm_step, ps_num, ps_range, ps_step, \
thr, elast, lowpass, matrix)
clip = core.OPP2RGB(clip, 1) if rgb else clip
del core
return clip
def Deblocking(src, ref, radius=6, h=6.4, sigma=16.0, \
mse=[None, None], hard_thr=3.2, block_size=8, block_step=1, group_size=32, bm_range=24, bm_step=1, ps_num=2, ps_range=8, ps_step=1, \
lowpass=[0.0,0.0, 0.12,1024.0, 1.0,1024.0]):
if not isinstance(src, vs.VideoNode):
raise TypeError("Oyster.Deblocking: src has to be a video clip!")
elif src.format.sample_type != vs.FLOAT or src.format.bits_per_sample < 32:
raise TypeError("Oyster.Deblocking: the sample type of src has to be single precision!")
elif src.format.subsampling_w > 0 or src.format.subsampling_h > 0:
raise RuntimeError("Oyster.Deblocking: subsampled stuff not supported!")
if not isinstance(ref, vs.VideoNode):
raise TypeError("Oyster.Deblocking: ref has to be a video clip!")
elif ref.format.sample_type != vs.FLOAT or ref.format.bits_per_sample < 32:
raise TypeError("Oyster.Deblocking: the sample type of ref has to be single precision!")
elif ref.format.subsampling_w > 0 or ref.format.subsampling_h > 0:
raise RuntimeError("Oyster.Deblocking: subsampled stuff not supported!")
if not isinstance(radius, int):
raise TypeError("Oyster.Deblocking: radius has to be an integer!")
elif radius < 1:
raise RuntimeError("Oyster.Deblocking: radius has to be greater than 0!")
if not isinstance(h, float) and not isinstance(h, int):
raise TypeError("Oyster.Deblocking: h has to be a real number!")
elif h <= 0:
raise RuntimeError("Oyster.Deblocking: h has to be greater than 0!")
if not isinstance(mse, list):
raise TypeError("Oyster.Deblocking: mse parameter has to be an array!")
elif len(mse) != 2:
raise RuntimeError("Oyster.Deblocking: mse parameter has to contain 2 elements exactly!")
for i in range(2):
if not isinstance(mse[i], float) and not isinstance(mse[i], int) and mse[i] is not None:
raise TypeError("Oyster.Deblocking: elements in mse must be real numbers or None!")
if not isinstance(lowpass, list):
raise TypeError("Oyster.Deblocking: lowpass has to be a list!")
core = import core
rgb = False
color = True
mse[0] = sigma * 160.0 + 1200.0 if mse[0] is None else mse[0]
mse[1] = sigma * 120.0 + 800.0 if mse[1] is None else mse[1]
matrix = None
colorspace = src.format.color_family
if colorspace == vs.RGB:
rgb = True
matrix = 100
src = core.RGB2OPP(src, 1)
ref = core.RGB2OPP(ref, 1)
if colorspace == vs.GRAY:
color = False
src = core.SetFieldBased(src, 0)
ref = core.SetFieldBased(ref, 0)
clip = internal.deblocking(core, src, ref, radius, h, sigma, \
mse, hard_thr, block_size, block_step, group_size, bm_range, bm_step, ps_num, ps_range, ps_step, \
lowpass, color, matrix)
clip = core.OPP2RGB(clip, 1) if rgb else clip
del core
return clip
ChaosKing
23rd January 2023, 10:46
First vs.core() is old syntax. Now it's simply vs.core (you still need to have import vapoursynth as vs)
Never saw something like this core = import core (no a python pro here) but I think you can also replace it with vs.core.
Oh in case you didn't know, scripts/plugins by feisty2 are very very very slow :p
Emulgator
23rd January 2023, 10:53
Thanks, that helped ! Getting futher.
Now next comes up:
2023-01-23 10:50:22.589
Failed to evaluate the script:
Python exception: name 'vs' is not defined
Traceback (most recent call last):
File "src\cython\vapoursynth.pyx", line 2832, in vapoursynth._vpy_evaluate
File "src\cython\vapoursynth.pyx", line 2833, in vapoursynth._vpy_evaluate
File "C:/_SOFT/! Vapoursynth/VapourSynth64PortableFatpack_2021_10_16/userscripts/Haley A.vpy", line 49, in
ref_s = Oyster.Basic(clip, short_time=True)
File "C:\_SOFT\! Vapoursynth\VapourSynth64PortableFatpack_2021_10_16\Scripts\Oyster.py", line 233, in Basic
if not isinstance(src, vs.VideoNode):
NameError: name 'vs' is not defined
P.S. Slooow: Yes, I heard.. Hoping for some newer HW to deliver someting like >0,05fps ;-)
At the same time trying to get Dogway's Oyster rewrite for AviSynth+ 3.7.3 to run, unsuccessful so far as well..
ChaosKing
24th January 2023, 11:03
I got Oyster to work.
I think you are using an older version of Oyster. Download the newest version from his github page https://github.com/IFeelBloated/Oyster
It also needs the latest version (r10) of mvtools-sf https://github.com/IFeelBloated/vapoursynth-mvtools-sf
Delete libmvtools_sf_em64t.dll (it's the old one. Otherwise there will be a namespace conflict and only one of the plugins will be loaded)
All you have to fix is line 14 in Oyster.py
self.core = vs.get_core()
to
self.core = vs.core
import vapoursynth as vs
import Oyster
core = vs.core
clip = core.lsmas.LWLibavSource(source=r"F:\video.mkv")
clip = core.fmtc.bitdepth( clip, bits = 32 )
clip = core.fmtc.resample( clip, css = "444" )
ref_s = Oyster.Basic(clip, short_time=True)
clip = Oyster.Deringing(clip, ref_s, block_step=2)
clip.set_output()
This took about a minute to display one frame (720x480) in vsedit
p.s. If you make changes to a python script (Oyster.py) make sure to restart vsedit!
kedautinh12
24th January 2023, 11:05
Dogway's Oyster don't work cause W.I.P
Emulgator
25th January 2023, 03:02
Chaosking, you are a hero. Indeed r10-prerelease was needed.
Many thanks ! This is with your fatpack 2021 10 16:
Script loaded, no fault comments, i9-11900K CPU breathing hot air @ 100%,
waiting for the first frame to emerge...
10...48...128GB RAM used up, then 69GB...then 29GB, then 14GB
And here it is ! 1 frame deringing only like 3 minutes...
Lets see if I can move this to my R61 portable.
Selur
25th January 2023, 21:06
Small question seeing:
self.core = vs.core()
self.MSuper = self.core.mvsf.Super
self.MAnalyze = self.core.mvsf.Analyze
self.MRecalculate = self.core.mvsf.Recalculate
self.MDegrain = self.core.mvsf.Degrain
self.RGB2OPP = self.core.bm3d.RGB2OPP
self.OPP2RGB = self.core.bm3d.OPP2RGB
self.BMBasic = self.core.bm3d.VBasic
self.BMFinal = self.core.bm3d.VFinal
self.Aggregate = self.core.bm3d.VAggregate
self.DFTTest = self.core.dfttest.DFTTest
self.KNLMeansCL = self.core.knlm.KNLMeansCL
self.NNEDI = self.core.nnedi3.nnedi3
self.Resample = self.core.fmtc.resample
self.Expr = self.core.std.Expr
self.MakeDiff = self.core.std.MakeDiff
self.MergeDiff = self.core.std.MergeDiff
self.Crop = self.core.std.CropRel
self.CropAbs = self.core.std.CropAbs
self.Transpose = self.core.std.Transpose
self.BlankClip = self.core.std.BlankClip
self.AddBorders = self.core.std.AddBorders
self.StackHorizontal = self.core.std.StackHorizontal
self.StackVertical = self.core.std.StackVertical
self.MaskedMerge = self.core.std.MaskedMerge
self.ShufflePlanes = self.core.std.ShufflePlanes
self.SetFieldBased = self.core.std.SetFieldBased
Woud it speed things up to use:
BM3DCUDA instead of BM3D ?
NNEDI3CL instead of NNEDI3? (or at least znedi3?)
ChaosKing
26th January 2023, 00:18
You can replace nnedi3 with: self.NNEDI = self.core.nnedi3cl.NNEDI3CL
I removed RGB2OPP() and replaced bm3d with
vs.core.bm3dcuda_rtc.BM3Dv2(dif, cleansed, radius=radius, sigma=sigma, \
block_step=block_step, bm_range=bm_range, \
ps_num=ps_num, ps_range=ps_range)
I had to remove some parameters since they are not present in bm3dcuda. Not sure if I replaced it correctly, but at least it looks very similar (not much tested)
For this example it is twice as fast for me.
ref_s = Oyster.Basic(clip, short_time=True)
clip = Oyster.Deringing(clip, ref_s, block_step=2)
With radius=2 it is actually usable now with ~15sec for a single frame
import Oystergpu as Oy
ref_s = Oy.Basic(clip, short_time=True, radius=2)
clip = Oy.Deringing(clip, ref_s, block_step=2, radius=2)
Download here
https://gist.github.com/theChaosCoder/314900908082a67901cb54994eacf9ca
EDIT
Just found this https://github.com/AmusementClub/vs-nlm-cuda
EDIT2
Replaced knlm with nlm_cuda
Dogway
26th January 2023, 09:00
Dogway's Oyster don't work cause W.I.P
I've been following the thread and decided to finish the filter for AVS+
The main problem with Deringing is the use of NLMeans, which loops KNLMeansCL several times, maybe not in VS but in AVS that causes an out of resources error when used more than twice (1 loop in 2 dif calls), and I have 32Gb of RAM.
Aside of that for BM3D I found that radius doesn't make a big difference, and blockstep=1 is only a slightly bit sharper than with 2, but at the expense of magnitudes times slower.
The main trick I did to speed it up was to remake FreqMerge() using GuidedBlur() (at half res) instead of DFTTest which is known to be slow.
Here are my tests using oyster_Deblocking, and some further custom filtering to recover back some structure.
src
http://i.imgur.com/l3hUCCFm.png (https://i.imgur.com/l3hUCCF.png)
blockstep = 1..........................................................blockstep = 2
http://i.imgur.com/5VAzF1Gm.png (https://i.imgur.com/5VAzF1G.png)_______http://i.imgur.com/qAQermkm.png (https://i.imgur.com/qAQermk.png)
Structure sharpen......................................................Recover smearing
http://i.imgur.com/OecMKy1m.png (https://i.imgur.com/OecMKy1.png)_______http://i.imgur.com/F8mF7xsm.png (https://i.imgur.com/F8mF7xs.png)
ConverttoYUV444().ConvertBits(32)
clp = last
sup = oyster_Super(clp)
ref_s = oyster_Basic(clp, sup, short_time=true)
dbl = oyster_Deblocking (clp, radius=4, ref_s, block_step=1)
dbl
# De-smearing
ex_lfr(clp,LFR=130)
# Re-structure
ex_unsharp(0.4, Fc=400, th=0, safe=true)
# Recover some saturation
ex_vibrance(1.15)
ChaosKing
26th January 2023, 10:38
Aside of that for BM3D I found that radius doesn't make a big difference, and blockstep=1 is only a slightly bit sharper than with 2, but at the expense of magnitudes times slower.
ex_vibrance(1.15)[/CODE]
In the deringing function bm3d basic is called, then It's "refined" with loop(None, ref, src, 4), so called x4 again and finally bm3d final.
So bm3d is called at least 6 times. Combine this with radius=6 und you know why it takes 3 minutes to process a single frame. feisty2 makes zero compromises :devil:
Missed the dfttest part: dfttest could be replaced with neo_dfttest or https://github.com/AmusementClub/vs-dfttest2
EDIT: Oh you're right NLMeans is called 4 times, not bm3d. Well never code when tired xD
kedautinh12
26th January 2023, 10:54
@Dogway, if you had problem with KNLMeansCL, you can ask Asd-g to port nlm_cuda to avs+
https://github.com/Asd-g/AviSynthPlus-Scripts/issues
Dogway
26th January 2023, 11:48
I think he is taking a break, anyway I think it's better he does what he pleases.
DGDenoise is CUDA NL Means, but it lacks the options KNLMeansCL has besides the important 'rclip' for guidance.
BTW, updated Oyster to fix a chroma issue, chroma always happens to be an afterthought, poor chroma...
ChaosKing
26th January 2023, 11:50
This as a graph
clip = core.vivtc.VFM(clip,0).vivtc.VDecimate()
clip = core.fmtc.bitdepth( clip, bits = 32 )
clip = core.fmtc.resample( clip, css = "444")
ref_s = Oy.Basic(clip, short_time=True,radius=2)
clip = Oy.Deringing(clip, ref_s, block_step=2,radius=2)
Oyster: https://i.imgur.com/ggNKprI.png
My gpu mod: https://i.imgur.com/2uvZ1Z7.png
I counted 10 KNLMeansCL calls and 4 Dfttest calls
You can created it with vspipe -g full or simple
Use https://dreampuf.github.io/GraphvizOnline with dot engine
Dogway
26th January 2023, 12:10
My gosh... did he ever manage to run that? in 2017 or therebouts?
Looks like he did some kind of manual NN, using NLMeans residuals and then refining the output.
I liked the deblocking, looks like a clean reinterpretation, I wonder if there's any actual ML model designed for this task.
As for neo_dfttest I tested it before but didn't make a big difference speed wise, just testing on AvsPmod GuidedBlur felt much faster but haven't benchmarked, also I had to parametrize it. GuidedBlur is also in VS so maybe you can check if it makes it any faster.
Those graphs look cool, although I'm still searching for an IDE with logic highlighting.
ChaosKing
26th January 2023, 12:18
My gosh... did he ever manage to run that? in 2017 or therebouts?
You click on run, got to sleep and in the morning 5 seconds are rendered :p
He showed mostly Britney Spears music videos, so not that unreasonable for a ~3min long clip if Oyster was created for these short clips.
I think it was more for education purpouses.
ChaosKing
26th January 2023, 12:33
As for neo_dfttest I tested it before but didn't make a big difference speed wise, just testing on AvsPmod GuidedBlur felt much faster but haven't benchmarked, also I had to parametrize it. GuidedBlur is also in VS so maybe you can check if it makes it any faster.
Where did you saw GuidedBlur for VS?
Dogway
26th January 2023, 13:00
Sorry was called GuidedFilter (https://github.com/WolframRhodium/muvsfunc/blob/master/muvsfunc.py#L2983).
Yes I remember encoding anime shorts at 0.1 fps with tnlmeans, the good days haha
zorr
26th January 2023, 22:15
There's also WNNM (https://github.com/AmusementClub/VapourSynth-WNNM). I'm running some tests with it but can't say anything conclusive yet. It's supposed to be better quality than BM3D.
ChaosKing
26th January 2023, 23:18
Quality seems to be better with the loop approach compared to plain bm3d (not Oyster related)
ref = haf.SMDegrain(clip,tr=3, thSAD=1000)
clip = core.fmtc.bitdepth( clip, bits = 32)
ref = core.fmtc.bitdepth( ref, bits = 32 )
for i in range(5):
if i == 0:
previous = clip
elif i == 1:
previous = denoised
else:
previous = core.std.Expr([clip, previous, denoised], "x y - {factor} * z +".format(factor=0.1))
denoised = previous.wnnm.WNNM(sigma=7, radius = 3, rclip = ref)
The more iterations the lower sigma needs to be it seems.
Even 10 iterations are still faster then Oyster :p
zorr
27th January 2023, 00:32
ref = haf.SMDegrain(clip,tr=3, thSAD=1000)
...
denoised = previous.wnnm.WNNM(sigma=7, radius = 3, rclip = ref)
I was wondering about the reference clip. The official implementation doesn't use it and it's probably there just because BM3D has it and it was easy to add.
Perhaps the loop approach is a replacement for the reference clip. Or maybe you're supposed to generate a new ref clip for each iteration. Have you tried it without the reference clip?
Emulgator
27th January 2023, 01:28
AviSynth+ 3.7.3 Oyster attempt, thanks Dogway for your patience !
<Sourcefilter>
<Sourcefilter>
va=AudioDub(v,a)
clp=va.ConvertToYV24().ConvertBits(32)
sup = oyster_Super(clp)
ref_f = oyster_Basic(clp, sup, short_time=False)
ref_s = oyster_Basic(clp, sup, short_time=True)
oyster_Deblocking(clp, ref_f, block_step=2)
still gets me
"nnedi3wrap: Field must be 0 or 1 for scaling"
ResizersPack 10.9.avsi, line 678
DeblockPack 2.7.avsi, line 396
Path\File\script.avs line 62,
(which is sup=oyster_Super(clp))
Which version of nnedi3 is it I am hunting ?
I have NNEDI3CL.dll 1.0.6.0 with nnedi3_weights.bin
and nnedi3.dll 0.9.4.61
Dogway
27th January 2023, 02:52
Maybe your source is tagged as interlaced in frameprops?
Try with:
propSet("_FieldBased",0)
sup = oyster_Super(clp)
ref_s = oyster_Basic(clp, sup, short_time=True)
oyster_Deblocking(clp, ref_s, block_step=2)
You also need latest yugefunc on my repo.
Emulgator
27th January 2023, 14:22
Thanks for the tip, Dogway!
I had yugefunc 0.9, now 1.0 is in, still no success.
Properties were Frame Based before and still is...
P.S. Ouch, AvsPMod tells so at its status bar.
The real frame properties are _FieldBased (2 [top-field])
(Source is 23.976 pulldowned to 29.97fps.
Sourcefilter was .d2v with Forced Film so good I hoped.)
propSet("_FieldBased",0) returns error: invalid arguments to propSet, I have to dig...
Was MYFAULTOFCOURSE, I had videostream named variable, so last() was empty or contained something else...
To use PropSet was the right hint, thanks again, Dogway.
Now with these elaborated scripts under AviSynth+ I have to use these property guided thingies much more often.
And now under AviSynth+ oyster_Deblocking has indeed delivered the first frame in like 30secs ! Yay !
And the next frames within 1..2secs. RTX3080 doing the dirty work. Wow.
Many thanks to all involved ! That had been a nice community climbing.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.