Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. |
1st December 2016, 12:08 | #1 | Link |
Registered User
Join Date: Nov 2016
Posts: 151
|
DeSub – automatic hardcoded subtitles removal
DeSub – automatic hardcoded subtitles removal
First post here, so please be patient! Long time lurker, it's time to give my (very little) contribution. Is it too good to be true? Well, it needs two clips, one with subtitles (or logo), and the other without; will create a mask “on the fly”, and the subtitles (logo) will be replaced with the corresponding part of the image of the clip without logo. For best result, it’s better to limit usage only to frames with subtitles; clips must be aligned perfectly, both temporally and spatially; must have the same (or very similar) colors; it’s always possible to merge the result and the existing not subbed clip to improve quality. Save it as DeSub.avsi and put into your AviSynth plugins folder. Code: Code:
########################################################################################### ### DeSub 1.0: removes the subtitles with no need to prepare a mask for every line! ### ### ### ### Two spatially and aligned clips are needed, one with hardcoded subtitles, or logo, ### ### and the other without; the script creates a mask "on the fly" that will be used to ### ### cover the subtitles with the corresponding parts of the clip without them. ### ### ### ### Usage: DeSub(clipwithsubs,clipwithoutsubs,subcolor) ### ### ### ### Example: goodclip.avi has subtitles, badclip.avi has no subtitles, subs color white ### ### ### ### DeSub(goodclip,badclip,$ffffff) ### ### ### ### It is highly reccomended to use it only on frames with subtitles ### ### Possible update: limit the use to a certain area of the frame, perfect for logo! ### ### ### ### AviSynth script made by spoRv (http://blog.sporv.com) - Created: 2016-11-29 ### ### ### ### Creative Commons 4,0 - Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) ### ### Link to the licence page: https://creativecommons.org/licenses/by-sa/4.0/ ### ########################################################################################### function DeSub (clip withsubs, clip nosubs, val "color") { withsubs=withsubs.converttoyv24 nosubs=nosubs.converttoyv24 color=default(color,$ffffff) subs = withsubs.converttorgb mask = ColorKeyMask(subs, color, 20) blk = blankclip(length=withsubs.FrameCount,width=withsubs.width,height=withsubs.height) over=Overlay(withsubs, blk, mask=mask.ShowAlpha, mode="blend", opacity=1) mk=over.levels(235,1,255,1,255) w=2 a=mk.addborders(0,0,w,w).crop(w,w,0,0) b=mk.addborders(0,0,0,w).crop(0,w,0,0) c=mk.addborders(w,0,0,w).crop(0,w,-w,0) d=mk.addborders(w,0,0,0).crop(0,0,-w,0) e=mk.addborders(w,w,0,0).crop(0,0,-w,-w) f=mk.addborders(0,w,0,0).crop(0,0,0,-w) g=mk.addborders(0,w,w,0).crop(w,0,0,-w) h=mk.crop(w,0,0,0).addborders(0,0,w,0) x= overlay(b, f, mode="add") y= overlay(d, h, mode="add") xx=overlay(a, e, mode="add") yy=overlay(c, g, mode="add") z= overlay(x, y, mode="add") zz=overlay(xx,yy,mode="add") nu=overlay(z,zz,mode="add") mk=nu.levels(235,1,255,1,255) w=3 a=mk.addborders(0,0,w,w).crop(w,w,0,0) b=mk.addborders(0,0,0,w).crop(0,w,0,0) c=mk.addborders(w,0,0,w).crop(0,w,-w,0) d=mk.addborders(w,0,0,0).crop(0,0,-w,0) e=mk.addborders(w,w,0,0).crop(0,0,-w,-w) f=mk.addborders(0,w,0,0).crop(0,0,0,-w) g=mk.addborders(0,w,w,0).crop(w,0,0,-w) h=mk.crop(w,0,0,0).addborders(0,0,w,0) x= overlay(b, f, mode="add") y= overlay(d, h, mode="add") xx=overlay(a, e, mode="add") yy=overlay(c, g, mode="add") z= overlay(x, y, mode="add") zz=overlay(xx,yy,mode="add") nu=overlay(z,zz,mode="add") mk=nu.levels(235,1,255,1,255) w=4 a=mk.addborders(0,0,w,w).crop(w,w,0,0) b=mk.addborders(0,0,0,w).crop(0,w,0,0) c=mk.addborders(w,0,0,w).crop(0,w,-w,0) d=mk.addborders(w,0,0,0).crop(0,0,-w,0) e=mk.addborders(w,w,0,0).crop(0,0,-w,-w) f=mk.addborders(0,w,0,0).crop(0,0,0,-w) g=mk.addborders(0,w,w,0).crop(w,0,0,-w) h=mk.crop(w,0,0,0).addborders(0,0,w,0) x= overlay(b, f, mode="add") y= overlay(d, h, mode="add") xx=overlay(a, e, mode="add") yy=overlay(c, g, mode="add") z= overlay(x, y, mode="add") zz=overlay(xx,yy,mode="add") nu=overlay(z,zz,mode="add").levels(235,1,255,1,255) numask = ColorKeyMask(nu.ConvertToRGB32, color, 30) Overlay(nosubs, withsubs, mask=numask.ShowAlpha, mode="blend", opacity=1) converttoyv12 } Examples – top DeSub result, bottom original: My function programming is really basic; I know this script is rough, and could be improved a lot; it should contain the "box" coordinates where the subtitles (or logo) are located, to limit the filter to work just in that area; and I would like to reiterate the paint function, and limit it to three passes - with a variable like strenght, where 1 does one pass with w=2, 2 does two passes with w=2 and then w=3, and 3 does three passes, with w=2 then w=3 then w=4 - like I did in the script. Any modification, correction or improvement is really welcome! |
1st December 2016, 21:51 | #2 | Link |
Registered User
Join Date: Apr 2008
Posts: 418
|
Would it be possible to do the opposite, meaning adding hardcoded subtitles from a video to a clean video?
And how about using mt_merge from MaskTools2 instead of Overlay to avoid colorspace conversion. Last edited by Gser; 1st December 2016 at 21:58. |
2nd December 2016, 00:26 | #3 | Link |
Registered User
Join Date: Sep 2003
Location: Berlin, Germany
Posts: 3,079
|
Sorry, I am sure missing something here, but I do not get the point of this script...
Why in the world do you want to remove hard coded subs from the first clip if you already have a second clip which does not have hardcoded subs? Why are you not just using this second clip? Cheers manolito |
2nd December 2016, 01:11 | #4 | Link | |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Quote:
https://en.wikiquote.org/wiki/George_Mallory
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 2nd December 2016 at 01:13. |
|
2nd December 2016, 03:41 | #5 | Link |
Registered User
Join Date: Nov 2016
Posts: 151
|
Because:
1) "spatially aligned" could also means the clip with subtitles is HD, while the one without is SD... hence, the superior HD quality will be preserved almost entirely, minus the replaced subtitles, that will be just upscales 2) clip without subs could have lower quality, even if have the same resolution - for example, web clip Vs DVD, highly compressed Vs less compressed, web download Vs BD etc. 3) two clips (or more) averaged have less noise (apart the replaced subtitles, that will be the same for both, of course) |
2nd December 2016, 05:17 | #6 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Maybe, this should be in the Usage forum, not really a developer thing, really.
Anyways, we are glad to have you, good luck and may your god smile upon you. We wish you a very good & warm Welcome to the forum
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? |
2nd December 2016, 12:26 | #7 | Link |
Registered User
Join Date: Nov 2016
Posts: 151
|
Thanks Stainless! I followed you since many years ago, I like your scripts and your will to help!
Don't know if this thread should be moved to the avisynth usage subforum instead; I saw filters and scripts posted here, so I thought it was the right place; but if moderators think it should be moved, it is ok! |
12th August 2021, 15:08 | #8 | Link |
Registered User
Join Date: Dec 2012
Posts: 65
|
Can someone add a mask output function to the script?
I would also like an adjustable blur overlay on the mask and the ability to limit the area of the script using cropping.
__________________
Ryzen 2700x | ASUS ROG Strix GTX 1080 Ti | 16 Gb DDR4
Windows 10 x64 20H2 KD-55XE9005 | Edifier R2800 |
13th August 2021, 02:03 | #9 | Link | |
Banana User
Join Date: Sep 2008
Posts: 990
|
Quote:
Can you share snippets from your clips? Last edited by VoodooFX; 13th August 2021 at 02:07. |
|
13th August 2021, 06:04 | #11 | Link | |
Registered User
Join Date: Dec 2012
Posts: 65
|
Quote:
I need to remove hurdsub from a good quality video (WEBDL 720p) using a less good quality video (DVDRip 480p). Can InpaintDelogo create a mask based on the difference between two clips and accept a video clip mask as an input to the mask?
__________________
Ryzen 2700x | ASUS ROG Strix GTX 1080 Ti | 16 Gb DDR4
Windows 10 x64 20H2 KD-55XE9005 | Edifier R2800 |
|
13th August 2021, 09:14 | #12 | Link | ||
Banana User
Join Date: Sep 2008
Posts: 990
|
Quote:
I was thinking about a video guide as the visual guides are faster to understand, but it basically would be repeating what is already written in the help (inside the script). At what part of the help did you stuck? Quote:
It can create a clip mask without second video. I did same things as you want to do, and even used it to convert mask to soft subs. PS: I see multiple experimental versions of the script on my HDD, looks like I was doing those experiments with subtitles after the last published version, could be that v1.24 is not fine-tuned for subs. If you can, share ~10mins cuts from your videos so I can check what is what with those versions. PS2: Looks like I was stuck on extracting subs: Dynamic mask to images for OCR I was able to do it anyway with some external program, still would be nice to do it in AvS, maybe @StainlessS would know how to make that happen. Last edited by VoodooFX; 14th August 2021 at 03:09. |
||
13th August 2021, 10:04 | #13 | Link | ||
Registered User
Join Date: Dec 2012
Posts: 65
|
Quote:
Quote:
the main task is to replace the subtitles using a mask with the background from another video DeSub does this in principle, but the edge of the mask is hard, which is why the joint is often visible, I added fastBlur() to it and the result became much better, but I do not know how to output the fastBlur() settings to the DeSub parameters so that it is convenient to use. Also, to eliminate possible errors, it would be good to limit the DeSub application area to the approximate location of subtitles.
__________________
Ryzen 2700x | ASUS ROG Strix GTX 1080 Ti | 16 Gb DDR4
Windows 10 x64 20H2 KD-55XE9005 | Edifier R2800 Last edited by Shinkiro; 13th August 2021 at 10:15. |
||
14th August 2021, 03:03 | #14 | Link | |
Banana User
Join Date: Sep 2008
Posts: 990
|
Quote:
But you won't be able to get the good results with your video, as subbed sample has wonky decimation, so I dunno how you'll align both videos frame to frame. Plus, levels are shifted, bright areas are darker when dark areas are brighter in nonsubbed video, but that's a minor problem. InpaintDelogo mask example: DeSub mask example: Last edited by VoodooFX; 14th August 2021 at 03:15. |
|
14th August 2021, 03:11 | #15 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
post #1 of 2
Well, seems that VoodooFX has sorted you out here:- https://forum.doom9.org/showthread.p...52#post1949752 But, I've been playing a little bit with an older script, thats detects subs with halo. DetectSub_MI.avsi Code:
### # DetectSub.MI.avsi":- https://forum.doom9.org/showthread.php?p=1782036#post1782036 ### # DetectSub, MultiInstance script, MultiInstance not necessary here but easy convenient way to use Scriptclip, GScript and double quoted # strings in same script. Would have been nice if Avisynth also recognised groups of 5 sets of double quotes as well as groups of 3 and # single double quotes. # # req RT_Stats v2.00 Beta 02, GScript, Grunt, CallCmd, MaskTools v2.0. # RT_Stats v2.00 Beta2 first posted here:- http://forum.doom9.org/showthread.php?p=1782028#post1782028 # ### Function DetectSub_MI(clip c,string "Override", \ Int "X",Int "Y",Int "W",Int "H", \ Int "Text_w",Int "Text_h",Int "TextCol",Int "TextVar", \ Int "Halo_L",Int "Halo_T",Int "Halo_R",Int "Halo_B",Int "HaloCol",Int "HaloVar", \ Int "THysCNT",Int "HHysCNT",Int "DHysCNT",Bool "ShowInPand", \ Int "Baffle_w",Int "Baffle_h",Float "Thresh_w",Float "Thresh_h",Bool "ReScan", \ Bool "Show",Int "stack",Bool "ShowArea",Int "AreaColor",String "DB",Bool "Debug") { myName="DetectSub_MI: " c IsPlus=FindStr(VersionString,"AviSynth+")!=0 Assert(RT_FunctionExist("GScriptClip"),myName+"Essential GRunT plugin installed, http://forum.doom9.org/showthread.php?t=139337") Assert(IsPlus||RT_FunctionExist("GScript"),myName+"Essential GScript plugin installed, http://forum.doom9.org/showthread.php?t=147846") Assert(RT_FunctionExist("CallCmd"),myName+"Essential CallCmd plugin installed, http://forum.doom9.org/showthread.php?t=166063") Assert(RT_FunctionExist("mt_expand"),myName+"Essential MaskTools v2 plugin installed, http://forum.doom9.org/showthread.php?t=98985") Override=Default(OverRide,"") X=Default(X,0) Y=Default(Y,Height-120) W=Default(W,0) H=Default(H,-8) W=(W<=0)?Width-X+W:W H=(H<=0)?Height-Y+H:H Text_w=Default(Text_w,3) Text_h=Default(Text_h,3) TextCol=Default(TextCol,$FCFCFC) TextVar=Default(TextVar,3) Halo_L=Default(Halo_L,3) Halo_T=Default(Halo_T,4) Halo_R=Default(Halo_R,5) Halo_B=Default(Halo_B,6) HaloCol=Default(HaloCol,$030303) HaloVar=Default(HaloVar,3) THysCNT=Default(THysCNT,0) HHysCNT=Default(HHysCNT,0) DHysCNT=Default(DHysCNT,0) ShowInpand=(Show)?Default(ShowInpand,False):False Baffle_w=Default(Baffle_w,0) Baffle_h=Default(Baffle_h,0) Thresh_w=Default(Thresh_w,0.0) Thresh_h=Default(Thresh_h,0.0) ReScan=Default(ReScan,False) Show=Default(Show,False) Stack=(Show)?default(Stack,0):0 ShowArea=(Show)?Default(ShowArea,True):False AreaColor=Default(AreaColor,$FF00FF) DB=Default(DB,"") UserDB=(DB!="") DB=(!UserDB) ? "~"+RT_LocalTimeString+".DB" : DB DB=RT_GetFullPathName(DB) Debug=Default(Debug,False) VW=Width VH=Height /* Fields 0) Status, 0=Unknown (unvisited), 1=Sub, 2 Not sub, 3 User OverRide 1) X 2) Y 3) W 4) H */ RT_DBaseAlloc(DB,FrameCount,"iiiii") Function CnvStr(clip c) { Return c.IsRGB24?"ConvertToRGB24":c.IsRGB32?"ConvertToRGB32":c.IsYUY2?"ConvertToYUY2":c.IsYV12?"ConvertToYV12" \ :c.IsYV16?"c.ConvertToYV16":c.IsYV24?"c.ConvertToYV24":c.IsY8?"c.ConvertToY8":"" } CNVS=CnvStr(c) Assert(CNVS!="",RT_String("%sRGB24, RGB32, YUY2, YV12, YV16, YV24,and Y8 Only",myName)) Function ChrIsStar(String S) {return RT_Ord(S)==42} Function ChrIsNul(String S) {return RT_Ord(S)== 0} # End of String Function ChrIsHash(String S) {return RT_Ord(S)==35} # # Function ChrIsDigit(String S) {C=RT_Ord(S) return C>=48&&C<=57} FuncS=""" Function ChrEatWhite(String S) {i=1 C=RT_Ord(S,i) While(C==32||C>=8&&C<=13) {i=i+1 C=RT_Ord(S,i)} return i>1?MidStr(S,i):S} Function ChrEatDigits(String S) {i=1 C=RT_Ord(S,i) While(C>=48&&C<=57) {i=i+1 C=RT_Ord(S,i)} return i>1?MidStr(S,i):S} Function Fn@@@(clip c,String DB,Int VW,Int VH, \ int X,int Y,int W,int H,Int Text_w,Int Text_h,Int Halo_L,Int Halo_T,Int Halo_R,Int Halo_B, \ Int Baffle_w,Int Baffle_h,Float Thresh_w,Float Thresh_h,Bool ReScan, \ clip dc,bool Show,int Stack,bool ShowArea,Int AreaColor,bool Debug) { c n = current_frame Status = RT_DBaseGetField(DB,n,0) if(Show || Status <= 1) { # In here if Show or Status 0 or 1 (ie unvisited or Sub) if(Status==0) { # Unknown Status Bingo = dc.RT_YInRangeLocate(Baffle_w=Baffle_w,Baffle_h=Baffle_h, \ lo=255,hi=255,debug=Debug,Thresh_w=Thresh_w,Thresh_h=Thresh_h,ReScan=ReScan) Status=(Bingo)?1:2 if(Status==1) { RT_DBaseSet(DB,n,Status,X+YIRL_X,Y+YIRL_Y,YIRL_W,YIRL_H) } else { RT_DBaseSetField(DB,n,0,Status) } } if(Show) { if(Status==1) { SUB_X = RT_DBaseGetField(DB,n,1) SUB_Y = RT_DBaseGetField(DB,n,2) SUB_W = RT_DBaseGetField(DB,n,3) SUB_H = RT_DBaseGetField(DB,n,4) SUB_W=(SUB_W+1)/2*2 SUB_H=(SUB_H+1)/2*2 OverLay(Last.BlankClip(color=AreaColor,width=SUB_W,height=SUB_H),x=SUB_X,y=SUB_Y,opacity=0.25) RT_Subtitle("%d] Text @ x=%d y=%d w=%d h=%d",n,SUB_X,SUB_Y,SUB_W,SUB_H) } else if(Status==3) { RT_Subtitle("%d] User OverRide",n) } } } # End (Show || Status) Return Last } ####################################### # Unique Global Variables Initialization ####################################### if(OverRide!="") { if(ChrIsStar(Override)) {OverRide=MidStr(OverRide,2) } else { Assert(Exist(OverRide),RT_String("%sOverRide File does not exist",myName)) OverRide=RT_ReadTxtFromFile(Override) } LINES=RT_TxtQueryLines(OverRide) for(i=0,LINES-1) { SS=ChrEatWhite(RT_TxtGetLine(Override,i)) S=SS if(!ChrIsNul(S) && !ChrIsHash(S)) { if(ChrIsDigit(S)) { StartF = RT_NumberValue(S) EndF=StartF S=ChrEatWhite(ChrEatDigits(S)) if(ChrIsComma(S)){S=MidStr(S,2) S=ChrEatWhite(S)} if(ChrIsDigit(S)) { EndF=RT_NumberValue(S) S=ChrEatDigits(S) if(EndF==0) { EndF=FrameCount-1} Assert(StartF<=EndF,RT_String("%sError StartFrame(%d) > EndFrame(%d)",myName,StartF,EndF)) } (Debug)?RT_DebugF("OverRiding Range %d,%d to not detected",StartF,EndF,name=myName):NOP for(n=StartF,EndF) {RT_DBaseSetField(DB,n,0,3)} } S=ChrEatWhite(S) if(ChrIsHash(S)) {S=""} Assert(ChrIsNul(S),RT_String("%s *** NON-PARSE *** Error in Override Line %d\n'%s'",myName,i+1,SS)) } } } rgb=ConvertToRGB32.Crop(X,Y,W,H).ResetMask # Reset Alpha to White Txt=rgb.ColorKeyMask(TextCol,TextVar+1,TextVar+1,TextVar+1).ShowAlpha(Pixel_Type="Y8") # Set in range pixels to black Hal=rgb.ColorKeyMask(HaloCol,HaloVar+1,HaloVar+1,HaloVar+1).ShowAlpha(Pixel_Type="Y8") Txt=Txt.Invert # In range pixels white, else black Hal=Hal.Invert CHROMAPROC = "-128" HALO_MAX=Max(HALO_L,HALO_T,HALO_R,HALO_B) for(i=1,HALO_MAX) { HorFlg=(i<=HALO_L?1:0)+(i<=HALO_R?2:0) VerFlg=(i<=HALO_T?1:0)+(i<=HALO_B?2:0) if(HorFlg+VerFlg==6) {TXT=TXT.Mt_Expand(mode="square", chroma=CHROMAPROC) } else { if(HorFlg==3) {TXT=TXT.Mt_Expand(mode="horizontal", chroma=CHROMAPROC) HorFlg=0} if(VerFlg==3) {TXT=TXT.Mt_Expand(mode="vertical", chroma=CHROMAPROC) VerFlg=0} if(HorFlg!=0) {TXT=TXT.Mt_Expand(mode=HorFlg==1? " 1 0 0 0" : " -1 0 0 0", chroma=CHROMAPROC) } if(VerFlg!=0) {TXT=TXT.Mt_Expand(mode=VerFlg==1? " 0 1 0 0" : " 0 -1 0 0" , chroma=CHROMAPROC) } } } TEXT_MAX=Max(TEXT_W,TEXT_H) for(i=1,TEXT_MAX) { HorFlg=(i<=TEXT_W?1:0) VerFlg=(i<=TEXT_H?1:0) if(HorFlg+VerFlg==2) {HAL=HAL.Mt_Expand(mode="square", chroma=CHROMAPROC) } else { if(HorFlg!=0) {HAL=HAL.Mt_Expand(mode="horizontal", chroma=CHROMAPROC) } if(VerFlg!=0) {HAL=HAL.Mt_Expand(mode="vertical", chroma=CHROMAPROC) } } } # reduce strays a little WeeTxt=Txt WeeHal=Hal if(THysCNT>0) { For(i=1,THysCNT) {WeeTxt=WeeTxt.MT_Inpand(mode="both",chroma=CHROMAPROC)} Txt=WeeTxt.MT_Hysteresis(Txt,chroma=CHROMAPROC) } if(HHysCNT>0) { For(i=1,HHysCNT) {WeeHal=WeeHal.MT_Inpand(mode="both",chroma=CHROMAPROC)} Hal=WeeHal.MT_Hysteresis(Hal,chroma=CHROMAPROC) } dc=Mt_Logic(Txt,Hal,"and", chroma=CHROMAPROC) dc2=dc if(DHysCNT>0) { For(i=1,DHysCNT) {dc2=dc2.MT_Inpand(mode="both",chroma=CHROMAPROC)} dc=dc2.MT_Hysteresis(dc,chroma=CHROMAPROC) dc2 = (ShowInPand) ? dc2 : dc } if(Show && (Stack>=1 && Stack<=2)) { If(ShowInPand) {Txt=WeeTxt Hal=WeeHal} dc2=dc2.Eval(CnvS).AddBorders(X,0,Width-X-W,0).AddBorders(0,22,0,0,$C0C0C0).Subtitle("DETECT",y=2) if(Stack==2) { TXT = TXT.Eval(CnvS).AddBorders(X,0,Width-X-W,0).AddBorders(0,22,0,0,$C0C0C0).Subtitle("TEXT",y=2) HAL = HAL.Eval(CnvS).AddBorders(X,0,Width-X-W,0).AddBorders(0,22,0,0,$C0C0C0).Subtitle("HALO",y=2) c=StackVertical(Last,dc2,TXT,HAL) } else { c=StackVertical(Last,dc2) } } else {c=Last} if(Show&&ShowArea) { WW=(W+1)/2*2 HH=(H+1)/2*2 # YV12 Legal Msk=c.Blankclip(width=WW+2,height=HH+2,Length=1,pixel_type="YV12").Killaudio Infix=RT_string("(((x<=1|x>=%d|y<=1|y>=%d)&(x<4|x>=%d)&(y<4|y>=%d)|(x==0|x==%d|y==0|y==%d)))?255:0", W-2,H-2,W-4,H-4,W-1,H-1) Msk=Msk.mt_lutspa(relative = false,yExpr=mt_Polish(InFix), chroma = CHROMAPROC) Mrk=Msk.BlankClip(Color=AreaColor) Msk=Msk.Loop(FrameCount,0,0) Mrk=Mrk.Loop(FrameCount,0,0) c=c.Overlay(Mrk,x=X-1,y=Y-1,Mask=Msk,Mode="Blend",Opacity=0.5) } RT_DBaseSetID(DB,0,c.FrameCount,c.FrameRate,VW,VH,X,Y,W,H) ####################################### # Unique Runtime Call, GScriptClip must be a one-liner: ####################################### ARGS="DB,VW,VH,X,Y,W,H,Text_w,Text_h,Halo_L,Halo_T,Halo_R,Halo_B,Baffle_w,Baffle_h,Thresh_w,Thresh_h,ReScan,dc,Show,Stack,Showarea,AreaColor,debug" c.GScriptClip("Fn@@@(last, "+ARGS+")", local=true, args=ARGS) return Last """ ####################################### # Unique Identifier Definition ####################################### GIFunc="DetectSub_MI" # Function Name, Supply unique name for your multi-instance function. GIName=GIFunc+"_InstanceNumber" # Name of the Instance number Global RT_IncrGlobal(GIName) # Increment Instance Global (init to 1 if not already exists) GID = GIFunc + "_" + String(Eval(GIName)) InstS = RT_StrReplace(FuncS,"@@@","_"+GID) # RT_WriteFile("DEBUG_"+GID+".TXT","%s",InstS) (!IsPlus) ? GEval(InstS) : Eval(InstS) (!UserDB)?CallCmd(close=RT_String("""CMD /C chcp 1252 && del "%s" """,DB), hide=true, Synchronous=7):NOP # Auto delete non-User DB file on clip closure. Return Last }
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? |
14th August 2021, 03:11 | #16 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
post #2 of 2
Client, DetectSub_MI_Client.avs Code:
### # DetectSub.MI_Client.avs" ### Import("DetectSub_MI.avsi") HARDFN="hard sub - 01 WEBdlRip 720p, 23.976.mkv.AVI" # converted to AVI via ffmpeg HARDFN=HARDFN.RT_GetFullPathName AVISource(HARDFN) # Subtitle coords X = 40 Y = Height-140 W = -X H = -8 # Text, Halo color TEXTCOL = $F3F3F3 TEXTVAR = 12 # Text RGB channels can vary by as much as TEXTVAR, eg $FEFEFE with TEXTVAR=1 ranges $FDFDFD -> $FFFFFF HALOCOL = $092943 HALOVAR = 9 # Halo RGB channels can vary by as much as HALOVAR, eg $FEFEFE with HALOVAR=1 ranges $FDFDFD -> $FFFFFF # Text pixel width,height TEXT_W = 2 # minimum text pixel 'thickness' Horizontal (horizontal thickness of vertical strokes) TEXT_H = 2 # minimum text pixel 'thickness' Vertical (vertical thickness of horizontal strokes) # Halo pixel width,height HALO_L = 2 # Left Halo width in pixels HALO_R = 2 # Right Halo width in pixels HALO_T = 2 # Top Halo height in pixels HALO_B = 2 # Bot Halo height in pixels # Mt_Hysteresis (reduce stray pixels):- http://forum.doom9.org/showthread.php?p=1780589#post1780589 THYSCNT = 1 # Text Mask Mt_Hysteresis inpand count (prior to mt_hysteresis), Dont Mt_Hysteresis if 0 HHYSCNT = 1 # Halo Mask Mt_Hysteresis inpand count (prior to mt_hysteresis), Dont Mt_Hysteresis if 0 DHYSCNT = 1 # Detect clip Mt_Hysteresis inpand count (prior to mt_hysteresis), Dont Mt_Hysteresis if 0 ### Subs Locator### /* RT_YInRangeLocate(), scans all four sides looking for (in this case) white pixels in the Detect Mask clip. Function to scan frame for an area where percentage of pixels in luma range Lo to Hi (inclusive) breaks a threshold over at least Baffle consecutive number of scanlines (all four sides). In this script case, lo and hi are both 255, ie white pixels. RT_YInRangeLocate tests scanlines from outer most scanlines (h and v), towards inner most, stops where it finds Baffle consecutive scanlines that contain more than Thresh percent of pixels in range Lo to Hi. Object interiors are not tested and so could be hollow. Could also give +ve result for a disjoint shape like this -- | | -- Args: Baffle: Default=8, minimum number of scanlines that must have a percentage of pixels in range Lo to Hi, greater than Thresh. Avoids noise. Thresh: Default=0.0 (0.0->100.0). Percentage pixels above which breaks Threshold. Default is any pixel in the range Lo to Hi will break threshold. Baffle_W, Default Baffle. Thickness of Left and Right side vertical edges, silently limited to width W of search area. Baffle_H, Default Baffle. Thickness of Top and Bottom horizontal edges, silently limited to height H of search area. Script Specific::: RT_Stats v2.00 Beta 02, Added args Thresh_w and Thresh_h, and Bool ReScan. Say we are scanning to find top horizontal edge. We will scan and count number of white pixels in a horizontal scanline. If this percenage count EXCEEDS Thresh_w, and the total number of similarly exceeding consecutive scanlines exceeds Baffle_h (NOTE Baffle_h NOT Baffle_w, although scanlines are horizontal, we are counting the thickness of consecutive lines vertically) then we have found the top edge. Same thing for bottom edge using same variables Thesh_w and Baffle_h. Scanning vertical edges uses Thresh_h and Baffle_w. NOTE, for RT_Stats v2.00 Beta 02, you can also supply eg Thresh_w = -12 (minus) which is taken as a pixel count of +12, rather than as a percentage. This Thresh_x -ve pixel count will have a teeny weeny bit subtracted before use, as the pixel count must be greater (something like Thresh_w=Abs(Thresh_w)- 1.0/scanline_width). NOTE, the RT_YInRangeLocator() default of 0.0 detects more than 0.0 pixels in scanline percentage count, ie any pixel of 255 (in this script case) breaks the threshold and counted against baffle. The new Bool ReScan arg, forces a horizontal edge (top and bottom) rescan if a new vertical edge is found, and a vertical edge (left and right) rescan if a new horizontal edge is found. If top and bottom scan broke threshold and passed baffle, followed by left and right scans doing the same, the top and bottom pixel objects that caused the detections could well have 'moved' outside of the detected area, ie left and right edges moving inwards may leave those objects outside because in the left/right scan they did not satisfy thresh and baffle requirements, and detection will likely be bad. Rescan forces a further scan until all four sides scanned sides are a detection (or not). (Will not be any great overhead if the initial detect was good as it will just recan the same scanlines accessed immediately prior). The internal routine that RT_YInRangeLocate() uses, returns percentage of pixels that are in the required range, each time an edge is detected, the number of required pixels is recalculated as a percentage of the reduced scanline lengths (whether given as percentage, or as a -ve pixel count). */ THRESH_W = -(Text_w+(Halo_L+Halo_R)/2) # -ve, specifies Abs(Pixel width) {Else +ve = Percent width 0.0->100.0%) {0.0=any pixel in range) THRESH_H = -(Text_h+(Halo_T+Halo_B)/2) # -ve, specifies Abs(Pixel Height) {Else +ve = Percent width 0.0->100.0%) {0.0=any pixel in range) # BAFFLE_W = Text_w+Halo_L+Halo_R # Width of outermost Vertical edges. BAFFLE_H = Text_h+Halo_T+Halo_B # Height of outermost Horizontal edges. # RESCAN = true # Switching on might get rid of the odd stray pixel (most likely not). # SHOW = true # Show metrics. AREACOLOR = $8040FF # Subtitle area marker color SHOWAREA = true # Set True to mark subtitle scan area. (Show=False:No Effect) STACK = 2 # 0=Movie, 1=Movie + detection clip, 2=Movie detection clip + Text and Halo Mask clips. (Show=False:No Effect) SHOWINPAND = false # Show Mt_Inpand masks without doing Mt_Hysteresis, ie for THysCnt, HHysCnt, DHysCnt. (Show=False:No Effect) DB = "MyDB.DB" # If Named, then DB not deleted on exit. (Maybe DBase used by other scripts later) DEBUG = false # To DebugView (Google). RT_ v2.00 beta02 extends RT_YInRangeLocate() debug info a little. OverRide = "" # ""=Not used, "*..." multiline string of ranges, "OverRide.txt"=Text file of ranges. #OverRide="OverRide.txt" /* OverRide="""* # <<=== NOTE Asterisk (STAR). Example String OverRide (1st char is '*'). Ranges OverRidden to NO SUBTITLE 10 100 # A comment, SPACE or COMMA Separator 200,300 # 200 to 300. NOTE -ve frame count NOT supported. 3000,0 # 3000 till last frame. """ */ DetectSub_MI(Last,Override=Override, \ x=X,y=Y,w=W,h=H, \ Text_w=TEXT_W,Text_h=TEXT_H,TextCol=TEXTCOL,TextVar=TEXTVAR, \ Halo_L=HALO_L,Halo_T=HALO_T,Halo_R=HALO_R,Halo_B=HALO_B,HaloCol=HALOCOL,HaloVar=HALOVAR, \ THysCnt=THYSCNT,HHysCnt=HHYSCNT,DHysCnt=DHYSCNT,ShowInPand=SHOWINPAND, \ Baffle_w=BAFFLE_W,Baffle_h=BAFFLE_H,Thresh_w=THRESH_W,Thresh_h=THRESH_H,ReScan=RESCAN, \ Show=SHOW,stack=STACK,ShowArea=SHOWAREA,AreaColor=AREACOLOR,db=DB,Debug=DEBUG) Return Last Above , clip overlayed with purple block where subs detected [purple wire frame marks search area]. Below the clip, [from bottom up], Halo, Text, and Detect, masks shown. Detect is result from which overlayed purple block was produced. I had to stop before finishing repair script, as thread had suggestion of rule break:- https://forum.doom9.org/showthread.p...36#post1782036 For the repair script to work [if ever finished] then would require nosubs clip to be EXACTLY SAME SIZE & FRAMERATE as hardsubs clip. EDIT: We'll see if we can output a mask for VoodooFX delogo whotsit, if VoodooFX thinks it necessary [and tells me what he wants].
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 14th August 2021 at 05:06. |
14th August 2021, 18:28 | #17 | Link | ||
Registered User
Join Date: Dec 2012
Posts: 65
|
Quote:
Code:
MaskSub(file="SoftSub.ass", width=1280, height=720, fps=23.976, length=39536).FlipVertical().FastBlur(1.4) Quote:
__________________
Ryzen 2700x | ASUS ROG Strix GTX 1080 Ti | 16 Gb DDR4
Windows 10 x64 20H2 KD-55XE9005 | Edifier R2800 |
||
14th August 2021, 18:56 | #18 | Link | |
Registered User
Join Date: Dec 2012
Posts: 65
|
Quote:
Logically. but as always, what we have does not fit into the framework of an ideal world
__________________
Ryzen 2700x | ASUS ROG Strix GTX 1080 Ti | 16 Gb DDR4
Windows 10 x64 20H2 KD-55XE9005 | Edifier R2800 Last edited by Shinkiro; 14th August 2021 at 19:04. |
|
14th August 2021, 22:21 | #20 | Link |
Registered User
Join Date: Mar 2012
Location: Texas
Posts: 1,666
|
Google is your friend: http://avisynth.nl/index.php/Xy-VSFilter#MaskSub
MaskSub has been around for a very long time, starting with the original VSFilter. |
|
|