Log in

View Full Version : "Screen" algo in mt_lutxy


Dogway
25th March 2011, 14:47
I borrowed the polish syntax from another function, but couldnt make the screen blend mode to perform correctly. It is most noticeable when black over black, where luma should be 16 is 31. Im using the next code:

mt_lutxy(a,b,"256 256 x - 256 y - * 256 / - " ,Y=3, U=2, V=2)

I also found in another web (http://forensicphotoshop.blogspot.com/2007/09/blending-mode-math-part-2.html?showComment=1261435548101#c8741541460559691405) the infix syntax, I tried using it like so:
mt_lutxy(a,b,mt_infix("255 - (255-U)*(255-L)/255 ***"),Y=3, U=2, V=2)

but everything renders black.

Gavino
25th March 2011, 15:31
Your formula assumes PC levels (0-255) rather than the normal 'TV' levels (16-235). Although the formula could be rewritten, the simplest solution is to use ColorYUV(levels="TV->PC") on both input clips before calling mt_lutxy, and ColorYUV(levels="PC->TV") after. But I think all your 256's probably should be 255's.

I've never heard of mt_infix - do you mean mt_polish?
The call could be written as:
mt_lutxy(a,b,mt_polish("255 - (255-x)*(255-y)/255"),Y=3, U=2, V=2)

Didée
25th March 2011, 15:34
It's rather obvious. The formula is laid out for black=0, white=255. But in YV12 with TV levels, it's black=16, white=235.

Replacing all "256" with "236 16 -", and all "x" or "y" with "x 16 -" and "y 16 -" respectively, should result in a correct screen formula for 16-235 TV scale.

236 16 - 236 16 - x 16 - - 236 16 - y 16 - - * 236 16 - / -


In your 2nd script line ... do you really expect mt_lutxy to reckognize the letters "U" and "L"? ;)

Dogway
25th March 2011, 15:45
Yes, you are right, I didnt pay attention to that point. I guess then the formula becomes rather tricky if done mt_lutxy.

Dogway
25th March 2011, 15:49
halooo Didée; soo fast lol. I was actually trying to replace 256 with 219, but I dont understand plish notation so it is more a try and cross fingers+waste of time. Thanks!
U and L are just the variables. I posted them as they were in the webpage for reference. I wondered if that ".../255 ***" meant something, although it didnt got me an error.

edit=result is a bit dark, still testing...

Gavino
25th March 2011, 15:57
Replacing all "256" with "236 16 -", and all "x" or "y" with "x 16 -" and "y 16 -" respectively, should result in a correct screen formula for 16-235 TV scale.
Not quite. You also have to add 16 back into the final result, requiring " 16 +" at the end.
U and L are just the variables. I posted them as they were in the webpage for reference. I wondered if that ".../255 ***" meant something, although it didnt got me an error.
One of the 'features' of Masktools is that it does not check the validity of expressions and just returns garbage (or crashes) instead of reporting an error.

Dogway
25th March 2011, 16:04
@Gavino: Gracias! worked like charm. What I didn't know was that 255 ***. Of course in the practice I replaced U and L with x and y. At least I know that :helpful:

edit: In gratitude just wanted to share my little function for what this was. Didn't test it deeply so it'll mostly contain errors.
FUNCTION Logo(clip clip,string path, int "x", int "y",int "length", bool "alpha",int "start",float "Opac",int "I",int "O",float "blur"){

path=string(path)
alpha=default(alpha,true)
x=default(x, 0)
y=default(y, 0)
start=default(start, 0)
length=default(length, 50)
I=default(I, 20)
O=default(O, 20)
Opac=default(Opac, 1.0)
Sblur=default(blur, 0.0)

logo0=CoronaSequence(path).trim(0,length).FadeIn(I).FadeOut(O)
logo0a=logo0.addborders(x,y,clip.width,clip.height).crop(0,0,-logo0.width-x,-logo0.height-y).blur(Sblur)
logo1=logo0a.converttoyv12().assumefps(Framerate(Clip))

video0=clip.trim(0,start == 1 ? -1 : start-1)
video1=clip.trim(start,start+length-1)
video2=clip.trim(start+length,0)

msk=ShowAlpha(logo0a,"rgb").converttoyv12

video1 = (alpha==true) ?
\ mt_merge(video1,logo1,mt_lut(msk," x 16 - "+String(Opac)+" * "),luma=true)
\ : mt_lutxy(video1,logo1,Y=3, U=2, V=2,
\ "236 16 - 236 16 - x 16 - - 236 16 - y 16 - - * 236 16 - / - 16 + "+String(Opac)+" * x 1 "+String(Opac)+" - * + ")

video=start >0 ? video0+video1+video2 : video1+video2
return video}

Gavino
26th March 2011, 11:05
I've never heard of mt_infix - do you mean mt_polish?
The call could be written as:
mt_lutxy(a,b,mt_polish("255 - (255-x)*(255-y)/255"),Y=3, U=2, V=2)
I've discovered mt_infix converts from polish to infix, so your original code would not have worked, even without the "***".

edit: In gratitude just wanted to share my little function for what this was. Didn't test it deeply so it'll mostly contain errors.
...
logo0=CoronaSequence(path).trim(0,length).FadeIn(I).FadeOut(O)
...
msk=ShowAlpha(logo0a,"rgb").converttoyv12

video1 = (alpha==true) ?
\ mt_merge(video1,logo1,mt_lut(msk," x 16 - "+String(Opac)+" * "),luma=true)
...
When using alpha, your mask is set up wrong, eg alpha mask 255 becomes 219.
Also, logo0 has the wrong number of frames (length+3 instead of length).
You want:
logo0=CoronaSequence(path).trim(0,length-1).FadeIn0(I).FadeOut0(O)
...
msk=ShowAlpha(logo0a,"YV12")

video1 = (alpha==true) ?
\ mt_merge(video1,logo1,mt_lut(msk,"x "+String(Opac)+" * "),luma=true)

Dogway
26th March 2011, 11:33
Thanks thanks a lot, maybe thats the reason of the "darkening" of fadein fadeout, before/after disappearing. Good tips
I also had realised about mt_infix, I tested after that with mt_polish...
I rely on blur() but do you think 0.0 is a no-operator? should I better use GaussianBlur?

I updated the function:
FUNCTION Logo(clip clip,string path, int "x", int "y",int "start",int "length", bool "alpha",float "Opac",int "I",int "O",float "blur")
{
path=string(path)
alpha=default(alpha,true)
x=default(x, 0)
y=default(y, 0)
start=default(start, 0)
length=default(length, 50)
I=default(I, 20)
O=default(O, 20)
Opac=default(Opac, 1.0)
Sblur=default(blur, 0.0)

logo0=CoronaSequence(path).trim(0,length-1).FadeIn0(I).FadeOut0(O)
logo0a=logo0.addborders(x,y,clip.width,clip.height).crop(0,0,-logo0.width-x,-logo0.height-y).blur(Sblur)
logo1=logo0a.converttoyv12().assumefps(Framerate(Clip))

video0=clip.trim(0,start == 1 ? -1 : start-1)
video1=clip.trim(start,start+length-1)
video2=clip.trim(start+length,0)

video1 = (alpha==true) ?
\ mt_merge(video1,logo1,mt_lut(ShowAlpha(logo0a,"YV12")," x "+String(Opac)+" * "),luma=true)
\ : mt_lutxy(video1,logo1,Y=3, U=2, V=2,
\ "236 16 - 236 16 - x 16 - - 236 16 - y 16 - - * 236 16 - / - 16 + "+String(Opac)+" * x 1 "+String(Opac)+" - * + ")

video=start >0 ? video0+video1+video2 : video1+video2

return video}

Gavino
26th March 2011, 11:59
Blur(0.0) is a no-op. The code is optimised and just returns the input clip.
Regarding GaussianBlur, it depends what sort of effect you want. The range of Blur() is limited to 1.58 and even repeating this has a limited effect, so if you want to blur more you have to use a gaussian.

Dogway
27th March 2011, 06:47
logo0 =CoronaSequence(path).trim(0,end-start-1).FadeIn0(I).FadeOut0(O)
logo0a=logo0.addborders(x,y,clip.width,clip.height).crop(0,0,-logo0.width-x,-logo0.height-y).blur(Sblur)
logo1 =logo0a.converttoyv12().assumefps(Framerate(Clip))

s=ShowAlpha(logo0a,"YV12")

video1 = AverageLuma(s) == float(HexValue("FFFFFF")) ?
\ mt_merge(clip.trim(start,end-1),logo1,mt_lut(s," x "+String(Opac)+" * "),luma=true)
\ : mt_lutxy(clip.trim(start,end-1),logo1,Y=3, U=2, V=2,
\ "236 16 - 236 16 - x 16 - - 236 16 - y 16 - - * 236 16 - / - 16 + "+String(Opac)+" * x 1 "+String(Opac)+" - * + ")

return start >0 ? clip.trim(0,start == 1 ? -1 : start-1)+video1+clip.trim(end,0) : video1+clip.trim(end,0)}

I updated the code a bit, mostly nesting functions, do you think this is better for RAM optimization?
Also I want to automatically detect alpha so I can remove the alpha parameter.
As theres are no clip properties associated to alpha evaluation, I try to compare the result from the average of ShowAlpha to White, if false then it has alpha.
Problem here is Im getting errors ("Invalid arguments")when I try AverageLuma, I think because some the ISSE requeriments:
AverageLuma(ShowAlpha(logo0a,"YV12")) == float(HexValue("FFFFFF"))

Gavino
27th March 2011, 10:47
I updated the code a bit, mostly nesting functions, do you think this is better for RAM optimization?
It can be in some cases. Nested function calls do not save anything per se, but if you have filters that are only used on a conditional branch, it can help to avoid calling them unnecessarily outside the condition. (But filters like Trim use very little memory anyway.)
Also I want to automatically detect alpha so I can remove the alpha parameter.
As theres are no clip properties associated to alpha evaluation, I try to compare the result from the average of ShowAlpha to White, if false then it has alpha.
Problem here is Im getting errors ("Invalid arguments")when I try AverageLuma, I think because some the ISSE requeriments:
AverageLuma(ShowAlpha(logo0a,"YV12")) == float(HexValue("FFFFFF"))
The immediate problem here is that AverageLuma is not a clip property, but a frame property, so you can only use it inside a run-time (http://avisynth.org/mediawiki/Runtime_environment) filter such as ScriptClip.
However, you can't reliably detect the presence of alpha by looking at single frames - you would need to check the whole clip for the existence of some frames with AverageLuma not equal to zero or 255 ($ff, not $ffffff). Too complicated to be worth doing, I think.

Dogway
27th March 2011, 19:43
I read that page before but thanks to your guidance I think I got it working.
The only pitfall here is in case the logo is animated, and the sample frame to take the alpha from (Default FadeIn(I)) has alpha set to 100% opacity. Its quite unlikely, but Im done in this regard. Maybe only that ConditionalFilter feels a bit unstable, like in the same boat as layer, or overlay...

The only last part I want to fix is making chroma work in blending modes.
The function where I took the blend mode from is Blend_MT_alpha3 (http://forum.doom9.org/showthread.php?p=1400434#post1400434), but even in that function, chroma seems broken.

FUNCTION Logo(clip clip,string path, int "x", int "y",int "start",int "end", float "Opac",int "I",int "O",float "blur",string "mode", bool "anim_gif")
{
path=string(path)
x=default(x, 0)
y=default(y, 0)
start=default(start, 0)
end=default(end, 100)
I=default(I, 20)
O=default(O, I)
Opac=default(Opac, 1.0)
Sblur=default(blur, 0.0)
gif=default(anim_gif,false)
mode=default(mode,"Screen")


logo0 = gif == false ? CoronaSequence(path,start=start,stop=end-1).mmod2.FadeIn0(I).FadeOut0(O)
\ : ImmaRead(path,start=start,end=end-1,animation=true).mmod2.FadeIn0(I).FadeOut0(O)
logo0a=logo0.addborders(x,y,clip.width,clip.height).crop(0,0,-logo0.width-x,-logo0.height-y).blur(Sblur)
logo1 =logo0a.converttoyv12().assumefps(Framerate(Clip))

video1=ConditionalFilter(ShowAlpha(logo0,"YV12").trim(I+1,I),
\ mt_lutxy(clip.trim(start,end-1),logo1,Y=3, U=2, V=2,
\ (mode=="Screen") ? "236 16 - 236 16 - x 16 - - 236 16 - y 16 - - * 236 16 - / - 16 + "+String(Opac)+" * x 16 - 1 "+String(Opac)+" - * + "
\:(mode=="Multiply") ? "x 16 - y 16 - * 236 16 - / 16 + "+String(Opac)+" * x 16 - 1 "+String(Opac)+" - * + " : Assert(false, "Unsupported Blending Mode")
\), mt_merge(clip.trim(start,end-1),logo1,mt_lut(ShowAlpha(logo0a,"YV12")," x "+String(Opac)+" * "),luma=true),"AverageLuma()","==","255",false)

return start >0 ? clip.trim(0,start == 1 ? -1 : start-1)+video1+clip.trim(end,0) : video1+clip.trim(end,0)}
Edit: I reworked the function completly, I fixed some things, and added option for Over blending mode. Syntax is awful with my limited knowledge... so Im sure the code can be optimized far far better. I really just would like to fix the chroma blending, I tried everything but my guess is it has to do with the polish notation formula.
Edit2:I read a paper. Im going to try to compute the effect in RGB and add the difference to my YUV clip. Maybe there's less degradation in this way... I might also fix something I saw when I got time.
Edit3: I didn't come to think masktools is only for YV12, so I guess chroma blending stays unfunctional, unless I find a way to compute blend modes in RGB. Also I updated/fixed/optimized the code for the new workaround, now this is a working release. Enjoy it.

(Old)
FUNCTION Logo(clip clip,string path, int "x", int "y",int "start",int "end", float "Opac",int "I",int "O",float "blur",string "mode",bool "matte",bool "anim_gif")
{
path=string(path)
x=default(x, 0)
y=default(y, 0)
start=default(start, 0)
end=default(end, 100)
I=default(I, 20)
O=default(O, I)
Opac=default(Opac, 1.0)
Sblur=default(blur, 0.0)
gif=default(anim_gif,false)
mode=default(mode,"Over")
matte=default(matte,false)


logo0 = gif == false ? CoronaSequence(path,start=start,stop=end-1).mmod2.FadeIn0(I).FadeOut0(O)
\ : ImmaRead(path,start=start,end=end-1,animation=true).mmod2.FadeIn0(I).FadeOut0(O)
logo0a=logo0.addborders(x,y,clip.width,clip.height).crop(0,0,-logo0.width-x,-logo0.height-y).blur(Sblur)
logo1 =logo0a.converttoyv12().assumefps(Framerate(Clip))

msk = matte == false ? ShowAlpha(logo0a,"YV12")
\ : ShowAlpha(logo0a,"YV12").lanczosresize(logo0a.width*3,logo0a.height*3).mt_inpand(mode="both").LanczosResize(logo0a.width,logo0a.height)
org=clip.trim(start,end-1)
screen="236 16 - 236 16 - x 16 - - 236 16 - y 16 - - * 236 16 - / - "+String(Opac)+" * x 16 - 1 "+String(Opac)+" - * + 16 + "
multiply=" x 16 - y 16 - * 236 / "+String(Opac)+" * x 16 - 1 "+String(Opac)+" - * + 16 + "

video1 =
\ (mode=="Screen") ? mt_merge(org,mt_lutxy(org,logo1,Y=3, U=2, V=2,screen) ,msk,luma=true)
\:(mode=="Multiply") ? mt_merge(org,mt_lutxy(org,logo1,Y=3, U=2, V=2,multiply),msk,luma=true)
\:(mode=="Over") ? mt_merge(org,logo1,mt_lut(msk," x "+String(Opac)+" * "),luma=true)
\:Assert(false, "Unsupported Blending Mode")

return start >0 ? clip.trim(0,start == 1 ? -1 : start-1)+video1+clip.trim(end,0) : video1+clip.trim(end,0)}

function mmod2(clip c){
bh = 2 - ((c.Width()-1)%2 + 1)
bv = 2 - ((c.Height()-1)%2 + 1)
l = bh/2
l = c.IsYUV() && l%2 != 0 ? l-1 : l
r = bh - l
t = bv/2
t = c.IsYV12() && t%2 != 0 ? t-1 : t
b = bv - t
c.crop(l,t,-r,-b)}

(Updated)
Logo9.0.avsi (http://www.mediafire.com/?0qmaw0m18obn8ii)