View Full Version : Extend duration of intertitles
bruno321
19th December 2020, 08:06
I've got an old silent film with intertitles. An x264 mp4 file. The problem is, for some weird reason the intertitles play way too fast (like 5 frames with the intertitle at all, at 25fps). The rest of the film plays fine. So I just want to extend the duration of the intertitles.
Hopeful solution: there exists a way for avisynth to automatically detect which frames are intertitles. It's mostly black background with some text in it in the middle of the screen... Is there such a way?
Manual solution: I have to select the intertitles by hand. Too bad, but I can live with that. But what would be the best way to code the repetition? I thought Loop should work, but I get confused about simple syntax. I did Loop(125,102,102) to repeat 125 times frame 102, but when I follow that with Loop(100,103,103) to repeat 100 times frame 103 (which is the next intertitle), it doesn't do what I expected it to do.
VoodooFX
19th December 2020, 09:40
I guess you are looping the looped frame in second loop, after the first loop your "103"th frame actually is 125 frames away from "102"th frame and is 227th frame.
Better is to loop whole intertitle like Loop(25,102,107).
johnmeyer
19th December 2020, 17:29
Hopeful solution: there exists a way for avisynth to automatically detect which frames are intertitles. It's mostly black background with some text in it in the middle of the screen... Is there such a way?Suggest the RT_Stats (https://forum.doom9.org/showthread.php?t=165479) AVISynth function, by StainlessS. The YInRange call may do what you want. If not, the other comparison functions will do it. You could also simply look at the exterior of the frame (i.e., exclude the portion containing the titles) and then simply look for a low averageluma value (a built-in AVISynth function).
poisondeathray
19th December 2020, 17:52
If you loop() starting from the last section, then work your way backwards, it won't screw up the original frame number referencing for multiple intertitle(s)
hello_hello
19th December 2020, 17:54
Manual solution: I have to select the intertitles by hand. Too bad, but I can live with that. But what would be the best way to code the repetition? I thought Loop should work, but I get confused about simple syntax. I did Loop(125,102,102) to repeat 125 times frame 102, but when I follow that with Loop(100,103,103) to repeat 100 times frame 103 (which is the next intertitle), it doesn't do what I expected it to do.
If you display the frame number first you can find the intertitles using the original frame numbers. That will probably make singling them out with Trim() easier. That's how I generally loop frames, as using Loop on it's own tends to confuse me. It also makes it easy to change your mind regarding the range of frames or the frame being looped, and the number of times they repeat.
If for some reason you need it, you can display the new frame numbers as well.
ScriptClip("subtitle(string(current_frame), align=5, size=30)")
Trim(0,101) ++ \
Trim(102,102).Loop(125) ++ \
Trim(103,103).Loop(100) ++ \
Trim(104,0)
ScriptClip("subtitle(string(current_frame), align=2, size=30)")
I've no idea how you'd go about locating the intertitles automatically.
VoodooFX
19th December 2020, 18:34
EDIT: nonsense below. Backwards is the way!
I tend to do with Trim's too, but that's a lot of typing, now I think that easier would be to chain the loops incrementally offsetting them if you have frame numbers already, or just work your way forward.
If you loop() starting from the last section, then work your way backwards, it won't screw up the original frame number referencing for multiple intertitle(s)
That should work forwards.
poisondeathray
19th December 2020, 18:46
If you loop() starting from the last section, then work your way backwards, it won't screw up the original frame number referencing for multiple intertitle(s)
That should work forwards.
If you start with the last section, you will miss all the other previous intertitles if you work forwards in time. You want to work backwards
Loop changes the framecount , but previous sections prior to the loop statement retain their original framenumbers
If you had intertitles represented by a,b,c,d . You want to work with d,c,b,a in that order
VoodooFX
19th December 2020, 18:57
EDIT:
nonsense below. skip.
If you start with the last section, you will miss all the other previous intertitles if you work forwards in time. You want to work backwards
Loop changes the framecount , but previous sections prior to the loop statement retain their original framenumbers
If you had intertitles represented by a,b,c,d . You want to work with d,c,b,a in that order
If you start from the last section then there is nothing ahead to work with. If you work backwards then it would mess framecount for later intertitles.
Going forward from the first by a,b,c,d wont mess previous intertitles as framecount changes forwards not backwards.
poisondeathray
19th December 2020, 18:59
If you start from the last section then there is nothing ahead to work with. If you work backwards then it would mess framecount for later intertitles.
Going forward from the first by a,b,c,d wont mess previous intertitles as framecount changes forwards not backwards.
e.g lets say you run a script and detect intertitles starting at original frame numbers 100 ,200 ,300, 400 . The video goes to frame 1000 . Each intertitle might be 5 frames or so
If you start at the "100" segment, adding a loop there will "push" the framenumbers of 200,300,400 forward by adding frames so they are no longer starting at 200,300,400 frame referencing
If you start at "400" to perform the 1st loop, everything later in time gets pushed forward, but it doesn't matter because you're already starting at the last intertitle segment. 100,200,300 sections retain their original framenumbering references
VoodooFX
19th December 2020, 19:09
After another sip I see that I wrote nonsense. :D
hello_hello
19th December 2020, 19:13
I tend to do with Trim's too, but that's a lot of typing, now I think that easier would be to chain the loops incrementally offsetting them if you have frame numbers already, or just work your way forward.
To find the next frame number to loop you'd want to display the new frame numbers, as that way you can add a loop, refresh the video, and navigate to the next intertitle to find it's new frame number. Actually that's not so bad. This would repeat frame number 102, then frame number 103.
Loop(125, 102,102)
Loop(100, 227,227)
ScriptClip("subtitle(string(current_frame), align=5, size=30)")
If the next intertitle happens to be frame number 501 for example (the original frame number), I don't actually need to know that frame number, I can just navigate to the next intertitle and see it's now frame number 724. So....
Loop(125, 102,102)
Loop(100, 227,227)
Loop(120, 724,724)
ScriptClip("subtitle(string(current_frame), align=5, size=30)")
Yeah.... that works. As long as you don't forget to refresh the Avisynth output each time you add a loop to update the frame numbers.
The major downside is, if I later decide to change the number of times I want to loop frame 102, it'll mess up every loop that follows.
VoodooFX
19th December 2020, 19:22
Actually that's not so bad. This would repeat frame number 102, then frame number 103.
Working backwards is easiest way, no need for trims nor math for offsets.
hello_hello
19th December 2020, 19:44
Actually, thinking about it, as long as you know the original frame numbers rather than the new frame numbers, you should be able to work forwards.
Looping #102
ScriptClip("subtitle(string(current_frame), align=5, size=30)")
Loop(125, 102,102)
Then looping #103
ScriptClip("subtitle(string(current_frame), align=5, size=30)")
Loop(100, 103,103)
Loop(125, 102,102)
Then lopping #501
ScriptClip("subtitle(string(current_frame), align=5, size=30)")
Loop(120, 501,501)
Loop(100, 103,103)
Loop(125, 102,102)
It's just a matter of stacking the loops in reverse order as you progress instead of having to work backwards.
Or am I missing something?
StainlessS
19th December 2020, 20:21
You got a sample ?
EDIT:
Script to detect intertitles?
https://forum.doom9.org/showthread.php?t=167882&highlight=InterTitle
EDIT:
For above detect script, need remove GScript(""" ... """) thingy for AVS+.
EDIT: Also, Best change from FrameSelect() plugin, to FrameSel() plugin,
ie change all
FrameSelect to FrameSel,
and FrameReplace to FrameRep.
StainlessS
20th December 2020, 19:58
See updated post #36 :- https://forum.doom9.org/showthread.php?p=1932187#post1932187
Previous script removed.
Still no test sample, working in dark, got this, test it out.
EDIT: I think this will solve your prob, but needs some testing with your sample.
Have made assumption that titles may have black only either side of titles [EDIT: before/after], we process this too for applying Levels using string "Func".
Have implemented extending titles ONLY [actually only middle frame of titles is extended, making assumption that it may be least noisy].
Anyways, here tis, cant really give good test without some sample.
/*
Req AVS+ and RT__Stats v2.0 Beta, FrameSel Plugins.
*/
#------------------------
# DEMO Test clip - Comment out and use source clip where AviSource Below
ColorBars(Pixel_type="YV12").Trim(0,10000).KillAudio.TestClip().AssumeFPS(25) # Just for testing not crash
#------------------------
#AVISource("D:\V\Cabaret.avi") # non demo Source # Should be YUV
#------------------------
#EDIT BELOW Paramaters
X=0 Y=0 W=0 H=0 # OUTERMOST Coords where Titles will be found, 0,0,0,0 search entire frame
BLKHI = 32 # Highest Black level
WHTLO = 200 # Lowest White level
THRESH = 97.5 # Total WHITE + BLACK, minimum Percent to be Inter Title
HILITE = True # Switch on text location hi-liting in ShowMetrics, Added nicety, no particular use here, demo only.
DB = "bruno321.DB" # DBase
FUNC = "Levels(16+32,1.0,235-32,16,235,coring=false)" # Applied to entire Black (Incl titles) sections
FRAMEEXTCNT = 100 # Titles Extended by this many frames [excluding non-titles Black]
#---------------------
# [0] Routine 0, View Metrics Only - Comment Out when not in-use
# Show Metrics to get correct parameters prior to MakeFiles()
#Return ShowMetrics(blk_hi=BLKHI,Wht_Lo=WHTLO,IT_THRESH=THRESH,HiLite=HILITE,x=X,y=Y,w=W,h=H) # Show Metrics ONLY
#---------------------
# [1] Routine 1, Create Files required for Process_Titles - Comment Out when not in-use
# Make command files, MUST use before Process_Titles function. Can use DebugView to View Progress.
# Returns MessageClip("ALL DONE") style clip when finished, does not return until entire clip processed.
#return MakeFiles(DB,blk_hi=BLKHI,Wht_Lo=WHTLO,IT_THRESH=THRESH,x=X,y=Y,w=W,h=H)
#---------------------
# [2] Routine 2, Process_Titles using files created via Routine 1 MakeFiles.
Process_Titles(DB,FRAMEEXTCNT,FUNC)
Return Last
#---------------------
Function ShowMetrics(clip c,int "Blk_hi",int "Wht_Lo",Float "IT_Thresh",Bool "HiLite",int "X",int "Y",int "W",int "H") {
# Use for finding best parameters to MakeFiles()
c
ConvertToRGB32() # for HiLite non mod coords
Blk_hi=Default(Blk_hi,40)
Wht_lo=Default(Wht_lo,200)
IT_Thresh=Float(Default(IT_Thresh,97.5))
HiLite=Default(HiLite,False)
X=Default(X,0) Y=Default(Y,0) W=Default(W,0) H=Default(H,0)
ScriptClip("""
KPerc = RT_YInRange(lo=0,hi=Blk_hi,x=X,y=Y,w=W,h=H) * 100.0
WPerc = RT_YInRange(lo=Wht_lo,hi=255,x=X,y=Y,w=W,h=H) * 100.0
itot = WPerc + KPerc # Total frame area that is Black OR White
IsBLK = itot >= IT_Thresh && WPerc < KPerc
Got=(IsBLK && HiLite) ? RT_YInRangeLocate(Baffle=2,lo=Wht_lo/2,hi=255,prefix="SHWM_",x=X,y=Y,w=W,h=H) : False
(Got) ? OverLay(Last.BlankClip(color=$FF8080,width=SHWM_W,height=SHWM_H),x=SHWM_X,y=SHWM_Y,opacity=0.5) : NOP
SS=String(current_frame) + "] W%="+String(WPerc,"%-6.2f")+" K%="+String(KPerc,"%-6.2f")+" Tot%="+String(itot,"%-6.2f") + \
" BLACK="+((IsBLK)?"YES":"NO")+ " : FOUNDTITLE="+((Got)?"YES":"NO")
Subtitle(SS)
""",args="Blk_hi,Wht_lo,IT_Thresh,HiLite,X,Y,W,H") # Needs Grunt for args
return Last
}
Function MakeFiles(clip c,String DB,int "Blk_hi",int "Wht_Lo",Float "IT_Thresh",int "X",int "Y",int "W",int "H") {
# Make detect files for Process_titles
c
Assert(DB!="","MakeFiles: Need DB")
DB = DB.RT_GetFullPathName
Blk_hi=Default(Blk_hi,40) Wht_lo=Default(Wht_lo,200) IT_Thresh=Float(Default(IT_Thresh,97.5))
X=Default(X,0) Y=Default(Y,0) W=Default(W,0) H=Default(H,0)
BlackFrames=RT_GetFullPathName("BlackFrames.txt")
TitleFrames=RT_GetFullPathName("TitleFrames.txt")
(Exist(BlackFrames)) ? RT_FileDelete(BlackFrames) : NOP # Delete existing
(Exist(TitleFrames)) ? RT_FileDelete(TitleFrames) : NOP
ScriptClip("""
n=current_frame
KPerc = RT_YInRange(lo=0,hi=Blk_hi,x=X,y=Y,w=W,h=H) * 100.0
WPerc = RT_YInRange(lo=Wht_lo,hi=255,x=X,y=Y,w=W,h=H) * 100.0
itot = WPerc + KPerc
if(itot >= IT_Thresh && WPerc < KPerc) {
RT_WriteFile(BlackFrames,"%d",n,append=True)
if(RT_YInRangeLocate(Baffle=2,lo=Wht_lo/2,hi=255,prefix="SHWM_",x=X,y=Y,w=W,h=H)) {
RT_WriteFile(TitleFrames,"%d",n,append=True)
}
}
return Last
""",args="Blk_hi,Wht_lo,IT_Thresh,X,Y,W,H,BlackFrames,TitleFrames") # Needs Grunt for args
RT_ForceProcess() # returns only on completion
BlackRanges=RT_GetFullPathName("BlackRanges.txt")
TitleRanges=RT_GetFullPathName("TitleRanges.txt")
# Make additional ranges files
Last.FrameSel_CmdReWrite(BlackRanges,Cmd=BlackFrames,Reject=false, Ordered=true,Range=true, Space=False,Prune=False)
Last.FrameSel_CmdReWrite(TitleRanges,Cmd=TitleFrames,Reject=false, Ordered=true,Range=True, Space=False,Prune=False)
# and a DBase of black ranges
BlackDB = RT_GetFullPathName("Black.DB")
RT_DBaseAlloc(BlackDB,0,"ii")
RT_DBaseReadCSV(BlackDB,BlackRanges)
# and a DBase of Title ranges
TitleDB = RT_GetFullPathName("Title.DB")
RT_DBaseAlloc(TitleDB,0,"ii")
RT_DBaseReadCSV(TitleDB,TitleRanges)
Black_Records = RT_DBaseRecords(BlackDB)
RT_DBaseAlloc(DB,0,"iibii")
TitiX=0
# Create and combine Black and Title into single DBase for client [ There may be a black section without a text title ]
for(i=0,Black_Records-1) {
BS = RT_DBaseGetField(BlackDB,i,0)
BE = RT_DBaseGetField(BlackDB,i,1)
TS = RT_DBaseGetField(TitleDB,TitiX,0)
TE = RT_DBaseGetField(TitleDB,TitiX,1)
Got = (TS >= BS && TE <= BE) # Is next Title in current Black section ?
RT_DBaseAppend(DB,BS,BE,Got,(Got)?TS:0,(Got)?TE:0)
TitIx = (Got) ? TitIx+1 : TitIx # if got processed title, then look for next one
}
# Dump temps, but keep ranges files, perhaps of use
RT_FileDelete(BlackFrames)
RT_FileDelete(TitleFrames)
RT_FileDelete(BlackDB)
RT_FileDelete(TitleDB)
return MessageClip("Makefiles ALL DONE")
}
Function Process_Titles(clip c,String DB,int "FrameExtendCnt",String "func") {
Assert(DB!="","MakeFiles: Need DB")
DB = DB.RT_GetFullPathName
FrameExtendCnt=Default(FrameExtendCnt,50)
Func=Default(Func,"")
Records = RT_DBaseRecords(DB)
C2 = c.Blankclip(Length=0)
E = -1
For(rec=0,Records-1) {
S = RT_DBaseGetField(DB,Rec,0) # Start of this BLack Range [with possible title]
if(S > 0) {
C2 = C2 ++ c.Trim(E + 1,S - 1) # non black between prev black and this one
}
E = RT_DBaseGetField(DB,Rec,1) # End of this Black
BTS = RT_DBaseGetField(DB,Rec,3) - S # start of title relative Black section
BTE = RT_DBaseGetField(DB,Rec,4) - S # end of title relative Black section
BTF = (BTS + BTE) / 2 # Middle frame of title
Got = RT_DBaseGetField(DB,rec,2)
Black = c.Trim(S , E) # Current Black
Black = (Func!="") ? Black.Eval(Func) : Black # Levels on whole Black section inc possible title
if(Got && FrameExtendCnt > 0) { # Black section Has Title, and extending title ?
Black = Black.Loop(FrameExtendCnt + 1,BTF,BTF) # Extend framecount of middle title frame only
}
C2 = C2 ++ Black
}
if(E < c.FrameCount -1) {
C2 = C2 + c.Trim(E + 1, 0)
}
Return C2
}
###################
###################
###################
Function TestClip(clip c) {
# TestClip generator.
c
K=c.BlankClip().Trim(0,-100)
KT=K.Subtitle("This is just a test text ABCDEFGHIJKLM\nAnd some more text abcdefghijklm\nAaBbCcDdeEFfGgHhIiJjKkLlMm\n", \
x=K.width/2-150,y=K.Height-100,text_color=$E0E0E0,lsp=0)
KC = k.Trim(0,-50) ++ kt.Trim(0,-100) ++ k.Trim(0,-50)
C2=c.BlankClip(length=0)
for(i=0,Framecount-1,200) {
C2 = C2 + C.Trim(i,min(c.FrameCount-1,i+199))
C2 = C2 + KC
}
return C2
}
Small edits.
Demo/Testclip.
Pre Black is 2 seconds, titles is 4 seconds, post black is 2 seconds. Titles extended by 100 frames to 8 seconds. [25FPS].
The problem is, for some weird reason the intertitles play way too fast (like 5 frames with the intertitle at all, at 25fps).
Perhaps static titles detected as dupes, removing limited number of them.
bruno321
21st December 2020, 07:04
Thank you all for the tips!
Here's a sample containing two of those intertitles https://www.sendspace.com/file/6y3h7y
After some tests, it seems the optimal thing to do would be to keep only one of those frames showing the intertitle, and loop that one, to avoid jumpiness... The fact that the number of frames an intertitle is shown in is not constant further complicates automation.
StainlessS
21st December 2020, 10:26
See updated post #36 :- https://forum.doom9.org/showthread.php?p=1932187#post1932187
OK, try this. [thanks for posting your sample]
# InterTitle_ReTime.Avs : by StainlessS @ doom9 :- https://forum.doom9.org/showthread.php?t=182176
/*
Req AVS+ and RT__Stats v2.0 Beta, FrameSel, Grunt, Plugins.
*/
#------------------------
# DEMO Test clip - Comment out and use source clip where AviSource Below
#ColorBars(Pixel_type="YV12").Trim(0,10000).KillAudio.TestClip().AssumeFPS(25) # Just for testing not crash
#------------------------
AVISource(".\test5.mkv.AVI") # non demo Source # Should be YUV
#------------------------
#EDIT BELOW Paramaters
X=0 Y=0 W=0 H=0 # Exclude Borders, 0,0,0,0 search entire frame
BLKHI = 48 # Highest Black level
WHTLO = 150 # Lowest White level
THRESH = 95.0 # Total WHITE + BLACK, minimum Percent to be Inter Title
KTH = 92.0 # Minimum Percent of Black pixels [Try avoid false +ve detect due to very low WHTLO]
HILITE = True # Switch on text location hi-liting in ShowMetrics, Added nicety, no particular use here, demo only.
DB = "bruno321.DB" # DBase
FUNC = "GreyScale.Levels(32,1.0,65,16,235,coring=false).Blur(0.2,0.2)" # Applied to entire Black (Incl titles) sections
#FUNC = ""
TEXTCNT = Round(4*Framerate) # 4 seconds. Black + Titles replaced with this many frames of mid title frame
#---------------------
# [0] Routine 0, View Metrics Only - Comment Out when not in-use
# Show Metrics to get correct parameters prior to MakeFiles()
Return ShowMetrics(blk_hi=BLKHI,Wht_Lo=WHTLO,IT_THRESH=THRESH,kTh=KTH,HiLite=HILITE,x=X,y=Y,w=W,h=H) # Show Metrics ONLY
#---------------------
# [1] Routine 1, Create Files required for Process_Titles - Comment Out when not in-use
# Make command files, MUST use before Process_Titles function. Can use DebugView to View Progress.
# Returns MessageClip("ALL DONE") style clip when finished, does not return until entire clip processed.
return MakeFiles(DB,blk_hi=BLKHI,Wht_Lo=WHTLO,IT_THRESH=THRESH,kth=kTh,x=X,y=Y,w=W,h=H)
#---------------------
# [2] Routine 2, Process_Titles using files created via Routine 1 MakeFiles.
Process_Titles(DB,TextCnt,FUNC)
Return Last
#---------------------
Function ShowMetrics(clip c,int "Blk_hi",int "Wht_Lo",Float "IT_Thresh",Float "kTh",Bool "HiLite",int "X",int "Y",int "W",int "H") {
# Use for finding best parameters to MakeFiles()
c
ConvertToRGB32() # for HiLite non mod coords
Blk_hi=Default(Blk_hi,40)
Wht_lo=Default(Wht_lo,200)
IT_Thresh=Float(Default(IT_Thresh,97.5))
kTh=Float(Default(kTh,92.0))
HiLite=Default(HiLite,False)
X=Default(X,0) Y=Default(Y,0) W=Default(W,0) H=Default(H,0)
ScriptClip("""
KPerc = RT_YInRange(lo=0,hi=Blk_hi,x=X,y=Y,w=W,h=H) * 100.0
WPerc = RT_YInRange(lo=Wht_lo,hi=255,x=X,y=Y,w=W,h=H) * 100.0
itot = WPerc + KPerc # Total frame area that is Black OR White
IsBLK = itot >= IT_Thresh && KPerc >= kTh
Got=(IsBLK && HiLite) ? RT_YInRangeLocate(Baffle=2,lo=Wht_lo/2,hi=255,prefix="SHWM_",x=X,y=Y,w=W,h=H) : False
(Got) ? OverLay(Last.BlankClip(color=$FF8080,width=SHWM_W,height=SHWM_H),x=SHWM_X,y=SHWM_Y,opacity=0.5) : NOP
SS=String(current_frame) + "] W%="+String(WPerc,"%-6.2f")+" K%="+String(KPerc,"%-6.2f")+" Tot%="+String(itot,"%-6.2f") + \
"\nBLACK="+((IsBLK)?"YES":"NO")+ " : FOUNDTITLE="+((Got)?"YES":"NO")
Subtitle(SS,lsp=0)
""",args="Blk_hi,Wht_lo,IT_Thresh,kTh,HiLite,X,Y,W,H") # Needs Grunt for args
return Last
}
Function MakeFiles(clip c,String DB,int "Blk_hi",int "Wht_Lo",Float "IT_Thresh",Float "kTh",int "X",int "Y",int "W",int "H") {
# Make detect files for Process_titles
c
Assert(DB!="","MakeFiles: Need DB")
DB = DB.RT_GetFullPathName
Blk_hi=Default(Blk_hi,40) Wht_lo=Default(Wht_lo,200)
IT_Thresh=Float(Default(IT_Thresh,97.5))
kTh=Float(Default(kTh,92.0))
X=Default(X,0) Y=Default(Y,0) W=Default(W,0) H=Default(H,0)
BlackFrames=RT_GetFullPathName("BlackFrames.txt")
TitleFrames=RT_GetFullPathName("TitleFrames.txt")
(Exist(BlackFrames)) ? RT_FileDelete(BlackFrames) : NOP # Delete existing
(Exist(TitleFrames)) ? RT_FileDelete(TitleFrames) : NOP
ScriptClip("""
n=current_frame
KPerc = RT_YInRange(lo=0,hi=Blk_hi,x=X,y=Y,w=W,h=H) * 100.0
WPerc = RT_YInRange(lo=Wht_lo,hi=255,x=X,y=Y,w=W,h=H) * 100.0
itot = WPerc + KPerc
if(itot >= IT_Thresh && KPerc >= kTh) {
RT_WriteFile(BlackFrames,"%d",n,append=True)
if(RT_YInRangeLocate(Baffle=2,lo=Wht_lo/2,hi=255,prefix="SHWM_",x=X,y=Y,w=W,h=H)) {
RT_WriteFile(TitleFrames,"%d",n,append=True)
}
}
return Last
""",args="Blk_hi,Wht_lo,IT_Thresh,kTh,X,Y,W,H,BlackFrames,TitleFrames") # Needs Grunt for args
RT_ForceProcess() # returns only on completion
BlackRanges=RT_GetFullPathName("BlackRanges.txt")
TitleRanges=RT_GetFullPathName("TitleRanges.txt")
# Make additional ranges files
Last.FrameSel_CmdReWrite(BlackRanges,Cmd=BlackFrames,Reject=false, Ordered=true,Range=true, Space=False,Prune=False)
Last.FrameSel_CmdReWrite(TitleRanges,Cmd=TitleFrames,Reject=false, Ordered=true,Range=True, Space=False,Prune=False)
# and a DBase of black ranges
BlackDB = RT_GetFullPathName("Black.DB")
RT_DBaseAlloc(BlackDB,0,"ii")
RT_DBaseReadCSV(BlackDB,BlackRanges)
# and a DBase of Title ranges
TitleDB = RT_GetFullPathName("Title.DB")
RT_DBaseAlloc(TitleDB,0,"ii")
RT_DBaseReadCSV(TitleDB,TitleRanges)
Black_Records = RT_DBaseRecords(BlackDB)
RT_DBaseAlloc(DB,0,"iibii")
TitiX=0
# Create and combine Black and Title into single DBase for client [ There may be a black section without a text title ]
for(i=0,Black_Records-1) {
BS = RT_DBaseGetField(BlackDB,i,0)
BE = RT_DBaseGetField(BlackDB,i,1)
TS = RT_DBaseGetField(TitleDB,TitiX,0)
TE = RT_DBaseGetField(TitleDB,TitiX,1)
Got = (TS >= BS && TE <= BE) # Is next Title in current Black section ?
RT_DBaseAppend(DB,BS,BE,Got,(Got)?TS:0,(Got)?TE:0)
TitIx = (Got) ? TitIx+1 : TitIx # if got processed title, then look for next one
}
# Dump temps, but keep ranges files, perhaps of use
RT_FileDelete(BlackFrames)
RT_FileDelete(TitleFrames)
RT_FileDelete(BlackDB)
RT_FileDelete(TitleDB)
return MessageClip("Makefiles ALL DONE")
}
Function Process_Titles(clip c,String DB,int "TextCnt",String "func") {
Assert(DB!="","MakeFiles: Need DB")
DB = DB.RT_GetFullPathName
TextCnt=Default(TextCnt,50)
Func=Default(Func,"")
Records = RT_DBaseRecords(DB)
C2 = c.Blankclip(Length=0)
E = -1
For(rec=0,Records-1) {
S = RT_DBaseGetField(DB,Rec,0) # Start of this BLack Range [with possible title]
if(S > 0) {
C2 = C2 ++ c.Trim(E + 1,S - 1) # non black between prev black and this one
}
E = RT_DBaseGetField(DB,Rec,1) # End of this Black
BTS = RT_DBaseGetField(DB,Rec,3) - S # start of title relative Black section
BTE = RT_DBaseGetField(DB,Rec,4) - S # end of title relative Black section
BTF = (BTS + BTE) / 2 # Middle frame of title
Got = RT_DBaseGetField(DB,rec,2)
Black = c.Trim(S , E) # Current Black
Black = (Func!="") ? Black.Eval(Func) : Black # Levels on whole Black section inc possible title
if(Got && TextCnt > 0) { # Black section Has Title, and extending title ?
# Black = Black.Loop(TextCnt + 1,BTF,BTF) # Extend framecount of middle title frame only
Black = Black.Trim(BTF,-1).Loop(TextCnt) # ReTime titles for TextCnt frames. [entire BLACK + TITLES are replaced]
}
C2 = C2 ++ Black
}
if(E < c.FrameCount -1) {
C2 = C2 + c.Trim(E + 1, 0)
}
Return C2
}
###################
###################
###################
Function TestClip(clip c) {
# TestClip generator.
c
K=c.BlankClip().Trim(0,-100)
KT=K.Subtitle("This is just a test text ABCDEFGHIJKLM\nAnd some more text abcdefghijklm\nAaBbCcDdeEFfGgHhIiJjKkLlMm\n", \
x=K.width/2-150,y=K.Height-100,text_color=$E0E0E0,lsp=0)
KC = k.Trim(0,-50) ++ kt.Trim(0,-100) ++ k.Trim(0,-50)
C2=c.BlankClip(length=0)
for(i=0,Framecount-1,200) {
C2 = C2 + C.Trim(i,min(c.FrameCount-1,i+199))
C2 = C2 + KC
}
return C2
}
Have replaced ALL titles [plus any before/after black frames] with single [EDIT: looped] frame and processed via FUNC string.
Is not bullet proof detection of titles, them there whites aint nowhere near white, had to add another threshold ie kTh" to try avoud
false +ve detections.
Titles frames aint by any means perfect when applying FUNC Levels(), maybe add some further processing to the Levels thing eg
FUNC = "Levels(50,1.0,80,16,235,coring=false).Blur(1.0,1.0)"
Above totally untested [the Blur part].
Original frame
https://i.postimg.cc/pdWZ1t2r/Inter-Title-00.jpg (https://postimages.org/)
Levels only
https://i.postimg.cc/zvgSRzkt/Inter-Title-01.jpg (https://postimages.org/)
EDIT: TEXTCNT is now length in frames of ALL replaced titles. [Set above as 4 * Round(FrameRate) # about 4 seconds].
EDIT:
Below image used this
FUNC = "Levels(50,1.0,80,16,235,coring=false).Blur(1.0,1.0)" # Applied to entire Black (Incl titles) sections
https://i.postimg.cc/1X3XLJ8p/Inter-Title-Text-Time-00.jpg (https://postimages.org/)
EDIT: Oops, changed this
TEXTCNT = 4 * Round(Framerate) # 4 seconds. Black + Titles replaced with this many frames of mid title frame
to
TEXTCNT = Round(4*Framerate) # 4 seconds. Black + Titles replaced with this many frames of mid title frame
EDIT: Renamed script to [B]InterTitle_ReTime.Avs
EDIT: Had a bit more play, decided upon this [keeps a bit more of the 'g' of 'goodness' decender].
FUNC = "GreyScale.Levels(32,1.0,65,16,235,coring=false).Blur(0.2,0.2)" # Applied to entire Black (Incl titles) sections
https://i.postimg.cc/9Mqm70Dq/Inter-Title-Re-Time-00.jpg (https://postimages.org/)
EDIT: It is possible to apply a temporal filter in FUNC string, the entire Black + Title frames are processed before
plucking out the mid title frame and looping it for TEXTCNT frames. [I have made no attempt to do this myself]
bruno321
22nd December 2020, 07:11
How do I use your code? I pasted it into an avs, replaced the AVISource line with a line loading my clip, but I get "end of file reached without matching }"
StainlessS
22nd December 2020, 09:37
Works perfect for me with copy/paste into new file.
Well at a [good] guess, I'de say that you missed out the last character of the file, ie the '}' character on last line.
I would also add a couple of blank newlines after it too.
# ...
for(i=0,Framecount-1,200) {
C2 = C2 + C.Trim(i,min(c.FrameCount-1,i+199))
C2 = C2 + KC
}
return C2
} <<<===<<
EDIT: In a post CODE block, all trailing spaces and newlines are removed when creating forum page, so '}' is very last character
shown no matter how many SPACE or newline characters I add at the end after it.
You need to take care when copying code from a forum post, it happens all of the time, remember it for next time
bruno321
22nd December 2020, 10:23
You're right, lesson learned :)
I'm getting another error now. RT_DBaseRecords: error, cannot open DBase file bruno321.DB
Sorry if this is another newbie mistake :D
StainlessS
22nd December 2020, 10:27
There are 3 rountines that need uncommenting/re-commenting.
As posted both ShowMetrics() and MakeFiles() line are commented out, you need uncomment and run MakeFiles() first, then comment out again
and run Process_Titles(). Sorry, was posted with Process_Titles() only un-commented, but needs DBase created via MakeFiles().
bruno321
23rd December 2020, 09:15
Now I get "There is no function named RT_DBaseReadCSV".
I do have RT_Stats_x64.dll, for what it's worth, but it seems it doesn't have that function...?
StainlessS
23rd December 2020, 12:04
# InterTitle_ReTime.Avs : by StainlessS @ doom9 :- https://forum.doom9.org/showthread.php?t=182176
/*
Req AVS+ and RT__Stats v2.0 Beta, FrameSel Plugins.
*/
https://www.mediafire.com/file/dxea5nkox5wopjl/RT_Stats_25%252626_x86_x64_dll_v2.00Beta12_20181125.7z/file
bruno321
23rd December 2020, 13:35
Still the same problem. I have the RT_Stats_x64.dll from that folder in my plugins folder, being loaded fine by avisynth, I checked with avsmeter. Is there anything else I should do with that 7z other than take out the dll and load it in avisynth?
StainlessS
23rd December 2020, 13:44
Wild guess, you got 2 RT_stats dlls in you plugins folder, and its using the old one.
[the x64 Beta is called RT_Stats_x64.dll], delete original and rename new one to RT_stats.dll.
Will show what version you are using
BlankClip.RT_Stats()
EDIT: By the way, I downloaded the zip I pointed to and have installed in my plugins, so it does work, problem is at your end.
bruno321
23rd December 2020, 14:17
I only have one RT_Stats_x64.dll. Here's the version I have:
https://i.imgur.com/sb2iHWI.png
StainlessS
23rd December 2020, 14:26
OK, looks right, thats what I got.
In your InterTitle script, add this to first line
Return BlankClip.RT_Stats
Should show the same.
Maybe your actually using x86 Avs+ [and x86 old RT_Stats dll], how are you running the script, Vdub2 x64 ?
bruno321
23rd December 2020, 16:09
No, I have the 64-bit version, as reported by avsmeter. I run the script on avspmod (latest or almost latest version), is that the problem?
StainlessS
23rd December 2020, 16:34
What does that mean, no does not show the same ?
I am using the very same x86 or x64 version dll's as linked previously, with the required RT_DBaseReadCSV.
EDIT: You also need FrameSel() plugin, also listed as requirement.
bruno321
23rd December 2020, 21:52
"No" was replying to: "Maybe your actually using x86 Avs+ [and x86 old RT_Stats dll]". That's not the case. As for "Return BlankClip.RT_Stats" showing the same in the InterTitle script, yes, it shows the same. Also, I do have the FrameSel() plugin, x64 as well...
StainlessS
23rd December 2020, 22:16
So you have the correct dll, but it shows "There is no function named RT_DBaseReadCSV".
I totally dont get that ???
Anybody else try that script, problems or not ?
EDIT: What version avisynth you using ?
And can you try vdub2 x64 to load avs. [Clutching at straws]
bruno321
26th December 2020, 07:30
AviSynth+ 3.5 (r3106, 3.5, x86_64)
Getting the same message with vdub2_x64. Just in case, here's how I'm using it:
# InterTitle_ReTime.Avs : by StainlessS @ doom9 :- https://forum.doom9.org/showthread.php?t=182176
#Return BlankClip.RT_Stats
/*
Req AVS+ and RT__Stats v2.0 Beta, FrameSel Plugins.
*/
#------------------------
# DEMO Test clip - Comment out and use source clip where AviSource Below
#ColorBars(Pixel_type="YV12").Trim(0,10000).KillAudio.TestClip().AssumeFPS(25) # Just for testing not crash
#------------------------
LWLibAvVideoSource("c:\myfile.mp4")
#------------------------
#EDIT BELOW Paramaters
X=0 Y=0 W=0 H=0 # Exclude Borders, 0,0,0,0 search entire frame
BLKHI = 48 # Highest Black level
WHTLO = 150 # Lowest White level
THRESH = 95.0 # Total WHITE + BLACK, minimum Percent to be Inter Title
KTH = 92.0 # Minimum Percent of Black pixels [Try avoid false +ve detect due to very low WHTLO]
HILITE = True # Switch on text location hi-liting in ShowMetrics, Added nicety, no particular use here, demo only.
DB = "bruno321.DB" # DBase
FUNC = "GreyScale.Levels(32,1.0,65,16,235,coring=false).Blur(0.2,0.2)" # Applied to entire Black (Incl titles) sections
#FUNC = ""
TEXTCNT = Round(4*Framerate) # 4 seconds. Black + Titles replaced with this many frames of mid title frame
#---------------------
# [0] Routine 0, View Metrics Only - Comment Out when not in-use
# Show Metrics to get correct parameters prior to MakeFiles()
#Return ShowMetrics(blk_hi=BLKHI,Wht_Lo=WHTLO,IT_THRESH=THRESH,kTh=KTH,HiLite=HILITE,x=X,y=Y,w=W,h=H) # Show Metrics ONLY
#---------------------
# [1] Routine 1, Create Files required for Process_Titles - Comment Out when not in-use
# Make command files, MUST use before Process_Titles function. Can use DebugView to View Progress.
# Returns MessageClip("ALL DONE") style clip when finished, does not return until entire clip processed.
return MakeFiles(DB,blk_hi=BLKHI,Wht_Lo=WHTLO,IT_THRESH=THRESH,kth=kTh,x=X,y=Y,w=W,h=H)
#---------------------
# [2] Routine 2, Process_Titles using files created via Routine 1 MakeFiles.
#Process_Titles(DB,TextCnt,FUNC)
#Return Last
#---------------------
Function ShowMetrics(clip c,int "Blk_hi",int "Wht_Lo",Float "IT_Thresh",Float "kTh",Bool "HiLite",int "X",int "Y",int "W",int "H") {
# Use for finding best parameters to MakeFiles()
c
ConvertToRGB32() # for HiLite non mod coords
Blk_hi=Default(Blk_hi,40)
Wht_lo=Default(Wht_lo,200)
IT_Thresh=Float(Default(IT_Thresh,97.5))
kTh=Float(Default(kTh,92.0))
HiLite=Default(HiLite,False)
X=Default(X,0) Y=Default(Y,0) W=Default(W,0) H=Default(H,0)
ScriptClip("""
KPerc = RT_YInRange(lo=0,hi=Blk_hi,x=X,y=Y,w=W,h=H) * 100.0
WPerc = RT_YInRange(lo=Wht_lo,hi=255,x=X,y=Y,w=W,h=H) * 100.0
itot = WPerc + KPerc # Total frame area that is Black OR White
IsBLK = itot >= IT_Thresh && KPerc >= kTh
Got=(IsBLK && HiLite) ? RT_YInRangeLocate(Baffle=2,lo=Wht_lo/2,hi=255,prefix="SHWM_",x=X,y=Y,w=W,h=H) : False
(Got) ? OverLay(Last.BlankClip(color=$FF8080,width=SHWM_W,height=SHWM_H),x=SHWM_X,y=SHWM_Y,opacity=0.5) : NOP
SS=String(current_frame) + "] W%="+String(WPerc,"%-6.2f")+" K%="+String(KPerc,"%-6.2f")+" Tot%="+String(itot,"%-6.2f") + \
"\nBLACK="+((IsBLK)?"YES":"NO")+ " : FOUNDTITLE="+((Got)?"YES":"NO")
Subtitle(SS,lsp=0)
""",args="Blk_hi,Wht_lo,IT_Thresh,kTh,HiLite,X,Y,W,H") # Needs Grunt for args
return Last
}
Function MakeFiles(clip c,String DB,int "Blk_hi",int "Wht_Lo",Float "IT_Thresh",Float "kTh",int "X",int "Y",int "W",int "H") {
# Make detect files for Process_titles
c
Assert(DB!="","MakeFiles: Need DB")
DB = DB.RT_GetFullPathName
Blk_hi=Default(Blk_hi,40) Wht_lo=Default(Wht_lo,200)
IT_Thresh=Float(Default(IT_Thresh,97.5))
kTh=Float(Default(kTh,92.0))
X=Default(X,0) Y=Default(Y,0) W=Default(W,0) H=Default(H,0)
BlackFrames=RT_GetFullPathName("BlackFrames.txt")
TitleFrames=RT_GetFullPathName("TitleFrames.txt")
(Exist(BlackFrames)) ? RT_FileDelete(BlackFrames) : NOP # Delete existing
(Exist(TitleFrames)) ? RT_FileDelete(TitleFrames) : NOP
ScriptClip("""
n=current_frame
KPerc = RT_YInRange(lo=0,hi=Blk_hi,x=X,y=Y,w=W,h=H) * 100.0
WPerc = RT_YInRange(lo=Wht_lo,hi=255,x=X,y=Y,w=W,h=H) * 100.0
itot = WPerc + KPerc
if(itot >= IT_Thresh && KPerc >= kTh) {
RT_WriteFile(BlackFrames,"%d",n,append=True)
if(RT_YInRangeLocate(Baffle=2,lo=Wht_lo/2,hi=255,prefix="SHWM_",x=X,y=Y,w=W,h=H)) {
RT_WriteFile(TitleFrames,"%d",n,append=True)
}
}
return Last
""",args="Blk_hi,Wht_lo,IT_Thresh,kTh,X,Y,W,H,BlackFrames,TitleFrames") # Needs Grunt for args
RT_ForceProcess() # returns only on completion
BlackRanges=RT_GetFullPathName("BlackRanges.txt")
TitleRanges=RT_GetFullPathName("TitleRanges.txt")
# Make additional ranges files
Last.FrameSel_CmdReWrite(BlackRanges,Cmd=BlackFrames,Reject=false, Ordered=true,Range=true, Space=False,Prune=False)
Last.FrameSel_CmdReWrite(TitleRanges,Cmd=TitleFrames,Reject=false, Ordered=true,Range=True, Space=False,Prune=False)
# and a DBase of black ranges
BlackDB = RT_GetFullPathName("Black.DB")
RT_DBaseAlloc(BlackDB,0,"ii")
RT_DBaseReadCSV(BlackDB,BlackRanges)
# and a DBase of Title ranges
TitleDB = RT_GetFullPathName("Title.DB")
RT_DBaseAlloc(TitleDB,0,"ii")
RT_DBaseReadCSV(TitleDB,TitleRanges)
Black_Records = RT_DBaseRecords(BlackDB)
RT_DBaseAlloc(DB,0,"iibii")
TitiX=0
# Create and combine Black and Title into single DBase for client [ There may be a black section without a text title ]
for(i=0,Black_Records-1) {
BS = RT_DBaseGetField(BlackDB,i,0)
BE = RT_DBaseGetField(BlackDB,i,1)
TS = RT_DBaseGetField(TitleDB,TitiX,0)
TE = RT_DBaseGetField(TitleDB,TitiX,1)
Got = (TS >= BS && TE <= BE) # Is next Title in current Black section ?
RT_DBaseAppend(DB,BS,BE,Got,(Got)?TS:0,(Got)?TE:0)
TitIx = (Got) ? TitIx+1 : TitIx # if got processed title, then look for next one
}
# Dump temps, but keep ranges files, perhaps of use
RT_FileDelete(BlackFrames)
RT_FileDelete(TitleFrames)
RT_FileDelete(BlackDB)
RT_FileDelete(TitleDB)
return MessageClip("Makefiles ALL DONE")
}
Function Process_Titles(clip c,String DB,int "TextCnt",String "func") {
Assert(DB!="","MakeFiles: Need DB")
DB = DB.RT_GetFullPathName
TextCnt=Default(TextCnt,50)
Func=Default(Func,"")
Records = RT_DBaseRecords(DB)
C2 = c.Blankclip(Length=0)
E = -1
For(rec=0,Records-1) {
S = RT_DBaseGetField(DB,Rec,0) # Start of this BLack Range [with possible title]
if(S > 0) {
C2 = C2 ++ c.Trim(E + 1,S - 1) # non black between prev black and this one
}
E = RT_DBaseGetField(DB,Rec,1) # End of this Black
BTS = RT_DBaseGetField(DB,Rec,3) - S # start of title relative Black section
BTE = RT_DBaseGetField(DB,Rec,4) - S # end of title relative Black section
BTF = (BTS + BTE) / 2 # Middle frame of title
Got = RT_DBaseGetField(DB,rec,2)
Black = c.Trim(S , E) # Current Black
Black = (Func!="") ? Black.Eval(Func) : Black # Levels on whole Black section inc possible title
if(Got && TextCnt > 0) { # Black section Has Title, and extending title ?
# Black = Black.Loop(TextCnt + 1,BTF,BTF) # Extend framecount of middle title frame only
Black = Black.Trim(BTF,-1).Loop(TextCnt) # ReTime titles for TextCnt frames. [entire BLACK + TITLES are replaced]
}
C2 = C2 ++ Black
}
if(E < c.FrameCount -1) {
C2 = C2 + c.Trim(E + 1, 0)
}
Return C2
}
###################
###################
###################
Function TestClip(clip c) {
# TestClip generator.
c
K=c.BlankClip().Trim(0,-100)
KT=K.Subtitle("This is just a test text ABCDEFGHIJKLM\nAnd some more text abcdefghijklm\nAaBbCcDdeEFfGgHhIiJjKkLlMm\n", \
x=K.width/2-150,y=K.Height-100,text_color=$E0E0E0,lsp=0)
KC = k.Trim(0,-50) ++ kt.Trim(0,-100) ++ k.Trim(0,-50)
C2=c.BlankClip(length=0)
for(i=0,Framecount-1,200) {
C2 = C2 + C.Trim(i,min(c.FrameCount-1,i+199))
C2 = C2 + KC
}
return C2
}
StainlessS
26th December 2020, 16:06
Can you try with this one [Very latest]:- https://forum.doom9.org/showthread.php?p=1930453#post1930453
Copying x86 avisynth.dll to SYSWOW64 and x64 version to system32.
How was your Avisynth setup installed, Standard installer, Groucho2004 Universal Installer, ?
Return Version
Will return this [for x86]
https://i.postimg.cc/Jn6trXhN/Inter-Title-Re-Time-00.jpg (https://postimages.cc/)
EDIT:
You could also try copy RT_Stats Beta x64 dll into your current folder and LoadPlugin(".\RT_stats.dll") or LoadPlugin(".\RT_stats_x64.dll"),
depending upon what its called. [This is a temp fix for this script, you need find problem and fix it otherwise future problems are likely].
EDIT: You could also try remove RT_stats Beta 64 from your plugins, and again try
BlankClip.RT_Stats()
it should fail with something like "I dont know what RT_stats means", if it does not fail,
then is using RT_Stats from somewhere else, maybe you have multiple plugins directories in use.
StainlessS
29th December 2020, 19:04
bruno321,
Sorry, dont have a clue what I was doing wrong but I totally cocked up, was my fault and the RT_DBaseReadCSV thing
was abscent from the prev RT Beta. I'm totally baffled as to how I had no problems but you did, I should have had problems too.
Anyways, here is recompiled RT v2.0 Beta 13:- https://www.mediafire.com/file/xa3t1wx234gyzfq/RT_Stats_25%252626_x86_x64_dll_v2.00Beta13_20201229.zip/file
Should (I hope) prove to work first time.
Again, sorry.
EDIT: Forgot, also needs Grunt [as well as RT_Stats and FrameSel].
Grunt v1.02 x86 & x64 if you aint got it:- https://github.com/pinterf/GRunT/releases
StainlessS
31st December 2020, 14:51
bruno321,
Did you have any probs with fixed RT_Stats v2.0 Beta 13 ?
Here is output mp4 using [same as provided script]
X=0 Y=0 W=0 H=0 # Exclude Borders, 0,0,0,0 search entire frame
BLKHI = 48 # Highest Black level
WHTLO = 150 # Lowest White level
THRESH = 95.0 # Total WHITE + BLACK, minimum Percent to be Inter Title
KTH = 92.0 # Minimum Percent of Black pixels [Try avoid false +ve detect due to very low WHTLO]
HILITE = True # Switch on text location hi-liting in ShowMetrics, Added nicety, no particular use here, demo only.
DB = "bruno321.DB" # DBase
FUNC = "GreyScale.Levels(32,1.0,65,16,235,coring=false).Blur(0.2,0.2)" # Applied to entire Black (Incl titles) sections
#FUNC = ""
TEXTCNT = Round(4*Framerate) # 4 seconds. Black + Titles replaced with this many frames of mid title frame
[~1MB]:- https://www.mediafire.com/file/hdpbxt498hujwhw/InterTitle_ReTime-Video-muxed.mp4/file
And again on SendSpace:- https://www.sendspace.com/file/7cyp0z
Original bruno321 sample:- https://www.sendspace.com/file/6y3h7y
Extends 4[I think, maybe 5] frame Intertitles to 4 seconds duration.
EDIT: The Pre Black and Post Black I keep ranting on about are possible black only frames before and after Intertitles.
Your sample clip does not have any, but we detect if present so as to process entire BLK + Title + BLK
using Levels FUNC stuff, but then pick out only the middle Processed Title frame and replace entire BLK + Title + BLK
with that (looped) extended duration frame. Avoids nasty flashes if BLK frames are present somewhere else in your clip.
Any BLK only periods [without Title] will be processed with Levels FUNC stuff but will not be extended. [just made pure noisless black].
StainlessS
31st December 2020, 16:33
Made small addition to script, Added NewTitles.txt Frames/Ranges txt file.
# InterTitle_ReTime.Avs : by StainlessS @ doom9 :- https://forum.doom9.org/showthread.php?p=1932187#post1932187
/*
Req AVS+ and RT__Stats v2.0 Beta, FrameSel, Grunt Plugins.
*/
#------------------------
# DEMO Test clip - Comment out and use source clip where AviSource Below
#ColorBars(Pixel_type="YV12").Trim(0,10000).KillAudio.TestClip().AssumeFPS(25) # Just for testing not crash
#------------------------
AVISource(".\test5.mkv.AVI") # non demo Source # Should be YUV
#------------------------
#EDIT BELOW Paramaters
X=0 Y=0 W=0 H=0 # Exclude Borders, 0,0,0,0 search entire frame
BLKHI = 48 # Highest Black level
WHTLO = 150 # Lowest White level
THRESH = 95.0 # Total WHITE + BLACK, minimum Percent to be Inter Title
KTH = 92.0 # Minimum Percent of Black pixels [Try avoid false +ve detect due to very low WHTLO]
HILITE = True # Switch on text location hi-liting in ShowMetrics, Added nicety, no particular use here, demo only.
DB = "bruno321.DB" # DBase
FUNC = "GreyScale.Levels(32,1.0,65,16,235,coring=false).Blur(0.2,0.2)" # Applied to entire Black (Incl titles) sections
#FUNC = ""
TEXTCNT = Round(4*Framerate) # 4 seconds. Black + Titles replaced with this many frames of mid title frame
NewTitles = ".\NewTitles.Txt" # Result Frames/Ranges file for New Extended InterTitles.
# Allows for plucking out NewTitles OR Non NewTitles, processing and then replacing using FrameSel.
# Eg Denoise clip except for NewTitles, then replace denoised back from whence they came.
# See FrameSel/FrameRep.
# If NewTitles="", then dont create frames/ranges file.
#---------------------
# [0] Routine 0, View Metrics Only - Comment Out when not in-use
# Show Metrics to get correct parameters prior to MakeFiles()
Return ShowMetrics(blk_hi=BLKHI,Wht_Lo=WHTLO,IT_THRESH=THRESH,kTh=KTH,HiLite=HILITE,x=X,y=Y,w=W,h=H) # Show Metrics ONLY
#---------------------
# [1] Routine 1, Create Files required for Process_Titles - Comment Out when not in-use
# Make command files, MUST use before Process_Titles function. Can use DebugView to View Progress.
# Returns MessageClip("ALL DONE") style clip when finished, does not return until entire clip processed.
return MakeFiles(DB,blk_hi=BLKHI,Wht_Lo=WHTLO,IT_THRESH=THRESH,kth=kTh,x=X,y=Y,w=W,h=H)
#---------------------
# [2] Routine 2, Process_Titles using files created via Routine 1 MakeFiles.
Process_Titles(DB,TextCnt,FUNC,newtitles=NewTitles)
Return Last # Comment out to use below
############### DEMO NewTitles use.
# Process ONLY non New Extended Titles, then put back into PROC clip
PROC = Last # Processed clip, ie with extended Intertitles
REJECT = True # We are gonna Process frames NOT in NewTitles.
RADT=2 # Arg to SpotLess for denoise
SELECTED=PROC.FrameSel(cmd=NewTitles,ordered=TRUE,reject=REJECT) # We are going to use FrameRep, must use ORDERED=True (OR REJECT=True)
SELECTED=SELECTED.SpotLess(radt=RADT).Subtitle("SpotLess") # Do some editing on SELECTED Frames
FrameRep(PROC,SELECTED,cmd=NewTitles,reject=REJECT) # Put edited frames back into original PROC clip (audio from PROC)
StackVertical(PROC,Last)
Return Last
#---------------------
Function ShowMetrics(clip c,int "Blk_hi",int "Wht_Lo",Float "IT_Thresh",Float "kTh",Bool "HiLite",int "X",int "Y",int "W",int "H") {
# Use for finding best parameters to MakeFiles()
c
ConvertToRGB32() # for HiLite non mod coords
Blk_hi=Default(Blk_hi,40)
Wht_lo=Default(Wht_lo,200)
IT_Thresh=Float(Default(IT_Thresh,97.5))
kTh=Float(Default(kTh,92.0))
HiLite=Default(HiLite,False)
X=Default(X,0) Y=Default(Y,0) W=Default(W,0) H=Default(H,0)
ScriptClip("""
KPerc = RT_YInRange(lo=0,hi=Blk_hi,x=X,y=Y,w=W,h=H) * 100.0
WPerc = RT_YInRange(lo=Wht_lo,hi=255,x=X,y=Y,w=W,h=H) * 100.0
itot = WPerc + KPerc # Total frame area that is Black OR White
IsBLK = itot >= IT_Thresh && KPerc >= kTh
Got=(IsBLK && HiLite) ? RT_YInRangeLocate(Baffle=2,lo=Wht_lo/2,hi=255,prefix="SHWM_",x=X,y=Y,w=W,h=H) : False
(Got) ? OverLay(Last.BlankClip(color=$FF8080,width=SHWM_W,height=SHWM_H),x=SHWM_X,y=SHWM_Y,opacity=0.5) : NOP
SS=String(current_frame) + "] W%="+String(WPerc,"%-6.2f")+" K%="+String(KPerc,"%-6.2f")+" Tot%="+String(itot,"%-6.2f") + \
"\nBLACK="+((IsBLK)?"YES":"NO")+ " : FOUNDTITLE="+((Got)?"YES":"NO")
Subtitle(SS,lsp=0)
""",args="Blk_hi,Wht_lo,IT_Thresh,kTh,HiLite,X,Y,W,H") # Needs Grunt for args
return Last
}
Function MakeFiles(clip c,String DB,int "Blk_hi",int "Wht_Lo",Float "IT_Thresh",Float "kTh",int "X",int "Y",int "W",int "H") {
# Make detect files for Process_titles
c
Assert(DB!="","MakeFiles: Need DB")
DB = DB.RT_GetFullPathName
Blk_hi=Default(Blk_hi,40) Wht_lo=Default(Wht_lo,200)
IT_Thresh=Float(Default(IT_Thresh,97.5))
kTh=Float(Default(kTh,92.0))
X=Default(X,0) Y=Default(Y,0) W=Default(W,0) H=Default(H,0)
BlackFrames=RT_GetFullPathName("BlackFrames.txt")
TitleFrames=RT_GetFullPathName("TitleFrames.txt")
(Exist(BlackFrames)) ? RT_FileDelete(BlackFrames) : NOP # Delete existing
(Exist(TitleFrames)) ? RT_FileDelete(TitleFrames) : NOP
ScriptClip("""
n=current_frame
KPerc = RT_YInRange(lo=0,hi=Blk_hi,x=X,y=Y,w=W,h=H) * 100.0
WPerc = RT_YInRange(lo=Wht_lo,hi=255,x=X,y=Y,w=W,h=H) * 100.0
itot = WPerc + KPerc
if(itot >= IT_Thresh && KPerc >= kTh) {
RT_WriteFile(BlackFrames,"%d",n,append=True)
if(RT_YInRangeLocate(Baffle=2,lo=Wht_lo/2,hi=255,prefix="SHWM_",x=X,y=Y,w=W,h=H)) {
RT_WriteFile(TitleFrames,"%d",n,append=True)
}
}
return Last
""",args="Blk_hi,Wht_lo,IT_Thresh,kTh,X,Y,W,H,BlackFrames,TitleFrames") # Needs Grunt for args
RT_ForceProcess() # returns only on completion
BlackRanges=RT_GetFullPathName("BlackRanges.txt")
TitleRanges=RT_GetFullPathName("TitleRanges.txt")
# Make additional ranges files
Last.FrameSel_CmdReWrite(BlackRanges,Cmd=BlackFrames,Reject=false, Ordered=true,Range=true, Space=False,Prune=False)
Last.FrameSel_CmdReWrite(TitleRanges,Cmd=TitleFrames,Reject=false, Ordered=true,Range=True, Space=False,Prune=False)
# and a DBase of black ranges
BlackDB = RT_GetFullPathName("Black.DB")
RT_DBaseAlloc(BlackDB,0,"ii")
RT_DBaseReadCSV(BlackDB,BlackRanges)
# and a DBase of Title ranges
TitleDB = RT_GetFullPathName("Title.DB")
RT_DBaseAlloc(TitleDB,0,"ii")
RT_DBaseReadCSV(TitleDB,TitleRanges)
Black_Records = RT_DBaseRecords(BlackDB)
RT_DBaseAlloc(DB,0,"iibii")
TitiX=0
# Create and combine Black and Title into single DBase for client [ There may be a black section without a text title ]
for(i=0,Black_Records-1) {
BS = RT_DBaseGetField(BlackDB,i,0)
BE = RT_DBaseGetField(BlackDB,i,1)
TS = RT_DBaseGetField(TitleDB,TitiX,0)
TE = RT_DBaseGetField(TitleDB,TitiX,1)
Got = (TS >= BS && TE <= BE) # Is next Title in current Black section ?
RT_DBaseAppend(DB,BS,BE,Got,(Got)?TS:0,(Got)?TE:0)
TitIx = (Got) ? TitIx+1 : TitIx # if got processed title, then look for next one
}
# Dump temps, but keep ranges files, perhaps of use
RT_FileDelete(BlackFrames)
RT_FileDelete(TitleFrames)
RT_FileDelete(BlackDB)
RT_FileDelete(TitleDB)
return MessageClip("Makefiles ALL DONE")
}
Function Process_Titles(clip c,String DB,int "TextCnt",String "func",String "NewTitles") {
Assert(DB!="","MakeFiles: Need DB")
DB = DB.RT_GetFullPathName
TextCnt=Default(TextCnt,50)
Func=Default(Func,"")
NewTitles=Default(NewTitles,"")
NewTitles=(NewTitles=="") ? "" : NewTitles.RT_GetFullPathName
(NewTitles=="") ? NOP : RT_FileDelete(NewTitles)
Records = RT_DBaseRecords(DB)
C2 = c.Blankclip(Length=0)
E = -1
For(rec=0,Records-1) {
S = RT_DBaseGetField(DB,Rec,0) # Start of this BLack Range [with possible title]
if(S > 0) {
C2 = C2 ++ c.Trim(E + 1,S - 1) # non black between prev black and this one
}
E = RT_DBaseGetField(DB,Rec,1) # End of this Black
BTS = RT_DBaseGetField(DB,Rec,3) - S # start of title relative Black section
BTE = RT_DBaseGetField(DB,Rec,4) - S # end of title relative Black section
BTF = (BTS + BTE) / 2 # Middle frame of title
Got = RT_DBaseGetField(DB,rec,2)
Black = c.Trim(S , E) # Current Black
Black = (Func!="") ? Black.Eval(Func) : Black # Levels on whole Black section inc possible title
if(Got && TextCnt > 0) { # Black section Has Title, and extending title ?
# Black = Black.Loop(TextCnt + 1,BTF,BTF) # Extend framecount of middle title frame only
Black = Black.Trim(BTF,-1).Loop(TextCnt) # ReTime titles for TextCnt frames. [entire BLACK + TITLES are replaced]
}
if(NewTitles != "") {
NT_S = C2.FrameCount
NT_fc = Black.FrameCount
NT_E = (NT_S==0 && NT_fc==1) ? -1 : NT_S + NT_fc - 1
RT_Writefile(NewTitles,"%d,%d",NT_S,NT_E,Append=True)
}
C2 = C2 ++ Black
}
if(E < c.FrameCount -1) {
C2 = C2 + c.Trim(E + 1, 0)
}
Return C2
}
###################
###################
###################
Function TestClip(clip c) {
# TestClip generator.
c
K=c.BlankClip().Trim(0,-100)
KT=K.Subtitle("This is just a test text ABCDEFGHIJKLM\nAnd some more text abcdefghijklm\nAaBbCcDdeEFfGgHhIiJjKkLlMm\n", \
x=K.width/2-150,y=K.Height-100,text_color=$E0E0E0,lsp=0)
KC = k.Trim(0,-50) ++ kt.Trim(0,-100) ++ k.Trim(0,-50)
C2=c.BlankClip(length=0)
for(i=0,Framecount-1,200) {
C2 = C2 + C.Trim(i,min(c.FrameCount-1,i+199))
C2 = C2 + KC
}
return C2
}
New code in BLUE.
Newtitles.txt for sample clip. Resulting extended InterTitles ranges, after Process_Titles().
29,104
152,227
We dont use it for anything here, but is available if required.
EDIT:
Added this bit after Process_Titles()
#---------------------
# [2] Routine 2, Process_Titles using files created via Routine 1 MakeFiles.
Process_Titles(DB,TextCnt,FUNC,newtitles=NewTitles)
#Return Last # Comment out to use below
############### DEMO NewTitles use.
# Process ONLY non New Extended Titles, then put back into PROC clip
PROC = Last # Processed clip, ie with extended Intertitles
REJECT = True # We are gonna Process frames NOT in NewTitles.
RADT=2 # Arg to SpotLess for denoise
SELECTED=PROC.FrameSel(cmd=NewTitles,ordered=TRUE,reject=REJECT) # We are going to use FrameRep, must use ORDERED=True (OR REJECT=True)
SELECTED=SELECTED.SpotLess(radt=RADT).Subtitle("SpotLess") # Do some editing on SELECTED Frames
FrameRep(PROC,SELECTED,cmd=NewTitles,reject=REJECT) # Put edited frames back into original PROC clip (audio from PROC)
StackVertical(PROC,Last)
Return Last
Produces this
https://i.postimg.cc/kMtpVW56/Inter-Title-Re-Time-01.jpg (https://postimages.cc/)
ABOVE: Top, before denoise, bottom, FrameSel/SpotLess/FrameRep denoised.
Considering that above frame is immediately before extended title frame, is not too bad. [Different scene is following the Intertitle]
[ie cannot use next frame in Motion compensated denoise, only frames prior to noisy frame].
https://i.postimg.cc/jSGG3vCb/Inter-Title-Re-Time-02.jpg (https://postimages.cc/)
Above: Frame immediately following 1st image in PROC clip, not present in SELECTED clip, not denoised, or subtitled.
https://i.postimg.cc/J4CPJY6w/Inter-Title-Re-Time-03.jpg (https://postimages.cc/)
Above: In PROC clip, is the Frame AFTER INTERTITLE that is following the 1st image, is adjacent to first image in SELECTED clip when Denoised.
Not much in the way of noise in this frame.
EDIT: And just for good luck, below is how original non extended 4 frame InterTitle appeared.
https://i.postimg.cc/pdWZ1t2r/Inter-Title-00.jpg (https://postimages.cc/)
If 2nd Image FUNC processed and extended titles are too long, bright, or blurred, then can adjust with TEXTCNT and FUNC settings, I
aint spendin' a lot of time trying to guess anybodies preference.
EDIT: Using the NewTitles.txt thing and temporal processing ONLY non Extended_InterTitles_Ranges, could have benefit where original intertitles
were spliced into contiguous video stream, ie frame before and after intertitles where originally adjacent frames in same scene.
StainlessS
8th January 2021, 21:38
Bruno, I see you there,
can you at least acknowledge above post.
[also see post before it]
bruno321
11th January 2021, 15:56
Sorry for not reporting, StainlessS! The truth is that I recently learned that I may have access to a better source that doesn't have these problems, so the whole thing may be moot...
StainlessS
11th January 2021, 17:46
OK, thanks for reply, I'll take you off my ignore list.
EDIT: You only went on it about 30 mins ago. :)
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.