View Single Post
Old 27th July 2012, 15:21   #15  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
SEE Update Version Here:
http://forum.doom9.org/showthread.ph...57#post1586857

Here's a nice little script function written using both GScript and RT_Stats, I suspect that those
two plugins are quite often going to be used together. The function, "QueryBorderCrop()" returns the crop coords
to remove letter boxing or other black bars around the edges of a clip.
The return value is a string and you can 'read' the values in Avisynth by using an Eval on the string.

Heres the script:

Code:
Function QueryBorderCrop(clip c,int "Samples",Float "Thresh",bool "Laced",int "XMod",int "YMod",int "WMod",int "HMod",bool "CropMore", \
    bool "Relative", String "Prefix",int "RLBT",bool "DEBUG") {
# QueryBorderCrop v1.06, By StainlessS, Requires GScript & RT_Stats v1.01 Plugins.
# Prescan function to get coords for cropping black borders. Planar, YUY2, RGB.
# Returns a string holding crop coords eg "QBCropX=10 QBCropY=8 QBCropW=640 QBCropH=480", can use eg Eval(QueryBorderCrop()) to set values
# into QBCropX, QBCropY,QBCropW,QBCropH variables. v1.05 Added return variable eg QBCropThresh, perhaps useful if auto Thresh used.
# http://forum.doom9.org/showthread.php?p=1584626#post1584626
#
# Samples=32, Number of frames to sample from source clip c
# Thresh= -18.0, Average luma value below or equal to which is considered possible black border, above considered definitely image.
#   A zero or negative value is 'AutoThresh', will prescan 'Samples' frames (in suspect border area eg height/100), looking for minimum
#   pixel luma value (but ignoring the darkest 1%) and set 'Thresh' to that value plus the negated AutoThresh value,
#   ie default sets Thresh to minimum found Y value + 18.0.
#   Auto cropping will likely fail on END CREDITS ONLY clips, where on black background, and will probably crop off the sides that are no
#   different in average luma to any letterbox borders, if you cannot see the borders, then neither can QueryBorderCrop(), even setting the
#   auto Thresh to eg -1.0 or 0.0 is quite likely to fail. (See RLBT edge bitflags).
# Laced=true, set true for Interlaced.  (Modifies defaults for YMod,HMod, explicit YMod/HMod will override).
# XMod, Default: Planar 2, YUY2=2, RGB=1
# YMod, Default: Planar=2, YUY2=1, RGB=1: BUT, Doubled if laced=true.
# WMod, Default: Planar=4, YUY2=2, RGB=1
# HMod, Default: Planar=2, YUY2=1, RGB=1: BUT, Doubled if laced=true.
# CropMore=false, False = Leave some black for XMod,YMod,WMod,HMod, true=Crop off all black and a bit of image for XMod,WMod,WMod,HMod.
# Relative=false, False returns Width and Height, true returns Width/Height relative eg QBCropW=-6 QBCropH=-4.
# Prefix="QBCrop", string for returned variable names, only use valid variable name characters eg NO SPACES. Default returns eg "QBCropX".
# RLBT=15=All Borders, Bitflags of edges to crop, 15 ($0F) crops all four. Each letter in the name 'RLBT' represents an edge and bit position
# starting with 'R' in bit 3 representing the value 8 (2^3=8). 'L' = bit 2=4 (2^2=4), 'B' = bit 1=2 (2^1=2), 'T' = bit 0=1 (2^0=1).
# To calculate the RLBT bitflags, for 'R'(Right) add 8, for 'L'(Left) add 4, for 'B'(Bottom) add 2, and for 'T'(Top) add 1. 
# Add all of the bit flags together 8+4+2+1 (=15) crops all four edges, 8+4 crops only Right & Left, and 2+1 crops only Bottom & Top.
# DEBUG=False=No Debug. Set True for debugging info, need DebugView: http://technet.microsoft.com/en-gb/sysinternals/bb545027
#
# If not cropping enough border, then increase Samples. If cropping too much border, then decrease Thresh.
    VERS="QueryBorderCrop v1.06 - 7 Aug 2012"
    c
    Laced = Default(Laced,True)  
    XM = IsPlanar() ? 2 : IsYUY2() ? 2 : 1      WM = IsPlanar() ? 4 : IsYUY2() ? 2 : 1
    YM = IsPlanar() ? 2 : IsYUY2() ? 1 : 1      YM = (Laced) ? 2 * YM : YM
    Samples = Default(Samples,32)       Thresh= Float(Default(Thresh,-18.0))    DEBUG=default(DEBUG,False)
    XMod  = Default(XMod,XM)            YMod  = Default(YMod,YM)
    WMod  = Default(WMod,WM)            HMod  = Default(HMod,YM)
    Prefix= Default(Prefix,"QBCrop")
    CropMore = Default(CropMore,false)  Relative= Default(Relative,false)  RLBT=Default(RLBT,15)
    w=Width     h=Height    Frames = Framecount()
    Assert((Samples >= 1), "QueryBorderCrop: Requires Samples>=1")
    Assert(XMod>0 && YMod>0 && WMod>0 && HMod>0,"QueryBorderCrop: XMod,YMod,WMod,HMod Must be at least 1")
    Assert(RLBT>=1 && RLBT<=15,"QueryBorderCrop: RLBT 1->15 Only")
    flgR=(RLBT>=8) RLBT=RLBT % 8    flgL=(RLBT>=4) RLBT=RLBT % 4    flgB=(RLBT>=2) RLBT=RLBT % 2    flgT=(RLBT>=1)
    Samples = (Samples > Frames)? Frames : Samples
    CX=0 CY=0 CW=0 CH=0 Rgt=w/2 Bot=h/2 Lft=Rgt-1 Top=Bot-1
    GScript("""
        if(DEBUG){RT_Debug(":") RT_Debug(VERS,"- By StainlessS") RT_Debug(":")}
        if(Thresh <= 0.0) {
            thmin=255.0 prw=(w/100>=1) ? w/100 : 1  prh=(h/100>=1) ? h/100 : 1
            for(Samp = 1,Samples) {
                Frm = int(Samp * ((Frames - 1.0) / (Samples+1)) + 0.5)          
                if(flgT){th=c.RT_YPlaneMin(Frm,h=prh,  threshold=1.0)    if (thmin>th){thmin=th}}
                if(flgB){th=c.RT_YPlaneMin(Frm,y=h-prh,threshold=1.0)    if (thmin>th){thmin=th}}
                if(flgL){th=c.RT_YPlaneMin(Frm,w=prw,  threshold=1.0)    if (thmin>th){thmin=th}}
                if(flgR){th=c.RT_YPlaneMin(Frm,x=w-prw,threshold=1.0)    if (thmin>th){thmin=th}}
                if(DEBUG){RT_Debug("QBC_AutoThresh:",String(Samp)+")","["+String(Frm)+"]","YPlaneMin="+String(thmin))}
                if(thmin==0.0){Samp = Samples + 1} # No smaller possible, Break.
            }
            Thresh = thmin + (-Thresh) if(DEBUG){RT_Debug("QBC_AutoThresh:","Thresh="+String(Thresh))}
        }
        for(Samp = 1,Samples) {
            Frm = int(Samp * ((Frames - 1.0) / (Samples+1)) + 0.5)
            if(flgT){cnt=0 For(y=0,Top){th=c.RT_AverageLuma(Frm,y=y,h=1,x=CX,w=CW) if(th>Thresh){if(Cnt>=2){Top=y-2 CY=Top y=h
                        if(DEBUG){RT_Debug("QBC_Top:",String(Samp)+")","["+String(Frm)+"]","AveY="+String(th),"CY="+String(CY))}
                        } else {Cnt=Cnt+1}} else {Cnt=0}}}
            if(flgB){cnt=0 For(y=h-1,Bot,-1){th=c.RT_AverageLuma(Frm,y=y,h=1,x=CX,w=CW) if(th>Thresh){if(Cnt>=2){Bot=y+2 CH=-(h-1-Bot) y=0
                        if(DEBUG){RT_Debug("QBC_Bot:",String(Samp)+")","["+String(Frm)+"]","AveY="+String(th),"CH="+String(CH))}
                        } else {Cnt=Cnt+1}}else {Cnt=0}}}
            if(flgL){cnt=0 For(x=0,Lft){th=c.RT_AverageLuma(Frm,x=x,w=1,y=CY,h=CH) if(th>Thresh){if(Cnt>=2){Lft=x-2 CX=Lft x=w
                        if(DEBUG){RT_Debug("QBC_Lft:",String(Samp)+")","["+String(Frm)+"]","AveY="+String(th),"CX="+String(CX))}
                        } else {Cnt=Cnt+1}}else {Cnt=0}}}
            if(flgR){cnt=0 For(x=w-1,Rgt,-1){th=c.RT_AverageLuma(Frm,x=x,w=1,y=CY,h=CH) if(th>Thresh){if(Cnt>=2){Rgt=x+2 CW=-(w-Rgt-1) x=0
                        if(DEBUG){RT_Debug("QBC_Rgt:",String(Samp)+")","["+String(Frm)+"]","AveY="+String(th),"CW="+String(CW))}
                        } else {Cnt=Cnt+1}}else {Cnt=0}}}
#            if((!flgT||Top==0) && (!flgB||Lft==0) && (!flgL||Bot==h-1) && (!flgR||Rgt==w-1))  # Ooops v1.05
            if((!flgT||Top==0) && (!flgL||Lft==0) && (!flgB||Bot==h-1) && (!flgR||Rgt==w-1))
                {Samp = Samples + 1} # Does Not Require Cropping, Break.
        }
        XMode = (CropMore) ? XMod-1 : 0                  YMode = (CropMore) ? YMod-1 : 0        
        CX = int((CX+XMode)/XMod)*XMod                   CY = int((CY+YMode)/YMod)*YMod
        WW = w  - CX    HH = h  - CY    CW = WW + CW     CH = HH + CH
        WMode = (CropMore)?0:(WMod-1 < WW-CW) ? WMod-1 : WW-CW
        HMode = (CropMore)?0:(HMod-1 < HH-CH) ? HMod-1 : HH-CH
        CW = int((CW+WMode)/WMod)*WMod                   CH = int((CH+HMode)/HMod)*HMod
        if(Relative) {CW = -(WW -  CW)                   CH = -(HH - CH)}
        RS=Prefix+"X="+String(CX) + " " + Prefix+"Y=" + String(CY) + " " + Prefix+"W=" + String(CW) + " " + Prefix+"H=" + String(CH)
        RS=RS+ " " + Prefix+"Thresh="+String(Thresh)   # Return used Thresh, might be useful to avoid 2nd prescan for AutoThresh.
        if(DEBUG){RT_Debug("QBC_Return:",RS)}
    """)
    Return RS
}
And a test snippit:
Code:
import("D:\avs\bank\QueryBorderCrop.avs")
avisource("D:\avs\avi\1.avi")
Addborders(10,8,6,4)

DEBUG=True # Need DebugView: http://technet.microsoft.com/en-gb/sysinternals/bb545027

CropString=QueryBorderCrop(debug=DEBUG)

Eval(CropString)   # Assign return values to QBCropX QBCropY QBCropW QBCropH and QBCropThresh
Crop(QBCropX,QBCropY,QBCropW,QBCropH)
Subtitle(String(QBCropX),Align=7)
Subtitle(String(QBCropY),Align=8)
Subtitle(String(Width),Align=9)
Subtitle(String(Height),Align=2)
Subtitle(String(CropString),Align=5)
return last
v1.03, Added auto 'Thresh' functionality.
v1.04, Added RLBT edge Bitflags.
v1.05, Now returns used Thresh as eg QBCropThresh. Added Debug mode.
v1.06, EDIT: Fixed silly bug in v1.05, hilighted in source

SEE Update v1.07 Version Here:
http://forum.doom9.org/showthread.php?p=1586857#post1586857

If you want the coords for a resize without any black (instead of cropping of image) then set
XMod, YMod, WMod and HMod to 1 and use returned coords in a resize function. The below linked
function can be called with the crop coords prior to resize, to calculate the resultant Display Aspect Ratio
after resize and signaled to MeGUI so that you do not have to set DAR manually in MeGUI.

Below a post with script function to calc resultant Display Aspect Ratio after crop/resize with crop.
http://forum.doom9.org/showthread.ph...93#post1576193
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 23rd August 2012 at 02:07. Reason: update
StainlessS is offline   Reply With Quote