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. |
22nd August 2021, 07:15 | #1 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
DetSub - W.I.P
v0.00
Work In Progress. Post #1 of 6. DetSub, purpose to detect hard coded subtitles with halo. Here, import script to set common arguments. DetSub_Args.avs Code:
# DetSub_Args.avs # This just allows set exact same args eg coords in the different scripts ### # DetSub. # Req Avs+, RT_Stats v2.00 Beta 02, GScript, Grunt, MaskTools v2.0. RemoveGain or RGTools. # RT_Stats v2.00 Beta2 first posted here:- http://forum.doom9.org/showthread.php?p=1782028#post1782028 # If CallCmd plugin installed then will auto delete Temp DBase's on clip closure. ### # Sample from here:- https://forum.doom9.org/showthread.php?p=1949702#post1949702 HARDFN="hard sub - 01 WEBdlRip 720p, 23.976.mkv.AVI" # converted to AVI via ffmpeg [or Vdub2] HARDFN=HARDFN.RT_GetFullPathName AVISource(HARDFN) killaudio # Subtitle coords # Need some border around area for allow expand of masks. X = 44 Y = Height-132 W = -X H = -2 # Text, Halo color TEXTCOL = $F3F3F3 # Approx RGB color of text TEXTTOL = $0E0E0E # Per channel text tolerance TEXTTOLT = 0 # Additional text Tweak Tolerance, added to each individual channel of TEXTTOL [+/-]. HALOCOL = $102A37 # Approx RGB color of halo HALOTOL = $121212 # Per channel halo tolerance HALOTOLT = 0 # Additional halo Tweak Tolerance, added to each individual channel of TEXTTOL [+/-]. # Text pixel width,height TEXT_W = 4 # minimum text pixel 'thickness' Horizontal (horizontal thickness of vertical strokes) TEXT_H = 4 # minimum text pixel 'thickness' Vertical (vertical thickness of horizontal strokes) # Halo pixel width,height HALO_L = 3 # Left Halo width in pixels HALO_R = 3 # Right Halo width in pixels HALO_T = 3 # Top Halo height in pixels HALO_B = 3 # Bot Halo height in pixels MATRIX = "Rec601" ################## FrameDB = "FrameDB.DB" # If Named, then FrameDB not deleted on exit. (Maybe DBase used by other scripts later) 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. """ */ All scripts in folder and also IMAGE folder included inside. All you need is the sample in above script, resaved as avi via ffmpeg or Vdub2, and away you go.
__________________
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; 26th August 2021 at 21:33. Reason: Update |
22nd August 2021, 07:16 | #2 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Post #2 of 6
some additional routines DetSub_Sundry.avs Code:
# DetSub_Sundry.avs Function Hit_Marker(int W, Int H, Bool "Hit", Int "BW", Int "BH",Int "PW",Int "PH",Bool "YV12",Bool "Mod2") { /* Req RT_Stats & mt_tools v2. http://forum.doom9.org/showthread.php?t=174527 Creates a marker mask WxH, for use with Overlay as Mask arg. Intended for use via some kind of detector to show detection Hit, or Miss. Returns Single frame clip with null audio, the marker top left hand side is aligned to 0,0. Default return clip colorspace is Y8 for Avisynth v2.6 and above, or YV12 if defunct version. Args:- W,H, Size of marker mask (can be odd), return clip dimensions are rounded up to next multiple of 2 if YV12 return clip. Bare minimum usable size is 4x4 with defaulted BW, BH, PW, PH. HIT, Default False, returns marker as angled corners (Thickness set by BW and BH). True, returns marker as angled corners + outer perimeter where perimeter thickness set by PW and PH. BW, Default Max(W/8,1). Horizontal thickness of the marker corners. BH, Default Max(H/8,1). Vertical thickness of the marker corners. PW, Default Max(BW/8,1). Horizontal thickness of the vertical perimeter. PH, Default Max(BH/8,1). Vertical thickness of the horizontal perimeter. YV12, Default False if Avisynth version 2.6 or greater(Y8), else true(YV12). Selects return clip colorspace. Mod2, Default True. If Y8 then round odd dimensions up modulo 2 (the mask is still WxH). Example:- Import("Hit_Marker.avs") WW=128 HH=WW HIT=True BlankClip Yell=Last.BlankClip(Width=WW,Height=HH,Length=1,Color=$FFFF00) Return OverLay(Yell,x=(Width-WW)/2,y=(Height-HH)/2,mask=Hit_Marker(WW,HH,HIT)) */ Hit=Default(hit,False) BW=Max(Default(BW,W/8),1) BH=Max(Default(BH,H/8),1) BW2=(W>4)?BW*2:BW BH2=(H>4)?BH*2:BH PW=Max(Default(PW,BW/8),1) PH=Max(Default(PH,BH/8),1) is26 = VersionNumber>=2.6 YV12=(!is26) ? True : Default(YV12,False) Mod2=Default(Mod2,True) Mod = (YV12||Mod2) ? 2 : 1 CanvasW=(W+Mod-1)/Mod*Mod CanvasH=(H+Mod-1)/Mod*Mod Rpn= RT_String("x %d < x %d >= | y %d < | y %d >= | x %d < x %d >= | & y %d < y %d >= | & ",BW,W-BW,BH,H-BH,BW2,W-BW2,BH2,H-BH2) Rpn= (Hit) ? Rpn + RT_String("x %d < x %d >= | y %d < | y %d >= | | ",PW,W-PW,PH,H-PH) : Rpn Rpn= Rpn + RT_String("x %d < y %d < & & 255 0 ?",W,H) Blankclip(width=CanvasW,height=CanvasH,Length=1,pixel_type=YV12?"YV12":"Y8").Killaudio return mt_lutspa(relative = false,yExpr=Rpn, chroma = "-128") } 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} 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 DetSub_Override(string Override,string DB) { 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)) } 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)) } } return 0 } Function DetSub_AvgAll2(clip c) { c.FrameCount() <= 1 ? c : Merge(DetSub_AvgAll2(c.SelectEven()), DetSub_AvgAll2(c.SelectOdd())) } Function DetSub_AvgAll(clip c,int "Th",int "ExpandCnt") { Th = Min(Max(Default(Th,254),0),254) ExpandCnt = Min(Max(Default(ExpandCnt,0),0),16) c2=c.DetSub_AvgAll2.mt_binarize(threshold=Th) if(ExpandCnt>0) { c2=c2.mt_Expand(mode=mt_circle(ExpandCnt)) } return c2 } Function Frame2SMPTE(int Frameno,float Fps,int "digits",bool "File") { # ssS Mod of fn by tsp:- https://forum.doom9.org/showthread.php?p=551000#post551000 ch = Default(File,false) ?"_":":" digits = Default(digits, int(log(max(Fps,1))/log(10))+1) # Log10 v2.60+, [Log10(n) = Log(n) / Log(10)] hh=int(Frameno/3600/Fps) mm=int((Frameno-hh*3600*Fps)/60/Fps) ss=int((Frameno-hh*3600*Fps-mm*60*Fps)/Fps) ff=int((Frameno-hh*3600*Fps-mm*60*Fps-ss*Fps)) # return String(hh,"%02.0f")+ch+string(mm,"%02.0f")+ch+string(ss,"%02.0f")+ch+string(ff,"%0"+string(digits)+".0f") return RT_String("%02d%s%02d%s%02d%s%0*d",hh,ch,mm,ch,ss,ch,digits,ff) }
__________________
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; 26th August 2021 at 21:33. Reason: Update |
22nd August 2021, 07:18 | #3 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Post #3 of 6
Initial detector script, Code:
# DetSub_MaskClip.avs /* Function Prototype: DetSub_MaskClip(clip c,Int "X"=-10,Int "Y"=Height-120,Int "W"=-X,Int "H"=-8, \ Int "Text_w"=4,Int "Text_h"=4,Int "TextCol"=$FFFFFF,Int "TextTol"=$0F0F0F,Int "TextTolT"=0, \ Int "Halo_L"=3,Int "Halo_T"=3,Int "Halo_R"=3,Int "Halo_B"=3,Int "HaloCol"=$000000,Int "HaloTol"=$0F0F0F,Int "HaloTolT"=0, \ Int "ClipIx"=-1,string "Matrix"="rec601",string "Override"="",String "FrameDB"="",Bool "DB_ReUse"=False) Args:- X,Y,W,H, [defaults X=-10, Y=Height-120, W=-X. H=-8]. Coords to search for subtitles, subtitle Detect Area. Text_W, default 4, Width of text verticals. Text_H, default 4, Height of text horizontals. TextCol, default $FFFFFF, Color of Subtitle Text in RGB. TextTol, default $0F0F0F, RGB per channel tolerance for text. TextTolT, default 0, Addtional text tolerance tweaker. Added to each of the TextTol R, G, or B channel tolerances. [+/-] Halo_L, default 3, Width of Left halo verticals. Halo_T, default 3, Height of Top halo horizontals. Halo_R, default 3, Width of Right halo verticals. Halo_B, default 3, Height of Bottom halo horizontals. HaloCol, default $000000, Color of Subtitle Halo in RGB. HaloTol, default $0F0F0F, RGB per channel tolerance for Halo. HaloTolT, default 0, Addtional Halo tolerance tweaker. Added to each of the HaloTol R, G, or B channel tolerances. [+/-] ClipIx, Default -1 [SubsArea, full detect info clip]. Selects [and returns] from 16 subtitle masks, -1 -> 14. -1) = Full detect Info clip, same width as input clip with all Masks stacked vertically [color/tolerance tweaking]. 0->14) = Other mask clip, dimensions X,Y,W,H. ClipIx select which sub clip to return, [DetSub, output always RGB32 with Alpha = known state $FF (opaque)] Use ClipX=-1, to aid in selecting coords, colors, and tolerances. Matrix, default "rec601", for src conversion to RGB32. Override, default "" [Not used]. Allows for ignoring ranges where subtitles detected but not existing. ""=Not used, "*..." multiline string of ranges, "OverRide.txt"=Text file of ranges. 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. """ FrameDB, default "". If "" then the detect subtitles per frame DBase is private, and deleted on Function Exit. If provided with a DBase filename, then DBase will be created and will be available to calling routine on return. FrameDB DBase Fields:- 0) Status, 0=Unknown (unvisited), 1=Sub, 2 Not sub, 3 User OverRide to NoSub 1) X # Coords relative the Subtitles X,Y,W,H Detect Area 2) Y 3) W 4) H DB_ReUse, default False. If True, AND FrameDB supplied, then will use the already created DBase [avoid recreation], otherwise creates new DBase new. */ Function DetSub_MaskClip(clip c,Int "X",Int "Y",Int "W",Int "H", \ Int "Text_w",Int "Text_h",Int "TextCol",Int "TextTol",Int "TextTolT", \ Int "Halo_L",Int "Halo_T",Int "Halo_R",Int "Halo_B",Int "HaloCol",Int "HaloTol",Int "HaloTolT", \ Int "ClipIx",string "Matrix",string "Override",String "FrameDB",Bool "DB_reUse") { myName="DetSub_MaskClip: " 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("mt_expand"),myName+"Essential MaskTools v2 plugin installed, http://forum.doom9.org/showthread.php?t=98985") Assert(RT_FunctionExist("RemoveGrain"),myName+"Essential RemoveGrain installed.") X=Default(X,10) Y=Default(Y,Height-120) W=Default(W,-X) 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) TextTol=Default(TextTol,$030303) TextTolT=Default(TextTolT,0) Halo_L=Default(Halo_L,3) Halo_T=Default(Halo_T,3) Halo_R=Default(Halo_R,3) Halo_B=Default(Halo_B,3) HaloCol=Default(HaloCol,$030303) HaloTol=Default(HaloTol,$030303) HaloTolT=Default(HaloTolT,0) Text_Tol_B=Min(Max(0,RT_BitAnd(TextTol,$FF)+TextTolT),255) TextTol=RT_BitLSR(TextTol,8) Text_Tol_G=Min(Max(0,RT_BitAnd(TextTol,$FF)+TextTolT),255) TextTol=RT_BitLSR(TextTol,8) Text_Tol_R=Min(Max(0,RT_BitAnd(TextTol,$FF)+TextTolT),255) Halo_Tol_B=Min(Max(0,RT_BitAnd(HaloTol,$FF)+HaloTolT),255) HaloTol=RT_BitLSR(HaloTol,8) Halo_Tol_G=Min(Max(0,RT_BitAnd(HaloTol,$FF)+HaloTolT),255) HaloTol=RT_BitLSR(HaloTol,8) Halo_Tol_R=Min(Max(0,RT_BitAnd(HaloTol,$FF)+HaloTolT),255) ClipIx = Default(ClipIx,-1) Assert(-1 <= ClipIx <=14,MyName+"-1 <= ClipIx <=14") Matrix = Default(Matrix,"Rec601") Override=Default(OverRide,"") FrameDB=Default(FrameDB,"") UserDB=(FrameDB!="") FrameDB=(!UserDB) ? "~DetSub_Mask_FrameDB_"+RT_LocalTimeString+".DB" : FrameDB FrameDB=RT_GetFullPathName(FrameDB) DB_ReUse = (UserDB) ? Default(DB_ReUse,False) : False HasCallCmd = RT_FunctionExist("CallCmd") ### # Mt_Hysteresis (reduce stray pixels):- http://forum.doom9.org/showthread.php?p=1780589#post1780589 # Text Mask Mt_Hysteresis inpand count (prior to mt_hysteresis), Dont Mt_Hysteresis if 0 THYSCNT = Min(TEXT_W,TEXT_H)/2 - 1 # Halo Mask Mt_Hysteresis inpand count (prior to mt_hysteresis), Dont Mt_Hysteresis if 0 HHYSCNT = Min(HALO_L,HALO_R,HALO_T,HALO_B)/2 - 1 # Detect clip Mt_Hysteresis inpand count (prior to mt_hysteresis), Dont Mt_Hysteresis if 0 DHYSCNT = Min(TEXT_W+HALO_L+HALO_R,TEXT_H+HALO_T+HALO_B)/2 - 1 ###### Subs detect position 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). ### VW=Width VH=Height /* DBase Fields 0) Status, 0=Unknown (unvisited), 1=Sub, 2 Not sub, 3 User OverRide 1) X # Coords relative the Subtitles X,Y,W,H Detect Area 2) Y 3) W 4) H */ if(!DB_ReUse) { RT_DBaseAlloc(FrameDB,FrameCount,"iiiii") RT_DBaseSetID(FrameDB,0,c.FrameCount,c.FrameRate,VW,VH,X,Y,W,H) if(OverRide!="") {DetSet_Override(Override,FrameDB)} } FullWidSubC=ConvertToRGB32(matrix=Matrix).crop(0,Y,0,H) # Full width Subs area Area=FullWidSubC.Crop(X,0,W,0).ResetMask # Valid Subs Area only, Reset Alpha to White Text1=Area.ColorKeyMask(TextCol,Text_Tol_R,Text_Tol_G,Text_Tol_B).ShowAlpha(Pixel_Type="Y8") # Set TextCol in range pixels to black Halo1=Area.ColorKeyMask(HaloCol,Halo_Tol_R,Halo_Tol_G,Halo_Tol_B).ShowAlpha(Pixel_Type="Y8") # Set HaloCol in range pixels to black Text1=Text1.Invert # Text In-range pixels white, else black Halo1=Halo1.Invert # Halo In-range pixels white, else black Text2 = Text1.RemoveGrain(2).RemoveGrain(1) Halo2 = Halo1.RemoveGrain(2).RemoveGrain(1) Text3 = Text2 # Swell Text by Halo thickness [Including Halo Drop Shadow] 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) {Text3=Text3.Mt_Expand(mode="square") } else { if(HorFlg==3) {Text3=Text3.Mt_Expand(mode="horizontal") HorFlg=0} else if(VerFlg==3) {Text3=Text3.Mt_Expand(mode="vertical") VerFlg=0} if(HorFlg!=0) {Text3=Text3.Mt_Expand(mode=HorFlg==1? " 1 0 0 0" : " -1 0 0 0")} # ? Expand_Left : Expand_Right if(VerFlg!=0) {Text3=Text3.Mt_Expand(mode=VerFlg==1? " 0 1 0 0" : " 0 -1 0 0")} # ? Expand_Up : Expand_Down } } Text4=Text2 Text5=Text3 # reduce Text strays a little if(THysCNT>0) { For(i=1,THysCNT) {Text4=Text4.MT_Inpand(mode="both")} Text5=Text4.MT_Hysteresis(Text3) } Halo3 = Halo2 # Swell/close Halo by Text thickness 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) {Halo3=Halo3.Mt_Expand(mode="square") } else { if(HorFlg!=0) {Halo3=Halo3.Mt_Expand(mode="horizontal") } if(VerFlg!=0) {Halo3=Halo3.Mt_Expand(mode="vertical") } } } Halo3=Halo3.RemoveGrain(1) # contract again, we dont want halo outside of real halo for(i=1,TEXT_MAX) { HorFlg=(i<=TEXT_W?1:0) VerFlg=(i<=TEXT_H?1:0) if(HorFlg+VerFlg==2) {Halo3=Halo3.Mt_Inpand(mode="square") } else { if(HorFlg!=0) {Halo3=Halo3.Mt_Inpand(mode="horizontal") } if(VerFlg!=0) {Halo3=Halo3.Mt_Inpand(mode="vertical") } } } Halo4=Halo2 Halo5=Halo3 # reduce Halo strays a little if(HHysCNT>0) { For(i=1,HHysCNT) {Halo4=Halo4.MT_Inpand(mode="both")} Halo5=Halo4.MT_Hysteresis(Halo3) } Detect1=Mt_Logic(Text5,Halo5,"and") Detect2=Detect1 Detect3=Detect2 Ocr1=Text2 if(DHysCNT>0) { For(i=1,DHysCNT) {Detect2=Detect2.MT_Inpand(mode="both")} Detect3=Detect2.MT_Hysteresis(Detect1) Ocr1=Detect2.MT_Hysteresis(Mt_Logic(Text2,Detect3,"and")) } Grn=Detect3.BlankClip(Pixel_Type="RGB32",color=$00FF00) Ocr2=Grn.Overlay(Grn.BlankClip(color=$000000),Mask=Detect3.RemoveGrain(2)).Overlay(Ocr1,Mask=Ocr1) SSS1=""" n = current_frame Status = RT_DBaseGetField(FrameDB,n,0) if(Status==0) { # Unknown Status Status = (Detect3.RT_YInRangeLocate(Baffle_w=Baffle_w,Baffle_h=Baffle_h,lo=255,hi=255,Thresh_w=Thresh_w,Thresh_h=Thresh_h,ReScan=ReScan)) ? 1 : 2 if(Status==1) { RT_DBaseSet(FrameDB,n,Status,YIRL_X,YIRL_Y,YIRL_W,YIRL_H) } else { RT_DBaseSetField(FrameDB,n,0,Status) } } if(Status==1 && ClipIx<0) { # Overlay Detected area in purple, only for ClipIx -1 SUB_X = RT_DBaseGetField(FrameDB,n,1) SUB_Y = RT_DBaseGetField(FrameDB,n,2) SUB_W = RT_DBaseGetField(FrameDB,n,3) SUB_H = RT_DBaseGetField(FrameDB,n,4) OverLay(Last.BlankClip(color=$FF00FF,width=SUB_W,height=SUB_H),x=X+SUB_X,y=SUB_Y,opacity=0.25) } Return Last """ if(ClipIx<0) { FullWidSubC=FullWidSubC.GScriptClip(SSS1, local=true, args="Detect3,FrameDB,Baffle_w,Baffle_h,Thresh_w,Thresh_h,ReScan,X,ClipIx",after_frame=true) Mrk=FullWidSubC.BlankClip(Length=1,Width=W,Height=H,Color=$FFFF0000) Msk=Hit_Marker(W,H,True,8,8,1,1) FullWidSubC=FullWidSubC.Overlay(Mrk,Mask=Msk,x=X,y=0,Opacity=0.5) FullWidSubC=FullWidSubC.AddBorders(0,22,0,0,$F0F080).Subtitle("Full Width Source (Search area in Red, detected subs in purple)",y=2) Ocr2_T=Ocr2.AddBorders(X,0,Width-X-W,0,$00FF00).AddBorders(0,22,0,0,$F0F080).Subtitle("0] OCR2 : [GreenC.Overlay(Blackness.Mask=Detect3.RemoveGrain(2)).Overlay(Ocr1,Mask=Ocr1)]",y=2) Ocr1_T=Ocr1.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle("1] OCR1 : [Detect2.MT_Hysteresis(Mt_Logic(Text2,Detect3,'and'))]",y=2) Detect3_T=Detect3.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle("2] Detect3 : [Detect2.MT_Hysteresis(Detect1), reduce stray pixels]",y=2) Detect2_T=Detect2.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle(RT_String("3] Detect2 : [Detect1 Inpand by DHysCNT(%d))]",DHysCNT),y=2) Detect1_T=Detect1.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle("4] Detect1 : Text5 AND Halo5",y=2) Text5_T=Text5.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle("5] Text5 : [Text4.MT_Hysteresis(Text3), reduce stray pixels]",y=2) Text4_T=Text4.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle(RT_String("6] Text4 : [Text2 Inpand by THysCNT(%d)]",THysCNT),y=2) Text3_T=Text3.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle(RT_String("7] Text3 : [Swell Text2 by Halo thickness(%d,%d,%d,%d)]",HALO_L,HALO_T,HALO_R,HALO_B),y=2) Text2_T=Text2.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle("8] Text2 : [UnDot, Text1.RemoveGrain(2).RemoveGrain(1)]",y=2) Text1_T=Text1.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle("9] Text1 : [TextInRange via TEXTCOL & TEXTTOL]",y=2) Halo5_T=Halo5.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle("10] Halo5 : [Halo4.MT_Hysteresis(Halo3), reduce stray pixels]",y=2) Halo4_T=Halo4.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle(RT_string("11] Halo4 : [Halo2 Inpand by HHysCNT(%d)]",HHysCNT),y=2) Halo3_T=Halo3.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle(RT_String("12] Halo3 : [Close Halo2, Expand.RemoveGrain(1).Inpand by Text thickness(%d,%d))]",TEXT_W,TEXT_H),y=2) Halo2_T=Halo2.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle("13] Halo2 : [UnDot, Halo1.RemoveGrain(2).RemoveGrain(1)]",y=2) Halo1_T=Halo1.ConvertToRGB32.AddBorders(X,0,Width-X-W,0,$000000).AddBorders(0,22,0,0,$F0F080).Subtitle("14] Halo1 : [HaloInRange via HALOCOL & HALOTOL]",y=2) StackVertical(FullWidSubC,Ocr2_T,Ocr1_T,Detect3_T,Detect2_T,Detect1_T,Text5_T,Text4_T,Text3_T,Text2_T,Text1_T,Halo5_T,Halo4_T,Halo3_T,Halo2_T,Halo1_T) } else { ClipIx==0?Ocr2:ClipIx==1?Ocr1:ClipIx==2?Detect3:ClipIx==3?Detect2:ClipIx==4?Detect1:ClipIx==5?Text5:ClipIx==6?Text4: \ ClipIx==7?Text3:ClipIx==8?Text2:ClipIx==9?Text1:ClipIx==10?Halo5:ClipIx==11?Halo4:ClipIx==12?Halo3:ClipIx==13?Halo2:Halo1 Last.GScriptClip(SSS1, local=true, args="Detect3,FrameDB,Baffle_w,Baffle_h,Thresh_w,Thresh_h,ReScan,X,ClipIx",after_frame=true) } (!UserDB && HasCallCmd)?CallCmd(close=RT_String("""CMD /C chcp 1252 && del "%s" """,FrameDB), hide=true, Synchronous=7):NOP # Auto delete non-User DB file on clip closure. Return ConvertToRGB32(Matrix="PC601").ResetMask # Alpha = $FF }
__________________
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; 26th August 2021 at 21:34. Reason: Update |
22nd August 2021, 07:19 | #4 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Post #4 of 6
Client To view all masks and results Code:
# DetSub_MaskClip_Client.avs Import(".\DetSub_Sundry.avs") Import(".\DetSub_MaskClip.avs") Import(".\DetSub_Args.avs") ############################ ORG=Last ClipIx = -1 # Full metrics clip FRAMEDB = Undefined # We dont need it in this script, will auto delete itself [is defined in DetSub_Args.avs] DetSub_MaskClip(x=X,y=Y,w=W,h=H, \ Text_w=TEXT_W,Text_h=TEXT_H,TextCol=TEXTCOL,TextTol=TEXTTOL,TextTolT=TextTolT, \ Halo_L=HALO_L,Halo_T=HALO_T,Halo_R=HALO_R,Halo_B=HALO_B,HaloCol=HALOCOL,HaloTol=HALOTOL,HaloTolT=HaloTolT, \ clipIx=ClipIx,Matrix=MATRIX,Override=Override,framedb=FRAMEDB) 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 ??? Last edited by StainlessS; 26th August 2021 at 21:34. Reason: Update |
22nd August 2021, 07:21 | #5 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Post 5 of 6
extract subs images to IMAGE directory [Must Exist]. Code:
# DetSub_Extract.avs /* DetSub_Extract(), extracts subtitle images from video clip. Function Prototype: DetSub_Extract(clip c,Int "X"=-10,Int "Y"=Height-120,Int "W"=-X,Int "H"=-8, \ Int "Text_w"=4,Int "Text_h"=4,Int "TextCol"=$FFFFFF,Int "TextTol"=$0F0F0F,Int "TextTolT"=0, \ Int "Halo_L"=3,Int "Halo_T"=3,Int "Halo_R"=3,Int "Halo_B"=3,Int "HaloCol"=$000000,Int "HaloTol"=$0F0F0F,Int "HaloTolT"=0, \ Int "ClipIx"=1,string "Matrix"="rec601",string "Override"="",String "RangeDB"="" \ ) Args:- X,Y,W,H, [defaults X=-10, Y=Height-120, W=-X. H=-8]. Coords to search for subtitles, subtitle Detect Area. Text_W, default 4, Width of text verticals. Text_H, default 4, Height of text horizontals. TextCol, default $FFFFFF, Color of Subtitle Text in RGB. TextTol, default $0F0F0F, RGB per channel tolerance for text. TextTolT, default 0, Addtional text tolerance tweaker. Added to each of the TextTol R, G, or B channel tolerances. [+/-] Halo_L, default 3, Width of Left halo verticals. Halo_T, default 3, Height of Top halo horizontals. Halo_R, default 3, Width of Right halo verticals. Halo_B, default 3, Height of Bottom halo horizontals. HaloCol, default $000000, Color of Subtitle Halo in RGB. HaloTol, default $0F0F0F, RGB per channel tolerance for Halo. HaloTolT, default 0, Addtional Halo tolerance tweaker. Added to each of the HaloTol R, G, or B channel tolerances. [+/-] ClipIx, Default 1, OCR1 [Selects mask for output, 0 -> 2 ONLY. Mask clip, dimensions X,Y,W,H. ClipIx selects which subs images to extract as images to ImageDir. 0 = OCR2, Green background multi-mask with text in white, halo in black and other guys in green. 1 = OCR1, Text in White. 2 = Detect3, Text + Halo in White. Matrix, default "rec601", for src conversion to RGB32. Override, default "" [Not used]. Allows for ignoring ranges where subtitles detected but not existing. ""=Not used, "*..." multiline string of ranges, "OverRide.txt"=Text file of ranges. 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. """ RangeDB, default "". If "" then the subtitles ranges DBase is private, and deleted on Function Exit. If provided with a DBase filename, then DBase will be created and will be available to calling routine on return. RangeDB DBase Fields:- 0) Start frame of subtitle for current record subtitle range. 1) End frame of subtitle for current record subtitle range. ImageDir, Default "", ie invalid. MUST be set to existing directory, ".\" is current directory. Directory whe output images are to be written. CorrTh, default 0.5, [range 0.45 -> 0.55]. Correlations threshold to detect where subtitles in adjacent frames are the same, used to detect where to split apart non similar subs. Probably not need change. Ocr1AveTh, default 254. [0 -> 254]. Applied to binarize ClipIx==1 OCR1 mask, ie text. Threshold applied after average/blending all SubsArea regions of a subtitle. 0, If any pre-average pixel is above 0, then result is 255(white). [ AvgAll2.mt_binarize(threshold=0) ] 254, If ALL pre-average pixels are above 254, then result is 255(white). [ AvgAll2.mt_binarize(threshold=254) ] or 1 -> 253, somewhere between. [the pre-average pixels are always either 0 or 255]. Det3AveTh, default 254. [0 -> 254]. Applied to binarize ClipIx==2 Detect3 mask, ie Holo+Text combined. Threshold applied after average/blending all SubsArea regions of a subtitle. 0, If any pre-average pixel is above 0, then result is 255(white). [ AvgAll2.mt_binarize(threshold=0) ] 254, If ALL pre-average pixels are above 254, then result is 255(white). [ AvgAll2.mt_binarize(threshold=254) ] or 1 -> 253, somewhere between. [the pre-average pixels are always either 0 or 255]. Where ClipIx==0, ie the OCR2 green Multi-Mask, Det3AveTh is using in binarizing the black Text+Halo combined area and the Ocr1AveTh used on the foreground white Text only area. ExpandCnt, Default 0, [0 -> 16, silent limit at 16]. There should be enough clear area around detected subs in SubsArea to Expand. ClipIx 1, ie OCR1, applies to OCR1 Text. Eg, c.mt_Expand(mode=mt_circle(ExpandCnt) ClipIx 2, ie Detect3, applies to Detect3 Text+halo combined mask. ClipIx 0, ie OCR2, applied first to Text+halo combined black mask, and then to OCR1 Text white mask. ImgType, Default, "bmp". ["bmp", "png", "tif", "tiff"]. Select Image type to write. Smpte, Default false. False outputs style "SUB_000000.BMP". where 000000 is first subtitle group range in clip. [record 0 if DBase returned] True outputs SMPTE style filenames with start and end times, eg 00_01_03_013__00_01_06_010.png */ Function DetSub_Extract(clip c,Int "X",Int "Y",Int "W",Int "H", \ Int "Text_w",Int "Text_h",Int "TextCol",Int "TextTol",Int "TextTolT", \ Int "Halo_L",Int "Halo_T",Int "Halo_R",Int "Halo_B",Int "HaloCol",Int "HaloTol",Int "HaloTolT", \ Int "ClipIx",string "Matrix",string "Override",String "RangeDB",String "ImageDir",Float "CorrTh", \ Int "Ocr1AveTh",Int "Det3AveTh",int "ExpandCnt", \ String "ImgType",Bool "Smpte" \ ) { myName="DetSub_Extract: " c IsPlus=FindStr(VersionString,"AviSynth+")!=0 HasCallCmd = RT_FunctionExist("CallCmd") 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("mt_expand"),myName+"Essential MaskTools v2 plugin installed, http://forum.doom9.org/showthread.php?t=98985") Assert(RT_FunctionExist("RemoveGrain"),myName+"Essential RemoveGrain installed.") X=Default(X,10) Y=Default(Y,Height-120) W=Default(W,-X) H=Default(H,-8) W=(W<=0)?Width-X+W:W H=(H<=0)?Height-Y+H:H ClipIx = Default(ClipIx,1) # Default OCR1 Assert(0 <= ClipIx <=2 ,MyName+"0 <= ClipIx <= 2") Matrix = Default(Matrix,"Rec601") Override=Default(OverRide,"") RangeDB=Default(RangeDB,"") UserDB=(RangeDB!="") RangeDB=(!UserDB) ? "~DetSub_Extract_RangeDB_"+RT_LocalTimeString+".DB" : RangeDB RangeDB=RT_GetFullPathName(RangeDB) ImageDir = Default(ImageDir,"") # ImageDir for Images # Must Exist Assert(ImageDir!="",myName+"ImageDir Cannot be '', and must Exist."+Chr(10)+"Can use '.\' for current directory") ImageDir=RT_GetFullPathname(ImageDir) ImageDir=ImageDir.RevStr while(ImageDir.FindStr("\")==1 || ImageDir.FindStr("/")==1) { ImageDir=ImageDir.MidStr(2)} ImageDir=ImageDir.RevStr RT_DebugF("ImageDir=%s",ImageDir) Assert(ImageDir.Exist,myName+"ImageDir Does not exist") CorrTh = Default(CorrTh,0.5) # About 0.45 -> 0.55 [detect same subtile with/without crud] Ocr1AveTh = Max(Min(Default(Ocr1AveTh,254),254),0) Det3AveTh = Max(Min(Default(Det3AveTh,254),254),0) # ExpandCnt = Min(Max(((ClipIx>0) ? Default(ExpandCnt,0) : 0),0),16) ExpandCnt = Min(Max(Default(ExpandCnt,0),0),16) ImgType = Default(ImgType,"bmp") SMPTE = Default(SMPTE,false) Assert(imgtype=="bmp"||imgtype=="png"||imgtype=="tiff"||imgtype=="tif",myName+"ImgType only 'bmp', 'png', 'tiff' or 'tif'") Assert(RangeDB !="",myName+"RangeDB Cannot be ''") FrameDB= ("~DetSub_Extract_FrameDB_"+RT_LocalTimeString+".DB").RT_GetFullPathName OCR2 = DetSub_MaskClip(x=X,y=Y,w=W,h=H, \ Text_w=TEXT_W,Text_h=TEXT_H,TextCol=TEXTCOL,TextTol=TEXTTOL,TextTolT=TextTolT, \ Halo_L=HALO_L,Halo_T=HALO_T,Halo_R=HALO_R,Halo_B=HALO_B,HaloCol=HALOCOL,HaloTol=HALOTOL,HaloTolT=HALOTOLT, \ clipIx=0,Matrix=MATRIX,Override=Override,framedb=FrameDB) OCR2.RT_ForceProcess SubsFrameCnt = RT_DBaseRecords(FrameDB) # Number of possibly nopn separated Subs RT_DebugF("Detected Subtitle Frames=%d",SubsFrameCnt,name="DetSub_Extract: ") RT_DBaseAlloc(RangeDB,0,"ii") # fields, 0=StartFrameNo, 1=EndFrameNo MultiSubCnt=0 SplitCnt=0 MultiSubStart=-1 # Not currently within Subtitle range FC=FrameCount OCR1=OCR2.ShowRed(Pixel_Type="Y8") # White Text from red Channel RT_DebugF("Splitting contiguous subs",name="DetSub_Extract::SplitSub: ") for(n=0,FC) { # Scan & split Subtitle ranges [might not have clean frames between them] Status = (n>=FC) ? 0 : RT_DBaseGetField(FrameDB,n,0) Close = (MultiSubStart>=0 && Status!=1) # If we were scanning subs sequence but this one is invalid, then we will close. if(Status == 1) { # Valid Subtitle Frame ? if(MultiSubStart<0) { # n new MultiSub : New start of possibly non-separated sub MultiSubCnt=MultiSubCnt+1 # NEW possibly non contiguous subs sequence MultiSubStart=n S_X1 = RT_DBaseGetField(FrameDB,MultiSubStart,1) # Subs Detected area for start Frame S_Y1 = RT_DBaseGetField(FrameDB,MultiSubStart,2) S_X2 = S_X1 + RT_DBaseGetField(FrameDB,MultiSubStart,3) # X + W S_Y2 = S_Y1 + RT_DBaseGetField(FrameDB,MultiSubStart,4) # Y + H } else { # already inside MultiSub sequence R_X1 = RT_DBaseGetField(FrameDB,n,1) # Coords of current Subs frame R_Y1 = RT_DBaseGetField(FrameDB,n,2) R_X2 = R_X1 + RT_DBaseGetField(FrameDB,n,3) R_Y2 = R_Y1 + RT_DBaseGetField(FrameDB,n,4) U_X1 = min(S_X1,R_X1) # Union of both sets of Coords U_Y1 = min(S_Y1,R_Y1) U_X2 = max(S_X2,R_X2) U_Y2 = max(S_Y2,R_Y2) Corr=RT_LumaCorrelation(OCR1,OCR1,n=MultiSubStart,n2=n,x=U_X1,y=U_Y1,w=U_X2-U_X1,h=U_Y2-U_Y1) Close = (Corr<CorrTh) if(Close) { SplitCnt=SplitCnt+1 RT_DebugF("%d] SPLIT multi-subtitle, MultiSubCnt=%d SplitSubCnt=%d Corr=%.3f",n,MultiSubCnt,MultiSubCnt+SplitCnt,Corr,name="DetSub_Extract::SplitSub: ") } } } if(Close) { # We were scanning sequence and either, this frame is not sub OR sub split found. RT_DBaseAppend(RangeDB,MultiSubStart,n-1) # n is start of next new or split sequence or end of clip MultiSubStart = (Status==1 && n<FC) ? n : -1 if(MultiSubStart>=0) { # Closure was due to Sub Split, get new split START coords S_X1 = RT_DBaseGetField(FrameDB,MultiSubStart,1) # Subs Detected area for start Frame S_Y1 = RT_DBaseGetField(FrameDB,MultiSubStart,2) S_X2 = S_X1 + RT_DBaseGetField(FrameDB,MultiSubStart,3) # X + W S_Y2 = S_Y1 + RT_DBaseGetField(FrameDB,MultiSubStart,4) # Y + H } } } NSubs = RT_DBaseRecords(RangeDB) # Number of SEPARATE INDIVIDUAL Subtitles RT_DebugF("Contiguous Subs sequences=%d, Total split subtitles=%d",MultiSubCnt,NSubs,name="DetSub_Extract::SplitSub: ") RangeFile=".\SubRanges.txt".RT_GetFullPathName RT_FileDelete(RangeFile) Grn=OCR2.BlankClip(Length=1,Pixel_Type="RGB32",color=$00FF00) Blk=Grn.BlankClip(color=$000000) DET3 = mt_logic(OCR2.ShowRed(pixel_type="Y8"),OCR2.ShowGreen(pixel_type="Y8").Invert,"or") RT_DebugF("Writing %d %s images",NSubs,Select(ClipIx,"OCR2","OCR1","DET3"),name="DetSub_Extract: ") RT_DebugF("ExpandCnt=%d",ExpandCnt) fps=c.FrameRate for(i=0,NSubs-1) { S=RT_DBaseGetField(RangeDB,i,0) E=RT_DBaseGetField(RangeDB,i,1) RT_DebugF("Writing ... Subtitle %d, from range(%d,%d)",i,S,E) RT_WriteFile(RangeFile,"%d,%d # %d",S,E,i,Append=true) if(ClipIx==1) { # OCR1 T = OCR1.Trim(S,E).DetSub_AvgAll(Th=Ocr1AveTh,ExpandCnt=ExpandCnt) } else if(ClipIx==2) { # DET3 T = DET3.Trim(S,E).DetSub_AvgAll(Th=Ocr1AveTh,ExpandCnt=ExpandCnt) } else { # OCR2 T1 = OCR1.Trim(S,E).DetSub_AvgAll(Th=Ocr1AveTh,ExpandCnt=ExpandCnt) T2 = DET3.Trim(S,E).DetSub_AvgAll(Th=Det3AveTh,ExpandCnt=ExpandCnt) T=Grn.Overlay(Blk,Mask=T2).Overlay(T1,Mask=T1) } if(SMPTE) { FNam=Frame2SMPTE(S,fps,3,true) +"__" + Frame2SMPTE(E,fps,3,true) T.ImageWriter(ImageDir+"\"+FNam+"%.0d.%s",0,-1,ImgType).RT_YankChain(n=0) # Force Write image } else { T.Loop.ImageWriter(ImageDir+"\SUBS_%06d"+"."+Imgtype, i, i,ImgType).RT_YankChain(n=i) # Force Write image } } RT_FileDelete(FrameDB) (!UserDB)?RT_FileDelete(RangeDB):NOP return Messageclip(RT_String("%s %d Subtitle Images written.",myName,NSubs)) }
__________________
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; 26th August 2021 at 21:34. Reason: Update |
22nd August 2021, 07:26 | #6 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Post #6 of 6.
And the extractor client Code:
# DetSub_Extract_Client.avs Import(".\DetSub_Args.avs") Import(".\DetSub_Sundry.avs") Import(".\DetSub_MaskClip.avs") Import(".\DetSub_Extract.avs") ############################ ORG=Last ClipIx = 1 # Default 1, OCR1 ie text. [0 -> 2 ONLY, 0 OCR2 [green background], 1=Text, 2=Detect3=Text+Halo combined white mask] #RangeDB = ".\MyRange.DB".RT_GetFullPathName # Returns DBase with 2 fields, start and end of individual [separated] subtitle range. RangeDB = UnDefined # Dont Make DBase [deleted after use] ImageDir = ".\IMAGE"# MUST Exist. Output Images written here. CorrTh = 0.5 # Correlation Threshold, maybe about 0.45 -> 0.55 : used in separating subs without a clear nonsub frame separator Ocr1AveTh = 254 # Default 254 [0->254]. Applied to white mask pixels of all ClipIx [0,1,2] # 0=Result pixel white if any single pixel in range is white. 254=result white only if ALL pixels in range are white. Det3AveTh = 254 # Default 254 [0->254]. Applied to Black mask pixels of only ClipIx 2 [OCR2] ExpandCnt = 0 # Default 0, Ignored for ClipIx==0. Expands only OCR1(text) or Detect3(text+halo). [Limited @ max 16] Imgtype = "png" # Write BMP images. [BMP', "PNG", "TIFF", or "TIF" only] SMPTE = True # SMPTE Time Format DetSub_Extract(x=X,y=Y,w=W,h=H, \ Text_w=Text_W,Text_h=Text_h,TextCol=TextCol,TextTol=TextTol,TextTolT=TextTolT, \ Halo_L=Halo_L,Halo_T=Halo_T,Halo_R=Halo_R,Halo_B=Halo_B,HaloCol=HaloCol,HaloTol=HaloTol,HaloTolT=HaloTolT, \ ClipIx=ClipIx,Matrix=Matrix,Override=Override,RangeDB=RangeDB,ImageDir=ImageDir,CorrTh=CorrTh, \ Ocr1AveTh=Ocr1AveTh,Det3AveTh=Det3AveTh,ExpandCnt=ExpandCnt, \ Imgtype=ImgType, smpte=SMPTE \) return last /* Ocr1AveTh, default 254. [0 -> 254]. Applied to binarize ClipIx==1 OCR1 mask, ie text. Threshold applied after average/blending all SubsArea regions of a subtitle. 0, If any pre-average pixel is above 0, then result is 255(white). [ AvgAll2.mt_binarize(threshold=0) ] 254, If ALL pre-average pixels are above 254, then result is 255(white). [ AvgAll2.mt_binarize(threshold=254) ] or 1 -> 253, somewhere between. [the pre-average pixels are always either 0 or 255]. Det3AveTh, default 254. [0 -> 254]. Applied to binarize ClipIx==2 Detect3 mask, ie Holo+Text combined. Threshold applied after average/blending all SubsArea regions of a subtitle. 0, If any pre-average pixel is above 0, then result is 255(white). [ AvgAll2.mt_binarize(threshold=0) ] 254, If ALL pre-average pixels are above 254, then result is 255(white). [ AvgAll2.mt_binarize(threshold=254) ] or 1 -> 253, somewhere between. [the pre-average pixels are always either 0 or 255]. Where ClipIx==0, ie the OCR2 green Multi-Mask, Det3AveTh is used in binarizing the black Text+Halo combined area and the Ocr1AveTh used on the foreground white Text only area. ExpandCnt, Default 0, [0 -> 16, silent limit at 16]. There should be enough clear area around detected subs in SubsArea to Expand. ClipIx 1, ie OCR1, applies to OCR1 Text. Eg, c.mt_Expand(mode=mt_circle(ExpandCnt) ClipIx 2, ie Detect3, applies to Detect3 Text+halo combined mask. ClipIx 0, ie OCR2, applied first to Text+halo combined black mask, and then to OCR1 Text white mask. ImgType, Default, "bmp". ["bmp", "png", "tif", "tiff"]. Select Image type to write. Smpte, Default false. False outputs style "SUB_000000.BMP". where 000000 is first subtitle group range in clip. [record 0 if DBase returned] True outputs SMPTE style filenames with start and end times, eg 00_01_03_013__00_01_06_010.png */
__________________
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; 26th August 2021 at 21:34. Reason: Update |
22nd August 2021, 14:25 | #7 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Thanks, but you didn't say 'thanks'
__________________
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; 22nd August 2021 at 17:40. |
22nd August 2021, 17:30 | #8 | Link | |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Update to DetSub_Client_PASS2.avs
Moved EDITS from post #5 to here 59 separated subs detected [correct with given sample, about 32 without clear nonsub frame separator] but I think about 10 of them have edge crud [stuck for ideas on that]. Good subtitle [well just the first one, other good similar-ish] Worst subtitle crud. Edge crud images not too difficult to fix in paint package, flood fill crud with black, a few seconds of effort per sub. EDIT: @VX Your AvgAll2() thingy reduced the below image crud to above. And this to Bottom two images, the 'f' of "facilitator" is slimmed down in fixed version, do you have a similar routine to produce the greatest amount of white [rather than least], using that Hysterisis whosit, could fix the slimming effect of AvgAll2(). EDIT: I guess that change to mt_binarize(threshold=0) would probably do it. Using AvgAllMinMaxFix() instead of AvgAll() Code:
Function AvgAll2(clip c) { c.FrameCount() <= 1 ? c : Merge(AvgAll2(c.SelectEven()), AvgAll2(c.SelectOdd())) } #Function AvgAll(clip c) { c.AvgAll2().mt_binarize(threshold=254) } Function AvgAllMinMaxFix(clip c) { Ave = c.AvgAll2() thin = Ave.mt_binarize(threshold=254) Fat = Ave.mt_binarize(threshold=0) Return thin.MT_Hysteresis(fat) } image sharing Might change to using Clipblend instead of AvgAll2(). EDIT: @VX Quote:
EDIT: I presume that results with live video rather than anime will be somewhat better, less chance of edge crud. [due to less static nature of live video]
__________________
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; 22nd August 2021 at 18:48. |
|
22nd August 2021, 19:02 | #9 | Link |
Banana User
Join Date: Sep 2008
Posts: 983
|
I'm stuck trying to run your last script from my thread:
Code:
LWLibavVideoSource("D:\subs_anime.mkv") DetSub(Last, x="0",y="0",w="-0",h="-0", \ Text_w="3",Text_h="3",TextCol="$FCFCFC",TextTol="$030303", \ Halo_L="3",Halo_T="3",Halo_R="3",Halo_B="3",HaloCol="$102A37",HaloTol="$121212", \ backColor="$00FF00",ClipIx="0",Matrix="rec601",db="MyDBBB.DB",Override="") Code:
Script error: the named argument "x" to DetSub had the wrong type I've no idea how to do it. |
22nd August 2021, 19:17 | #10 | Link | |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
That looks like a function prototype [EDIT: ie args in double quotes signifies optional args with defaults], you seem to be calling function with eg X as string, it requires an int.
[not the coords themselves that are problem, you are using InPaintDeLogo style string coords]. (In fact you call with ALL string args) EDIT: Quote:
EDIT: Oh dear, I totally messed up the function prototype, by putting default in quotes rather than arg names, and did not notice the mistake as my brain stuck like it was when i did it [ *** SORRY *** ]. anyways, fixed the prototype in post#3, as here. [BackColor arg was dropped, now always Green $00FF00] Code:
function Prototype: DetSub(clip c,Int "X"=-10,Int "Y"=Height-120,Int "W"=-10,Int "H"=-8, \ Int "Text_w"=3,Int "Text_h"=3,Int "TextCol"=$FCFCFC,Int "TextTol"=$030303, \ Int "Halo_L"=3,Int "Halo_T"=3,Int "Halo_R"=3,Int "Halo_B"=3,Int "HaloCol"=$030303,Int "HaloTol"=$030303, \ Int "ClipIx"=0,string "Matrix"="rec601",string "Override"="",String "DB"="",Bool "DB_reUse"=False)
__________________
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; 22nd August 2021 at 20:09. |
|
22nd August 2021, 22:54 | #11 | Link |
Banana User
Join Date: Sep 2008
Posts: 983
|
My bad, after my post I noticed that you have updated the script there with the user part. I successfully run it and compared to the new InpaintDelogo version.
If there are persistent artifacts then "AvgAll2" wouldn't help much. PS Didn't had time to look at you new scripts, do you do range detection part employing stuff from previous subs detection or fresh detection from the mask? Last edited by VoodooFX; 22nd August 2021 at 23:00. |
22nd August 2021, 23:30 | #12 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Original DetSub() thing just detects if sub on individual frames, and writes DBase of detect coords [if detected].
DetSub_MakeRangesDB() thing, detects continuous frames where [not necessarily same] subs detected, and writes private DB of those ranges. [I think sample has 27 such ranges, and the DB 27 records, with only Start, End fields]. Then scans above mentioned ranges comparing adjacent frames, looking for subtitle change without intervening clear nosubs frame, and writes separated subs ranges to yet another DB. [in sample case DB has 59 records, ie 59 separated subs ranges] Then scans that last DB and picks out [trims] separated range and does the avgAll2() thing [actually as post #9 AvgAllMinMaxFix()] to average subs, and remove a bit of crud. Finally for each trimmed range average frame, writes a text file with ranges for each separated sub, and also writes BMP image for each, and then returns a clip with each frame the final detect cleaned up-ish sub, in sample case, 59 frames, ie 59 separated subs in sample. I'm changing the way it works to make the DetSub_MakeRangesDB() thing [under some other name, I usually use first name enters my head, and change later], be the 'master routine' which will call the current DetSub [soon named DetSub_Mask], and do the whole thing in single [internally multipass] script run. EDIT: A final detect stage might do some kind of detection of pixel fluxtuations, stationary-ish = GOOD subs+halos and other where coincide with detected subs/halos would be considered edge crud. Maybe AvsInPaint has such a pixel fluxtuation type function, which you use for InPaintDeLogo. Advantage to us would being able to apply that to already detected separated subs ranges.
__________________
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; 23rd August 2021 at 00:22. |
22nd August 2021, 23:54 | #13 | Link |
Banana User
Join Date: Sep 2008
Posts: 983
|
Nice!
Maybe it will help, from some old tools I remember that they were doing this kind of detection: Simplified logic: scan lines for white pixels, 2 most white lines should detect like the image above(discard line if it's too close), then ~half distance between 'red' lines extend to top and bottom. I'll look at my backup hdds' for those tools, maybe there are source codes. EDIT: Probably it helped to separate subs from artifacts, so it wont help for range detection as we supply a refined mask already. Last edited by VoodooFX; 22nd August 2021 at 23:59. |
23rd August 2021, 00:09 | #14 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Bottom and top of lower case [small] chars already considered, but complications of edge crud above same chars, and we dont know how many
lines of subs there will be, nor size of charcters, nor if all lower case, so I kind of forgot it altogether. [too many 'ifs' and 'buts'].
__________________
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 ??? |
23rd August 2021, 00:48 | #15 | Link | ||
Banana User
Join Date: Sep 2008
Posts: 983
|
Quote:
Quote:
"Edge crud" is a bad case and this sample is kinda synthetic... I'll check for some subs masks to do tests. EDIT: I've sent you PM with few masks. Last edited by VoodooFX; 23rd August 2021 at 01:26. |
||
23rd August 2021, 01:43 | #16 | Link | |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Got Masks thanks.
Quote:
also, I think some subs in our sample have subs on frame top too]. The DVD may have been season 1 "My Name Is Earl", where seems to have been translated into Chinese, and then from Chinese back to English, is quite hilarious in some places reading what it eventually returned as. The massively multi-line subs might have been Chinese language or other subs on that DVD [dont think was English subs]. [Seemed to be fair quality VHS cap [or TV station source], with HBO semi-transparent logo -Boxset does not look dodgy, but is a bit strange - not bought new] The DVD in question was seemingly of Chinese origin, Both English & Chinese on box cover [also think was NTSC]. I think I had heard long time ago that My Name Is Earl is/was hugely popular in China, one is curious as to why.
__________________
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; 23rd August 2021 at 02:00. |
|
23rd August 2021, 13:04 | #17 | Link |
Banana User
Join Date: Sep 2008
Posts: 983
|
That I would call intertitles.
Here are some subs tools with sources: AviSubDetector https://forum.doom9.org/showthread.php?t=89802 http://web.archive.org/web/200710311...ubdetector.htm I member it being good in comparisons to other tools at that time, I didn't managed to make it useful, maybe because I tried non anime stuff on it, when tool is aimed for anime. By "useful" I meant getting subs faster than just simply writing them down manually. SubLog Extractor (Vdub) https://www.softpedia.com/get/Multim...xtractor.shtml Don't remember about it, for some reason it's saved on my hdd. VideoSubFinder https://sourceforge.net/p/videosubfi...i/master/tree/ Still active dev and tool does decent job. From my tests: it can produce dozens of errors/artifacts if you let it do masks, lots of manual work to deal with them, could be fine-tuning problem on my side, so I simply supply my mask for it as video. Problem is that it tries to extract mask from my mask and sometimes damages some mask/subs lines, but its method to extract ranges is pretty good. EDIT: If "0_00_56_958__0_00_57_957.tiff" format is not possible/hard to do, there is option to nag SubtitleEdit's dev to support format like "000022__000374__23_976.tiff". Last edited by VoodooFX; 23rd August 2021 at 13:16. |
23rd August 2021, 15:17 | #18 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Thanks VX.
"0_00_56_958__0_00_57_957.tiff", Not really a problem. Why is tiff required, BMP not OK ? [compressed size ?] I think ImageWriter supports tiff, so could make optional. Found some dfferences between using AvgAll2() and the Hysterisis version and mod with ClipBlend instead of SelecteEven/Odd merge thingy. ClipBlend version can be worse results, I'm guessin' due to ClipBlend averaging and rounding only after all frames sampled [single rounding for entire range], whereas the merge thingy rounds with loss of precision at every recurse. Anyway, I'll have to extract the edge crud ranges and investigate exactly what is happening there. Maybe that average All whotsit dropped altogether if we instead scan trim/crop range of original source and somehow get flutuations for RGB pixels, [as we used tolerances in detecting halo/text], maybe fluctuating RGB is edge crud. EDIT: tolerances being somewhat spatial requirement, but fluctuations temporal. EDIT: 1st 2 links zips dead. EDITl: Oops, changed multiple "ClipClop"s to "ClipBlend"s.
__________________
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; 23rd August 2021 at 16:47. |
23rd August 2021, 19:24 | #19 | Link | ||
Banana User
Join Date: Sep 2008
Posts: 983
|
Quote:
Zips in the archived site works, need to wait some seconds when you press on download links there. Quote:
About temporal fluctuations: then why not take the mask from InpaintDelogo? I tried to employ RGB and YV12 colors in creating dynamic masks there, but it had small effect on reducing artifacts, could be that it didn't worked well with temporal stuff, or that clips were not anime, or I was doing it wrong, so I ditched that idea - and actually everything is done in greyscale there. Colored hardcoded subtitles are mostly a thing of the fansubs, I don't see point in dealing with such videos. I see that in your script color stuff works pretty well. I'm a bit worried about that "53" frames thingy slowing the script down. Edit: Nevermind, it won't have effect here. Edit2: I'm not sure... Last edited by VoodooFX; 27th August 2021 at 14:24. |
||
Thread Tools | Search this Thread |
Display Modes | |
|
|