Log in

View Full Version : Stab_Light - deshaker


Pages : 1 [2]

StainlessS
16th March 2021, 22:21
OK, new test Mod


# Stab_Light_Mod.avsi
/*
This script can be IMPORT()'ed under Avs+, OR, under Avs v2.60 Standard [ONLY IF GScript is installed].
Can also be GIMPORT()'ed when GScript Installed.
Can Also be auto Loaded by Avisynth if in Plugins directory. [needs Gscript installed if not AVS+].
Can Also be dumped in AvsInit()'s GIMPORT directory for auto loading by AvsInit().
*/

Function Fb2FnNameEx_Mod(String Fn){Try{Eval(Fn+"()")B=True}catch(e){Assert(e.FindStr("syntax")==0,"Fb2FnNameEx_Mod: Error in Function Name '"+Fn+"'")B=(e.FindStr("no function named")==0)}Return B}
Fb2IsPlus_Mod = (FindStr(VersionString,"AviSynth+")!=0)
Fb2HasGScript_Mod = Fb2FnNameEx_Mod("GScipt")

Fb2_GS_S_Mod = """
Function FillBorders2_Low_Mod(clip c, clip pre,clip cblank,clip preblank,Float thr,int Pad,int MaxB,bool debug,String Font) {
c
w=width h=height
x1=0 for(i=1, MaxB) { if(pre.Crop(i-1,0,1,0).AverageLuma < thr) { x1=i} else { i=MaxB } } x1=x1>0?x1+pad:0
x2=0 for(i=1, MaxB) { if(pre.Crop(w-i,0,1,0).AverageLuma < thr) { x2=i} else { i=MaxB } } x2=x2>0?x2+pad:0
y1=0 for(i=1, MaxB) { if(pre.Crop(0,i-1,0,1).AverageLuma < thr) { y1=i} else { i=MaxB } } y1=y1>0?y1+pad:0
y2=0 for(i=1, MaxB) { if(pre.Crop(0,h-i,0,1).AverageLuma < thr) { y2=i} else { i=MaxB } } y2=y2>0?y2+pad:0
PreBlur = 0 # If > 0 then there may be an error
PostBlur = 0 # Max(x1, x2, y1, y2, 4) #If > 0 then there may be an error
max_fix = Max(x1, x2, y1, y2)
msk = (max_fix >= 8)
\ ? preblank.LetterBox(y1, y2, x1, x2, color=$ffffff).ConvertToYV12()
\ : cblank
fixed = (max_fix==0) ? Last
\ : (max_fix < 8) ? FillBorders(left=x1, top=y1, right=x2, bottom=y2, mode=0, y=3, u=3, v=3)
\ : InpaintLogo(mask=msk, Radius=Max(max_fix,5)*1.5, PreBlur=PreBlur, PostBlur=PostBlur)
(debug)
\ ? mt_merge(fixed, cblank.ConvertToRGB().LetterBox(y1, y2, x1, x2, color=$ff3333)
\ .ConvertToYV12(),preblank.LetterBox(y1, y2, x1, x2, color=$ffffff).ConvertToYV12(), luma=true)
\ .Subtitle(FillBorders2_Mod_dBugS(y1,x1,x2,y2), lsp = 10, text_color=$ff3333, font=Font, x=MaxB+5, y=MaxB+5)
\ : fixed
Return Last
}
"""

/*
If this avsi script is not in plugins, then HasGScript [Fb2HasGScript_Mod] can be FALSE, even if using GImport() from Gscript dll.
Not sure why this occurs, so even if Fb2HasGScript_Mod==FALSE and is NOT Avs+, then we use Gscript's GEval instead of Eval to
install above FillBorders2_TestBord_Mod().
We use Eval() to install the function, ONLY if GScript not installed and is AVS+.
*/

Try {
(Fb2HasGScript_Mod||!Fb2IsPlus_Mod) ? GEval(Fb2_GS_S_Mod) : Eval(Fb2_GS_S_Mod)
} catch (msg) {
Assert(False,ScriptFile+": Need GScript or Avs+"+Chr(10)+
\ "IsPlus="+String(Fb2IsPlus_Mod)+" : HasGScript="+String(Fb2HasGScript_Mod)+Chr(10)+
\ "SysErr="+Msg)
}

Function Stab_Light_Mod(clip clp, int "ts", int "range", int "dxmax", int "dymax", float "zoom", float "PAR",
\ bool "mirror", int "MaxBorders", bool "FixBorders", bool "FixFalPos", bool "debug") {
ts = Default(ts, 7) # frames to temporal average for better motion estimation (max. 7)
range = Default(range, 1) # frames before/after to estimate motion
dxmax = Default(dxmax, Round(clp.Width()/180.0)) #maximum deviation in pixels
dymax = Default(dymax, dxmax) # x, and y should be the same
zoom = Default(zoom, 1) # maximum zoom factor (1 disabled)
PAR = Default(PAR, 1.0) # PAR of your source
mirror = Default(mirror, false) # Edge filling
MaxBorders = Default(MaxBorders, Max(Round(clp.Width()/60.0), 20))
FixBorders = Default(FixBorders, true)
FixFalPos = Default(FixFalPos, true) # Fixes borders of MaxBorders more pixels wide
debug = Default(debug, false)

temp = TemporalSoften(clp, ts, 255, 255, 25, 2) # SC thr to 25 otherwise pans will stutter
rep = Repair(temp, TemporalSoften(clp, 1, 255, 255, 25, 2))
inter = Interleave(rep, clp) # temporal stable (better subpixel detection)
pre_clp = inter.mt_lut(expr="x 20 1 x 127.5 / - 21 ^ pi x * 255 / cos 21 ^ - * 1.05 * -", Y=3, U=2, V=2).RemoveGrain(mode=17) #ColorYUV(levels="PC->TV")

mdata = DePanEstimate(pre_clp, range=range, pixaspect=PAR, trust=0, dxmax=dxmax, dymax=dymax, zoommax=zoom)
dp = DePan(inter, data=mdata, offset=-1, mirror=mirror?15:0, pixaspect=PAR, matchfields=false, subpixel=2)
stab = SelectEvery(dp, 2, 0)

w = Width(clp)
h = Height(clp)
thr = 10.0

pre = stab.ConvertToY8()#.ColorYUV(off_y=-15)
stab = (!mirror && FixFalPos)
\ ? gScriptClip(stab, "
AverageLuma(Crop(pre, 0, 0, -w+MaxBorders+1, 0)) < thr ? clp : \
AverageLuma(Crop(pre, w-MaxBorders-1, 0, 0, 0)) < thr ? clp : \
AverageLuma(Crop(pre, 0, 0, 0, -h+MaxBorders+1)) < thr ? clp : \
AverageLuma(Crop(pre, 0, h-MaxBorders-1, 0, 0)) < thr ? clp : Last
Return Last
", args="clp, pre, MaxBorders, w, h, thr",Local=true)
\ : stab
Return (!mirror && FixBorders)
\ ? FillBorders2_Mod(stab, thr=thr, pad=1, MaxBorders=MaxBorders, debug=debug)
\ : stab
}

Function FillBorders2_Mod(clip c, float "thr", int "pad", int "MaxBorders", bool "debug") {
Function FillBorders2_Mod_dBugS(int y1,int x1,int x2,int y2) {
Return "Black borders:\n "+string(y1)+"\n "+string(x1)+" "+string(x2)+"\n "+ string(y2)
}
thr = Default(thr, 5.0)
pad = Default(pad, 0)
MaxB = Default(MaxBorders, Max(Round(c.Width()/60.0), 20))
debug = Default(debug, false)
cblank = c.mt_lut( "0", chroma="-128")
pre = c.ConvertToY8()#.ColorYUV(off_y=-15) # Moved out of gScriptclip
preblank = cblank.ConvertToY8()
font="Courier New"
gScriptClip(c, "
Return FillBorders2_Low_Mod(Last,pre,cblank,preblank,thr,Pad,MaxB,debug,Font)
",args="pre,cblank,preblank,thr,pad,MaxB,debug,Font",Local=true)
}


test

AVSI_FN = ".\Stab_Light.avsi"
AVSI_FN_MOD = ".\Stab_Light_Mod.avsi"
Import(AVSI_FN)
Import(AVSI_FN_MOD)

DEBUG=True

ORG=AviSource(".\Src.Avi") # OP's sample, Left Half, After ffmpeg conversion to UT_Video AVI
A = ORG.Stab_Light (zoom = 1.00, mirror = false, FixFalPos = true, FixBorders = true, debug = DEBUG)
B = ORG.Stab_Light_Mod(zoom = 1.00, mirror = false, FixFalPos = true, FixBorders = true, debug = DEBUG)
D=B.ClipDelta(A,AMP=true)
T=StackHorizontal(ORG,A)
B=StackHorizontal(B,D)
StackVertical(T,B)
Return Last

# Return Clip Difference of input clips (amp==true = Amplified, show==true = show background)
Function ClipDelta(clip clip1,clip clip2,bool "amp",bool "show") {
amp=Default(amp,false)
show=Default(show,false)
c2=clip1.levels(128-32,1.0,128+32,128-32,128+32).greyscale()
c1=clip1.subtract(clip2)
c1=(amp)?c1.levels(127,1.0,129,0,255):c1
return (show)?c1.Merge(c2):c1
}

EDIT:

The results are definitely different, time for you to test.
(May need to try varying Thr [probably lower for mod]).

Actually, maybe Thr should be higher for AverageLuma on pixel rows/comumns, not lower.

Arx1meD
17th March 2021, 08:24
We are back to where we started. I think the best version of the script is in post #38 (https://forum.doom9.org/showthread.php?p=1938205#post1938205).
Actually, maybe Thr should be higher for AverageLuma on pixel rows/comumns, not lower.
Yes. If the border is 1 px, then border may not be found. But with an increase in Thr (from 1 to 25), the speed of the script decreases. I decided that the most optimal option is when Thr=10.

StainlessS
17th March 2021, 14:35
OK, but I may still continue playing with this.
(As currently implemented in Stab_Light/_Mod, it would seem to me to be a bit un-reliable,
ie testing blocks rather than scanlines with Averageluma.
If I can figure out what I/we are tryin' to do, then I could maybe make faster than post #38,
RT_Stats has some tools that could maybe be of great use here, but currently only for 8 bit.)

Does Depan thing generate digital 0 [Y=0] for synthetic borders ?
And is it the synthetic borders we are tryin' to detect, or includes original src borders too ?
[ I'm hoping to learn as little as possible about depan etc :) ]

Side topic,
This snippit from original stab3.avsi [modded somewhat, not sure if currently working as intended]

Function FindBlackBorders(clip c, int "width", int "thr", string "path", string "filename") {
add = Default(width,1) # Width for detection, normally 1 should suffix to most situations
thr = Default(thr,1) # Threshold for detection, pixels lower than this value will be considered a border
path = Default(path, "C:") # This is the path to store the statistics file
filename = Default(filename, "FindBlackBorders - Statistics.log") # Filename of the statistics file
fn = path + "\" + filename
Y =c.converttoy8()
L1=Y.crop(0,0,add,0)
R1=Y.crop(Y.width-add,0,0,0)
T1=Y.crop(0,0,0,add)
B1=Y.crop(0,Y.height-add,0,0)
c.ScriptClip("""
WriteFileIf(fn,string(L1.AverageLuma<thr||R1.AverageLuma<thr||T1.AverageLuma<thr||B1.AverageLuma<thr),
\ Chr(34)+"CHAPTER00="+FFFormatTime(round(current_frame*1000/framerate))+Chr(34),
\ Append=Current_frame!=0)
""", args= "thr,L1,R1,T1,B1, fn",Local=true)
#converttoyv12()
# Bug or limitations of 8-bit masktools with Overlay or...
# mt_merge (masking PC Range masks) so use Dither tools
#Dither_merge16_8(Dither_convert_8_to_16(),Dither_convert_8_to_16(c),mt_lut("255"),luma=true)
#ditherpost(mode=-1)
#c.Echo(Last) # Maybe replace above dither stuff ???
# EDIT: Not using Echo(), input clip c to Scriptclip instead.
return last
}

test

A=Colorbars(pixel_type="YV12").Trim(0,-10).KillAudio.AssumeFPS(10.0)
B=A.Letterbox(32,0,0,0)
B++A++B
FindBlackBorders(Path = "D:\DVD", thr=20)
return last


results

CHAPTER00=0:00:00.000
CHAPTER00=0:00:00.100
CHAPTER00=0:00:00.200
CHAPTER00=0:00:00.300
CHAPTER00=0:00:00.400
CHAPTER00=0:00:00.500
CHAPTER00=0:00:00.600
CHAPTER00=0:00:00.700
CHAPTER00=0:00:00.800
CHAPTER00=0:00:00.900
CHAPTER00=0:00:02.000
CHAPTER00=0:00:02.100
CHAPTER00=0:00:02.200
CHAPTER00=0:00:02.300
CHAPTER00=0:00:02.400
CHAPTER00=0:00:02.500
CHAPTER00=0:00:02.600
CHAPTER00=0:00:02.700
CHAPTER00=0:00:02.800
CHAPTER00=0:00:02.900


What is the stuff in RED supposed to do ? [and what is the problem (I never use the dither stuff) ]
Can it be replaced by v2.60 Echo() filter ? [to return original source clip and still write log file]
EDIT: Replaced Echo, see script in GREEN.


Original source script

####################################
###
### FindBlackBorders()
###
### (http://forum.videohelp.com/threads/371336)
###
### Script to find sources with black borders for example as a result of bad deshaking, run on analysis pass
### The output file is formatted to be imported to avspmod as bookmarks
### use ClipClop() afterwards on a scene by scene basis to fix this.
###
### "width" is border thickness for detection
### "thr" is threshold, pixel values below this will be considered borders
### "path" is the path to store the statistics file, with end backslash. Default is "C:"
### "filename" is the statistics file name. In case you don't want to overwrite old ones
###
### Dependencies:
###
### Required:
### ------------
###
### masktools (v2a48 or higher) (http://forum.doom9.org/showthread.php?t=98985)
### Dither (v1.26.5 or higher) (http://forum.doom9.org/showthread.php?p=1386559#post1386559)
###
####################################

function FindBlackBorders(clip c, int "width", int "thr", string "path", string "filename") {

add = Default(width,1) # Width for detection, normally 1 should suffix to most situations
thr = Default(thr,1) # Threshold for detection, pixels lower than this value will be considered a border
path = Default(path, "C:") # This is the path to store the statistics file
filename = Default(filename, "FindBlackBorders - Statistics.log") # Filename of the statistics file

c
converttoy8()
w=width()
h=height()

L1=crop(0,0,-w+add,0)
R1=crop(w-add,0,0 ,0)
T1=crop(0,0,0,-h+add)
B1=crop(0,h-add,0 ,0)

ScriptClip("""
x1 = AverageLuma(L1) < thr ? true : false
x2 = AverageLuma(R1) < thr ? true : false
y1 = AverageLuma(T1) < thr ? true : false
y2 = AverageLuma(B1) < thr ? true : false
function IsBorder(clip c, bool x1, bool x2, bool y1, bool y2) {return (x1||y1||x2||y2)?true:false}

q = chr(34)chr(34)chr(34)
WriteFileIf(""+path+"\"+filename+"", " "+string(IsBorder(x1,y1,x2,y2))+" ", q+"CHAPTER00="+q,
\ "FFFormatTime_stabi(round((current_frame * 1000) / framerate()))", "", "")
""",args="thr,L1,R1,T1,B1,path,filename")

converttoyv12()

# Bug or limitations of 8-bit masktools with Overlay or...
# mt_merge (masking PC Range masks) so use Dither tools
Dither_merge16_8(Dither_convert_8_to_16(),Dither_convert_8_to_16(c),mt_lut("255"),luma=true)
ditherpost(mode=-1) }


Is this what an AvsPMod bookmark looks like ? [how it relates to clipClop, I have no idea].
CHAPTER00=0:00:02.900

Sorry for all the 'q's :)

EDIT:
most optimal option is when Thr=10.
We really need to use same method [block/scanline] for single thr, to get best best result.

Arx1meD
17th March 2021, 16:41
DePan creates completely black borders. They can be seen if FixBorders=false. My algorithm finds any black borders, including in the original clip. I have created a "debug" option to control how the black border search algorithm works.
By the way, DePan can fix black borders by itself, but only with a mirror image. They can be seen if mirror=true.
I didn't understand why the FindBlackBorders (in stab3.avsi) function is needed. Why would I create a timestamped text file? What should I do with it? I don't see any point in it.

StainlessS
17th March 2021, 17:59
Thanks for your answers.

FindBlackBorders (in stab3.avsi) function is needed.

I said was a bit O.T.
I was just looking at it and it looked well weird.
eg

q=Chr(34)Chr(34)Chr(34)
x1 = AverageLuma(L1) < thr ? true : false
function IsBorder(clip c, bool x1, bool x2, bool y1, bool y2) {return (x1||y1||x2||y2)?true:false}

Parts in red did not do anything useful, and IsBorder() defined inside scriptclip, + other oddities.
I just asked as I thought you might be familiar with that original script, as you produced the light version FillBorders thing.

EDIT: The ?true:false constant whotsits are storeed in Global variables list, to access them, is slow, and scans Local vars and then Global if not found in locals. Global vars are slow to access, and true/false are stored right near end of list and so very slow to access,
Avs+ sped this up somewhat with a hash table but probably still slow, particularly irksome if in scriptclip and not actually needed
when logical true/false is already known.
[ie, instead of returning Global variable true when the answer is true, and Global variable false when the answer is false, just return the answer instead.
return (x1||y1||x2||y2)?true:false
this part, (x1||y1||x2||y2) is evaluated by the avs parser, and is quite quick, does not access true
or false globals at all, the result is calculated to be true or false.]

Arx1meD
17th March 2021, 18:49
I also found this FindBlackBorders function strange. I refused to use it. I took only two of the most efficient functions from stab3.avsi: Stab3 and FillBorders_stabi. Then I simplified them.
I am using AviSynth+ and have not even tried to test the script in other versions.

Arx1meD
17th March 2021, 19:04
Let me ask. Should always use return at the end of a function or not?

StainlessS
17th March 2021, 19:08
Your light version works in v2.60 and above.

The FindBlackBorders thing, I think that the dither stuff in it was because of a colorshift problem if using Overlay on a clip.
The reason for Overlay, was to ensure that WriteFile was processed on the Y8 clip. [must contribute to the output clip, else does nothing].
Must have been written before v2.60 Echo() which when given 2 clips can force read the 2nd one, and so force WriteFile to work proper.

I've changed it around to work without my guessed reason for Dither thing.

Also made small mod since prev post on it, changed thr to float.
Using RT_Stats RT_WriteFile is way easier then Avs standard builtin Writefile which I find infuriating [at times].

Here the slight mod

####################################
###
### FindBlackBorders()
###
### (http://forum.videohelp.com/threads/371336)
###
### Script to find sources with black borders for example as a result of bad deshaking, run on analysis pass
### The output file is formatted to be imported to avspmod as bookmarks
### use ClipClop() afterwards on a scene by scene basis to fix this.
###
### "width" is border thickness for detection
### "thr" is threshold, pixel values below this will be considered borders. ssS: changed to Float.
### "path" is the path to store the statistics file, without end backslash. Default is "C:"
### "filename" is the statistics file name. In case you don't want to overwrite old ones
###
### Dependencies:
###
### Required:
### ------------
### GRunT (v1.0.1 or higher) (http://forum.doom9.org/showthread.php?t=139337)
####################################

Function FindBlackBorders(clip c, int "width", Float "thr", string "path", string "filename") {
add = Default(width,1) # Width for detection, normally 1 should suffix to most situations
thr = Default(thr,1.0) # Threshold for detection, pixels lower than this value will be considered a border
path = Default(path, "C:") # This is the path to store the statistics file
filename = Default(filename, "FindBlackBorders - Statistics.log") # Filename of the statistics file
fn = path + "\" + filename
Y =c.converttoy8()
L1=Y.crop(0,0,add,0)
R1=Y.crop(Y.width-add,0,0,0)
T1=Y.crop(0,0,0,add)
B1=Y.crop(0,Y.height-add,0,0)
c.gScriptClip("""
WriteFileIf(fn,string(L1.AverageLuma<thr||R1.AverageLuma<thr||T1.AverageLuma<thr||B1.AverageLuma<thr),
\ Chr(34)+"CHAPTER00="+FFFormatTime(round(current_frame*1000/framerate))+Chr(34),
\ Append=Current_frame!=0)
""", args= "thr,L1,R1,T1,B1, fn",Local=true)
return last
}


I've just bought my 2nd Action Cam [Rollei 4S Plus], not bad at £19.95 Lidl's
[getting rid of old stock, was £39.95 when on sale at full price, 49.00 euros on Amazon, and 59.0 Euros on manufacturer site].
16MP, Has Fake [interpolated] 4K30FPS, but 2.7K30FPS, 1080P60FPS, 1080P30FPS, 720P90FPS, 720P60FPS, 720P30FPS.
Anyway, thought I might need a deshaker type thing for it, so looking at this stuff a bit more closely.
I Aint no photographer, I dont know an F Stop from a Bus Stop, but thought I might give it a try.

EDIT: My other action cam is crap with fake 1080P30FPS.

EDIT: I think it [Rollei] can also do 720P120FPS, according to Android app. it seems to be an AllWinner v3 camera. [Android SOC]
Here a site that I'm probably gonna join at some point, for hacking action camera firmware.
https://www.goprawn.com/forum
Somebody on-site seem to be aware of Vdub2 and Avisynth. although older [circa 2016 posts on it].

Arx1meD
18th March 2021, 06:50
I work on restoring old cartoons mostly. And they all have the same problems: shaking, flickering and wrong white balance. If the shaking problem is solved, but there is no good solution with the flickering. All existing filters do not work well with cartoons. I use your GamMac (https://forum.doom9.org/showthread.php?p=1774281) to correct the wrong white balance. Thank you so much! He gives the best result compared to others.

StainlessS
18th March 2021, 13:36
Sorry, I missed this question posted just before one of my posts.
Let me ask. Should always use return at the end of a function or not?
If it dont produce an error then OK.
There are some situations where implicit return of Last dont work proper eg,

Function z() {
q = BlankClip
q
Global Fred=True # If final line in function then cause implicit return Last to fail
# q
# return last
}
z

Above, must uncomment one of the two final commented lines, else error
EDIT: Must have Return Last at end, unless last line in script function is assignment to Last [either explicit or implicit assign].
[think that is about right]

I saw recently a Didee post on simple de-flicker, involved (I think) downsize, temporalsoften, upsize, maybe.
[EDIT: also maybe apply some masktools thing too at end].

EDIT: Think this was the thread on de-flicker that I was thinkin' bout [Deflicker]:- https://forum.doom9.org/showthread.php?t=166355

Arx1meD
18th March 2021, 18:35
Updated post #1

johnmeyer
18th March 2021, 19:18
I have a lot of background stabilizing images, having written several VirtualDub and Vegas scripts to permit stabilization of events within Vegas Pro using Deshaker inside of VirtualDub:

Deshaker Guide (https://drive.google.com/file/d/1hgJGIyxH1Sdbm8Cl19dyD_rUxm09ylnD/view?usp=sharing)

Deshaker VirtualDub & Vegas Scripts (http://www.lawrence-arnold.com/Vegas/DeshakerScript.htm)

I am therefore very interested in this work, but don't want to take the time to get it up and running without some idea of how well it works. I just skimmed through all the posts looking for links to "before/after" examples. Has anyone posted an example of how well this works?

Arx1meD
18th March 2021, 19:58
johnmeyer,
I tried Deshaker for VirtualDub, but I didn't like it. It is possible that I configured it incorrectly.
This script uses DePanEstimate to find motion vectors. Then DePan makes full or partial compensation based on these vectors. After working with DePan, black borders remain. FillBorders or AVSInpaint fixes them.
Check out the example in post #1 - "Original and stabilized clip".

kedautinh12
18th March 2021, 23:27
I think you wrong

For Win64 copy 32-bit version in C:\Windows\System32 and copy 64-bit version in C:\Windows\SysWOW64.

Right is 32 bit ver to SysWOW64 and 64 bit ver to System32

StainlessS
19th March 2021, 01:07
I think you wrong
Right is 32 bit ver to SysWOW64 and 64 bit ver to System32
Yep, Nice one, I did not spot that.

johnmeyer
19th March 2021, 02:33
This script uses DePanEstimate to find motion vectors. Then DePan makes full or partial compensation based on these vectors. After working with DePan, black borders remain. FillBorders or AVSInpaint fixes them.
Check out the example in post #1 - "Original and stabilized clip".Wow, how did I miss that link? Old age, I guess.

I too use Depan all the time inside of my movie film restoration script. If time permits, I'll IVTC your clip, apply that script and see if I can improve it, beyond simply stabilizing it.

johnmeyer
19th March 2021, 05:44
The test clip has lots of problems besides gate weave:

1. Horrible encoding artifacts.
2. Really bad flicker
3. Dirt

To fix these I first IVTC'd the clip. Since it is animation where the dup pattern is unpredictable I used large Cycle/CycleR values in TIVTC. I am not an animation expert so I don't know if the result of removing duplicates will make the cartoon play strangely. Someone else will have to address that. However, to remove dirt, denoise, eliminate flicker, etc. you have to remove all dups.

I used Depan to stabilize, but it didn't do a good job with the rotational stability issues. Most film doesn't have these. So I used Deshaker instead.

I took that stabilized footage and fed it into my film script (which is posted elsewhere in this forum). I turned off the Depan stabilization, since that work was already done, but enabled Deflicker, set DCT=1 for the noise reduction, and enabled GamMac. Each of these three things helps reduce flicker.

I turned up the dirt and noise reduction too far which results in some Jello artifacts. If this was important (to me) I'd go back and fiddle around with those. Here is the result:

https://www.mediafire.com/file/svdnmka3wki2e9j/Cartoon+-+stabilize,+remove+dirt,+flicker+&+noise.mp4/file

Arx1meD
19th March 2021, 07:41
I think you wrong

Right is 32 bit ver to SysWOW64 and 64 bit ver to System32

Thank you for noticing the mistake.

Arx1meD
19th March 2021, 08:58
johnmeyer,
thanks for your work. I was unable to make a video comparison because you changed the frame rate by 10 fps. I made a comparison with screenshots only.
https://thumbs2.imgbox.com/00/bb/WndVK0Sp_t.png (https://imgbox.com/WndVK0Sp) https://thumbs2.imgbox.com/03/2a/XPero6RV_t.png (https://imgbox.com/XPero6RV) https://thumbs2.imgbox.com/8e/76/tlp0BTUh_t.png (https://imgbox.com/tlp0BTUh) https://thumbs2.imgbox.com/01/b9/FrUJJNKD_t.png (https://imgbox.com/FrUJJNKD)
Deshaker for VirtualDub stabilized the clip better, but changed the zoom a lot. In my case, this is unacceptable.
If you need to fix the rotation then set MethodMS=2 and mirror=true to fix black borders.

P.S. Flickering is also poorly corrected. For cartoons, this is a big problem that I cannot solve normally.

johnmeyer
19th March 2021, 16:57
Sorry it wasn't to your liking. Best of luck with your efforts.

johnmeyer
19th March 2021, 21:17
It kinda bugged me that I don't think you really understood what I did with the deflicker, and that the stabilization was pretty good. Also, when you remove the duplicates, you HAVE to time it to play at 10 fps in order to get the right speed. If you want it to play at 23.976, then you have to re-insert duplicates.

Here is the original and my modified version, side-by-side, with duplicates added back so it will play at 23.976.

https://www.mediafire.com/file/bcfloi76x0ls5lc/Cartoon+fixed+deflicker,+stabilize,+gamma+corrected,+dirt+removal.mp4/file

I used Depan, since you seem to like that, even though it doesn't do a very good job with rotation stability, even with rotation correction enabled.

I will be interested to hear what other people think because, to me, the right side sure looks better than the right side, especially because for this clip, flicker is a far worse problem than stability. If you walk through it frame-by-frame, the lack of flicker in the "after" (right side) is even more apparent.

Arx1meD
20th March 2021, 04:58
johnmeyer, you got a good result. Only from 48 seconds the shaking remained.
What settings have you set for Depan? And what deflicker did you use?

johnmeyer
20th March 2021, 16:29
I only used Depan because you like it and you have spent a lot of time in this thread perfecting it. As I said earlier, I use it with the more normal gate weave on film, which usually does not include the rotation instability of your clip. So, for this clip, Depan didn't do a very good job, but I have other better ways to stabilize video (Deshaker, and the "ultimate" stabilizer, Mercalli), so I don't need help with Depan. I use it only because you didn't like my results with Deshaker.

I don't know why Depan introduced those strange jumps in the last scene.

For flicker reduction I used the Deflicker plugin, with default settings AND I changed the DCT setting in the MVTools2 denoiser to DCT=1 which substantially reduces flicker as a fortuitous side effect. Finally, I used StanlessS' "GamMAC" to help even out exposure. Between the three of them I was quite pleased with the flicker reduction.

Arx1meD
20th March 2021, 17:33
johnmeyer, thanks. I will try your recommendations not only on this clip but also on others.

real.finder
1st April 2021, 22:47
Side topic,
This snippit from original stab3.avsi [modded somewhat, not sure if currently working as intended]

Function FindBlackBorders(clip c, int "width", int "thr", string "path", string "filename") {
add = Default(width,1) # Width for detection, normally 1 should suffix to most situations
thr = Default(thr,1) # Threshold for detection, pixels lower than this value will be considered a border
path = Default(path, "C:") # This is the path to store the statistics file
filename = Default(filename, "FindBlackBorders - Statistics.log") # Filename of the statistics file
fn = path + "\" + filename
Y =c.converttoy8()
L1=Y.crop(0,0,add,0)
R1=Y.crop(Y.width-add,0,0,0)
T1=Y.crop(0,0,0,add)
B1=Y.crop(0,Y.height-add,0,0)
c.ScriptClip("""
WriteFileIf(fn,string(L1.AverageLuma<thr||R1.AverageLuma<thr||T1.AverageLuma<thr||B1.AverageLuma<thr),
\ Chr(34)+"CHAPTER00="+FFFormatTime(round(current_frame*1000/framerate))+Chr(34),
\ Append=Current_frame!=0)
""", args= "thr,L1,R1,T1,B1, fn",Local=true)
#converttoyv12()
# Bug or limitations of 8-bit masktools with Overlay or...
# mt_merge (masking PC Range masks) so use Dither tools
#Dither_merge16_8(Dither_convert_8_to_16(),Dither_convert_8_to_16(c),mt_lut("255"),luma=true)
#ditherpost(mode=-1)
#c.Echo(Last) # Maybe replace above dither stuff ???
# EDIT: Not using Echo(), input clip c to Scriptclip instead.
return last
}

test

A=Colorbars(pixel_type="YV12").Trim(0,-10).KillAudio.AssumeFPS(10.0)
B=A.Letterbox(32,0,0,0)
B++A++B
FindBlackBorders(Path = "D:\DVD", thr=20)
return last


results

CHAPTER00=0:00:00.000
CHAPTER00=0:00:00.100
CHAPTER00=0:00:00.200
CHAPTER00=0:00:00.300
CHAPTER00=0:00:00.400
CHAPTER00=0:00:00.500
CHAPTER00=0:00:00.600
CHAPTER00=0:00:00.700
CHAPTER00=0:00:00.800
CHAPTER00=0:00:00.900
CHAPTER00=0:00:02.000
CHAPTER00=0:00:02.100
CHAPTER00=0:00:02.200
CHAPTER00=0:00:02.300
CHAPTER00=0:00:02.400
CHAPTER00=0:00:02.500
CHAPTER00=0:00:02.600
CHAPTER00=0:00:02.700
CHAPTER00=0:00:02.800
CHAPTER00=0:00:02.900


What is the stuff in RED supposed to do ? [and what is the problem (I never use the dither stuff) ]
Can it be replaced by v2.60 Echo() filter ? [to return original source clip and still write log file]
EDIT: Replaced Echo, see script in GREEN.


Original source script

####################################
###
### FindBlackBorders()
###
### (http://forum.videohelp.com/threads/371336)
###
### Script to find sources with black borders for example as a result of bad deshaking, run on analysis pass
### The output file is formatted to be imported to avspmod as bookmarks
### use ClipClop() afterwards on a scene by scene basis to fix this.
###
### "width" is border thickness for detection
### "thr" is threshold, pixel values below this will be considered borders
### "path" is the path to store the statistics file, with end backslash. Default is "C:"
### "filename" is the statistics file name. In case you don't want to overwrite old ones
###
### Dependencies:
###
### Required:
### ------------
###
### masktools (v2a48 or higher) (http://forum.doom9.org/showthread.php?t=98985)
### Dither (v1.26.5 or higher) (http://forum.doom9.org/showthread.php?p=1386559#post1386559)
###
####################################

function FindBlackBorders(clip c, int "width", int "thr", string "path", string "filename") {

add = Default(width,1) # Width for detection, normally 1 should suffix to most situations
thr = Default(thr,1) # Threshold for detection, pixels lower than this value will be considered a border
path = Default(path, "C:") # This is the path to store the statistics file
filename = Default(filename, "FindBlackBorders - Statistics.log") # Filename of the statistics file

c
converttoy8()
w=width()
h=height()

L1=crop(0,0,-w+add,0)
R1=crop(w-add,0,0 ,0)
T1=crop(0,0,0,-h+add)
B1=crop(0,h-add,0 ,0)

ScriptClip("""
x1 = AverageLuma(L1) < thr ? true : false
x2 = AverageLuma(R1) < thr ? true : false
y1 = AverageLuma(T1) < thr ? true : false
y2 = AverageLuma(B1) < thr ? true : false
function IsBorder(clip c, bool x1, bool x2, bool y1, bool y2) {return (x1||y1||x2||y2)?true:false}

q = chr(34)chr(34)chr(34)
WriteFileIf(""+path+"\"+filename+"", " "+string(IsBorder(x1,y1,x2,y2))+" ", q+"CHAPTER00="+q,
\ "FFFormatTime_stabi(round((current_frame * 1000) / framerate()))", "", "")
""",args="thr,L1,R1,T1,B1,path,filename")

converttoyv12()

# Bug or limitations of 8-bit masktools with Overlay or...
# mt_merge (masking PC Range masks) so use Dither tools
Dither_merge16_8(Dither_convert_8_to_16(),Dither_convert_8_to_16(c),mt_lut("255"),luma=true)
ditherpost(mode=-1) }


Is this what an AvsPMod bookmark looks like ? [how it relates to clipClop, I have no idea].
CHAPTER00=0:00:02.900

Sorry for all the 'q's :)

EDIT:

We really need to use same method [block/scanline] for single thr, to get best best result.

FindBlackBorders is not needed in stab3

and mt_merge now don't has this problem thanks to pinterf

StainlessS
1st April 2021, 23:26
FindBlackBorders is not needed in stab3
Yes I know, but it presumably still has some functionality.

and mt_merge now don't has this problem thanks to pinterf
The Mt_Merge thing was [I think] just to ensure that WriteFileIf worked properley, and did write the output file.
The Mt_Merge thing is fixed anyway, either by the use of v2.60 Echo(), or my mod which changed to using c clip as input.

Dogway
2nd April 2021, 02:53
I made the original script long ago so I don't remember many things of it (like the Dither stuff or how I proceeded to load ClipClop formatted call, prolly through macros).
The stabilization tools pack was always a proof of concept, was never meant to be the end it all. At the time I tested DeShaker and I found it great for handheld shakiness but not for pixel or subpixel jitter like in anime.

I made stab2() to fix the following shortcomings of Depan:
-Color tint (hue shift to green) when subpixel>0 to stablizated frames --> addressed here
-Artifacts occasionally on frame borders (1px skew) --> crop out, check example
-No advanced border fill --> addressed above ( FillBorders() )
-Some false-positives when people clapping, trembling...
-Requires mod 4 inputs?
-No medium jitter fix
-Some thick borders (false positives) aren't 0 black on the inner side

So I'm glad someone resumes the project and takes it to the next level, that's basically the purpose of open source.