Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Usage

Reply
 
Thread Tools Search this Thread Display Modes
Old 6th January 2023, 08:25   #1  |  Link
coolgit
Registered User
 
Join Date: Apr 2019
Posts: 217
Letterbox detector

Here the suppose final scripts.

LetterBox detector.

Code:
video=LSMASHVideoSource("Filename").ConvertBits(8, dither=0).KillAudio()
#video=FFmpegSource2("Filename").KillAudio()
video
src=last

LeftA = 220     # For analysing border.
TopA = 0
RightA = 220
BottomA = 0

Left = 240     # For fixing letterbox.
Top = 0
Right = 240
Bottom = 0

Th1 = 18.0      # Threshold variables. Ensure black frames are the same blackness.
Th2 = 17.0      # Ensure letterbox exist and fix letterbox blackness after levels/filter adjustment.
Th3 = 16.0      # Ensure ImageMask isn't 100% black. 
Th4 = 150.0     # Detect white frames and fade in/out. Experimental Th4.

LB = $008080    # $008080 Letterbox colour. $FF00FF - see changes for debugging.

BorderMaskL = last.BlankClip().LetterBox(TopA, BottomA, LeftA, 0, $FFFFFF)  # White where there is border, else black. Leftside.
BorderMaskR = last.BlankClip().LetterBox(TopA, BottomA, 0, RightA, $FFFFFF)  # White where there is border, else black. Rightside.
BorderMask = last.BlankClip().LetterBox(TopA, BottomA, LeftA, RightA, $FFFFFF)  # White where there is border, else black.
ImageMask  = BorderMask.Invert


LBox="""
#    YPMin = RT_YPlaneMin()
    FrameB = RT_YPlaneMax()
#    FrameW = RT_AverageLuma()
    BorderL = RT_YPlaneMax(Mask=BorderMaskL,MaskMin=128,MaskMax=255)    # Measure area that is white in BorderMaskL.
    BorderR = RT_YPlaneMax(Mask=BorderMaskR,MaskMin=128,MaskMax=255)    # Measure area that is white in BorderMaskR.
    Image  = RT_YPlaneMax(Mask=ImageMask ,MaskMin=128,MaskMax=255)      # Measure area that is white in ImageMask.
    if (FrameB <= Th1) {
        Levels(0, 1.0, 255, 0, 0, coring=false)
#        Subtitle("Black Frame",Size=64,align=5)
#    } else if (FrameW > Th4) {
#        Dissolve()# or use Vdub2 curve editor or whatever filter fixes the problem. Use 'Video Debug.avs' to check if white frames exist.
#        Subtitle("White Frame",Size=64,align=5)
    } else if (BorderL <= Th2 && BorderR <= Th2 && Image > Th3) {
        SmoothLevels(0, 1.0, 255, 8, 255, Lmode=2, brightSTR=100, chroma=100, limiter=0, useMT=10)
        Letterbox(top, bottom, left, right, color_yuv=LB)
#        Subtitle("Has Border",Size=64,align=5)
    } else {
        SmoothLevels(0, 1.0, 255, 4, 255, Lmode=2, brightSTR=500, chroma=100, limiter=0, useMT=10)#.SmoothTweak(brightness=0, contrast=1.0, saturation=1.0, hue1=0, hue2=0, Lmode=0, limiter=false, useMT=10)
#        Subtitle("No Border",Size=64,align=5)
    }
    Return Last
"""

GScriptClip(Last,LBox)

#StackVertical(src.ColorYUV(analyze=true),last.ColorYUV(analyze=true))
StackHorizontal(src.ColorYUV(analyze=true),last.ColorYUV(analyze=true))

Return Last
Video Debug.

Code:
video=LSMASHVideoSource("Filename").ConvertBits(8, dither=0).KillAudio()
#video=FFmpegSource2("Filename").KillAudio()
video
src=last

Left = 220
Top = 0
Right = 220
Bottom = 0

Th1 = 16.0     # Threshold variables. Ensure black frames are the same blackness.
Th2 = 16.0     # Ensure letterbox exist and fix letterbox blackness after levels/filter adjustment.
Th3 = 16.0     # Ensure ImageMask isn't 100% black.
Th4 = 150.0    # Detect white frames and fade in/out. Fade needs to be fix manually.

BorderMaskL = last.BlankClip().LetterBox(Top, Bottom, Left, 0, $FFFFFF)  # White where there is border, else black. Leftside.
BorderMaskR = last.BlankClip().LetterBox(Top, Bottom, 0, Right, $FFFFFF)  # White where there is border, else black. Rightside.
BorderMask = last.BlankClip().LetterBox(Top, Bottom, Left, Right, $FFFFFF)  # White where there is border, else black.
ImageMask  = BorderMask.Invert

Debug="""
    YPMin = RT_YPlaneMin()
    FrameB = RT_YPlaneMax()
    FrameW = RT_AverageLuma()
    BorderL = RT_YPlaneMax(Mask=BorderMaskL,MaskMin=128,MaskMax=255)    # Just measure area that is white in BorderMaskL.
    BorderR = RT_YPlaneMax(Mask=BorderMaskR,MaskMin=128,MaskMax=255)    # Just measure area that is white in BorderMaskR.
    Image  = RT_YPlaneMax(Mask=ImageMask,MaskMin=128,MaskMax=255)    # Just measure area that is white in ImageMask for black frame.
    if (FrameB <= Th1) {
        RT_DebugF("%d Min Luma=%f Max Luma=%f Average Luma=%f Left Border=%f Right Border=%f Image=%f BLACK FRAME",current_frame,YPMin,FrameB,FrameW,BorderL,BorderR,Image)
#        Subtitle("BLACK FRAME",Size=64,align=5) # Disable Subtitle to increase FPS by x4
    } else if (BorderL <= Th2 && BorderR <= Th2 && Image > Th3) {
        RT_DebugF("%d Min Luma=%f Max Luma=%f Average Luma=%f Left Border=%f Right Border=%f Image=%f HAS BORDER",current_frame,YPMin,FrameB,FrameW,BorderL,BorderR,Image)
#        Subtitle("HAS BORDER",Size=64,align=5) # Disable Subtitle to increase FPS by x4
    } else if (FrameW > Th4) {
        RT_DebugF("%d Min Luma=%f Max Luma=%f Average Luma=%f Left Border=%f Right Border=%f Image=%f WHITE FRAME",current_frame,YPMin,FrameB,FrameW,BorderL,BorderR,Image)
#        Subtitle("WHITE FRAME",Size=64,align=5)# Disable Subtitle to increase FPS by x4
    } else {
        RT_DebugF("%d Min Luma=%f Max Luma=%f Average Luma=%f Left Border=%f Right Border=%f Image=%f NO BORDER",current_frame,YPMin,FrameB,FrameW,BorderL,BorderR,Image)
#        Subtitle("NO BORDER",Size=64,align=5)# Disable Subtitle to increase FPS by x4
    }
    Return Last
"""

GScriptClip(Last,Debug)


#StackHorizontal(src.ColorYUV(analyze=true),last.ColorYUV(analyze=true))
return last
Run Video debug script to get the required info in debug viewer.
Copy and paste into Notepad++.
Remove RT_DebugF: to avoid line auto wrap.
ctrl+M find 'black frame' and mark all. Do the same for white frame. Find 'has border' and mark all with bookmark line ticked.
Check 'find' highlights are grouped continuously. Ie can not have 'has border' then next line 'black frame' then next line 'has border'.
Scroll down or pgdn key, scanning at Min Luma - 5,7,4,6,7,3,8,4,6,7,6,7,8 (vertical) and so on until you get - 12,14,15,13,16,15,14,15,16,14 and so on. Vdub2 - Group 1st example as first trim file
making sure SmoothLevels output low is 8 to 10. Group 2nd example as second trim file with output low 4. So on.

Done 5 video clips and range from 5 to 12 trims. Better than typing in 40 to 60 trim() and having to be super careful not to get the frame numbers wrong. Plus a few trims correcting other 'defect' done separately.

Black fade in to out isn't a problem 99% of the time. If the fade looks bad then trim using vdub 2 curve editor. Easy.


***************
Below original query.

I have many videos with 16/9 and some 4/3 with letterbox mixed in and the levels are off.

The long version would be using trim function.

However, I want to automate it instead.

My idea is -

Code:
If frame averageluma < 16

then Levels(0, 1.0, 255, 0, 0, coring=false)

else if frame has letterbox and averageluma < 16

then SmoothLevels(0, 1.0, 255, 16, 235).Letterbox(0,0,240,240)

else SmoothLevels(0, 1.0, 255, 16, 235)
So what is the best way to do this? It seems Gscript would be ideal. Averageluma function should work.

However, for the life of me, i can't find any functions/plugins/whatever that allows me to search an area of a frame. In this case searching for letterbox would be 240x1080 left and right. I suppose i don't need to do 240 and i am sure 100x1080 is sufficient to prove letterbox exist. I know there is location specific part of frame but they all seem to be for logo removal.

Last edited by coolgit; 22nd January 2023 at 20:05. Reason: Add final scripts.
coolgit is offline   Reply With Quote
Old 6th January 2023, 09:31   #2  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Is this what you want, RoboCrop(Blank=True) :- https://forum.doom9.org/showthread.php?t=168053

EDIT: Oops no it ain't (after reading your post again properley), sorry.

Doing it frame by frame is destined to failure, must be at least scene based, you gotta detect scene ranges beforehand.

EDIT: This is what your script seems to be doing,

Code:
#If frame averageluma < 16
If frame Is BLACK
    #then Levels(0, 1.0, 255, 0, 0, coring=false)
    then FRAME = BLACK
#else if frame has letterbox and averageluma < 16
else if frame has letterbox and is also BLACK
    #then SmoothLevels(0, 1.0, 255, 16, 235).Letterbox(0,0,240,240)
    then compress PC levels range 0->255 to to TV.Levels 16 -> 235 and letterbox with black for good measure
#else SmoothLevels(0, 1.0, 255, 16, 235)
else compress PC levels range 0->255 to to TV.Levels 16 -> 235
Maybe intent need to be a bit more explicit, too ambiguous.
__________________
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; 6th January 2023 at 10:50.
StainlessS is offline   Reply With Quote
Old 6th January 2023, 10:41   #3  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Suggest take look at DBSC:- https://forum.doom9.org/showthread.php?t=171624

In particular (and a few posts following):- https://forum.doom9.org/showthread.p...83#post1733883

and :- https://forum.doom9.org/showthread.p...60#post1709460

Both for the DBSC_ProcessByDAR() thingy.

I aint got time to assist, I'm actually tryin' to find time to update DBSC, and it will likely take a couple of weeks if I am not interrupted.

EDIT: And this:- [Automatically apply different processing to letterboxed clips] :- https://forum.doom9.org/showthread.php?t=171777
__________________
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; 6th January 2023 at 11:16.
StainlessS is offline   Reply With Quote
Old 7th January 2023, 23:35   #4  |  Link
coolgit
Registered User
 
Join Date: Apr 2019
Posts: 217
This is what i have so far.

Quote:
# Slight modification of Manolito's code

#src=FFVideoSource(".mkv")
#src=FFmpegSource2(".avi")
LSMASHVideoSource("filename.mp4", format="YUV420P10", fpsnum=25, fpsden=1).ConvertBits(8, dither=0).KillAudio()

# Slight modification of Manolito's code

L = 0 # L is left
T = 0 # T is top
R = 1820 # R is right
B = 1080 # B is bottom


# Make the values MOD4

#L = L - (L % 4)
#T = T - (T % 4)
#R = (R + 3) / 4 * 4
#B = (B + 3) / 4 * 4


FrameArea = crop(L,T,R-L,B-T)
Left = L > 0 ? crop(0,T,L,B-T) : NOP
Top = T > 0 ? crop(0,0,width(),T) : NOP
Right = R < width() ? crop(R,T,width()-R,B-T) : NOP
Bottom = B < height() ? crop(0,B,width(),height()-B) : NOP
Last = FrameArea

GScript("""
al=AverageLuma()
if(src.al < 16){
Levels(0, 1.0, 255, 0, 0, coring=false)
}
else if(FrameArea().al < 16){
SmoothLevels(0, 1.0, 255, 16, 235).Letterbox(0,0,240,240)
}
else {
SmoothLevels(0, 1.0, 255, 16, 235)
}
Return last
""")

IsClip(Left) ? StackHorizontal(Left, Last) : NOP
IsClip(Top) ? StackVertical(Top, Last) : NOP
IsClip(Right) ? StackHorizontal(Last, Right) : NOP
IsClip(Bottom) ? StackVertical(Last, Bottom) : NOP

return Last.ColorYUV(analyze=true)
I can't seem to fix this error.

Avisynth open failure:
Average plane: this filter can only be used within run-time filters.
([gscript], line 2)
frame area.avs line 42 - which is """)

Comment out GScript(""" and """) as not needed in avs+ I think.

Get error same as above but line 31 - which is al=AverageLuma()

Any ideas anyone
coolgit is offline   Reply With Quote
Old 8th January 2023, 00:39   #5  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Where is the Manolito script ?

[I'll point in right direction, but aint doing anything past that (results may be automated but, I dont believe it will work well)]
It has to be done in ScriptClip, or in Gscript setting current_frame at each frame number. (for runtime functions, etc AverageLuma)
Also, probably not faster than manolito's trims, only advantage maybe is automated instead of hand edit trim / splice (If thats what Mani's did).
__________________
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; 8th January 2023 at 00:49.
StainlessS is offline   Reply With Quote
Old 8th January 2023, 00:43   #6  |  Link
coolgit
Registered User
 
Join Date: Apr 2019
Posts: 217
https://forum.doom9.org/showthread.php?t=166086
coolgit is offline   Reply With Quote
Old 8th January 2023, 01:48   #7  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
This is function equivalent to Mani's script:- https://forum.doom9.org/showthread.p...43#post1603343
Code:
Function AreaOp(clip c,int x1,int y1,int x2, int y2, String Op) { # https://forum.doom9.org/showthread.php?p=1603343#post1603343
/*
    x1 is left coord.
    x2 is leftmost pixel of unprocessed Right border (or x2=Width if no Right border)
    y1=top coord.
    y2 is topmost pixel of unprocessed Bottom border (or y2=Height if no Bottom border)
    op is Operation eg "BlackNess()" OR "Levels(16,1.0,235,235,16,coring=False)"
*/
    # Mod 4 coords
    x1 = x1 - (x1 % 4)
    y1 = y1 - (y1 % 4)
    x2 = (x2 + 3) / 4 * 4
    y2 = (y2 + 3) / 4 * 4

    Area=c.crop(X1,Y1,X2-X1,Y2-Y1)

    Above = Y1 > 0          ? c.crop(0,0,c.width(),Y1)              : NOP
    Below = Y2 < c.height() ? c.crop(0,Y2,c.width(),c.height()-Y2)  : NOP
    Left = X1 > 0           ? c.crop(0,Y1,X1,Y2-Y1)                 : NOP
    Right = X2 < c.width()  ? c.crop(X2,Y1,c.width()-X2,Y2-Y1)      : NOP

    Eval("Area." + OP)

    IsClip(Left)  ? StackHorizontal(Left, Last)  : NOP
    IsClip(Right) ? StackHorizontal(Last, Right) : NOP
    IsClip(Above) ? StackVertical(Above, Last)   : NOP
    IsClip(Below) ? StackVertical(Last, Below)   : NOP
    Return Last
}
and a test client
Code:
ColorBars()

X1=100
X2=400
Y1=100
Y2=200

AreaOp(x1,y1,x2,y2,"Blackness()")
#ConvertToYV12().AreaOp(x1,y1,x2,y2,"Descratch()")
__________________
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; 8th January 2023 at 05:18.
StainlessS is offline   Reply With Quote
Old 8th January 2023, 04:28   #8  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
I think this works OK (Not much testing),
does similar to above post, but with x,y,w,h coords for inner area (as in crop),
It requires YUV444 (eg YV24) or RGB input OR colorspace compatible crop coords.

Code:
Function AreaOp_444(clip c,int x,int y,int w, int h, String Op) {
/*
    YUV444 (eg YV24) or RGB only (or coords already crop compatible with colorspace eg all mod 2 for YV12, else error)
    x,y,w,h, coords of inner area as per crop(x,y,w,h), w and h can be <= 0 where width or height relative.
    op is Operation eg "BlackNess()" OR "Levels(16,1.0,235,235,16,coring=False)"
*/
    # Make w and h -ve or 0, ie width or height relative.
    w = (w <= 0) ? w : (x + w) - c.Width()
    h = (h <= 0) ? h : (y + h) - c.Height()

    Area=c.crop(x,y,w,h)        # Inner Area


    # Borders, Full width top and bottom, short left and right
    Above = (y>0)   ? c.crop(0,0,c.width(),y)             : NOP
    Below = (h<0)   ? c.crop(0,c.Height()+h,c.width(),0)  : NOP
    Left =  (x>0)   ? c.crop(0,y,x,h)                     : NOP
    Right = (w<0)   ? c.crop(c.Width+w,y,0,h)             : NOP

    Eval("Area." + OP)

    IsClip(Left)  ? StackHorizontal(Left, Last)  : NOP
    IsClip(Right) ? StackHorizontal(Last, Right) : NOP
    IsClip(Above) ? StackVertical(Above, Last)   : NOP
    IsClip(Below) ? StackVertical(Last, Below)   : NOP
    Return Last
}

BlankClip(Color=$FF0000)    # RGB32 crop mod 1

# Coords as for crop
AreaOp_444(5,7,-2,-54,"BlackNess()")


I'll come back again tomorrow.
__________________
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; 8th January 2023 at 05:18.
StainlessS is offline   Reply With Quote
Old 8th January 2023, 15:33   #9  |  Link
coolgit
Registered User
 
Join Date: Apr 2019
Posts: 217
Blimey... I had a plan.

To get the basic script working then modify Manolito's script to create my first function, similar to VoodooFX's inpaintloc and use some of VoodooFX code to allow ltrb coords similar to vdub.

Just spent a day researching how to create a function, jotting down some ideas and codes to use.

Then out of the blue you had already created a basic function... 10 bleeding years ago.

You could have posted it in your first reply

Done some tests and it worked as intended.

I need to get the 2nd part, Gscript to work, at the moment i am getting this annoying runtime error.

When that is done, i intend to expand the function itself. One step and a time.

Ideas I have for example:-
- to use the function for scene change detection - SCSelect_HBD - by zooming in the frame, say 50 off for all sides thus ignoring dodgy borders that may throw up false detection.
- to use the function for removing defects persistently in one area - spotless - fixing defect inside the cropped area and ignoring the rest of the frame. Should be useful if the rest of the frame has lots of motion and left untouched.
coolgit is offline   Reply With Quote
Old 8th January 2023, 16:30   #10  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
My idea was to create two masks, using above func [or via BlankClip and Letterbox],
can use mask mode of some RT_Stats (8 bit only) to measure eg Averageluma of total outer border area,
and/or inner area. And also can apply filter to inner area using AreaOp_444().
EDIT: Instead of two masks, can use one mask and altered MaskMin/MaskMax args in the calls to RT_Stats funcs.
EDIT:
Quote:
I need to get the 2nd part, Gscript to work, at the moment i am getting this annoying runtime error.
With AVS+, you dont need GScript(" ... "), simple for() loop iterating every frame and splice frames together [which is what I think you were trying to avoid (although dont need hand edited trims)],

or

using ScriptClip [Or GScriptClip from Grunt], where splicing is done by ScriptClip.

If using For(n=0,FrameCount EDIT: FrameCount-1) loop, then inside you need to set current_frame to the frame number (n) so that AverageLuma (or whatever) knows what frame to sample.
current_frame=n, is necessary as it tricks AVS into thinking its in runtime mode (eg ScriptClip), and AverageLuma (and other runtime funcs) then works ok.

EDIT:
Code:
****************************************
******* MASKED Luma Y Functions ********
****************************************

Compile time/runtime functions, Planar, YUY2, RGB24 & RGB32. (RGB internally converted to YUV-Y).

The compiletime/runtime clip functions share some common characteristics:-

The 'n' arg is an optional frame number and defaults to 'current_frame' if not specified.
The x,y,w,h, coords specify the source rectangle under scrutiny and are specified as for Crop(), the default 0,0,0,0 is full frame.
If 'interlaced' is true, then every other line is ommited from the scan, so if eg y=1, then scanlines 1,3,5,7 etc are scanned,
if eg y=4 then scanlines 4,6,8,10 etc are scanned. The 'h' coord specifies the full height scan ie same whether interlaced is true
or false, although it will not matter if the 'h' coord is specified as eg odd or even, internally the height 'h' is reduced by 1
when interlaced=true and 'h' is even.

Matrix: Conversion matrix for conversion of RGB to YUV-Y Luma.  0=REC601 : 1=REC709 : 2 = PC601 : 3 = PC709,
  Default = (Width > 1100 OR Height>600) then 3(PC709) else 2(PC601). YUV not used

The optional mask clip, governs which pixels are processed by the functions. Where a luma pixel in selected area of the the mask clip is
in range "MaskMin" to "MaskMax" inclusive, then those pixels will be processed. The Mask must also be Planar but not
necessarily the same colorspace as clip c, also must be same dimensions and have at least the same number of frames as clip c.
Calling without mask clip OR with MaskMin=0,MaskMax=255 will effectively ignore the mask and scan full x,y,w,h area.


RT_YPlaneMin(clip c,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,bool "interlaced"=false,
      float "threshold"=0.0, int "Matrix"=(Width>1100||Height>600?3:2),clip "mask"=NOT_USED,int "MaskMin"=128,"MaskMax"=255)
  Return int -1, if no valid pixels in Mask clip.
  Returns int value minimum luma (0 -> 255) in frame(n+delta) for area x,y,w,h.
  Threshold is a percentage, stating how many percent of the pixels are allowed below minimum (ignore extreme pixels ie noise).
  Threshold is % of valid mask pixels processed if Mask supplied. The threshold is optional and defaults to 0.0.

***
***
***

RT_YPlaneMax(clip c,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,bool "interlaced"=false,
      float "threshold"=0.0,int "Matrix"=(Width>1100||Height>600?3:2),clip "mask"=NOT_USED,int "MaskMin"=128,"MaskMax"=255)
  Return int -1, if no valid pixels in Mask clip.
  Returns int value maximum luma (0 -> 255) in frame(n+delta) for area x,y,w,h.
  Threshold is a percentage, stating how many percent of the pixels are allowed above maximum (ignore extreme pixels ie noise).
  Threshold is % of valid mask pixels processed if Mask supplied. The threshold is optional and defaults to 0.0.

***
***
***

RT_YPlaneMinMaxDifference(clip c,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,
      bool "interlaced"=false,float "threshold"=0.0, int "Matrix"=(Width>1100||Height>600?3:2),clip "mask"=NOT_USED,int "MaskMin"=128,"MaskMax"=255)
  Return int -1, if no valid pixels in Mask clip.
  Returns int value luma range (maximum - minimum difference) (0 -> 255) in frame(n+delta) for area x,y,w,h.
  Threshold is a percentage, stating how many percent of the pixels are allowed below minimum or above maximum (ignore extreme pixels ie noise).
  Threshold is % of valid mask pixels processed if Mask supplied. The threshold is optional and defaults to 0.0.

***
***
***

RT_YPlaneMedian(clip c,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,bool "interlaced"=false,
    int "Matrix"=(Width>1100||Height>600?3:2),clip "mask"=NOT_USED,int "MaskMin"=128,"MaskMax"=255)
  Return int -1, if no valid pixels in Mask clip.
  Returns int value luma median [equiv RT_YPlaneMin(threshold=50.0)] (0 -> 255) in frame(n+delta) for area x,y,w,h.

***
***
***

RT_AverageLuma(clip c,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,bool "interlaced"=false,
    int "Matrix"=(Width>1100||Height>600?3:2),clip "mask"=NOT_USED,int "MaskMin"=128,"MaskMax"=255)
  Return int -1, if no valid pixels in Mask clip.
  Returns FLOAT value average luma (0.0 -> 255.0) in frame(n+delta) for area x,y,w,h.

***
***
***

RT_YPlaneStdev(clip c,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,bool "interlaced"=false,
    int "Matrix"=(Width>1100||Height>600?3:2),clip "mask"=NOT_USED,int "MaskMin"=128,"MaskMax"=255)
  Return int -1, if no valid pixels in Mask clip.
  Returns FLOAT value luma Standard Deviation (0.0 -> 255.0) in frame(n+delta) for area x,y,w,h.
  Standard Deviation (Changed, from Sample Standard Deviation with Bessels Correction).
  http://en.wikipedia.org/wiki/Standard_deviation

***
***
***

RT_YInRange(clip c,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,bool "interlaced"=false,
      int "lo"=128,int "hi"=lo,int "Matrix"=(Width>1100||Height>600?3:2),clip "mask"=NOT_USED,int "MaskMin"=128,"MaskMax"=255)
  Return int -1, if no valid pixels in Mask clip.
  Returns FLOAT value (0.0 -> 1.0) being the amount of pixels in the range "lo" to "hi" (inclusive), 1.0 is equivalent to 100%.
  Implemented as requested by Martin53 (thankyou), NOTE, differs from other funcs that return range 0.0 to 255.0.
  NOTE, lo defaults to 128, "hi" defaults to "lo".

***
***
***

RT_YPNorm(clip c,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,bool "interlaced"=false,
      float "mu"=0.0,int "d"=1,int "p"=1,int "u"=1,int "Matrix"=(Width>1100||Height>600?3:2),clip "mask"=NOT_USED,int "MaskMin"=128,"MaskMax"=255)
  Return int -1 if no valid pixels in Mask clip.
  Returns FLOAT value greater or equal to 0.0, being the "Minkowski P-norm" (range depends upon values of 'd' and 'u') for frame(n+delta)
  area x,y,w,h.
  mu, Float, default 0.0 (0.0 -> 255.0)
  d,  int,   default 1 (1 -> 255)       # downscale
  p,  int,   default 1 (1 -> 16)        # power
  u,  int,   default 1 (1 -> 255)       # final upscale before returning result (experimental)
  Formula is: sum_over_pixels[ ((pixel-mu)/d)^p ]^(1/p) * u
  or in words: d and u are scaling aids. The differences between the pixel values and mu are scaled, taken to the power of p and added up
  over the frame. The sum is taken to the p-th root and finally rescaled.
  mu=0, d=1, p=1, u=1 yields the average.
  mu=average, d=1, p=2, u=1 yields the standard deviation (uncorrected sample standard deviation).
  Implemented as requested by Martin53 (thankyou). *** EXPERIMENTAL ***
  http://en.wikipedia.org/wiki/P-norm#The_p-norm_in_finite_dimensions
  http://en.wikipedia.org/wiki/Minkowski_distance


***
***
***


RT_Ystats(clip c,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,bool "interlaced"=false,
      float "threshold"=0.0,int "lo"=128,int "hi"=lo,int "flgs"=255,string "prefix"="YS_",
        float "mu"=0.0,int "d"=1,int "p"=1,int "u"=1, int "Matrix"=(Width>1100||Height>600?3:2),clip "mask"=NOT_USED,int "MaskMin"=128,"MaskMax"=255)
  Returns multiple results as for above single frame Luma sampling functions as Local Variables (prefixed with the prefix string arg).
  The args up to "interlaced", are as for all other clip functions, "threshold" used only for "RT_YPlaneMin", "RT_YPlaneMax" and
  "RT_YPlaneMinMaxDifference" equivalent routines with same functionality.
  "lo" and "hi" are used only with the "RT_YInRange" equivalent routine with same functionality.
  "mu" and "d" and "p" and "u" are used only with the "RT_YPNorm" equivalent routine with same functionality.
  The new arg "Flgs" selects which results you want returned and the string "Prefix" that is prepended
  to the returned Local variable names.
  The actual return result is a copy of the flgs arg with any non valid bits reset, ie the Local variables that were set.
  Local variables are NOT altered for any function not selected in flgs.
  Returns 0 if no pixels found in search area of mask within MaskMin and MaskMax.

  Flgs_Bit_Number   Add_To_Flgs     Equivalent_Function             Local_Var_Set_Excluding_Prefix
     0                 1($01)        RT_YPlaneMin()                     "yMin"        (0->255)
     1                 2($02)        RT_YPlaneMax()                     "yMax"        (0->255)
     2                 4($04)        RT_YPlaneMinMaxDifference()        "yMinMaxDiff" (0->255)
     3                 8($08)        RT_YPlaneMedian()                  "yMed"        (0->255)
     4                16($10)        RT_AverageLuma()                   "yAve"        (0.0->255.0)
     5                32($20)        RT_YPlaneStdev()                   "yStdev"      (0.0->255.0)
     6                64($40)        RT_YInRange()                      "yInRng"      (0.0->1.0)
     7               128($80)        RT_YPNorm()                        "yPNorm"      (0.0->??? depends upon d and u)
  RT_Ystats() allows you to inquire multiple results simultaneously, with not much more overhead than calling a single individual
  routine, however, you should not select sub functions that you dont need as there may be an additional unnecessary overhead.
  The Default flgs=255($FF) are all bits set and so sets ALL Local vars at once.
  RT_Ystats(flgs=1+2+16) would set Local vars "YS_yMin", "YS_yMax" and "YS_yAve" for full frame current_frame.

  In addition to above Local Variables, RT_YStats() sets an int Local variable (where default prefix) of "YS_PixelCount" being
  the number of pixels in mask area X,Y,W,H between MaskMin and MaskMax inclusive, or pixels scanned in X,Y,W,H area where mask
  not used.
  NOTE, If no valid flg bits set (eg $FF00), then returns 0, YS_PixelCount and all other variables remain as before call.
  Assuming some valid flg bits, if no valid pixels were found in mask then function returns 0, and only YS_PixelCount would be set
  to 0, no other variables are touched (remain as before call, undefined if not previously existing).
  Example usage:
    ScriptClip("""
      got = RT_Ystats(c,mask=Mask,flgs=$10) # AverageLuma
      (got != 0) ? RT_debug("AverageLuma = " + String(YS_yAve) + "PixelCount = " + String(YS_PixelCount)) : RT_Debug("NO VALID PIXELS FOUND")
      Return Last # EDIT: Added, else would error as above line does not set a Last clip
    """)
Also some for RGB, I've only just included the intro, but quite similar to YUV stuff above,
Code:
********************************************
********* RGB MASKED Channel FUNCTIONS *****
********************************************

 RGB32, RGB24 source clip.

 The source clip c must be RGB32 or RGB24.

 The compiletime/runtime clip functions share some common characteristics.
 The 'n' and (where used) 'n2' args are the optional frame numbers and default to 'current_frame' if not specified.
 The x,y,w,h, coords specify the source rectangle under scrutiny and are specified as for Crop(), the default 0,0,0,0 is full frame.
 If 'interlaced' is true, then every other line is ommited from the scan, so if eg x=0,y=1, then scanlines 1,3,5,7 etc are scanned,
 if eg x=0,y=4 then scanlines 4,6,8,10 etc are scanned. The 'h' coord specifies the full height scan ie same whether interlaced is true
 or false, although it will not matter if the 'h' coord is specified as eg odd or even, internally the height 'h' is reduced by 1 when
 interlaced=true and 'h' is even.

 Optional mask clip Planar ONLY [v2.6 colorpspaces OK]
 The Planar mask clip, governs which pixels are processed by the functions. Where a luma pixel in selected area of the the mask clip is
 in range "MaskMin" to "MaskMax" inclusive, then those pixels will be processed.
 Mask MUST, be same dimensions and have at least the same number of frames as clip c.
 Calling without mask OR with MaskMin=0,MaskMax=255 will effectively ignore the mask and scan full x,y,w,h area.

 The Chan arg specifies which R or G or B channel to process [the multi-functional RT_RgbChanStats() function also allows a Chan arg of -1,
 which processes R and G and B simulaneously for all functions selected by flgs arg, also allowed is chan arg of -2 which additionally
 processes the ALPHA channel if RGB32 but throws an error if RGB24].
 Default Chan is 0 (Red), 1 = Green, 2=Blue channel and 3=ALPHA channel when RGB32 ONLY else error.
I still think your idea will not work well but well carry on a bit longer.

Do you have [EDIT: frame size and] fixed number and coords of letter boxed sequences ? (what are they)
__________________
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; 8th January 2023 at 18:01.
StainlessS is offline   Reply With Quote
Old 8th January 2023, 18:20   #11  |  Link
coolgit
Registered User
 
Join Date: Apr 2019
Posts: 217
Quote:
Originally Posted by StainlessS View Post
I still think your idea will not work well but well carry on a bit longer.

Do you have fixed number and coords of letter boxed sequences ?
For HD 1920x1080 letterbox is 240 each vert side. l=0, t=0, r=100 or -1820, b=1080 or 0.
For SD 720x576 letterbox is 90 each vert side.

Quote:
Originally Posted by StainlessS View Post
With AVS+, you dont need GScript(" ... "), simple for() loop iterating every frame and splice frames together [which is what I think you were trying to avoid],

or

using ScriptClip [Or GScriptClip from Grunt], where splicing is done by ScriptClip.

If using For(n=0,FrameCount) loop, then inside you need to set current_frame to the frame number (n) so that AverageLuma (or whatever) knows what frame to sample.
current_frame=n, is necessary as it tricks AVS into thinking its in runtime mode (eg ScriptClip), and AverageLuma (and other runtime funcs) then works ok.
The for() loop necessary? Vdub would process every frame so why do i need for() unless it is another tricking avs.

If... else... doesn't work in scriptclip does it? I thought the whole point of gscript was to use if... else...
Gscriptclip - i was looking at that but according to the website grunt "The alternative (G*) names may be used if you wish, but this is optional in AviSynth version 2.58 or later." So if "g" isn't necessary then i should simply use scriptclip. Or am i missing something.

I seen codes with current_frame being used but for the life of me i can't understand why. Now i see you need it to trick avs into runtime mode. Got it. Surely if one has to trick avs into doing something then it must be a bug of sort?

Last edited by coolgit; 8th January 2023 at 19:50.
coolgit is offline   Reply With Quote
Old 8th January 2023, 19:16   #12  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Quote:
For HD 1920x1080 letterbox is 240 each vert side. l=0, t=0, r=100 or -1820, b=1080 or 0.
Thats got me confused.
You mean crop left and right both by 240 pixels : Crop(240,0,-240,-0)
or crop top, bot both by 240 pixels : Crop(0,240,-0,-240)

Quote:
For SD 720x576 letterbox is 90 each vert side.
You mean crop left and right both by 90 pixels : Crop(90,0,-90,-0)
or crop top, bot both by 90 pixels : Crop(0,90,-0,-90)

Quote:
The for() loop necessary? Vdub would process every frame so why do i need for() unless it is another tricking avs.
Because without for(), AverageLuma and other runtime funcs dont have a clue what frame you want to test,
In standard frameserving stage all frames are processed in order, just like in VDub,
VDub dont have option to process and make decision on a single frame, only entire clip processed identically,
[EDIT: So far as I remember, VD dont have per frame processed by user script, could be wrong though, if it does then similar to scriptclip]
ScriptClip does allow decision making inside runtime script but is slower than frameserving stage (where all processed identically), OR,
with trickery can set curent_frame to sample a SINGLE frame only, not applicable to entire clip, so,
can do as below
Code:
Avisource("...")
current_frame = 42
Y = Averageluma # single frame access to frame 42
Subtitle( "AverageLuma of frame 42 = " + String(Y) ) # ALL frames in clip subtitled as for frame 42, was evaluated before frameserving started.
return last
whereas
Code:
Avisource("...")
SSS = """
    Y = Averageluma # current_frame is set by AVS at each frame, automatically in the background
    Subtitle( "AverageLuma of frame " + String(current_frame) + " = " + String(Y) )
   return last
"""
Return last
During standard frameserving stage without any scriptclip() type runtime stuff, filter graph is already created and processing on each and every
frame has already been decided.

Where ScriptClip() or other runtime filter is included in script, each frame is processed and evaluated in the real time runtime script given to the runtime filter,
and includes script parsing and evaluating at each current_frame frame.

Quote:
Surely if one has to trick avs into doing something then it must be a bug of sort?
Current_frame trickery was never endorsed, even frowned upon by IanB (previous sole dev of Avs).

EDIT:
Quote:
If... else... doesn't work in scriptclip does it? I thought the whole point of gscript was to use if... else...
This does [in AVS+]
Code:
AviSource(".\vid.avi")

SSS = """
    if(current_frame % 2 == 0) {
        Subtitle("EVEN")
    } else {
        Subtitle("ODD")
    }
    Return last
"""

ScriptClip(SSS)

return last
EDIT:
Quote:
Gscriptclip
A bit annoying that one, something to do with Grunt GScriptClip only calling standard non GScript Scriptclip internally which dont support GScript extensions,
I did post somewhere a better explanation, but cannot remember now offhand why this is.

EDIT:
This does actually work, I cant remember the conditions that cause it to fail.
Code:
AviSource(".\vid.avi")

SSS = """
    if(current_frame % 2 == 0) {
        Subtitle("EVEN")
    } else {
        Subtitle("ODD")
    }
    Return last
"""

GScriptClip(SSS)

return last
EDIT: Maybe this is what I was thinking of(or at least related):- https://forum.doom9.org/showthread.p...87#post1956987
__________________
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; 8th January 2023 at 20:45.
StainlessS is offline   Reply With Quote
Old 8th January 2023, 23:41   #13  |  Link
coolgit
Registered User
 
Join Date: Apr 2019
Posts: 217
Quote:
Originally Posted by StainlessS View Post
Thats got me confused.
You mean crop left and right both by 240 pixels : Crop(240,0,-240,-0)
or crop top, bot both by 240 pixels : Crop(0,240,-0,-240)


You mean crop left and right both by 90 pixels : Crop(90,0,-90,-0)
or crop top, bot both by 90 pixels : Crop(0,90,-0,-90)
No. The size of the letterbox themselves. Different video resolution = different letterbox size.
l=0, t=0, r=100 or -1820, b=1080 or 0 is the area size... crop(0,0,100,1080) or vdub style crop(0,0,-1820,0). This area for HD should be sufficient to determine whether letterbox exist.
coolgit is offline   Reply With Quote
Old 9th January 2023, 01:29   #14  |  Link
coolgit
Registered User
 
Join Date: Apr 2019
Posts: 217
src=LSMASHVideoSource("filename.mp4", format="YUV420P10", fpsnum=25, fpsden=1).ConvertBits(8, dither=0).KillAudio()

#al=AverageLuma
#if(src.AverageLuma < 16){
# Levels(0, 1.0, 255, 0, 0, coring=false)
# } screws up fade in/out to/from black

#current_frame=n

For(n=0,FrameCount-1){
current_frame=n
fc=FrameCount()
if(current_frame < fc && AreaOp(src,0,100,0,1080).AverageLuma < 16){
SmoothLevels(0, 1.0, 255, 16, 235).Letterbox(0,0,240,240)
}
else {
SmoothLevels(0, 1.0, 255, 16, 235)
}
current_frame=current_frame+1
Return Last
}

StackHorizontal(src,last)
#Return last

After eliminating an error, another one pops up and so and so. The latest "I don't know what framecount means" line 22 } after return last.
coolgit is offline   Reply With Quote
Old 9th January 2023, 23:19   #15  |  Link
coolgit
Registered User
 
Join Date: Apr 2019
Posts: 217
Area of frame function.

Code:
# L is left border. T is top border. R is right border. B is bottom border. Op is Operation eg. "BlackNess()".
Function FrameArea(clip c,int L,int T,int R, int B) { # https://forum.doom9.org/showthread.p...43#post1603343

    # Modulo 4 coords
    L = L - (L % 4)
    T = T - (T % 4)
    R = (R + 3) / 4 * 4
    B = (B + 3) / 4 * 4

    Area=c.crop(L,T,R-L,B-T)
    Left = L > 0           ? c.crop(0,T,L,B-T)                 : NOP
    Top = T > 0          ? c.crop(0,0,c.width(),T)              : NOP
    Right = R < c.width()  ? c.crop(R,T,c.width()-R,B-T)      : NOP
    Bottom = B < c.height() ? c.crop(0,B,c.width(),c.height()-B)  : NOP

    Eval("Area")
    IsClip(Left)  ? StackHorizontal(Left, Last)  : NOP
    IsClip(Top) ? StackVertical(Top, Last)   : NOP
    IsClip(Right) ? StackHorizontal(Last, Right) : NOP
    IsClip(Bottom) ? StackVertical(Last, Bottom)   : NOP
    Return Last
}


/*
L=0
R=100
T=0
B=1080

FrameArea(src,L,T,R,B)

StackHorizontal(src,last)
#Return Last
*/
StainlessS - slight mod as removed string Op as couldn't see the point of it, except for testing purpose. Couldn't get AverageLuma to work as string Op. Couldn't ignore it as avs throws an error.

Latest code

Code:
src=LSMASHVideoSource("filename.mp4", format="YUV420P10", fpsnum=25, fpsden=1).ConvertBits(8, dither=0).KillAudio()

#al=AverageLuma
#if(src.AverageLuma < 16){
#	Levels(0, 1.0, 255, 0, 0, coring=false)
#	} screws up fade in/out to/from black

#current_frame=n
#fc=FrameCount(src)
#AL=AverageLuma

SL="""
For (n=0,FrameCount-1){
	AL=AverageLuma
	current_frame=n
	fc=FrameCount
	if (current_frame < fc){
		if (FrameArea(src,0,100,0,1080) && (AL < 16)){
		SmoothLevels(0, 1.0, 255, 16, 235).Letterbox(0,0,240,240)
		}}
		else {
		SmoothLevels(0, 1.0, 255, 16, 235)
		}
#	Return Last
}
"""

GScriptClip(SL)

# another method
#For(n=0,FrameCount-1){
#frame=(FrameArea(src,0,100,0,1080).AverageLuma < 16) ? SmoothLevels(0, 1.0, 255, 16, 235).Letterbox(0,0,240,240) : SmoothLevels(0, 1.0, 255, 16, 235)
#}

StackHorizontal(src,last)
#Return last
Getting 'invalid arguments to function gscriptclip'
coolgit is offline   Reply With Quote
Old 17th January 2023, 03:33   #16  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Sorry, not been on-site for a while, probably not be around much in near future.

Something like this with scriptclip,
Code:
TOP    = 0
BOTTOM = 0
LEFT   = 240
RIGHT  = 240

THRESH = 16.0
NEW_BORDER_COLOR = $FF00FF  # So you can see where was changed

A = ColorBars(pixel_type="YV24").KillAudio.Spline36Resize(1920,1080).Trim(0,-10) # 10 frames
B = A.LetterBox(TOP,BOTTOM,RIGHT,LEFT, $000000)

A ++ B ++ A ++ B ++ A   # 50 frames

Src = Last
# Return Last

BORDER_MASK = Last.BlankClip().LetterBox(TOP,BOTTOM,LEFT,RIGHT,$FFFFFF)  # WHITE where there is BORDER, Else BLACK
#Return BORDER_MASK
IMAGE_MASK  = BORDER_MASK.INVERT
#Return IMAGE_MASK

OP = "Levels(0, 1.0, 255, 16, 235, coring=false)"   # NOT SURE WHAT YOU TRY TO DO HERE, YRange Compress ? # Also, get it working with simple stuff before you get more complicated.

SL="""
    BorderY = RT_AverageLuma(Mask=BORDER_MASK,MaskMin=128,MaskMax=255)  # Just measure area that is WHITE in BORDER_MASK
    ImageY  = RT_AverageLuma(Mask=IMAGE_MASK ,MaskMin=128,MaskMax=255)  # Just measure area that is WHITE in IMAGE_MASK { HERE WE ONLY SHOW IT in DebugView, NOT USED FOR ANYTHING ELSE }
    RT_DebugF("\n%d] BorderY = %f ImageY=%f",current_frame,BorderY,ImageY,name="COOLGIT: ")                       # To DebugView [google]
    if (BorderY <= THRESH) {
        RT_DebugF("%d] HAS BORDER",current_frame,name="COOLGIT: ")
        AreaOp_444( LEFT, TOP, -RIGHT, -BOTTOM, OP )                    # Apply levels, only image area [EDIT: -ve Right, and -ve BOTTOM, as in crop with -ve width/height]
#        Levels(0, 1.0, 255, 16, 235,coring=false)                      # Alternative, Apply to whole frame
        Letterbox(TOP,BOTTOM,RIGHT,LEFT, Color=NEW_BORDER_COLOR)
        Subtitle("Fixed",Size=64,align=5)
    } else {
        RT_DebugF("%d] NO BORDER",current_frame,name="COOLGIT: ")
        Levels(0, 1.0, 255, 16, 235,coring=false)           # Apply Smoothlevels, whole image area
    }
    Return Last
"""

GScriptClip(Last,SL)

StackVertical(src,last)


Return Last


Function AreaOp_444(clip c,int x,int y,int w, int h, String Op) {
/*
    YUV444 (eg YV24) or RGB only (or coords already crop compatible with colorspace eg all mod 2 for YV12, else error)
    x,y,w,h, coords of inner area as per crop(x,y,w,h), w and h can be <= 0 where width or height relative.
    op is Operation eg "BlackNess()" OR "Levels(16,1.0,235,235,16,coring=False)"
*/
    # Make w and h -ve or 0, ie width or height relative.
    w = (w <= 0) ? w : (x + w) - c.Width()
    h = (h <= 0) ? h : (y + h) - c.Height()

    Area=c.crop(x,y,w,h)        # Inner Area


    # Borders, Full width top and bottom, short left and right
    Above = (y>0)   ? c.crop(0,0,c.width(),y)             : NOP
    Below = (h<0)   ? c.crop(0,c.Height()+h,c.width(),0)  : NOP
    Left =  (x>0)   ? c.crop(0,y,x,h)                     : NOP
    Right = (w<0)   ? c.crop(c.Width+w,y,0,h)             : NOP

    Eval("Area." + OP)

    IsClip(Left)  ? StackHorizontal(Left, Last)  : NOP
    IsClip(Right) ? StackHorizontal(Last, Right) : NOP
    IsClip(Above) ? StackVertical(Above, Last)   : NOP
    IsClip(Below) ? StackVertical(Last, Below)   : NOP
    Return Last
}
You could also, instead of
Code:
ImageY  = RT_AverageLuma(Mask=IMAGE_MASK ,MaskMin=128,MaskMax=255)
use
Code:
ImageY  = RT_AverageLuma(Mask=BORDER_MASK ,MaskMin=0,MaskMax=127)
(Sampling AverageLuma where BORDER_MASK is BLACK {well 0->127}, ie the Image Area) And not bother with the IMAGE_MASK at all.

EDIT:
Quote:
Getting 'invalid arguments to function gscriptclip'
Because you did not give it a clip, [your clip was Src, implicit Last not defined]

EDIT:
A bit of the DebugView output
Code:
00009968    1.55998325  [9336] COOLGIT:
00009969    1.56004477  [9336] COOLGIT: 5] BorderY = 84.625000 ImageY=95.467987
00009970    1.56010675  [9336] COOLGIT: 5] NO BORDER
00009971    1.58738816  [9336] COOLGIT:
00009972    1.58743227  [9336] COOLGIT: 6] BorderY = 84.625000 ImageY=95.467987
00009973    1.58748627  [9336] COOLGIT: 6] NO BORDER
00009974    1.61540735  [9336] COOLGIT:
00009975    1.61546588  [9336] COOLGIT: 7] BorderY = 84.625000 ImageY=95.467987
00009976    1.61552966  [9336] COOLGIT: 7] NO BORDER
00009977    1.64438224  [9336] COOLGIT:
00009978    1.64442945  [9336] COOLGIT: 8] BorderY = 84.625000 ImageY=95.467987
00009979    1.64449239  [9336] COOLGIT: 8] NO BORDER
00009980    1.67529500  [9336] COOLGIT:
00009981    1.67534482  [9336] COOLGIT: 9] BorderY = 84.625000 ImageY=95.467987
00009982    1.67541265  [9336] COOLGIT: 9] NO BORDER
00009983    1.71268141  [9336] COOLGIT:
00009984    1.71272635  [9336] COOLGIT: 10] BorderY = 16.000000 ImageY=95.467987
00009985    1.71278882  [9336] COOLGIT: 10] HAS BORDER
00009986    1.79725134  [9336] COOLGIT:
00009987    1.79730320  [9336] COOLGIT: 11] BorderY = 16.000000 ImageY=95.467987
00009988    1.79736423  [9336] COOLGIT: 11] HAS BORDER
00009989    1.90727317  [9336] COOLGIT:
00009990    1.91610396  [9336] COOLGIT: 12] BorderY = 16.000000 ImageY=95.467987
00009991    1.91829336  [9336] COOLGIT: 12] HAS BORDER
00009992    2.00985384  [9336] COOLGIT:
00009993    2.00990272  [9336] COOLGIT: 13] BorderY = 16.000000 ImageY=95.467987
00009994    2.00996470  [9336] COOLGIT: 13] HAS BORDER
00009995    2.08401132  [9336] COOLGIT:
00009996    2.08404684  [9336] COOLGIT: 14] BorderY = 16.000000 ImageY=95.467987
00009997    2.08408642  [9336] COOLGIT: 14] HAS BORDER
00009998    2.15086484  [9336] COOLGIT:
00009999    2.15089631  [9336] COOLGIT: 15] BorderY = 16.000000 ImageY=95.467987
00010000    2.15093732  [9336] COOLGIT: 15] HAS BORDER
00010001    2.23550248  [9336] COOLGIT:
Result: Downsized for forum [border replaced with NEW_BORDER_COLOR = $FF00FF]
EDIT: And image Y range compressed as per levels.



EDIT: I still kinda think that you're wasting your time, unlikely to work well
Might work well for most clips, but there will likely be the occasional totally bad mistake on some frames/sequences, borders are unlikely to "play ball" and be exactly what you hope they are.
I've seen borders and lowest image black being about 32.xxx [usually result of bad processing somewhere, and looking very 'wishy washy'], but less likely on HD/FHD.
They may also not be positioned exactly where you would like them to be, or have edge crud, it's an odd life.
__________________
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; 17th January 2023 at 06:27.
StainlessS is offline   Reply With Quote
Old 22nd January 2023, 19:01   #17  |  Link
coolgit
Registered User
 
Join Date: Apr 2019
Posts: 217
Here the suppose final scripts.

LetterBox detector.

Code:
video=LSMASHVideoSource("Filename").ConvertBits(8, dither=0).KillAudio()
#video=FFmpegSource2("Filename").KillAudio()
video
src=last

LeftA = 220     # For analysing border.
TopA = 0
RightA = 220
BottomA = 0

Left = 240     # For fixing letterbox.
Top = 0
Right = 240
Bottom = 0

Th1 = 18.0      # Threshold variables. Ensure black frames are the same blackness.
Th2 = 17.0      # Ensure letterbox exist and fix letterbox blackness after levels/filter adjustment.
Th3 = 16.0      # Ensure ImageMask isn't 100% black. 
Th4 = 150.0     # Detect white frames and fade in/out. Experimental Th4.

LB = $008080    # $008080 Letterbox colour. $FF00FF - see changes for debugging.

BorderMaskL = last.BlankClip().LetterBox(TopA, BottomA, LeftA, 0, $FFFFFF)  # White where there is border, else black. Leftside.
BorderMaskR = last.BlankClip().LetterBox(TopA, BottomA, 0, RightA, $FFFFFF)  # White where there is border, else black. Rightside.
BorderMask = last.BlankClip().LetterBox(TopA, BottomA, LeftA, RightA, $FFFFFF)  # White where there is border, else black.
ImageMask  = BorderMask.Invert


LBox="""
#    YPMin = RT_YPlaneMin()
    FrameB = RT_YPlaneMax()
#    FrameW = RT_AverageLuma()
    BorderL = RT_YPlaneMax(Mask=BorderMaskL,MaskMin=128,MaskMax=255)    # Measure area that is white in BorderMaskL.
    BorderR = RT_YPlaneMax(Mask=BorderMaskR,MaskMin=128,MaskMax=255)    # Measure area that is white in BorderMaskR.
    Image  = RT_YPlaneMax(Mask=ImageMask ,MaskMin=128,MaskMax=255)      # Measure area that is white in ImageMask.
    if (FrameB <= Th1) {
        Levels(0, 1.0, 255, 0, 0, coring=false)
#        Subtitle("Black Frame",Size=64,align=5)
#    } else if (FrameW > Th4) {
#        Dissolve()# or use Vdub2 curve editor or whatever filter fixes the problem. Use 'Video Debug.avs' to check if white frames exist.
#        Subtitle("White Frame",Size=64,align=5)
    } else if (BorderL <= Th2 && BorderR <= Th2 && Image > Th3) {
        SmoothLevels(0, 1.0, 255, 8, 255, Lmode=2, brightSTR=100, chroma=100, limiter=0, useMT=10)
        Letterbox(top, bottom, left, right, color_yuv=LB)
#        Subtitle("Has Border",Size=64,align=5)
    } else {
        SmoothLevels(0, 1.0, 255, 4, 255, Lmode=2, brightSTR=500, chroma=100, limiter=0, useMT=10)#.SmoothTweak(brightness=0, contrast=1.0, saturation=1.0, hue1=0, hue2=0, Lmode=0, limiter=false, useMT=10)
#        Subtitle("No Border",Size=64,align=5)
    }
    Return Last
"""

GScriptClip(Last,LBox)

#StackVertical(src.ColorYUV(analyze=true),last.ColorYUV(analyze=true))
StackHorizontal(src.ColorYUV(analyze=true),last.ColorYUV(analyze=true))

Return Last
Video Debug.

Code:
video=LSMASHVideoSource("Filename").ConvertBits(8, dither=0).KillAudio()
#video=FFmpegSource2("Filename").KillAudio()
video
src=last

Left = 220
Top = 0
Right = 220
Bottom = 0

Th1 = 16.0     # Threshold variables. Ensure black frames are the same blackness.
Th2 = 16.0     # Ensure letterbox exist and fix letterbox blackness after levels/filter adjustment.
Th3 = 16.0     # Ensure ImageMask isn't 100% black.
Th4 = 150.0    # Detect white frames and fade in/out. Fade needs to be fix manually.

BorderMaskL = last.BlankClip().LetterBox(Top, Bottom, Left, 0, $FFFFFF)  # White where there is border, else black. Leftside.
BorderMaskR = last.BlankClip().LetterBox(Top, Bottom, 0, Right, $FFFFFF)  # White where there is border, else black. Rightside.
BorderMask = last.BlankClip().LetterBox(Top, Bottom, Left, Right, $FFFFFF)  # White where there is border, else black.
ImageMask  = BorderMask.Invert

Debug="""
    YPMin = RT_YPlaneMin()
    FrameB = RT_YPlaneMax()
    FrameW = RT_AverageLuma()
    BorderL = RT_YPlaneMax(Mask=BorderMaskL,MaskMin=128,MaskMax=255)    # Just measure area that is white in BorderMaskL.
    BorderR = RT_YPlaneMax(Mask=BorderMaskR,MaskMin=128,MaskMax=255)    # Just measure area that is white in BorderMaskR.
    Image  = RT_YPlaneMax(Mask=ImageMask,MaskMin=128,MaskMax=255)    # Just measure area that is white in ImageMask for black frame.
    if (FrameB <= Th1) {
        RT_DebugF("%d Min Luma=%f Max Luma=%f Average Luma=%f Left Border=%f Right Border=%f Image=%f BLACK FRAME",current_frame,YPMin,FrameB,FrameW,BorderL,BorderR,Image)
#        Subtitle("BLACK FRAME",Size=64,align=5) # Disable Subtitle to increase FPS by x4
    } else if (BorderL <= Th2 && BorderR <= Th2 && Image > Th3) {
        RT_DebugF("%d Min Luma=%f Max Luma=%f Average Luma=%f Left Border=%f Right Border=%f Image=%f HAS BORDER",current_frame,YPMin,FrameB,FrameW,BorderL,BorderR,Image)
#        Subtitle("HAS BORDER",Size=64,align=5) # Disable Subtitle to increase FPS by x4
    } else if (FrameW > Th4) {
        RT_DebugF("%d Min Luma=%f Max Luma=%f Average Luma=%f Left Border=%f Right Border=%f Image=%f WHITE FRAME",current_frame,YPMin,FrameB,FrameW,BorderL,BorderR,Image)
#        Subtitle("WHITE FRAME",Size=64,align=5)# Disable Subtitle to increase FPS by x4
    } else {
        RT_DebugF("%d Min Luma=%f Max Luma=%f Average Luma=%f Left Border=%f Right Border=%f Image=%f NO BORDER",current_frame,YPMin,FrameB,FrameW,BorderL,BorderR,Image)
#        Subtitle("NO BORDER",Size=64,align=5)# Disable Subtitle to increase FPS by x4
    }
    Return Last
"""

GScriptClip(Last,Debug)


#StackHorizontal(src.ColorYUV(analyze=true),last.ColorYUV(analyze=true))
return last
Run Video debug script to get the required info in debug viewer.
Copy and paste into Notepad++.
Remove RT_DebugF: to avoid line auto wrap.
ctrl+M find 'black frame' and mark all. Do the same for white frame. Find 'has border' and mark all with bookmark line ticked.
Check 'find' highlights are grouped continuously. Ie can not have 'has border' then next line 'black frame' then next line 'has border'.
Scroll down or pgdn key, scanning at Min Luma - 5,7,4,6,7,3,8,4,6,7,6,7,8 (vertical) and so on until you get - 12,14,15,13,16,15,14,15,16,14 and so on. Vdub2 - Group 1st example as first trim file
making sure SmoothLevels output low is 8 to 10. Group 2nd example as second trim file with output low 4. So on.

Done 5 video clips and range from 5 to 12 trims. Better than typing in 40 to 60 trim() and having to be super careful not to get the frame numbers wrong. Plus a few trims correcting other 'defect' done separately.

Black fade in to out isn't a problem 99% of the time. If the fade looks bad then trim using vdub 2 curve editor. Easy.

Last edited by coolgit; 22nd January 2023 at 20:05.
coolgit is offline   Reply With Quote
Old 22nd January 2023, 19:34   #18  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
So, it works for you, Yes, and you are a happy bunny ?
__________________
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 ???
StainlessS is offline   Reply With Quote
Old 22nd January 2023, 20:04   #19  |  Link
coolgit
Registered User
 
Join Date: Apr 2019
Posts: 217
Quote:
Originally Posted by StainlessS View Post
Sorry, not been on-site for a while, probably not be around much in near future.
EDIT:
Quote:
Getting 'invalid arguments to function gscriptclip'
Because you did not give it a clip, [your clip was Src, implicit Last not defined]
I always used src to pass clip into filter but from what you were saying that scriptclip requires implicit Last to feed a clip to process?
Got to remember that one. I had actually got a working script over a week ago but couldn't understand the error as it kept on pointing at line whatever with }
However when I used

Code:
video=LSMASHVideoSource("Filename")
video=Last
it wouldn't work.
Used

Code:
video=LSMASHVideoSource("Filename")
video
src=last
it worked. What I don't under what does the 2nd line 'video' do that the first line already does?

Quote:
Originally Posted by StainlessS View Post
EDIT: I still kinda think that you're wasting your time, unlikely to work well
Might work well for most clips, but there will likely be the occasional totally bad mistake on some frames/sequences, borders are unlikely to "play ball" and be exactly what you hope they are.
I've seen borders and lowest image black being about 32.xxx [usually result of bad processing somewhere, and looking very 'wishy washy'], but less likely on HD/FHD.
They may also not be positioned exactly where you would like them to be, or have edge crud, it's an odd life.
Have faith!! I am not expecting 100% automation as that is the Holy Grail. I had done testing, over the last 2 years, all the autolevels, autobalance, auto whatever and none worked 100% throughout a whole film etc. They all suffer from flickers and weird outputs. I tested...

Quote:
SmoothLevels(0, 1.0, 255, 16-YPlaneMin(), 235, Lmode=2, brightSTR=10000, chroma=100, limiter=0, useMT=10)
and didn't work. I could reduce the flicker to near nothingness on my monitor but the final testing of moving vdub2 to my TV and the flicker becomes noticeable. To avoid flickers output low, such as 6 or 8 or 16, etc must be the same in every frame in same scene. Hence I needed the above script.

For my purpose it works very very well. The amount of trim is vastly reduce and clicking on 'home' and 'end' key using vdub2 is million times better than typing out frames numbers. Threshold Th1, etc, can be adjusted slightly when necessary according to video debug outputs. Time spent per video is reduced by say 70%, off the head estimate.

Is there a way to save/use avisynth script when using Vdub2 job control. Tried it and avisynth was ignored.

Last edited by coolgit; 22nd January 2023 at 20:08.
coolgit is offline   Reply With Quote
Old 22nd January 2023, 21:39   #20  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Quote:
I always used src to pass clip into filter but from what you were saying that scriptclip requires implicit Last to feed a clip to process?
Scriptclip does not require "implicit Last" clip, but it does require some clip, and if not explicitly given a clip (eg Src) then it tries to use Implicit Last, which if not defined then has no idea what clip it is supposed to use (you supplied neither).

Quote:
video=LSMASHVideoSource("Filename")
video=Last # Last undefined, FAIL
FAIL: In the first line you assigned a clip to video, and then assign undefined implicit last again to video clip. Of course that dont work.



Quote:
video=LSMASHVideoSource("Filename")
video # Last = video : If not assigned to anything else, then assigned to Last [ie implicit]
src=last
OK: Here, you assign a clip to video, and then assign video to implicit Last, then assign implicit [EDIT: explicit] Last to src. [OK, but a bit 'long winded']



Either
Code:
LSMASHVideoSource("Filename") # Assign to Implict Last (If not assigned to anything else, then is assigned to Implicit Last), same as Last=LSMASHVideoSource("Filename")
src=last  # Assign Last to Src
or
Code:
src=LSMASHVideoSource("Filename") # Assign to src
src  # Assign to implcit Last, ie same as Last=src
Quote:
Is there a way to save/use avisynth script when using Vdub2 job control. Tried it and avisynth was ignored.
No idea what that means.
If you wanna save the script, do it before you save it to the Job control whatsit, ie

CTRL S # if in VDub main screen, [see Menu hints]

or if in VD2 script Editor (via F1 or menu Help, below F5 and F7 as described in VD2 script editor help window)
Quote:
F5 (save script and refresh) or F7 save file and load movie into main window.

F5 saves, reloads, and jumps back to original frameNo.
F7 saves, reloads, and jumps to frameNo 0.

EDIT:
Quote:
Is there a way to save/use avisynth script when using Vdub2 job control. Tried it and avisynth was ignored.
After saving script as above {Main window CTRL-S or Script editor F5 or F7},

THEN

"Menu/File/Queue Batch Operation/" sub menu "Save Video", which uses the saved script as source script.

OR,

"Menu/File/Save Video", And change the "Do Now" option button to "Save to job Queue", then click "Save" button.

THEN,

"Menu/File/Job Control" and select "START" button {Not OK button which will just exit job control}
__________________
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 January 2023 at 01:11.
StainlessS is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 00:04.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.