Log in

View Full Version : Conditional selection help


VoodooFX
24th December 2020, 21:10
Before I've used only simple conditional filtering, so no idea how to approach more complex stuff like selecting frames by average luma variable from three source clips:


x=BlankClip(length=100)
x1=x.Subtitle("Sample1")
x2=x.Subtitle("Sample2")
x3=x.Subtitle("Sample3")

clp1=x+x1+x1+x1
clp2=x2+x+x2+x2
clp3=x3+x+x+x3


If frame in clp1 is below threshold then frame should be taken from clp3.
If frame in clp1 is above threshold then frame should be taken from clp3 or clp2 or clp1, frame must be above threshold (clip priority clp3 > clp2 > clp1).

Desired output should look like this: "x3+x1+x2+x3"

StainlessS
24th December 2020, 22:39
Its not 100% clear what you want, and does not allow for clp1 == Th, but maybe something like this

[Scriptclip is most versatile of the conditionalSelect type whosits]

FRAMES=1
x=BlankClip(length=FRAMES,Pixel_type="YV12")
x1=x.Subtitle("Sample1") # Y = 16.222197
x2=x.Subtitle("Sample2") # Y = 16.233568
x3=x.Subtitle("Sample3") # Y = 16.231783

clp1=x+x1+x1+x1
clp2=x2+x+x2+x2
clp3=x3+x+x+x3

Th=16.0

# NOTE, DOES NOT allow for eg clp1.AverageLuma == Th
expression = """
return clp1.AverageLuma < Th ? clp3 : clp3.AverageLuma > Th ? clp3 : clp2.AverageLuma > Th ? clp2 : clp1
"""

clp1.ScriptClip(expression)

Something like that ?

VoodooFX
26th December 2020, 14:40
Its not 100% clear what you want, and does not allow for clp1 == Th, but maybe something like this


I'm not sure what finally I'll want, for a start I want to make this work what I have described, I guess "clp1 == Th" issue is relatively safe.

I expect frame from clp3 if "clp1.AverageLuma < Th" is true, no matter what, but if you change to "clp3=x+x+x+x3" then frame from clp2 is returned, why this is happening?
I guess running ScriptClip inside eval(""" """) would be a problem?

EDIT:
"This is happening" because I ignored the fact that "x" levels are in tv range (look at post 7).

StainlessS
26th December 2020, 15:49
I'm not sure what finally I'll want,
Me neither.
I guess "clp1 == Th" issue is relatively safe.
Bit slipshod.
I guess running ScriptClip inside eval(""" """) would be a problem?
This works [3,1,2,3]

FRAMES=1
x=BlankClip(length=FRAMES,Pixel_type="YV12")
x1=x.Subtitle("Sample1") # Y = 16.222197
x2=x.Subtitle("Sample2") # Y = 16.233568
x3=x.Subtitle("Sample3") # Y = 16.231783

clp1=x+x1+x1+x1
clp2=x2+x+x2+x2
clp3=x3+x+x+x3

Th=16.0

# NOTE, DOES NOT allow for eg clp1.AverageLuma == Th
expression = """
return clp1.AverageLuma < Th ? clp3 : clp3.AverageLuma > Th ? clp3 : clp2.AverageLuma > Th ? clp2 : clp1
"""

Exp2="""clp1.ScriptClip(expression)"""

Eval(Exp2)

Crop(0,0,128,32)
StackHorizontal(Trim(0,-1),Trim(1,-1),Trim(2,-1),Trim(3,-1))

https://i.postimg.cc/L4NGRx6G/Vx1-00.jpg (https://postimages.org/)

but if you change to "clp3=x+x+x+x3"

FRAMES=1
x=BlankClip(length=FRAMES,Pixel_type="YV12")
x1=x.Subtitle("Sample1") # Y = 16.222197
x2=x.Subtitle("Sample2") # Y = 16.233568
x3=x.Subtitle("Sample3") # Y = 16.231783

clp1=x+x1+x1+x1
clp2=x2+x+x2+x2
#clp3=x3+x+x+x3
clp3=x+x+x+x3

Th=16.0

# NOTE, DOES NOT allow for eg clp1.AverageLuma == Th
expression = """
return clp1.AverageLuma < Th ? clp3 : clp3.AverageLuma > Th ? clp3 : clp2.AverageLuma > Th ? clp2 : clp1
"""

Exp2="""clp1.ScriptClip(expression)"""

Eval(Exp2)

Crop(0,0,128,32)
StackHorizontal(Trim(0,-1),Trim(1,-1),Trim(2,-1),Trim(3,-1))

https://i.postimg.cc/TwPqcJMW/Vx1-01.jpg (https://postimages.org/)

I expect frame from clp3 if "clp1.AverageLuma < Th"
Yeah well, I set Th at 16.0, having no other instruction for such [see above quote 1].
(16.0, is below all of them, NOTE AverageLuma in comment after subtitle)

EDIT: Is this required at script Main level as in above examples, or within a script Function ?

VoodooFX
26th December 2020, 17:14
EDIT: Is this required at script Main level as in above examples, or within a script Function ?
Intended use would be within a script Function.


Yeah well, I set Th at 16.0, having no other instruction for such [see above quote 1].
(16.0, is below all of them, NOTE AverageLuma in comment after subtitle)
That is a right threshold to use to test the sample. The sample clips doesn't matter, only matters this desired selection logic:

If frame in clp1 is below threshold then frame should be taken from clp3.
If frame in clp1 is above threshold then frame should be taken from clp3 or clp2 or clp1, frame must be above threshold (clip priority clp3 > clp2 > clp1).

EDIT:
Clarification: "must be above threshold" is valid only in the second quoted sentence. The first frame from clp2 in the outcome contradicts the first sentence (I mean outcome from the sample in above post).

EDIT:
Outcome doesn't "contradict" anything (look at post 7)!

StainlessS
26th December 2020, 19:25
I still dont know what you want.

FRAMES=1
x=BlankClip(length=FRAMES,Pixel_type="YV12")
x1=x.Subtitle("Sample1") # Y = 16.222197
x2=x.Subtitle("Sample2") # Y = 16.233568
x3=x.Subtitle("Sample3") # Y = 16.231783

clp1=x+x1+x1+x1
clp2=x2+x+x2+x2
#clp3=x3+x+x+x3
clp3=x+x+x+x3

Th=16.0

Vx(clp1,clp2,clp3,Th)


Crop(0,0,128,32)
Return StackHorizontal(Trim(0,-1),Trim(1,-1),Trim(2,-1),Trim(3,-1))


/* from Docs:
ScriptClip (clip, string filter, bool "show", bool "after_frame")

ScriptClip returns the clip returned by the filter evaluated on every frame.
The string filter can be any expression returning a clip, including internal or user clip functions,
and may include line breaks (allowing a sequence of statements to be evaluated).
Also, also some functions which are predefined (the Runtime Functions) and the special runtime
variable current_frame (the framenumber of the requested frame) can be used in the filter expression.
Adding show="true" will display the actual values on the screen.
*/

Function Vx(clip c1,clip c2,clip c3,Float Th) {
# I was gonna try GConditionalSelect() but Grunt dont have an "G" version ConditionalSelect() with args, so GScriptclip pretty much only option.
# Needs "G" Scriptclip version to import Args.
/*
If frame in clp1 is below threshold then frame should be taken from clp3.
If frame in clp1 is above [OR EQUAL] threshold then frame should be taken from clp3 or clp2 or clp1,
frame must be above threshold (clip priority clp3 > clp2 > clp1).
*/
expression = """
Yc1 = c1.AverageLuma
Yc2 = c2.AverageLuma
Yc3 = c3.AverageLuma
RT_DebugF("%d] Yc1=%f : Yc2=%f : Yc3=%f",current_frame,Yc1,Yc2,Yc3, name="AveLuma: ")
if(Yc1 < Th) { # If frame in clp1 is below threshold then frame should be taken from clp3.
c3
RT_DebugF("%d] Yc1 < Th {Yc1=%f Last=c3} ",current_frame,Yc1,name="DUE TO: ")
} else { # If frame in clp1 is above [OR EQUAL] threshold then frame should be taken from clp3 or clp2 or clp1,
# clip priority clp3 > clp2 > clp1
if (Yc3 > Th) {
c3
RT_DebugF("%d] Yc3 > Th {Yc3=%f Last=c3}",current_frame,Yc3,name="DUE TO: ")
} else if (Yc2 > Th) {
c2
RT_DebugF("%d] Yc2 > Th {Yc2=%f Last=c2}",current_frame,Yc2,name="DUE TO: ")
} else {
c1
RT_DebugF("%d] Else {Last=c1}",current_frame,name="DUE TO: ")
}
}
RT_DebugF("##################",name="########")
return Last
"""
# Below Scriptclip requires a 1st clip arg which defines Scriptclip returned characteristics eg dimensions, length etc.
# Apart from setting characterists, Last clip is not used in Expression here [except after assigning some other clip to Last].
Dummy = c1
GScriptClip(Dummy,expression,Args="c1,c2,c3,th",local=True) # GScriptClip requires Grunt, for Args [so can import into expression in script function].
Return Last
}

clip priority clp3 > clp2 > clp1
Is that comparining with Th, [ie what does "priority" mean here], surely you can arrange whatever logic you want from above.

EDIT: Or maybe you want something like if (c3.AverageLuma > c2.AverageLuma && c2.AverageLuma > c1.AverageLuma)
And dont forget eg "<=" or "==" can exist and is bug waiting to happen if not catered for.

EDIT:
Or something Like

if(Max(c3.AverageLuma,c2.AverageLuma,c1.AverageLuma) == c3.AverageLuma) {
c3
} else {... }


EDIT:
I expect frame from clp3 if "clp1.AverageLuma < Th"
But "clp1.AverageLuma < Th", it is NOT < th, it is EQUAL when clp1=x+x1+x1+x1 and x = BlankClip, and Th=16.0 [ie BlankClip() = 16.0 Averageluma].

EDIT: I've added debug output to script, and got AverageLuma of frames before logic.
clp3=x3+x+x+x3

00001249 0.26846156 [360] AveLuma: 0] Yc1=16.000000 : Yc2=16.233568 : Yc3=16.231783
00001250 0.26852497 [360] DUE TO: 0] Yc3 > Th {Yc3=16.231783 Last=c3}
00001251 0.26858366 [360] ######## ##################
00001252 0.29166538 [360] AveLuma: 1] Yc1=16.222197 : Yc2=16.000000 : Yc3=16.000000
00001253 0.29172081 [360] DUE TO: 1] Else {Last=c1}
00001254 0.29178059 [360] ######## ##################
00001255 0.32554993 [360] AveLuma: 2] Yc1=16.222197 : Yc2=16.233568 : Yc3=16.000000
00001256 0.32562023 [360] DUE TO: 2] Yc2 > Th {Yc2=16.233568 Last=c2}
00001257 0.32567856 [360] ######## ##################
00001258 0.34885412 [360] AveLuma: 3] Yc1=16.222197 : Yc2=16.233568 : Yc3=16.231783
00001259 0.34892657 [360] DUE TO: 3] Yc3 > Th {Yc3=16.231783 Last=c3}


clp3=x+x+x+x3

00001360 0.27071226 [3720] AveLuma: 0] Yc1=16.000000 : Yc2=16.233568 : Yc3=16.000000
00001361 0.27077714 [3720] DUE TO: 0] Yc2 > Th {Yc2=16.233568 Last=c2}
00001362 0.27084377 [3720] ######## ##################
00001363 0.29513890 [3720] AveLuma: 1] Yc1=16.222197 : Yc2=16.000000 : Yc3=16.000000
00001364 0.29519615 [3720] DUE TO: 1] Else {Last=c1}
00001365 0.29525268 [3720] ######## ##################
00001366 0.33002707 [3720] AveLuma: 2] Yc1=16.222197 : Yc2=16.233568 : Yc3=16.000000
00001367 0.33009374 [3720] DUE TO: 2] Yc2 > Th {Yc2=16.233568 Last=c2}
00001368 0.33015099 [3720] ######## ##################
00001369 0.34207556 [3720] AveLuma: 3] Yc1=16.222197 : Yc2=16.233568 : Yc3=16.231783
00001370 0.34214655 [3720] DUE TO: 3] Yc3 > Th {Yc3=16.231783 Last=c3}

VoodooFX
26th December 2020, 20:55
But "clp1.AverageLuma < Th", it is NOT < th, it is EQUAL when clp1=x+x1+x1+x1 and x = BlankClip, and Th=16.0 [ie BlankClip() = 16.0 Averageluma].

Bingo!!! Now for an half hour I was looking at the sample, at the scripts and thinking that something is not right... :D

It should be (to be working in my head):
x=BlankClip(length=FRAMES,Pixel_type="YV12").ColorYUV(levels="tv->pc")
and th=0.2

I still dont know what you want.
Thanks for having a patience with us, the common earthlings. :)

I want to get new 4th clip by combining frames from the three other clips.
"clip priority clp3 > clp2 > clp1" is just for frame above threshold (if it's above in clp3 then I don't care what luma is in the other clips).

EDIT:
I'm gathering ideas for improved "DynMask 3" method for InpaintDelogo, for the short variable duration "logos" aka subtitles. Lets see how much all this helps in practice...

StainlessS
26th December 2020, 21:09
Does the Debug stuff I just added help.

EDIT:
x=BlankClip(length=FRAMES,Pixel_type="YV12").ColorYUV(levels="tv->pc")
For AVS+,
x=BlankClip(length=FRAMES,Pixel_type="YV12",Color_YUV=$008080)

EDIT:
Now for an half hour I was looking at the sample
Yep, can't see the wood for the trees. I've been in that forest many a time :)

If someone can't see the wood for the trees in British English, or can't see the forest for the trees in American English, they are very involved in the details of something and so they do not notice what is important about the thing as a whole.
https://www.collinsdictionary.com/dictionary/english/cant-see-the-wood-for-the-trees

feisty2
26th December 2020, 21:15
You should probably give vaporsynth a shot if you need to mess with dynamic filter graphs

VoodooFX
8th January 2021, 23:20
Sadly, idea didn't gave desired improvements, at least on one case.

Btw, noticed that this runs 30% faster:


expression = """
if(c1.AverageLuma < Th) {
c3
} else {
if (c3.AverageLuma > Th) {
c3
} else if (c2.AverageLuma > Th) {
c2
} else {
c1
}
}
return Last
"""


Than this:


expression = """
Yc1 = c1.AverageLuma
Yc2 = c2.AverageLuma
Yc3 = c3.AverageLuma

if(Yc1 < Th) {
c3
} else {
if (Yc3 > Th) {
c3
} else if (Yc2 > Th) {
c2
} else {
c1
}
}
return Last
"""

StainlessS
9th January 2021, 02:06
Well yeah, was done as it was for debugging stuff.
Once working you could mod as required.