Log in

View Full Version : Hardsub Removal using another source


blaze077
31st August 2016, 22:34
While I know that hardsub removal is probably a hard or impossible process to do, is it possible to remove hardsubs from the video considering you have another source without the hardsubs but with less quality than the one with the hardsubs?

I know that the best way is to use the source without hardsubs but I would just like to know. I'm not that experienced with Avisynth so can't seem to come up with anything but vague ideas. I am just taking plain white subs. Anything to get me started on would be great.

1. For removing hardsubs, first there would have to be masks. Can the formation of masks be done by finding the differences in both the videos or through something similar? Or maybe cropping to the area where the subtitles are, finding the whitest parts of the image and then comparing that to the other source?

2. Once the masks are made either manually or through a script, can one remove the subtitles by replacing the masked area with the same area from the other source? Afterwards, filtering can be applied to make it the replaced part seem natural with the video.

Thank you.

johnmeyer
31st August 2016, 22:55
I've actually done this, both to remove hard subs by using a lesser quality source that doesn't have subs, as well as adding subs from a lesser-quality source that has them. In both cases, I used my NLE (Sony Vegas). In that application, it is trivial:

1. You put each source on its own timeline, and line them up (sometimes there are extra scenes in one source, and sometimes the editing is a little different, so you have to do a quick scrub to make sure they are more or less lined up). If they aren't perfectly lined up, it won't matter too much.

2. Create a mask so that the sub area shows through.

3. Feather the mask.

4. Turn mask off during any long portions that don't have subs so you don't have a small, slightly fuzzy window in the sub area.

blaze077
1st September 2016, 21:53
I've actually done this, both to remove hard subs by using a lesser quality source that doesn't have subs, as well as adding subs from a lesser-quality source that has them. In both cases, I used my NLE (Sony Vegas). In that application, it is trivial:

1. You put each source on its own timeline, and line them up (sometimes there are extra scenes in one source, and sometimes the editing is a little different, so you have to do a quick scrub to make sure they are more or less lined up). If they aren't perfectly lined up, it won't matter too much.

2. Create a mask so that the sub area shows through.

3. Feather the mask.

4. Turn mask off during any long portions that don't have subs so you don't have a small, slightly fuzzy window in the sub area.

Any idea as to how to do it in Avisynth? I'm not that familiar with most video editing software and want to learn how to perform something like this in Avisynth for my own knowledge. :)

johnmeyer
1st September 2016, 22:16
In AVISynth you should search this forum for the "Overlay" function:

Overlay (http://avisynth.nl/index.php/Overlay)

"Puts clip overlay on top of clip base using different blend modes, and with optional x,y positioning, masking and opacity."

You would precede the call to Overlay with a Crop statement for the subtitle clip so that you only overlay the portion of the inferior clip that contains the subs.

I'm sure that if you search these forums for "overlay" and either "subs," "subtitles," or "logo" that you will find either an exact script, or at least enough code that you can do what you want by only altering a few lines. Since I haven't done it this way myself, I can't offer a working script.

blaze077
1st September 2016, 22:39
In AVISynth you should search this forum for the "Overlay" function:

Overlay (http://avisynth.nl/index.php/Overlay)

"Puts clip overlay on top of clip base using different blend modes, and with optional x,y positioning, masking and opacity."

You would precede the call to Overlay with a Crop statement for the subtitle clip so that you only overlay the portion of the inferior clip that contains the subs.

I'm sure that if you search these forums for "overlay" and either "subs," "subtitles," or "logo" that you will find either an exact script, or at least enough code that you can do what you want by only altering a few lines. Since I haven't done it this way myself, I can't offer a working script.

I have tried Overlay before and it works as it should which gives good results but I would like to compromise as little of the hardsubbed video as possible which is why I'm seeking an answer to Question 2 in my post. :)

Thank you.

johnmeyer
2nd September 2016, 02:25
I have tried Overlay before and it works as it should which gives good results but I would like to compromise as little of the hardsubbed video as possible which is
why I'm seeking an answer to Question 2 in my post. :)

"2. Once the masks are made either manually or through a script, can one remove the subtitles by replacing the masked area with the same area from the other source? Afterwards, filtering can be applied to make it the replaced part seem natural with the video."The answer to #2 is no. This is the answer because you said the other version of the video is lower quality. You cannot make lower quality video look like better quality video. There are about a thousand posts in this forum asking for someone to create software to do this impossible task, but so far the unicorn programmers have been unable to come up with a solution.

raffriff42
2nd September 2016, 04:16
For removing hardsubs, first there would have to be masks. Can the formation of masks be done by finding the differences in both the videos or through something similar?I was going to explain how easy it would be to do this, until I tried it, and realized that any tiny difference between the sources -- a frame out of sync, film transfer issues such as weave, color differences, dirt -- really destroys your difference mask. If the sources don't match very well indeed you could go crazy trying to fix all these little issues. Better to use a feathered box mask as johnmeyer suggests!

blaze077
3rd September 2016, 07:05
The answer to #2 is no. This is the answer because you said the other version of the video is lower quality. You cannot make lower quality video look like better quality video. There are about a thousand posts in this forum asking for someone to create software to do this impossible task, but so far the unicorn programmers have been unable to come up with a solution.

I was going to explain how easy it would be to do this, until I tried it, and realized that any tiny difference between the sources -- a frame out of sync, film transfer issues such as weave, color differences, dirt -- really destroys your difference mask. If the sources don't match very well indeed you could go crazy trying to fix all these little issues. Better to use a feathered box mask as johnmeyer suggests!

I see. I will have to do with Overlay for now then. I'll try and make some progress. Just to check, is this the method you were suggesting?

MPEG2Source("xxx")
noSubs = MPEG2Source("yyy")
removeSubs = noSubs.crop(300,580,644,90)
Overlay(removeSubs, x=300, y=580)

Thank you.

real.finder
3rd September 2016, 14:35
I see. I will have to do with Overlay for now then. I'll try and make some progress. Just to check, is this the method you were suggesting?

MPEG2Source("xxx")
noSubs = MPEG2Source("yyy")
removeSubs = noSubs.crop(300,580,644,90)
Overlay(removeSubs, x=300, y=580)

Thank you.

there are this http://sasamisi.blog24.fc2.com/blog-entry-326.html

didn't use it before but some people use it to do what you talk about

raffriff42
3rd September 2016, 16:58
http://sasamisi.blog24.fc2.com/blog-entry-326.htmlInteresting; will have to try that. (EDIT tried it, but do not understand it)


Note johnmeyer was using "my NLE (Sony Vegas)," not AviSynth. It's possible in Avisynth though:MPEG2Source("xxx")
noSubs = MPEG2Source("yyy")
mask = ImageSource("zzz")
Overlay(noSubs, mask=mask)
...where the mask image looks something like this:
https://www.dropbox.com/s/be39luans9dnwqi/subtitle-remove-tut-4-final-mask-small.jpg?raw=1


However, this is oversimplified. You will want to use the original video in sections without subtitles:main = MPEG2Source("xxx")
noSubs = MPEG2Source("yyy")
mask = ImageSource("zzz")
fixed = main.Overlay(noSubs, mask=mask)
edit = main.Trim(0, 100) [* "100" = 1st edit point, etc *]
\ + fixed.Trim(101, 200)
\ + main.Trim(201, 300)
\ + fixed.Trim(301, 400)
\ [* ...et cetera *]
\ + main.Trim(901, 0)
return edit.AudioDub(main)

Even this is simplified, if you want to make smooth transitions with Dissolve in place of '+' (Splice), which gets maddeningly complex.

johnmeyer
3rd September 2016, 17:27
Even this is simplified, if you want to make smooth transitions with Dissolve in place of '+' (Splice), which gets maddeningly complex.Which is why my original suggestion was -- and still is -- to use your NLE, especially Vegas. The neat thing about Vegas is that, if you know how, you can write scripts which automate repetitive edits. So, as an example, I could "drag select" the portion of video where I want to remove the sub, and then invoke the Vegas script which would assign a mask to that section, feather the edges, and then do a cross fade to make the mask appear and disappear gradually, leaving the original video in portions where no subtitles appear.

blaze077
3rd September 2016, 21:16
there are this http://sasamisi.blog24.fc2.com/blog-entry-326.html

didn't use it before but some people use it to do what you talk about
Thank you, reel.deel. This works great and matches what I was looking for. I haven't test it out with sources that are very different in colors or other details but with some tweaking I can use it properly.

Interesting; will have to try that. (EDIT tried it, but do not understand it)


Note johnmeyer was using "my NLE (Sony Vegas)," not AviSynth. It's possible in Avisynth though:MPEG2Source("xxx")
noSubs = MPEG2Source("yyy")
mask = ImageSource("zzz")
Overlay(noSubs, mask=mask)
...where the mask image looks something like this:
https://dl.dropboxusercontent.com/u/108089426/Screenshots/subtitle-remove-tut-4-final-mask-small.jpg


However, this is oversimplified. You will want to use the original video in sections without subtitles:main = MPEG2Source("xxx")
noSubs = MPEG2Source("yyy")
mask = ImageSource("zzz")
fixed = main.Overlay(noSubs, mask=mask)
edit = main.Trim(0, 100) [* "100" = 1st edit point, etc *]
\ + fixed.Trim(101, 200)
\ + main.Trim(201, 300)
\ + fixed.Trim(301, 400)
\ [* ...et cetera *]
\ + main.Trim(901, 0)
return edit.AudioDub(main)

Even this is simplified, if you want to make smooth transitions with Dissolve in place of '+' (Splice), which gets maddeningly complex.

The script reel.deel linked to works great so I don't need Overlay anymore but now I know how the mask can be used for Overlay which I was confused with before thanks to you. :D

Which is why my original suggestion was -- and still is -- to use your NLE, especially Vegas. The neat thing about Vegas is that, if you know how, you can write scripts which automate repetitive edits. So, as an example, I could "drag select" the portion of video where I want to remove the sub, and then invoke the Vegas script which would assign a mask to that section, feather the edges, and then do a cross fade to make the mask appear and disappear gradually, leaving the original video in portions where no subtitles appear.

I have installed Vegas and am trying to work it out. Plus, if I am going to spend time matching the video and fixing it, then I might as well use Vegas. :) Thank you.

Reel.Deel
3rd September 2016, 22:15
The script reel.deel linked to works great...


I did no such thing, it was actually real.finder :D


------

I forgot to celebrate my 1000th post, thanks for the reminder LigH.

http://www.cosgan.de/images/smilie/musik/h025.gif

Motenai Yoda
3rd September 2016, 22:28
instead of simple overlay you can also use an mt_lutxy or simila like dither_limitdiff16 too to check differences between high quality subbed source and lower quality clean one, and use the clean one only over a given threshold.

real.finder
3rd September 2016, 23:30
instead of simple overlay you can also use an mt_lutxy or simila like dither_limitdiff16 too to check differences between high quality subbed source and lower quality clean one, and use the clean one only over a given threshold.

that what OverDiff5 did

GMJCZP
4th September 2016, 02:15
Take a look to MSU Subtitle Remover or SubRip Companion Subtitle Remover.

blaze077
4th September 2016, 07:53
I did no such thing, it was actually real.finder :D


------

I forgot to celebrate my 1000th post, thanks for the reminder LigH.

http://www.cosgan.de/images/smilie/musik/h025.gif
Haha, my bad. Sorry, real.finder. :scared: I read lots of reel.deel posts on doom9 so his name got stuck in my brain. :D

And Happy 1000th post to reel.deel!

Take a look to MSU Subtitle Remover or SubRip Companion Subtitle Remover.

I will try it tomorrow. I don't have very high hopes for it though. Thank you for the suggestion.

StainlessS
4th September 2016, 15:04
This thread reminded me of another some time ago:- http://forum.doom9.org/showthread.php?t=167882&highlight=intertitle

Perhaps the below would be a starting point in locating subtitles (and decision as to whether there is a sub on frame or not).

#AVISource("D:\V\Cabaret.avi") # A Clip with perhaps some white titles
#------------------------
BlankClip(Length=10000) # for testclip
TestClip() # Just for testing not crash
#------------------------
#EDIT BELOW Paramaters
X=0 Y=0 W=0 H=0 # Coords, exclude borders
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.
SEP = "," # Separator for Range files in MakeFiles().
#---------------------
# 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
#---------------------
# Make command files, MUST use before ANY of remainding functions.
#return MakeFiles(blk_hi=BLKHI,Wht_Lo=WHTLO,IT_THRESH=THRESH,x=X,y=Y,w=W,h=H,sep=SEP).AssumeFPS(250.0) # Commands files for both titles & scenes
#---------------------
# Just a demo which modifies BOTH Scene and Title frames, and puts them BOTH back into original clip. Requires MakeFiles generated command files.
TitleClip=SelectTitleFrames().FlipHorizontal() # Select Titles only Clip, and demo EDIT
SceneClip=SelectSceneFrames().Invert() # Select Scene only clip, and demo EDIT
return ReplaceSceneFrames(SceneClip).ReplaceTitleFrames(TitleClip) # Return demo EDITED Video, original Audio.
#---------------------

Function TestClip(clip c) {
# TestClip generator.
c
K=c.BlankClip()
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)
C2=0
GScript("""
for(i=0,Framecount-1,200) {
s=i
e=min(FrameCount-1,s+149)
NewC=Trim(s,e)
C2 = (C2.IsClip()) ? C2 + NewC : NewC
if(i+200 < FrameCount -1) {
C2=C2+ K.Trim(e+1,-10)
C2=C2+ KT.Trim(e+11,-30)
C2=C2+ K.Trim(e+41,-10)
}
}
""")
return C2
}

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
IsTit = itot >= IT_Thresh && WPerc < KPerc
Got=(IsTit && 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") + \
" Title="+((IsTit)?"YES":"NO")+ " : FoundText="+((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,int "Blk_hi",int "Wht_Lo",Float "IT_Thresh",int "X",int "Y",int "W",int "H",String "Sep", \
String "TitleFrames",String "SceneFrames",String "TitleRange",String "SceneRange") {
# Make Command files for Select and Replace functions
c
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) Sep=Default(Sep,",")
TitleFrames=Default(TitleFrames,"TitleFrames.txt")
SceneFrames=Default(SceneFrames,"SceneFrames.txt")
TitleRange=Default(TitleRange,"TitleRange.txt")
SceneRange=Default(SceneRange,"SceneRange.txt")
(Exist(TitleFrames)) ? RT_FileDelete(TitleFrames) : NOP # Delete existing
(Exist(SceneFrames)) ? RT_FileDelete(SceneFrames) : NOP
(Exist(TitleRange)) ? RT_FileDelete(TitleRange) : NOP
(Exist(SceneRange)) ? RT_FileDelete(SceneRange) : NOP
KPerc = RT_YInRange(n=0,lo=0,hi=Blk_hi,x=X,y=Y,w=W,h=H) * 100.0
WPerc = RT_YInRange(n=0,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
IsTit = itot >= IT_Thresh && WPerc < KPerc
Global PTit = IsTit
Global PS = 0
ScriptClip("""
n=current_frame
KPerc = RT_YInRange(n=n+1,lo=0,hi=Blk_hi,x=X,y=Y,w=W,h=H) * 100.0
WPerc = RT_YInRange(n=n+1,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
IsTit = itot >= IT_Thresh && WPerc < KPerc # Title status for NEXT FRAME
RT_TxtWriteFile(String(n),(PTit)?TitleFrames:SceneFrames,append=True) # Write frame commands (sampled on previous iteration)
Close = (PTit!=IsTit || n==FrameCount-1) # Next frame changed OR Last Frame
(Close) ? RT_TxtWriteFile(String(PS)+Sep+String(n),(PTit)?TitleRange:SceneRange,append=True): NOP
Global PS= (Close) ? n+1 : PS # Next frame is new range ?
Global PTit=IsTit
return Last
""",args="Blk_hi,Wht_lo,IT_Thresh,X,Y,W,H,TitleFrames,SceneFrames,TitleRange,SceneRange,Sep") # Needs Grunt for args
return Last
}

Function SelectTitleFrames(clip c,bool "Show",String "fn") {
# Select Title Frames from clip c using fn command file.
c
fn=Default(fn,"TitleFrames.txt")
# fn=Default(fn,"TitleRange.txt") # TitleRange.txt could also be used if SEP="," or " "
Show=Default(Show,False)
FrameSelect(CMD=fn,show=Show) # Returns NO audio
}

Function SelectSceneFrames(clip c,bool "Show",String "fn") {
# Select Scene Frames from clip c using fn command file.
c
fn=Default(fn,"SceneFrames.txt")
# fn=Default(fn,"SceneRange.txt") # SceneRange.txt could also be used if SEP="," or " "
Show=Default(Show,False)
FrameSelect(CMD=fn,show=Show) # Returns NO audio
}

Function ReplaceTitleFrames(clip c,clip RepC,bool "Show",String "fn") {
# Replace Titles RepC back into clip c using fn command file.
c
fn=Default(fn,"TitleFrames.txt")
# fn=Default(fn,"TitleRange.txt") # TitleRange.txt could also be used if SEP="," or " "
Show=Default(Show,False)
FrameReplace(RepC,CMD=fn,show=Show) # Returns Audio from clip c
}

Function ReplaceSceneFrames(clip c,clip RepC,bool "Show",String "fn") {
# Replace Scene RepC back into clip c using fn command file.
c
fn=Default(fn,"SceneFrames.txt")
# fn=Default(fn,"SceneRange.txt") # SceneRange.txt could also be used if SEP="," or " "
Show=Default(Show,False)
FrameReplace(RepC,CMD=fn,show=Show) # Returns Audio from clip c
}


RT_Stats also has function to locate RGB range instead of Luma_Y so could perhaps mod to search in specific area of frame for subtitle
and if any suspect found, make decision as to whether or not is it a subtitle (using other RT_Stats stats).
I dont really have the time to do this myself but it is probably quite do-able.

Here, a demo script from RT_Stats v2.0 beta (In MediaFire below in my sig), demo's find RGB object.
EDIT: There is a similar locator script in RT for locating a luma object rather than rgb range object.
EDIT: Below script does not need RT_ v2.0, any recent version will do, but added the location detection Marker, which requires MaskTools v2.0.

# RGBInRangeLocate_Test

# NOTE, Angle corners show detection.
# req RT_Stats & mt_tools_2

RED =$AA # Object Color to look for
GREEN =$CC
BLUE =$FF

OBJECT_W = 10 # Object Width
OBJECT_H = 10 # Object Height

AREA_X = 0 # Area of frame to search (0,0,0,0=full frame, As Crop)
AREA_Y = 0
AREA_W = 0
AREA_H = 0

R_MIN = RED R_MAX = RED
G_MIN = GREEN G_MAX = GREEN
B_MIN = BLUE B_MAX = BLUE

# Overlay Converts RGB->YUV->RGB (can set inexact color). Use Layer Instead, MUST set ALPHA
RGBA=((255 * 256 + RED)*256+GREEN)*256+BLUE

COORDINATES="RGB_Coordinates.txt"

# Fake input clip, for testing
a = BlankClip(length=480,width=480,height=480)
b = a.BlankClip(width=OBJECT_W, height=OBJECT_H, color=RGBA)
a.Animate (0, a.FrameCount () - 1, "Layer", b,"add",257, 0, 0, b,"add",257, 479, 479)

MarkerColor = $FFFF00 # Detection marker color
MARKER_TYPE = false # False = Corners only marker, True=Full Rect Marker
Msk = Last.RectMarker(OBJECT_W+8,OBJECT_H+8,MARKER_TYPE)
Mrk = Msk.BlankClip(Color=MarkerColor)


NOTFOUND="NOT FOUND" # Will be NOT FOUND, As OBJECT moves out of frame at end of clip (can no longer find size OBJECT_W x OBJECT_H)
sep = ", "
Ket = "] "
RT_FileDelete(COORDINATES) # Delete coordinates file
DEBUG=False
ScriptClip ("""
Bingo=RT_RgbInRangeLocate(x=AREA_X,y=AREA_Y,w=AREA_W,h=AREA_H,
\ RLo=R_MIN,Rhi=R_MAX,GLo=G_MIN,Ghi=G_MAX,BLo=B_MIN,Bhi=B_MAX,Baffle_W=OBJECT_W,Baffle_H=OBJECT_H,debug=DEBUG)
(Bingo) ? WriteFile (COORDINATES,"current_frame", "Ket", "RGBIRL_X", "sep", "RGBIRL_Y")
\ : WriteFile (COORDINATES,"current_frame", "Ket", "NOTFOUND")

(Bingo) ? Overlay(Mrk,x=RGBIRL_X-4,y=RGBIRL_Y-4,Mask=Msk,Mode="Blend")
\ : NOP
Return Last
""")

Return Last

Function RectMarker(clip c,int W, Int H,Bool "Hit") {
# req RT_Stats & mt_tools_2, Returns YV12 frame WxH same FPS as c and without audio
Hit=Default(hit,False)
InFix = (Hit)
\ ? 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)
\ : RT_string("((x<=1|x>=%d|y<=1|y>=%d)&(x<4|x>=%d)&(y<4|y>=%d))?255:0", W-2,H-2,W-4,H-4)
c.Blankclip(width=W,height=H,Length=1,pixel_type="YV12").Killaudio
return mt_lutspa(relative = false,yExpr=mt_Polish(InFix), chroma = "128")
}

StainlessS
4th September 2016, 21:21
Here the OverDiff5() function, with trailing comments translated to english [EDIT: As linked by Real.Finder in post #9]


# http://sasamisi.blog24.fc2.com/blog-entry-326.html

function OverDiff5 (clip clip1,clip clip2,int "mode",int "top",int "bottom",int "left",int "right",int "smask",int "lmask",
\ clip "c1",clip "c2",int "margin",bool "show") {
mode=default(mode,0)
top=default(top,0)
bottom=default(bottom,0)
left=default(left,0)
right=default(right,0)
smask=default(smask,40)
lmask=default(lmask,20)
margin=default(margin,0)
show=default(show,false)
c1=default(c1,clip1.crop(left,top,-right,-bottom).blur(0,1))
c2=default(c2,clip2.crop(left,top,-right,-bottom).blur(0,1))

check_diff=mt_lutxy(c1,c2,"x y - abs",chroma="process").mt_binarize(5).mt_inpand.mt_inpand.mt_inpand
over_mask=BlankClip(clip1,color=$ffffff).Letterbox(top,bottom,left,right).mt_binarize()
masked_1=mt_merge(clip1,clip2,over_mask,luma=true)
show_mask=Overlay(BlankClip(clip1),check_diff).Grayscale()
show_merge=merge(clip1,clip2)

clip_0=masked_1
clip_0=(show) ? merge(show_merge,over_mask) : clip_0
clip_1=ConditionalFilter(check_diff,clip1,masked_1,"AverageLuma","<","1.0",show=show)
clip_1_show=ConditionalFilter(check_diff,show_merge,show_merge,"AverageLuma","<","1.0",show=show)
clip_1=(show) ? StackVertical(merge(clip_1_show,over_mask),show_mask) : clip_1

c1=clip1.blur(0,1).Letterbox(top,bottom,left,right)
c2=clip2.blur(0,1).Letterbox(top,bottom,left,right)
small=mt_lutxy(c1,c2,"x y - abs",chroma="process").letterbox(0,0,2,2).mt_binarize(smask)
small_u=mt_lutxy(c1.UToY,c2.UToY,"x y - abs",chroma="process")
small_v=mt_lutxy(c1.VToY,c2.VToY,"x y - abs",chroma="process")
small_uv=mt_logic(small_u,small_v,mode="or").PointResize(c1.width,c1.height).letterbox(0,0,2,2).mt_binarize(smask)
small=(mode>=3) ? mt_logic(small,small_uv,mode="or") : small
small_e=mt_lutxy(c1,c2,"x y - abs",chroma="process").letterbox(2,2,2,2).mt_edge
small_e=(mode==4) ? small_e.mt_inpand : small_e
small=mt_logic(small_e,small,mode="or")
small=(margin==0) ? small : mt_logic(small,mt_logic(small.Loop(0,0,margin-1),small.Loop(margin+1,0,0),mode="or"),mode="or")
small=(mode>=4) ? small : small.mt_inpand

big=mt_lutxy(c1,c2,"x y - abs 1.5 ^",chroma="process")
big_u=mt_lutxy(c1.UToY,c2.UToY,"x y - abs 1.5 ^",chroma="process")
big_v=mt_lutxy(c1.VToY,c2.VToY,"x y - abs 1.5 ^",chroma="process")
big_uv=mt_logic(big_u,big_v,mode="or").PointResize(c1.width,c1.height)
big=(mode>3) ? mt_logic(big,big_uv,mode="or") : big
big=big.mt_binarize(lmask)

diff_mask=mt_hysteresis(small,big).mt_expand.mt_expand.mt_expand.mt_expand.mt_expand.mt_expand.mt_expand
masked_2=mt_merge(clip1,clip2,diff_mask,luma=true)
clip_2=ConditionalFilter(check_diff,clip1,masked_2,"averageluma","=","0",show=show)
clip_2_show=ConditionalFilter(check_diff,show_merge,show_merge,"averageluma","=","0",show=show)
clip_2=(show) ? StackVertical(merge(clip_2_show,diff_mask.Grayscale()),show_mask) : clip_2
return select(mode,clip_0,clip_1,clip_2,clip_2,clip_2)
}


Comments


clip1: the underlying clip
clip2: clip for overwritten clip1
mode: do an override in the mode = 0 unconditionally.
/ Overwriting if the mode = 1 to some extent of the difference in clip1 and clip2 was observed.
/ Mode = 2 clip1 and create a mask to the difference between the clip2, overwriting only that portion.
/ To add the color difference in the mode = 3 mode = 2. / To expand the mode = 4 mode = 2 of the mask.
top, bottom, left, right: exclude the up, down, left and right of the difference.
smask: underlying difference mask. The range of smask to enlarge lmask, the final mask is created.
lmask: mask in order to expand the smask.
c1, c2: input clip for judging to clip1 and clip2 whether there is a difference.
A clip that was processed in the Overlay and Blur and the like can be used in the determination.
margin: superimposing the difference mask of the front and rear frame.
show: to confirm the difference mask.


Example of use
To override the clip2 to the difference between # clip1 and clip2
clip1 = OverDiff5 (clip1, clip2,2)

# ANIME +
checktelop = mt_lutxy. (clip1, clip2, "xy - abs", chroma = "process") crop (560,0, -600, -820) .mt_binarize (20) .mt_inpand (mode = "horizontal")
clip1_ANIME = OverDiff5 (clip1, clip2,1,0,820,100,1360)
clip1 = ConditionalFilter (checktelop, clip1_ANIME, clip1, "averageluma", "<", "5")

Replace # the left and right 4px of clip2 to clip1
clip2 = OverDiff5 (clip1, clip2,0,0,0,4,4)
# note that in the above the voice of clip2 alternates clip1

# To specify the scope of application
clip1 = clip1.ApplyRange (0,1000, "OverDiff5", clip2,3,700,0,0,0)
# 0-1000 frame interval, excluding the top 700px

StainlessS
4th September 2016, 21:28
Below probably not of use, but interesting excercise (still needs some additional detection [if non black frame]).


Function RectMarker(clip c,int W, Int H,Bool "Hit") {
# req RT_Stats & mt_tools_2, Returns YV12 frame WxH same FPS as c and without audio
Hit=Default(hit,False)
InFix = (Hit)
\ ? 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)
\ : RT_string("((x<=1|x>=%d|y<=1|y>=%d)&(x<4|x>=%d)&(y<4|y>=%d))?255:0", W-2,H-2,W-4,H-4)
c.Blankclip(width=W,height=H,Length=1,pixel_type="YV12").Killaudio
return mt_lutspa(relative = false,yExpr=mt_Polish(InFix), chroma = "128")
}

Function ShowMarker(clip c,int x,int y,int w,int h,Int color,bool type) {
W=(W<=0) ? c.Width-X+W : W H=(H<=0) ? c.Height-Y+H : H
Msk = c.RectMarker(W+2,H+2,type) Mrk=Msk.BlankClip(Color=Color)
Return c.Overlay(Mrk,x=X-1,y=Y-1,Mask=Msk,Mode="Blend")
}

Function ShowMetrics(clip c,int "X",int "Y",int "W",int "H",Int "Lo",Int "Hi",Int "Baffle",Bool "HiLite",Bool "Show",Bool "ShowArea") {
GSCript("""
Function _ShowMetrics_Lo(clip c,int X,int Y,int W,int H,Int Lo,Int Hi,Int Baffle,Bool HiLite,Bool Show) {
c
n=current_frame
located = RT_YInRangeLocate(baffle=Baffle,lo=Lo,hi=Hi,x=X,y=Y,w=W,h=H)
If(Show) {
if(Located) {
# Round Coords to YV12 Chroma, mod 2x2
LX2=(YIRL_X+YIRL_W+1)/2*2-1 LY2=(YIRL_Y+YIRL_H+1)/2*2-1
LX1=YIRL_X/2*2 LY1=YIRL_Y/2*2
LW=LX2-LX1+1 LH=LY2-LY1+1
OverLay(Last.BlankClip(color=$FF8080,width=LW,height=LH),x=LX1,y=LY1,opacity=0.5)
RT_Subtitle("%d] : FoundText='YES' : x=%d y=%d w=%d h=%d",n,LX1,LY1,LW,LH)
} else {
RT_Subtitle("%d] : FoundText='NO'",n)
}
}
Return Last
}
""")
c
ConvertToYV24() # for HiLite non mod coords
X=Default(X,0) Y=Default(Y,0) W=Default(W,0) H=Default(H,0)
Lo=Default(Lo,200)
Hi=Default(Hi,255)
Baffle=Default(Baffle,2)
HiLite=Default(HiLite,False)
(SHOWAREA)?ShowMarker(Last,X,Y,W,H,$FF0000,true):NOP
args="X,Y,W,H,Lo,Hi,Baffle,HiLite,Show"
ScriptClip("_ShowMetrics_Lo("+args+")",args=args)
return Last
}

#---------------------
AVISource("D:\V\Cabaret.avi") # Some Clip with appropriate Subtitle SRT file. (Cabaret, border cropped, 668x396, 25FPS, 177640 frames)
SRT="Cabaret.srt" # Subtitle for Above Clip
Last.BlankClip(Pixel_type="YV12") # Same size, FPS and frames as Template clip
TextSub(SRT) # Add subtitles to Black frame
### Subtitle Search area
X = 100
Y = Height-120
W = -X
H = -8
#
BAFFLE = 2 # text pixel 'thickness'
SHOWAREA = True # Set True to view subtitle scan area
SHOW = True # Show Metrics And Overlay if Hilite true
HILITE = True
LO = 200 # Lowest Y of Subtitle
HI = 255 # Highest Y of Subtitle

ShowMetrics(x=X,y=Y,w=W,h=H,lo=LO,hi=HI,baffle=BAFFLE,HiLite=HILITE,show=SHOW,showarea=SHOWAREA)

Return ConvertToYV12 # From YV24


Can supply any clip with srt subtitle file, just currently test/demo functionality (subtitles put on BlackClip for detection).

blaze077
4th September 2016, 23:32
Thank you StainlessS for your effort. I'm still trying out GMJCZP's method and will try out your suggestions tomorrow.

An off-topic question: When I use Maa2 downloaded from here (https://github.com/AviSynth/avs-scripts/blob/master/maa2+.avsi) with chroma=false, it gives the following error in AvspMod - Traceback (most recent call last):
File "avsp.pyo", line 9043, in OnMenuVideoRefresh
File "avsp.pyo", line 13855, in ShowVideoFrame
File "avisynth.pyo", line 462, in GetFrame
WindowsError: exception: access violation reading 0x00000000
Traceback (most recent call last):
File "avsp.pyo", line 10614, in OnMouseMotionVideoWindow
File "avsp.pyo", line 13156, in SetVideoStatusText
File "avsp.pyo", line 13308, in GetVideoInfoDict
File "avsp.pyo", line 16436, in FormatTime
TypeError: %d format: a number is required, not float

Everything works fine with chroma=true. I tried out the maa2 script from the Avisynth wiki and it poses the same problem. Any solutions?

StainlessS
5th September 2016, 08:06
No solutions to your AvsPMod problem here, sorry.

The Real.Finder linked script performs really very well (at least on two identical clips, but one with added subtitles).

Here, another excursion into insanity

Function RectMarker(clip c,int W, Int H,Bool "Hit") {
Hit=Default(hit,False)
InFix = (Hit)
\ ? 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)
\ : RT_string("((x<=1|x>=%d|y<=1|y>=%d)&(x<4|x>=%d)&(y<4|y>=%d))?255:0", W-2,H-2,W-4,H-4)
c.Blankclip(width=W,height=H,Length=1,pixel_type="YV12").Killaudio
return mt_lutspa(relative = false,yExpr=mt_Polish(InFix), chroma = "128")
}

Function ShowMarker(clip c,int x,int y,int w,int h,Int color,bool type,Float "Opacity") {
Opacity=Default(Opacity,1.0)
W=(W<=0) ? c.Width-X+W : W H=(H<=0) ? c.Height-Y+H : H
Msk = c.RectMarker(W+2,H+2,type) Mrk=Msk.BlankClip(Color=Color)
Return c.Overlay(Mrk,x=X-1,y=Y-1,Mask=Msk,Mode="Blend",Opacity=Opacity)
}

Function FindSub(clip c,int "X",int "Y",int "W",int "H",Int "TextCol",Int "HaloCol",Int "ChanVar",Int "Text_w",Int "Text_h",Int "Halo_w",Int "Halo_h",Bool "ShowArea") {
GSCript("""
Function _FindSub_Lo(clip c,int X,int Y,int W,int H,Int TextCol,Int HaloCol,Int ChanVar,Int Text_w,Int Text_h,Int Halo_w,Int Halo_h) {
c
TcB=RT_BitAnd(TextCol,$FF) TextCol=TextCol/256 TcG=RT_BitAnd(TextCol,$FF) TextCol=TextCol/256 TcR=RT_BitAnd(TextCol,$FF)
HcB=RT_BitAnd(HaloCol,$FF) HaloCol=HaloCol/256 HcG=RT_BitAnd(HaloCol,$FF) HaloCol=HaloCol/256 HcR=RT_BitAnd(HaloCol,$FF)
TcBLo=Max(TcB-ChanVar,0) TcGLo=Max(TcG-ChanVar,0) TcRLo=Max(TcR-ChanVar,0)
TcBHi=Min(TcB+ChanVar,255) TcGHi=Min(TcG+ChanVar,255) TcRHi=Min(TcR+ChanVar,255)
HcBLo=Max(HcB-ChanVar,0) HcGLo=Max(HcG-ChanVar,0) HcRLo=Max(HcR-ChanVar,0)
HcBHi=Min(HcB+ChanVar,255) HcGHi=Min(HcG+ChanVar,255) HcRHi=Min(HcR+ChanVar,255)
Thresh=Min(Text_W*100.0/W,Text_H*100.0/H)
GotText=RT_RgbInRangeLocate(x=X,y=Y,w=W,h=H,Thresh=Thresh,
\ RLo=TcRLo,RHi=TcRHi,GLo=TcGLo,GHi=TcGHi,BLo=TcBLo,BHi=TcBHi,Prefix="TXT_",Baffle_w=Text_W,Baffle_h=Text_H)
n=current_frame
if(GotText) {
KX=TXT_X-Halo_w KY=TXT_Y-Halo_h
GotHalo=RT_RgbInRangeLocate(x=KX,y=KY,w=TXT_W+2*Halo_w,h=TXT_H+2*Halo_h,Thresh=Thresh,
\ RLo=HcRLo,RHi=HcRHi,GLo=HcGLo,GHi=HcGHi,BLo=HcBLo,BHi=HcBHi,Prefix="HAL_",Baffle_w=Halo_W,Baffle_h=Halo_H)
if(GotHalo) {
TXT_X2=TXT_X+TXT_W-1 TXT_Y2=TXT_Y+TXT_H-1
HAL_X2=HAL_X+HAL_W-1 HAL_Y2=HAL_Y+HAL_H-1
GudK=(HAL_X<=TXT_X && HAL_Y<=TXT_Y && HAL_X2>=TXT_X2 && HAL_Y2>=TXT_Y2)
if(GudK) {
OverLay(Last.BlankClip(color=$00FF00,width=HAL_W,height=HAL_H),x=HAL_X,y=HAL_Y,opacity=0.5) # Green Halo marker ON HALO
RT_Subtitle("%d] Text='YES' : x=%d y=%d w=%d h=%d",n,TXT_X,TXT_Y,TXT_W,TXT_H)
RT_Subtitle("Halo='YES' : x=%d y=%d w=%d h=%d",HAL_X,HAL_Y,HAL_W,HAL_H,y=20)
} Else {
OverLay(Last.BlankClip(color=$FFFF00,width=TXT_W,height=TXT_H),x=TXT_X,y=TXT_Y,opacity=0.5) # Yellow Text marker
OverLay(Last.BlankClip(color=$FF0000,width=HAL_W,height=HAL_H),x=HAL_X,y=HAL_Y,opacity=0.5) # Red BAD halo marker
RT_Subtitle("%d] Text='YES' : x=%d y=%d w=%d h=%d",n,TXT_X,TXT_Y,TXT_W,TXT_H)
RT_Subtitle("Halo='FAIL' : x=%d y=%d w=%d h=%d",HAL_X,HAL_Y,HAL_W,HAL_H,y=20)
}
} Else {
OverLay(Last.BlankClip(color=$FFFF00,width=TXT_W,height=TXT_H),x=TXT_X,y=TXT_Y,opacity=0.5) # Yellow Text marker
RT_Subtitle("%d] Text='YES' : x=%d y=%d w=%d h=%d\nHalo='NO'",n,TXT_X,TXT_Y,TXT_W,TXT_H)
}
} else {RT_Subtitle("%d]",n)}
Return Last
}
""")
c
X=Default(X,0) Y=Default(Y,0) W=Default(W,0) H=Default(H,0)
W=(W<=0) ? c.Width-X+W : W H=(H<=0) ? c.Height-Y+H : H
TextCol=Default(TextCol,$FEFEFE) HaloCol=Default(HaloCol,$020202) ChanVar=Default(ChanVar,2)
Halo_w=Default(Halo_w,4) Halo_h=Default(Halo_h,4)
Text_w=Default(Text_w,2) Text_h=Default(Text_h,2)
(SHOWAREA)?ShowMarker(Last,X,Y,W,H,$FF80FF,true,0.4):NOP
args="X,Y,W,H,TextCol,HaloCol,ChanVar,Text_w,Text_h,Halo_w,Halo_h"
ScriptClip("_FindSub_Lo("+args+")",args=args)
return Last
}

#---------------------
AVISource("D:\V\Cabaret.avi") # Some Clip with appropriate Subtitle SRT file. (Cabaret, border cropped, 668x396, 25FPS, 177640 frames)
ConvertToRGB24
SRT="Cabaret.srt" # Subtitle for Above Clip
### Subtitle Search area
X = 100
Y = Height-120
W = -X
H = -8
#
TEXT_W = 2 # minimum text pixel 'thickness' Horizontal
TEXT_H = 2 # minimum text pixel 'thickness' Vertical
HALO_W = 4 # Halo width in pixels (horizontal minimum, Could still be more Halo outside of detected area)
HALO_H = 4 # Halo height in pixels (vertical minimum, Could still be more Halo outside of detected area)
TEXTCOL = $FEFEFE
HALOCOL = $010101
CHANVAR = 1 # Text and Halo RGB channels can vary by as much as CHANVAR, eg $FEFEFE with CHANVAR=1 ranges $FDFDFD -> $FFFFFF
SHOWAREA = True # Set True to mark subtitle scan area
BLANKCOL = $808080 # Color used if DOBLANK ie Blankclip color
DOBLANK = False # Use only BlankClip not video
DOAUDIO = True # Use audio
###
Blank=AudioDub(Last.BlankClip(Color=BLANKCOL),Last) # Same size, FPS and frames as Template clip
Last=(DOBLANK)?Blank:Last
!DOAUDIO?KillAudio:NOP
TextSub(SRT) # Add subtitles to frame
FindSub(x=X,y=Y,w=W,h=H,TextCol=TEXTCOL,HaloCol=HALOCOL,Text_W=TEXT_W,Text_h=TEXT_H,halo_w=HALO_W,halo_h=HALO_H,showarea=SHOWAREA)
Return Last

Could probably still do better.

StainlessS
5th September 2016, 22:51
Here, a bit better, shows stacked vertical


Function RectMarker(clip c,int W, Int H,Bool "Hit") {
Hit=Default(hit,False)
InFix = (Hit)
\ ? 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)
\ : RT_string("((x<=1|x>=%d|y<=1|y>=%d)&(x<4|x>=%d)&(y<4|y>=%d))?255:0", W-2,H-2,W-4,H-4)
c.Blankclip(width=W,height=H,Length=1,pixel_type="YV12").Killaudio
return mt_lutspa(relative = false,yExpr=mt_Polish(InFix), chroma = "128")
}

Function ShowMarker(clip c,int x,int y,int w,int h,Int color,bool type,Float "Opacity") {
Opacity=Default(Opacity,1.0)
W=(W<=0) ? c.Width-X+W : W H=(H<=0) ? c.Height-Y+H : H
Msk = c.RectMarker(W+2,H+2,type) Mrk=Msk.BlankClip(Color=Color)
Return c.Overlay(Mrk,x=X-1,y=Y-1,Mask=Msk,Mode="Blend",Opacity=Opacity)
}

Function DetClip(clip c,int x,int y,int w,int h,Int TextCol,Int HaloCol,Int ChanVar,Int Text_w,Int Text_h,Int Halo_w,Int Halo_h) {
c W=(W<=0)?c.Width-X+W:W H=(H<=0)?c.Height-Y+H:H ConvertToRGB24
TB=RT_BitAnd(TextCol,$FF) TextCol=TextCol/256 TG=RT_BitAnd(TextCol,$FF) TextCol=TextCol/256 TR=RT_BitAnd(TextCol,$FF)
TBLo=Max(TB-ChanVar,0) TGLo=Max(TG-ChanVar,0) TRLo=Max(TR-ChanVar,0)
TBHi=Min(TB+ChanVar,255) TGHi=Min(TG+ChanVar,255) TRHi=Min(TR+ChanVar,255)
HB=RT_BitAnd(HaloCol,$FF) HaloCol=HaloCol/256 HG=RT_BitAnd(HaloCol,$FF) HaloCol=HaloCol/256 HR=RT_BitAnd(HaloCol,$FF)
HBLo=Max(HB-ChanVar,0) HGLo=Max(HG-ChanVar,0) HRLo=Max(HR-ChanVar,0)
HBHi=Min(HB+ChanVar,255) HGHi=Min(HG+ChanVar,255) HRHi=Min(HR+ChanVar,255)
LimS="((x>=%d)&(x<=%d))?255:0"
TRed=ShowRed (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,TRLo,TRHi)))
TGrn=ShowGreen(Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,TGLo,TGHi)))
TBlu=ShowBlue (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,TBLo,TBHi)))
HRed=ShowRed (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,HRLo,HRHi)))
HGrn=ShowGreen(Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,HGLo,HGHi)))
HBlu=ShowBlue (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,HBLo,HBHi)))
TXT=Mt_Logic(TRed,TGrn,"and").Mt_Logic(TBlu,"and").Mt_Expand().Mt_Expand()
HAL=Mt_Logic(HRed,HGrn,"and").Mt_Logic(HBlu,"and").Mt_Expand().Mt_Expand()
Mt_Logic(TXT,HAL,"and")
return last
}

Function FindSub(clip c,int "X",int "Y",int "W",int "H",Int "TextCol",Int "HaloCol",Int "ChanVar",Int "Text_w",Int "Text_h",Int "Halo_w",Int "Halo_h",Bool "ShowArea") {
GSCript("""
Function _FindSub_Lo(clip c,int X,int Y,int W,int H,Int Text_w,Int Text_h,Int Halo_w,Int Halo_h,clip dc) {
c
n=current_frame
Bingo = RT_YInRangeLocate(dc,x=x,y=y,w=W,h=H,Baffle_w=Text_w+Halo_W,Baffle_h=Text_h+Halo_H,lo=255,hi=255)
if(Bingo) {
OverLay(Last.BlankClip(color=$FF8080,width=YIRL_W,height=YIRL_H),x=YIRL_X,y=YIRL_Y,opacity=0.5)
RT_Subtitle("%d] : FoundText='YES' : x=%d y=%d w=%d h=%d",n,YIRL_X,YIRL_Y,YIRL_W,YIRL_H)
} else {
RT_Subtitle("%d] NO",n)
}
Return Last
}
""")
c
X=Default(X,0) Y=Default(Y,0) W=Default(W,0) H=Default(H,0)
W=(W<=0) ? c.Width-X+W : W H=(H<=0) ? c.Height-Y+H : H
TextCol=Default(TextCol,$FEFEFE) HaloCol=Default(HaloCol,$010101) ChanVar=Default(ChanVar,1)
Text_w=Default(Text_w,2) Text_h=Default(Text_h,2)
Halo_w=Default(Halo_w,2) Halo_h=Default(Halo_h,2) dc=DetClip(x,y,w,h,TextCol,HaloCol,ChanVar,Text_w,Text_h,Halo_w,Halo_h)
dc=dc.ConvertToRGB24
dc
(SHOWAREA)?ShowMarker(Last,X,Y,W,H,$FF80FF,true,0.4):NOP
args="X,Y,W,H,Text_w,Text_h,Halo_w,Halo_h,dc"
ScriptClip("_FindSub_Lo("+args+")",args=args)
return Last
}

#---------------------
AVISource("D:\V\Cabaret.avi") # Some Clip with appropriate Subtitle SRT file. (Cabaret, border cropped, 668x396, 25FPS, 177640 frames)
ConvertToRGB24
SRT="Cabaret.srt" # Subtitle for Above Clip
### Subtitle Search area
X = 100
Y = Height-120
W = -X
H = -8
#
TEXT_W = 2 # minimum text pixel 'thickness' Horizontal
TEXT_H = 2 # minimum text pixel 'thickness' Vertical
HALO_W = 4 # Halo width in pixels (horizontal minimum, Could still be more Halo outside of detected area)
HALO_H = 4 # Halo height in pixels (vertical minimum, Could still be more Halo outside of detected area)
TEXTCOL = $FEFEFE
HALOCOL = $010101
CHANVAR = 1 # Text and Halo RGB channels can vary by as much as CHANVAR, eg $FEFEFE with CHANVAR=1 ranges $FDFDFD -> $FFFFFF
SHOWAREA = True # Set True to mark subtitle scan area
BLANKCOL = $808080 # Color used if DOBLANK ie Blankclip color
DOBLANK = False # Use only BlankClip not video
DOAUDIO = True # Use audio
###
ORG=Last
Blank=AudioDub(Last.BlankClip(Color=BLANKCOL),Last) # Same size, FPS and frames as Template clip
Last=(DOBLANK)?Blank:Last
!DOAUDIO?KillAudio:NOP
TextSub(SRT) # Add subtitles to frame
ORG=Last
FindSub(x=X,y=Y,w=W,h=H,TextCol=TEXTCOL,HaloCol=HALOCOL,Text_W=TEXT_W,Text_h=TEXT_H,halo_w=HALO_W,halo_h=HALO_H,showarea=SHOWAREA)
StackVertical(Org,Last)
Return Last

StainlessS
7th September 2016, 07:18
Bit of a hack version, shows 4 window result, maybe a bit better.
I'm working on assumption that subs have a halo.
This is of course just requiring single clip (not 2nd clip with clean source) and so possibly having more uses that in your case.

Perhaps RaffRiff42 could do better, I'm somewhat limited in experience handling masks and the like.

Anyways, here tis:-

Function RectMarker(clip c,int W, Int H,Bool "Hit") {
Hit=Default(hit,False)
InFix = (Hit)
\ ? 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)
\ : RT_string("((x<=1|x>=%d|y<=1|y>=%d)&(x<4|x>=%d)&(y<4|y>=%d))?255:0", W-2,H-2,W-4,H-4)
c.Blankclip(width=W,height=H,Length=1,pixel_type="YV12").Killaudio
return mt_lutspa(relative = false,yExpr=mt_Polish(InFix), chroma = "128")
}

Function ShowMarker(clip c,int x,int y,int w,int h,Int color,bool type,Float "Opacity") {
Opacity=Default(Opacity,1.0)
W=(W<=0) ? c.Width-X+W : W H=(H<=0) ? c.Height-Y+H : H
Msk = c.RectMarker(W+2,H+2,type) Mrk=Msk.BlankClip(Color=Color)
Return c.Overlay(Mrk,x=X-1,y=Y-1,Mask=Msk,Mode="Blend",Opacity=Opacity)
}

GSCript("""
Function FindSub(clip c,int X,int Y,int W,int H,Int Text_w,Int Text_h,Int Halo_w,Int Halo_h,clip dc) {
c
n=current_frame
Thresh=Min((Text_w+Halo_w*2)*100.0/W,(Text_h+Halo_h*2)*100.0/H)
Bingo = dc.RT_YInRangeLocate(x=x,y=y,w=W,h=H,Baffle_w=Text_w+Halo_w,Baffle_h=Text_h+Halo_H,lo=255,hi=255,Thresh=Thresh)
if(Bingo) {
OverLay(Last.BlankClip(color=$FFFFFF,width=YIRL_W,height=YIRL_H),x=YIRL_X,y=YIRL_Y,opacity=0.2)
RT_Subtitle("%d] Text @ x=%d y=%d w=%d h=%d",n,YIRL_X,YIRL_Y,YIRL_W,YIRL_H)
}
Return Last
}
""")

AVISource("D:\V\Cabaret.avi") # Some Clip with appropriate Subtitle SRT file. (Cabaret, border cropped, 668x396, 25FPS, 177640 frames)
ConvertToRGB24
SRT="Cabaret.srt" # Subtitle for Above Clip
### Subtitle Search area
X = 100
Y = Height-120
W = -X
H = -8
#
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_W = 6 # Halo width in pixels (horizontal minimum, Could still be more Halo outside of detected area)
HALO_H = 6 # Halo height in pixels (vertical minimum, Could still be more Halo outside of detected area)
TEXTCOL = $FEFEFE
HALOCOL = $010101
CHANVAR = 1 # Text and Halo RGB channels can vary by as much as CHANVAR, eg $FEFEFE with CHANVAR=1 ranges $FDFDFD -> $FFFFFF
SHOWAREA = True # Set True to mark subtitle scan area
BLANKCOL = $808080 # Color used if DOBLANK ie Blankclip color
DOBLANK = False # Use only BlankClip not video
DOAUDIO = True # Use audio
###
ORG=Last
Blank=AudioDub(Last.BlankClip(Color=BLANKCOL),Last) # Same size, FPS and frames as Template clip
Last=(DOBLANK)?Blank:Last
!DOAUDIO?KillAudio:NOP
TextSub(SRT) # Add subtitles to frame
ORG=Last

W=(W<=0)?Width-X+W:W H=(H<=0)?Height-Y+H:H
TB=RT_BitAnd(TextCol,$FF) TextCol=TextCol/256 TG=RT_BitAnd(TextCol,$FF) TextCol=TextCol/256 TR=RT_BitAnd(TextCol,$FF)
TBLo=Max(TB-ChanVar,0) TGLo=Max(TG-ChanVar,0) TRLo=Max(TR-ChanVar,0)
TBHi=Min(TB+ChanVar,255) TGHi=Min(TG+ChanVar,255) TRHi=Min(TR+ChanVar,255)
HB=RT_BitAnd(HaloCol,$FF) HaloCol=HaloCol/256 HG=RT_BitAnd(HaloCol,$FF) HaloCol=HaloCol/256 HR=RT_BitAnd(HaloCol,$FF)
HBLo=Max(HB-ChanVar,0) HGLo=Max(HG-ChanVar,0) HRLo=Max(HR-ChanVar,0)
HBHi=Min(HB+ChanVar,255) HGHi=Min(HG+ChanVar,255) HRHi=Min(HR+ChanVar,255)
LimS="((x>=%d)&(x<=%d))?255:0"
TRed=ShowRed (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,TRLo,TRHi)))
TGrn=ShowGreen(Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,TGLo,TGHi)))
TBlu=ShowBlue (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,TBLo,TBHi)))
HRed=ShowRed (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,HRLo,HRHi)))
HGrn=ShowGreen(Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,HGLo,HGHi)))
HBlu=ShowBlue (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,HBLo,HBHi)))
TXT=Mt_Logic(TRed,TGrn,"and").Mt_Logic(TBlu,"and")
HAL=Mt_Logic(HRed,HGrn,"and").Mt_Logic(HBlu,"and")
GSCript("""
for(i=1,HALO_H) {TXT=TXT.Mt_Expand(mode="vertical")}
for(i=1,HALO_W) {TXT=TXT.Mt_Expand(mode="horizontal")}
for(i=1,TEXT_H) {HAL=HAL.Mt_Expand(mode="vertical")}
for(i=1,TEXT_W) {HAL=HAL.Mt_Expand(mode="horizontal")}
Res=Mt_Logic(TXT,HAL,"and")
""")
args="X,Y,W,H,Text_w,Text_h,Halo_w,Halo_h,res"
ORG=ORG.ScriptClip("FindSub("+args+")",args=args)
ORG=(SHOWAREA)?ORG.ShowMarker(X,Y,W,H,$FFFFFF,true,0.25):ORG
TXT=TXT.ConvertToRGB24
HAL=HAL.ConvertToRGB24
res=res.ConvertToRGB24
LFT=StackVertical(ORG,TXT.RT_Subtitle("\a!TEXT COLOR"))
RGT=StackVertical(HAL.RT_Subtitle("\a!HALO COLOR"),Res.RT_Subtitle("\a!DETECT"))
StackHorizontal(Lft,Rgt)
ConvertToRGB24


Perhaps you'de like to post several minutes with plenty of subs (maybe max 200->300MB), cut using eg DGIndex, mark section with '[' and ']',
then "Save Project & Demux Video".

OverDiff5(), is probably as good as you will get but above routines could prove of use in other cases, and/or identify sections where you need to
dissolve in the overlays. I could also add in some kind of OverRide to mark sections containing credits (which play havoc with detection).

Above can be used with clean source and adding in subtitles using TextSub(), never tried with real hardcoded subs (dont think I've got any such footage).
Can also just load in hardsubbed clip and comment out the TextSub() line.
If anybody tries with hard subs, might want to tell of experience here.

EDIT: Changed TEXT_W/H to 4, HALO_W/H to 6.

raffriff42
7th September 2016, 14:40
Perhaps RaffRiff42 could do better, Not likely! Your script above seems to detect subtitles fine (the ones I tested).
So does OverDiff5, as far as I can see.
Have not looked at fades credits etc.

To make it easier for people to try your script, here it is with some small changes:## Dependencies:
LoadPlugin(p + "MaskTools2\tp7masktools\masktools2.dll")
LoadPlugin(p + "GRunT\GRunT.dll")
LoadPlugin(p + "GScript\GScript.dll")
LoadPlugin(p + "RT_Stats\RT_Stats26.dll")
LoadPlugin(p + "VSFilter\VSFilter.dll")

Function RectMarker(clip c,int W, Int H,Bool "Hit") {
Hit=Default(hit,False)
InFix = (Hit)
\ ? 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)
\ : RT_string("((x<=1|x>=%d|y<=1|y>=%d)&(x<4|x>=%d)&(y<4|y>=%d))?255:0", W-2,H-2,W-4,H-4)
c.Blankclip(width=W,height=H,Length=1,pixel_type="YV12").Killaudio
return mt_lutspa(relative = false,yExpr=mt_Polish(InFix), chroma = "128")
}

Function ShowMarker(clip c,int x,int y,int w,int h,Int color,bool type,Float "Opacity") {
Opacity=Default(Opacity,1.0)
W=(W<=0) ? c.Width-X+W : W H=(H<=0) ? c.Height-Y+H : H
Msk = c.RectMarker(W+2,H+2,type) Mrk=Msk.BlankClip(Color=Color)
Return c.Overlay(Mrk,x=X-1,y=Y-1,Mask=Msk,Mode="Blend",Opacity=Opacity)
}

GSCript("""
Function FindSub(clip c,int X,int Y,int W,int H,Int Text_w,Int Text_h,Int Halo_w,Int Halo_h,clip dc) {
c
n=current_frame
Thresh=Min((Text_w+Halo_w*2)*100.0/W,(Text_h+Halo_h*2)*100.0/H)
Bingo = dc.RT_YInRangeLocate(x=x,y=y,w=W,h=H,Baffle_w=Text_w+Halo_w,Baffle_h=Text_h+Halo_H,lo=255,hi=255,Thresh=Thresh)
if(Bingo) {
OverLay(Last.BlankClip(color=$FFFFFF,width=YIRL_W,height=YIRL_H),x=YIRL_X,y=YIRL_Y,opacity=0.2)
RT_Subtitle("%d] Text @ x=%d y=%d w=%d h=%d",n,YIRL_X,YIRL_Y,YIRL_W,YIRL_H)
}
Return Last
}
""")

AVISource("D:\V\Cabaret.avi")
ConvertToRGB24
NOS=Last ## <<no-subtitle source>>

#[[ TEST
SRT="Cabaret.srt" # subtitles for above clip
TextSub(SRT) ## add subtitles
#][ PRODUCTION
#AVISource("D:\V\Cabaret-hardsubbed.avi")
#]]
SUB=Last ## <<subtitle source>>

### Subtitle Search area
X = 100
Y = Height-120
W = -X
H = -8
#
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_W = 6 # Halo width in pixels (horizontal minimum, Could still be more Halo outside of detected area)
HALO_H = 6 # Halo height in pixels (vertical minimum, Could still be more Halo outside of detected area)
TEXTCOL = $FEFEFE
HALOCOL = $010101
CHANVAR = 1 # Text and Halo RGB channels can vary by as much as CHANVAR, eg $FEFEFE with CHANVAR=1 ranges $FDFDFD -> $FFFFFF
SHOWAREA = True # Set True to mark subtitle scan area
BLANKCOL = $808080 # Color used if DOBLANK ie Blankclip color
DOBLANK = False # Use only BlankClip not video
DOAUDIO = True # Use audio
###
Blank=AudioDub(Last.BlankClip(Color=BLANKCOL),Last) # Same size, FPS and frames as Template clip
Last=(DOBLANK)?Blank:Last
!DOAUDIO?KillAudio:NOP
#
#TextSub(SRT) (this line commented out & moved to top of script)
#
ORG=Last

W=(W<=0)?Width-X+W:W H=(H<=0)?Height-Y+H:H
TB=RT_BitAnd(TextCol,$FF) TextCol=TextCol/256 TG=RT_BitAnd(TextCol,$FF) TextCol=TextCol/256 TR=RT_BitAnd(TextCol,$FF)
TBLo=Max(TB-ChanVar,0) TGLo=Max(TG-ChanVar,0) TRLo=Max(TR-ChanVar,0)
TBHi=Min(TB+ChanVar,255) TGHi=Min(TG+ChanVar,255) TRHi=Min(TR+ChanVar,255)
HB=RT_BitAnd(HaloCol,$FF) HaloCol=HaloCol/256 HG=RT_BitAnd(HaloCol,$FF) HaloCol=HaloCol/256 HR=RT_BitAnd(HaloCol,$FF)
HBLo=Max(HB-ChanVar,0) HGLo=Max(HG-ChanVar,0) HRLo=Max(HR-ChanVar,0)
HBHi=Min(HB+ChanVar,255) HGHi=Min(HG+ChanVar,255) HRHi=Min(HR+ChanVar,255)
LimS="((x>=%d)&(x<=%d))?255:0"
TRed=ShowRed (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,TRLo,TRHi)))
TGrn=ShowGreen(Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,TGLo,TGHi)))
TBlu=ShowBlue (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,TBLo,TBHi)))
HRed=ShowRed (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,HRLo,HRHi)))
HGrn=ShowGreen(Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,HGLo,HGHi)))
HBlu=ShowBlue (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,HBLo,HBHi)))
TXT=Mt_Logic(TRed,TGrn,"and").Mt_Logic(TBlu,"and")
HAL=Mt_Logic(HRed,HGrn,"and").Mt_Logic(HBlu,"and")
GSCript("""
for(i=1,HALO_H) {TXT=TXT.Mt_Expand(mode="vertical")}
for(i=1,HALO_W) {TXT=TXT.Mt_Expand(mode="horizontal")}
for(i=1,TEXT_H) {HAL=HAL.Mt_Expand(mode="vertical")}
for(i=1,TEXT_W) {HAL=HAL.Mt_Expand(mode="horizontal")}
Res=Mt_Logic(TXT,HAL,"and")
""")
args="X,Y,W,H,Text_w,Text_h,Halo_w,Halo_h,res"
ORG=ORG.ScriptClip("FindSub("+args+")",args=args)
ORG=(SHOWAREA)?ORG.ShowMarker(X,Y,W,H,$FFFFFF,true,0.25):ORG
TXT=TXT.ConvertToRGB24
HAL=HAL.ConvertToRGB24
res=res.ConvertToRGB24

LFT=StackVertical(ORG,TXT.RT_Subtitle("\a!TEXT COLOR"))
RGT=StackVertical(HAL.RT_Subtitle("\a!HALO COLOR"),Res.RT_Subtitle("\a!DETECT"))
StackHorizontal(Lft,Rgt)
ConvertToRGB24


##[[ OUTPUT - pick one; comment out the others
#return Last ## diagnostic, 4-way split
return Overlay(SUB, NOS, mask=res, opacity=0.9) ## test, subtitles show faintly
#return Overlay(SUB, NOS, mask=res) ## final run, subtitles removed completely
#]]

StainlessS
7th September 2016, 15:29
Thank you Raff, I'll have a try with mods later on.
I was not so much worried about the actual removal yet, just identification, will undoubtedly be made into a mutli-instance function
when more final, perhaps with OverrDiff5() re-worked into it (if I can figure out how that works :) ).

Guess I should have made it easier to use, LoadPlugin etc, but you came to rescue, cheers. :)

EDIT: OT. I might steal some of your audio matching code (posted in another thread) in my matching script, I only
really bother with conversion to 0, 1 or two channel (using FavC.avsi, from somewhere on-site) [I only bother really with stereo,
the only multi speaker setup I ever had, I gave away because I could not be bothered to set it up, nor wanted to feel like
there were people creeping all around me whilst playing a movie as a background noise maker, and working at same time]..

blaze077
8th September 2016, 02:28
OverDiff5 works great on all scenes that are identical like you said. I tried out your script (the version posted by raffriff), StainlessS and the detection works well. The script is pretty complex for me so I cannot understand how most of the script functions but can make out some of the things. When I ran it, these lines gave the error:
#LINES:

TRed=ShowRed (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,TRLo,TRHi)))
TGrn=ShowGreen(Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,TGLo,TGHi)))
TBlu=ShowBlue (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,TBLo,TBHi)))
HRed=ShowRed (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,HRLo,HRHi)))
HGrn=ShowGreen(Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,HGLo,HGHi)))
HBlu=ShowBlue (Pixel_Type="Y8").mt_lut(mt_Polish(RT_string(LimS,HBLo,HBHi)))

ERROR:

mt_lut: unsupported colorspace. masktools only supports planar YUV colorspaces (YV12, YV16, YV24)

I changed the Y8 to YV12 and it worked but was I really supposed to do that or was that just a problem on my side?

Also, I could not check the actual subtitle removal because for some reason, the last line returned the same hardsubbed clip.
return Overlay(SUB, NOS, mask=res)

:confused:

The hardsub removal did actually work once however, upon refreshing the preview, I got the problem. Restarted everything but still nothing.

This is the script I used:

Function RectMarker(clip c,int W, Int H,Bool "Hit") {
Hit=Default(hit,False)
InFix = (Hit)
\ ? 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)
\ : RT_string("((x<=1|x>=%d|y<=1|y>=%d)&(x<4|x>=%d)&(y<4|y>=%d))?255:0", W-2,H-2,W-4,H-4)
c.Blankclip(width=W,height=H,Length=1,pixel_type="YV12").Killaudio
return mt_lutspa(relative = false,yExpr=mt_Polish(InFix), chroma = "128")
}

Function ShowMarker(clip c,int x,int y,int w,int h,Int color,bool type,Float "Opacity") {
Opacity=Default(Opacity,1.0)
W=(W<=0) ? c.Width-X+W : W H=(H<=0) ? c.Height-Y+H : H
Msk = c.RectMarker(W+2,H+2,type) Mrk=Msk.BlankClip(Color=Color)
Return c.Overlay(Mrk,x=X-1,y=Y-1,Mask=Msk,Mode="Blend",Opacity=Opacity)
}

GSCript("""
Function FindSub(clip c,int X,int Y,int W,int H,Int Text_w,Int Text_h,Int Halo_w,Int Halo_h,clip dc) {
c
n=current_frame
Thresh=Min((Text_w+Halo_w*2)*100.0/W,(Text_h+Halo_h*2)*100.0/H)
Bingo = dc.RT_YInRangeLocate(x=x,y=y,w=W,h=H,Baffle_w=Text_w+Halo_w,Baffle_h=Text_h+Halo_H,lo=255,hi=255,Thresh=Thresh)
if(Bingo) {
OverLay(Last.BlankClip(color=$FFFFFF,width=YIRL_W,height=YIRL_H),x=YIRL_X,y=YIRL_Y,opacity=0.2)
RT_Subtitle("%d] Text @ x=%d y=%d w=%d h=%d",n,YIRL_X,YIRL_Y,YIRL_W,YIRL_H)
}
Return Last
}
""")

MPEG2Source("C:\Anime Encoding\Hardsub Removal\NoSub.d2v")
TFM().TDecimate()
Crop(2, 0, -2, 1080, align=False)
Trim(696, 4675)++Trim(6354,16279)++Trim(18438,38456)++Trim(39896,40254)
Spline36Resize(1280,720)
Trim(0,13897)++Trim(13906,0)
Trim(0,25924) ++ Trim(25926,33915) ++ Trim(33904,33915) ++ Trim(33916, 0) #Trims made to match the hardsubbed clip
FreezeFrame(33916, 33927, 33915)
ConvertToRGB24
NOS=Last ## <<no-subtitle source>>

FFVideoSource("C:\Anime Encoding\Hardsub Removal\HardSubbed.mkv")
Trim(82, 0)
Trim(0,25763)++Trim(25765,0) #Trims made to match other clip
ConvertToRGB24
SUB=Last ## <<subtitle source>>

### Subtitle Search area
X = 100
Y = Height-180
W = -X
H = -8
#
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_W = 6 # Halo width in pixels (horizontal minimum, Could still be more Halo outside of detected area)
HALO_H = 6 # Halo height in pixels (vertical minimum, Could still be more Halo outside of detected area)
TEXTCOL = $FEFEFE
HALOCOL = $010101
CHANVAR = 1 # Text and Halo RGB channels can vary by as much as CHANVAR, eg $FEFEFE with CHANVAR=1 ranges $FDFDFD -> $FFFFFF
SHOWAREA = True # Set True to mark subtitle scan area
BLANKCOL = $808080 # Color used if DOBLANK ie Blankclip color
DOBLANK = False # Use only BlankClip not video
DOAUDIO = False # Use audio
###
#Blank=AudioDub(Last.BlankClip(Color=BLANKCOL),Last) # Same size, FPS and frames as Template clip
Last=(DOBLANK)?Blank:Last
!DOAUDIO?KillAudio:NOP
#
#TextSub(SRT) (this line commented out & moved to top of script)
#
ORG=Last

W=(W<=0)?Width-X+W:W H=(H<=0)?Height-Y+H:H
TB=RT_BitAnd(TextCol,$FF) TextCol=TextCol/256 TG=RT_BitAnd(TextCol,$FF) TextCol=TextCol/256 TR=RT_BitAnd(TextCol,$FF)
TBLo=Max(TB-ChanVar,0) TGLo=Max(TG-ChanVar,0) TRLo=Max(TR-ChanVar,0)
TBHi=Min(TB+ChanVar,255) TGHi=Min(TG+ChanVar,255) TRHi=Min(TR+ChanVar,255)
HB=RT_BitAnd(HaloCol,$FF) HaloCol=HaloCol/256 HG=RT_BitAnd(HaloCol,$FF) HaloCol=HaloCol/256 HR=RT_BitAnd(HaloCol,$FF)
HBLo=Max(HB-ChanVar,0) HGLo=Max(HG-ChanVar,0) HRLo=Max(HR-ChanVar,0)
HBHi=Min(HB+ChanVar,255) HGHi=Min(HG+ChanVar,255) HRHi=Min(HR+ChanVar,255)
LimS="((x>=%d)&(x<=%d))?255:0"
TRed=ShowRed (Pixel_Type="YV12").mt_lut(mt_Polish(RT_string(LimS,TRLo,TRHi)))
TGrn=ShowGreen(Pixel_Type="YV12").mt_lut(mt_Polish(RT_string(LimS,TGLo,TGHi)))
TBlu=ShowBlue (Pixel_Type="YV12").mt_lut(mt_Polish(RT_string(LimS,TBLo,TBHi)))
HRed=ShowRed (Pixel_Type="YV12").mt_lut(mt_Polish(RT_string(LimS,HRLo,HRHi)))
HGrn=ShowGreen(Pixel_Type="YV12").mt_lut(mt_Polish(RT_string(LimS,HGLo,HGHi)))
HBlu=ShowBlue (Pixel_Type="YV12").mt_lut(mt_Polish(RT_string(LimS,HBLo,HBHi)))
TXT=Mt_Logic(TRed,TGrn,"and").Mt_Logic(TBlu,"and")
HAL=Mt_Logic(HRed,HGrn,"and").Mt_Logic(HBlu,"and")
GSCript("""
for(i=1,HALO_H) {TXT=TXT.Mt_Expand(mode="vertical")}
for(i=1,HALO_W) {TXT=TXT.Mt_Expand(mode="horizontal")}
for(i=1,TEXT_H) {HAL=HAL.Mt_Expand(mode="vertical")}
for(i=1,TEXT_W) {HAL=HAL.Mt_Expand(mode="horizontal")}
Res=Mt_Logic(TXT,HAL,"and")
""")
args="X,Y,W,H,Text_w,Text_h,Halo_w,Halo_h,res"
ORG=ORG.ScriptClip("FindSub("+args+")",args=args)
ORG=(SHOWAREA)?ORG.ShowMarker(X,Y,W,H,$FFFFFF,true,0.25):ORG
TXT=TXT.ConvertToRGB24
HAL=HAL.ConvertToRGB24
res=res.ConvertToRGB24

LFT=StackVertical(ORG,TXT.RT_Subtitle("\a!TEXT COLOR"))
RGT=StackVertical(HAL.RT_Subtitle("\a!HALO COLOR"),Res.RT_Subtitle("\a!DETECT"))
StackHorizontal(Lft,Rgt)

##[[ OUTPUT - pick one; comment out the others
#return Last ## diagnostic, 4-way split
#return Overlay(SUB, NOS, mask=res, opacity=0.9) ## test, subtitles show faintly
return Overlay(SUB, NOS, mask=res) ## final run, subtitles removed completely
#]]

Thank you for investing so much time in this. I will try and post 2 short clips (one hardsub and one without subs) tomorrow.

nor wanted to feel like
there were people creeping all around me whilst playing a movie as a background noise maker, and working at same time
:D

raffriff42
8th September 2016, 03:28
making the change below ...
GSCript("""
for(i=1,HALO_H) {TXT=TXT.Mt_Expand(mode="vertical")}
for(i=1,HALO_W) {TXT=TXT.Mt_Expand(mode="horizontal")}
for(i=1,TEXT_H) {HAL=HAL.Mt_Expand(mode="vertical")}
for(i=1,TEXT_W) {HAL=HAL.Mt_Expand(mode="horizontal")}
Res=Mt_Logic(TXT,HAL,"and", u=-128, v=-128)
""")
...fixes the problem. It's some interaction with your "YV12" mod, which normally would be a good idea. Perhaps the original error you were getting was because of a different MaskTools version... not sure.

EDIT I've run into this kind of problem a lot with MaskTools, and forcing the mask clip to gray is always the solution.

EDIT 2 @StainlessS, use u=-128, v=-128 as above, chroma="128" or chroma="copy" on all MaskTools functions (especially mt_logic & mt_expand) where you are processing a grayscale clip, or you can get invalid U & V data (the clip goes "green").

PS @blaze077, thanks for posting your complete script without having to be asked!!

StainlessS
8th September 2016, 08:53
OK, I'll switch to YV12, The Mt_Tools v2.1.0.0 version I was using is 839KB (859,648 bytes) in size, not sure where I got it (but fairly recent).

blaze077, looking forward to the samples, thanx.

The script basically extracts from RGB color value eg $FEFEFE, the individual R,G,B components of both Text and Halo, then calculates the range limits for
each channel using CHANVAR (just saves user from specifying min and max for each color channel individually for both text and halo).
The ShowRed, etc lines isolate pixels that fall within the acceptable ranges for all 3 channels for text, and then AND's them together so result is pixels where all 3 channels are in acceptable range. Same is then done for HALO.

The for next loop, Expands (swells) the text [edit: by halo HALO_W,HALO_H] so as to swell into the halo region (both horizontally and vertically), and then expands the halo to swell into the text region [edit: by TEXT_W,TEXT_H]. (These are two swelled frames shown in diagnostic as TEXT and HALO frames).
Finally, the expanded/swelled frames are AND'ed together for the diagnostic shown DETECT frame.
This detect frame therefore contains white pixels where text/halo were valid colors, and because of the AND'ed swellings, it also shows where both
text and halo swelled 'into' each other ie where they were adjacent to each other (allows to ignore randomly positioned pixels which just happen to be the
sort after colors).

The FindSub routine just checks the scan area using RT_YInRangeLocate() to see if there is a suspect area of white(good) pixels of sufficient 'bulk'.

EDIT: The plugin I'm using seems to be this one in Downloads v2.0b1 masktools2-x86.zip, here on Wiki:- http://avisynth.nl/index.php/MaskTools2
Seems to works flawlessly for me, Y8.

EDIT: Hit a small problem, TextSub() seems to produce drop shadow halos, and so more black halo below text [EDIT: and to the right] rather than above,
we could improve things here if we could expand in only single direction (ie downwards, or upwards), but we dont know how :(
It still works without this, but a little more error prone and would need to set HALO_H to maximum drop shadow size.

blaze077
8th September 2016, 23:06
Thank you, raffriff. It works now. I have the same version of masktools as you, StainlessS. I even added the plugins again but it doesn't work. It isn't a problem though because the script works now.

The subtitle removal works great for the most part but leaves out certain parts of the subtitle (mostly around the edges). In my clips, the source without the subtitles is actually better quality and is just for testing purposes for now. The subtitles are surrounded by uniform black borders all around.

Also, thank you for the concise explanation of your script.

Lining up clips is a pain though. DGIndex doesn't allow me to do precise frame cutting so I can only offer the best I could to trim to match the hardsubbed video without reencoding. It has a few mismatches in scenes but you can find many scenes with subs that are matching.
Clips here. The hardsubbed video is pretty small in size however, the non-subbed version is a little too big.

I really wish I could assist you but I am not capable of doing so. :(

StainlessS
9th September 2016, 12:42
Thanx, I'll grab a copy later today.
DGIndex precise lineup dont matter, easy to do that here.

Raff, how does one feather, a binary mask ?

EDIT: blaze077, you seem to have a bit of a God complex (profile), why dont you just magic the subtitles away ?

raffriff42
9th September 2016, 13:57
Raff, how does one feather, a binary mask ?The mask may have been created with mt_binary, but it is grayscale. You can Blur it as much as you please.
Even more mt_expand-ing* will be needed, or the subtitles will leak through around the edges.
To expand & blur more easily, I would downscale, expand, blur, upscale.

* edit - see here (http://forum.doom9.org/showthread.php?p=1780335#post1780335) for some mt_expand tricks.

StainlessS
9th September 2016, 14:06
Thanx Raff, easy when you know how :)

blaze077
9th September 2016, 15:19
EDIT: blaze077, you seem to have a bit of a God complex (profile), why dont you just magic the subtitles away ?
Haha, that was quite some time ago. :p

StainlessS
11th September 2016, 05:03
Well about to get some shut eye, so here, something to play with (it aint blisteringly fast, still only detecting).


Function RemoveSubs_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",
\ Bool "Show",Int "stack",Bool "ShowArea",Int "AreaColor") {
c
myName="RemoveSubs_MI: "
Assert(RT_FunctionExist("GScriptClip"),myName+"Essential GRunT plugin installed, http://forum.doom9.org/showthread.php?t=139337")
Assert(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")
c
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)
Show=Default(Show,False) Stack=(Show)?default(Stack,0):0
ShowArea=(Show)?Default(ShowArea,True):False AreaColor=Default(AreaColor,$FF00FF)
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))
DB=RT_GetFullPathName("~"+RT_LocalTimeString+".DB")
/* 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")

FuncS="""
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 Fn@@@(clip c,String DB,
\ 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,
\ Float Thresh_w,Float Thresh_h,
\ clip dc,bool Show,int Stack,bool ShowArea,Int AreaColor) {
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
if(RT_Version >= 1.99902) { # RT_Stats version 2.00Beta2
Bingo = dc.RT_YInRangeLocate(x=x,y=y,w=W,h=H,Baffle_w=Text_w+(Halo_L+Halo_R)*9/10,Baffle_h=Text_h+(Halo_T+Halo_B)*9/10,
\ lo=255,hi=255,Thresh_w=Thresh_w,Thresh_h=Thresh_h)
} else {
Thresh=min(Thresh_w,Thresh_h)
Bingo = dc.RT_YInRangeLocate(x=x,y=y,w=W,h=H,Baffle_w=Text_w+(Halo_L+Halo_R)*9/10,Baffle_h=Text_h+(Halo_T+Halo_B)*9/10,
\ lo=255,hi=255,Thresh=Thresh)
}
Status=(Bingo)?1:2
(Status==1) ? RT_DBaseSet(DB,n,Status,YIRL_X,YIRL_Y,YIRL_W,YIRL_H) : 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))
}
RT_DebugF("OverRiding Range %d,%d",StartF,EndF,name=myName)
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.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

HALO_W_MIN=Min(HALO_L,HALO_R) HALO_W_MAX=Max(HALO_L,HALO_R) HALO_H_MIN=Min(HALO_T,HALO_B) HALO_H_MAX=Max(HALO_T,HALO_B)
HALO_MIN=Min(HALO_W_MIN,HALO_H_MIN) HALO_MAX=Max(HALO_W_MAX,HALO_H_MAX)
for(i=0,HALO_MIN-1) {
RT_DebugF("HALO Square")
TXT=TXT.mt_expand(mode="square", chroma="1")
} ## expand square

if(HALO_W_MAX>HALO_MIN) {
for(i=HALO_MIN,HALO_W_MIN-1) {
RT_DebugF("HALO Horizontal")
TXT=TXT.mt_expand(mode="horizontal", chroma="1")
} ## expand horizontal
if(HALO_W_MAX>HALO_W_MIN) {
mode=HALO_R>HALO_L ? "-1 0 0 0" : " 1 0 0 0"
for(i=HALO_W_MIN,HALO_W_MAX-1) {
RT_DebugF(HALO_R>HALO_L?"HALO right":"HALO left")
TXT=TXT.mt_expand(mode=mode, chroma="1")
} ## expand left or right
}
}

if(HALO_H_MAX>HALO_MIN) {
for(i=HALO_MIN,HALO_H_MIN-1) {
RT_DebugF("HALO Vertical")
TXT=TXT.mt_expand(mode="vertical", chroma="1")
} ## expand vertical
if(HALO_H_MAX>HALO_H_MIN) {
mode=HALO_B>HALO_T ? " 0 -1 0 0" : " 0 1 0 0"
for(i=HALO_H_MIN,HALO_H_MAX-1) {
RT_DebugF(HALO_B>HALO_T?"HALO down":"HALO up")
TXT=TXT.mt_expand(mode=mode, chroma="1")
} ## expand up or down
}
}
TEXT_MIN=Min(TEXT_W,TEXT_H)
for(i=0,TEXT_MIN-1) {
RT_DebugF("TEXT square")
HAL=HAL.Mt_Expand(mode="square", chroma="1")
}
if(TEXT_W>TEXT_MIN) {
for(i=TEXT_MIN,TEXT_W-1) {
RT_DebugF("TEXT horizontal")
HAL=HAL.Mt_Expand(mode="horizontal", chroma="1")
}
}
else if(TEXT_H>TEXT_MIN) {
for(i=TEXT_MIN,TEXT_H-1) {
RT_DebugF("TEXT vertical")
HAL=HAL.Mt_Expand(mode="vertical", chroma="1")
}
}
dc=Mt_Logic(TXT,HAL,"and", chroma="-128")

if(Show && (Stack>=1 && Stack<=2)) {
dc2=dc.Eval(CnvS)
dc2=dc2.Subtitle("DETECT")
if(Stack==2) {
TXT = TXT.Eval(CnvS)
TXT=TXT.Subtitle("TEXT")
HAL = HAL.Eval(CnvS)
HAL = HAL.Subtitle("HALO")
c=StackHorizontal(StackVertical(Last,dc2),StackVertical(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 = "128")
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.4)
}
Thresh_w=(Text_w+(Halo_L+Halo_R)*9/10)*100.0/W Thresh_h=(Text_h+(Halo_T+Halo_B)*9/10)*100.0/H
#######################################
# Unique Runtime Call, GScriptClip must be a one-liner:
#######################################
ARGS="DB,X,Y,W,H,Text_w,Text_h,Halo_L,Halo_T,Halo_R,Halo_B,Thresh_w,Thresh_h,dc,Show,Stack,Showarea,AreaColor"
c.GScriptClip("Fn@@@(last, "+ARGS+")", local=true, args=ARGS)
return Last
"""
#######################################
# Unique Identifier Definition
#######################################
GIFunc="RemoveSubs_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)
GScript(InstS)
CallCmd(close=RT_String("""CMD /C chcp 1252 && del "%s" """,DB), hide=true, Synchronous=7) # Auto delete DB file on clip closure.
Return Last
}


AVISource("Hardsubbed.mkv.AVI")

X = 100
Y = Height-144
W = -X
H = -44
#
TEXT_W = 3 # minimum text pixel 'thickness' Horizontal (horizontal thickness of vertical strokes)
TEXT_H = 3 # minimum text pixel 'thickness' Vertical (vertical thickness of horizontal strokes)
HALO_L = 4 # Left Halo width in pixels
HALO_R = 4 # Right Halo width in pixels
HALO_T = 4 # Top Halo height in pixels
HALO_B = 4 # Bot Halo height in pixels
TEXTCOL = $FDFDFD
TEXTVAR = 2 # Text RGB channels can vary by as much as TEXTVAR, eg $FEFEFE with TEXTVAR=1 ranges $FDFDFD -> $FFFFFF
HALOCOL = $020202
HALOVAR = 2 # Halo RGB channels can vary by as much as HALOVAR, eg $FEFEFE with HALOVAR=1 ranges $FDFDFD -> $FFFFFF
AREACOLOR= $FF00FF
SHOWAREA = True # Set True to mark subtitle scan area
STACK = 0 # 0=Off, 1=2 Window Stack, 2=4 window stack
OverRide = "" # ""=Not used, "*..." multiline string of ranges, "OverRide.txt"=Text file string of ranges.
SHOW =true

#OverRide="OverRide.txt"

/*
# Example String OverRide (1st char is '*'). Ranges OverRidden to NO SUBTITLE
OverRide="""*
10 100 # A comment, SPACE or COMMA Separator
200,300
3000,0
"""
*/

RemoveSubs_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,
\ Show=SHOW,stack=STACK,ShowArea=SHOWAREA,AreaColor=AREACOLOR)

Return Last


EDIT: Updated. Stamped on a few bugs, a bit faster.

StainlessS
11th September 2016, 18:37
Blaze, finally gotten around to looking at the nonsubbed clip.
The hardsubs clip is 1280x720@23.976 and the nonsubbed at 1920x1080@29.97,
are you aware that they are different frame size and frameRate ?

I'll still continue with current script a bit but no way will it be able to perform the required magic on those clips.
I think you said somewhere that thread was just experimentation, if so then need compatible clips.
Dont know if JohnMeyer mentioned Vegas can deal with varying clip characteristics.

blaze077
12th September 2016, 04:18
Blaze, finally gotten around to looking at the nonsubbed clip.
The hardsubs clip is 1280x720@23.976 and the nonsubbed at 1920x1080@29.97,
are you aware that they are different frame size and frameRate ?

I'll still continue with current script a bit but no way will it be able to perform the required magic on those clips.
I think you said somewhere that thread was just experimentation, if so then need compatible clips.
Dont know if JohnMeyer mentioned Vegas can deal with varying clip characteristics.

Oh, yes. Sorry, I forgot to mention that. I simply use the following script to make the clips matching in properties (besides the trimming):

TFM().TDecimate()
Crop(2, 0, -2, 1080, align=False)
Spline64Resize(1280,720)

I tested the new and I can't really say anything because the detection still seems to work well. It highlights all the subtitles very well. It's only on the removal when I can actually see it.

colours
12th September 2016, 17:28
I'm just going to give some generic advice here.

Firstly, this is obviously a rule 6 violation, though I guess this stopped mattering when neuron2 became Guest.

Secondly, if you're looking for help with encoding for fansubs, ask other fansubbers. I hear this is a problem that they have researched reasonably well and have existing solutions for.

Thirdly, anime series licensed from TV Tokyo on Crunchyroll and Funimation tend to have IVTC-related issues, and these issues are usually inconsistent between episodes. A majority of Funimation's streams are fine, but this particular series you're using as an example is not.

Fourthly, you should ensure that the clips align as well as possible, both spatially and temporally. The aforementioned IVTC issues essentially guarantee that temporal alignment will require duplicating and deleting frames at random places (use a script, obviously; doing this manually is insane and a complete waste of time). As for spatial alignment, cropping the subtitle-free source by two pixels on the left and right sides is obviously not the right thing to do, as a frame comparison would tell you; all you have to do is to resize to 720p and you're done.

blaze077
16th September 2016, 02:44
I'm just going to give some generic advice here.

Firstly, this is obviously a rule 6 violation, though I guess this stopped mattering when neuron2 became Guest.

Secondly, if you're looking for help with encoding for fansubs, ask other fansubbers. I hear this is a problem that they have researched reasonably well and have existing solutions for.

Thirdly, anime series licensed from TV Tokyo on Crunchyroll and Funimation tend to have IVTC-related issues, and these issues are usually inconsistent between episodes. A majority of Funimation's streams are fine, but this particular series you're using as an example is not.

Fourthly, you should ensure that the clips align as well as possible, both spatially and temporally. The aforementioned IVTC issues essentially guarantee that temporal alignment will require duplicating and deleting frames at random places (use a script, obviously; doing this manually is insane and a complete waste of time). As for spatial alignment, cropping the subtitle-free source by two pixels on the left and right sides is obviously not the right thing to do, as a frame comparison would tell you; all you have to do is to resize to 720p and you're done.

1. Sorry, I have deleted the links from my posts.
2. That did occur to me but I did not know where to ask and hence, arrived here.
4. I have PMed you.

Thanks you, everyone for your help. :thanks:

StainlessS
2nd October 2016, 17:31
post #1 of 2

I had done this script update anyway, but requires RT_Stats v2.0 Beta2


###
# 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
}

EDITED: Error setting chroma to "1", changed to "-128"

StainlessS
2nd October 2016, 17:31
post #2 of 2

And the client script.

###
# DetectSub_MI_Client.avs"
###

Import("DetectSub_MI.avsi")

AVISource("Hardsubbed.mkv.AVI")

# Subtitle coords
X = 180
Y = Height-140
W = -X
H = -44
# Text, Halo color
TEXTCOL = $FDFDFD
TEXTVAR = 2 # Text RGB channels can vary by as much as TEXTVAR, eg $FEFEFE with TEXTVAR=1 ranges $FDFDFD -> $FFFFFF
HALOCOL = $020202
HALOVAR = 2 # Halo RGB channels can vary by as much as HALOVAR, eg $FEFEFE with HALOVAR=1 ranges $FDFDFD -> $FFFFFF
# 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 = 5 # Left Halo width in pixels
HALO_R = 5 # Right Halo width in pixels
HALO_T = 5 # Top Halo height in pixels
HALO_B = 5 # Bot Halo height in pixels
# Mt_Hysteresis (reduce stray pixels):- http://forum.doom9.org/showthread.php?p=1780589#post1780589
THYSCNT = 5 # Text Mask Mt_Hysteresis inpand count (prior to mt_hysteresis), Dont Mt_Hysteresis if 0
HHYSCNT = 5 # Halo Mask Mt_Hysteresis inpand count (prior to mt_hysteresis), Dont Mt_Hysteresis if 0
DHYSCNT = 5 # 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).
edit: Above seems to be as clear as mud, but I am trying, sorry.
*/
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-2 # 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, was already pretty good, suggest always on).
#
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

blaze077
5th October 2016, 01:57
Thank you, StainlessS for the script and the explanation along with that. I understand it much better now.