Log in

View Full Version : Overlay_MTools


Arx1meD
1st July 2021, 13:55
Overlay_MTools

Overlay puts two clips on top of each other with an optional masking, and using different blending methods. Furthermore opacity can be adjusted for the overlay clip.

This script is not as versatile as the Overlay filter in AviSynth (http://avisynth.nl/index.php/Overlay). But it has more blend modes and is a bit faster. Input clips (base, overlay and mask) must be in the same colorspace and have the same frame size.

Attention!
1. Overlay in AviSynth, this script and Photoshop overlay methods give different results. If you want to get a result similar to the one in Photoshop, then set blend_rgb=true in function.
2. In AviSynth Overlay, softlight and hardlight modes give completely different results. Because the source code (https://github.com/AviSynth/AviSynthPlus/blob/master/avs_core/filters/overlay/OF_softhardlight.cpp) contains other formulas for these modes. In my opinion, this is a mistake (based on information found about blending modes). The softlight mode in AviSynth Overlay is actually grainmerge, and hardlight is actually linearlight.


# Overlay_MTools() v1.1
#
# v1.0 : - first release
# v1.1 : - changed the blending method when is no mask clip

/*
Needed plugins: MaskTools2 v2.2.16 or greater.
https://github.com/pinterf/masktools/releases
http://avisynth.nl/index.php/Masktools2

Overlay_MTools(source, over, mask, mode, opacity, chroma, blend_rgb)

source:
-------
This clip is base.

over:
-----
This clip will be placed on top of the base clip.

mask:
-----
This clip will be used as the transparency mask for the overlay clip.
The darker the image is, the more transparent will the overlay clip be.
Default: Undefined

mode:
-----
Mode (or overlay method) defines how overlay clip should be overlaid on base image.

Group | Mode
-----------|-----------------------------------------------------------------------------------------------------------------
Simple | blend, average
Darken | darken, multiply, colorburn, linearburn
Lighten | lighten, screen, colordodge, add (aka lineardodge)
Mix | overlay, softlight, hardlight, vividlight, linearlight, pinlight, hardmix, softburn, softdodge, interpolation
Difference | difference, difference_grey, subtract, exclusion, negation, extremity, divide, phoenix, grainextract, grainmerge
Quadratic | reflect, glow, freeze, heat
Binary | AND, OR, XOR - These modes available for 8-bit color bit depth only

Default: "blend"

opacity:
--------
This will set how transparent overlay clip will be. The value 0 is transparent and 1.0 is fully opague.
Range: 0 ... 1.0
Default: 1.0

chroma:
-------
This option specifies whether to use chroma channels.
true - it means "process" (set u = v = 3 in mt_lut() MaskTools2).
false - it means "copy" or "copy first" (set u = v = 2).
Default: false

blend_rgb:
----------
Use this option if you want to get a blending effect like in Photoshop (with RGB color space).
true - do blending in RGB color space.
false - do blending in YUV (YCbCr) color space.
Default: false

Usage Default:
Overlay_MTools(source, over, mode="blend", opacity=1.0, chroma=false, blend_rgb=false)
or with clip mask
Overlay_MTools(source, over, mask=mask, mode="blend", opacity=1.0, chroma=false, blend_rgb=false)
*/


function Overlay_MTools(clip source, clip over, clip "mask", string "mode", float "opacity", bool "chroma", bool "blend_rgb"){
mask = Default(mask, Undefined)
mode = Default(mode, "blend")
opacity = Default(opacity, 1.0)
chroma = Default(chroma, false)
blend_rgb = Default(blend_rgb, false)

src_411 = source.IsYV411
src_420 = source.Is420
src_422 = source.Is422
src_444 = source.Is444
src_Y = source.IsY
src_Pl = source.IsPlanarRGB

# Simple modes:
md = mode=="blend" ? "x 0 * y +" : "ERR"
md = mode=="average" ? "x y + 2 /" : md

# Darken/Burn modes:
md = mode=="darken" ? "x y min" : md
md = mode=="multiply" ? "x y * 255 /" : md
md = mode=="colorburn" ? "y 0 == y 255 255 x - 255 * y / - ?" : md
md = mode=="linearburn" ? "x y + 255 < 0 x y + 255 - ?" : md

# Lighten/Dodge modes:
md = mode=="lighten" ? "x y max" : md
md = mode=="screen" ? "x y + x y * 255 / -" : md
md = mode=="colordodge" ? "y 255 == y x 255 * 255 y - / ?" : md # inverse the ColorBurn
md = mode=="add" ? "x y +" : md # aka LinearDodge mode

# Mix/Combine modes:
md = mode=="overlay" ? "x 127.5 > 2 x y + x y * 255 / - * 255 - x y * 127.5 / ?" : md # inverse the HardLight (like in Photoshop)
md = mode=="softlight" ? "x 255 / x y 2 * + x y * 127.5 / - *" : md # combination of Multiply and Screen (like in Photoshop)
md = mode=="hardlight" ? "y 127.5 > 2 x y + x y * 255 / - * 255 - x y * 127.5 / ?" : md # combination of Multiply and Screen (like in Photoshop)
md = mode=="vividlight" ? "y 127.5 < y 0 <= 2 y * 255 255 x - 255 * 2 y * / - ? 2 y 127.5 - * 255 >= 2 y 127.5 - * x 255 * 255 2 y 127.5 - * - / ? ?" : md # combination of ColorBurn and ColorDodge
md = mode=="linearlight" ? "x 2 y * + 255 -" : md # combination of LinearBurn and LinearDodge (or stamp mode)
md = mode=="pinlight" ? "y 127.5 < x 2 y * min x 2 y 127.5 - * max ?" : md # combination of Darken and Lighten
md = mode=="hardmix" ? "x 255 y - < 0 255 ?" : md # or (vividlight < 128 ? 0 : 255)
md = mode=="softburn" ? "x y + 255 < x 255 == x 255 y * 2 255 x - * / ? y 0 == y 255 255 x - 255 * y 2 * / - ? ?" : md # combination of ColorBurn and inverse ColorDodge
md = mode=="softdodge" ? "x y + 255 < y 255 == y x 255 * 2 255 y - * / ? x 0 == x 255 255 255 y - * 2 x * / - ? ?" : md # combination of ColorDodge and inverse ColorBurn
md = mode=="interpolation" ? "255 0.5 pi x * 255 / cos 4 / - pi y * 255 / cos 4 / - *" : md

# Difference modes:
md = mode=="difference" ? "x y - abs" : md
md = mode=="difference_grey" ? "x y - abs 127.5 +" : md # like in AviSynth, use with chroma=true
md = mode=="subtract" ? "x y -" : md
md = mode=="exclusion" ? "x y + x y * 127.5 / -" : md
md = mode=="negation" ? "255 255 x - y - abs -" : md
md = mode=="extremity" ? "255 x - y - abs" : md # inverse the Difference
md = mode=="divide" ? "y 0 <= 255 255 x * y / ?" : md
md = mode=="phoenix" ? "x y min x y max - 255 +" : md # inverse the Negation
md = mode=="grainextract" ? "x y - 127.5 +" : md
md = mode=="grainmerge" ? "x y + 127.5 -" : md # inverse the GrainExtract

# Quadratic modes:
md = mode=="reflect" ? "y 255 == y x x * 255 y - / ?" : md
md = mode=="glow" ? "x 255 == x y y * 255 x - / ?" : md # inverse the Reflect
md = mode=="freeze" ? "y 0 == 0 255 255 x - 2 ^ y / -?" : md
md = mode=="heat" ? "x 0 == 0 255 255 y - 2 ^ x / -?" : md # inverse the Freeze

# Binary modes:
md = mode=="AND" ? "x y &u" : md
md = mode=="OR" ? "x y |u" : md
md = mode=="XOR" ? "x y @u" : md

Assert(opacity >= 0 && opacity <= 1, "Overlay_MTools: Opacity must be in the range 0 to 1.0")
Assert(md != "ERR", "Overlay_MTools: Invalid 'mode' specified")

bpc = source.BitsPerComponent
chrom = blend_rgb || chroma ? "process" : "copy"
# chrom_m = blend_rgb && src_Pl ? "process" : !src_Pl ? "copy" : chrom

# mask = Defined(mask) ? mask : source.mt_lut("range_max", Y=3, chroma=chrom_m)

source = blend_rgb ? src_Pl || src_Y ? source : source.ConvertToPlanarRGB() : source
over = blend_rgb ? src_Pl || src_Y ? over : over.ConvertToPlanarRGB() : over
mask = Defined(mask) ? blend_rgb ? src_Pl || src_Y ? mask : mask.ConvertToPlanarRGB() : mask : Undefined
# mask = blend_rgb ? src_Pl || src_Y ? mask : mask.ConvertToPlanarRGB() : mask

# with a mask slower
# blend = mt_lutxyz(source, over, mask,
# \ expr="x x "+md+" - z 255 / * "+String(opacity)+" * -",
# \ Y=3, chroma=chrom, scale_inputs=bpc==8?"none":"allf", use_expr=bpc==8?0:2)

blend = mt_lutxy(source, over,
\ expr="x x "+md+" - "+String(opacity)+" * -",
\ Y=3, chroma=chrom, scale_inputs=bpc==8?"none":"allf", use_expr=bpc==8?0:2)

blend = Defined(mask) ? mt_merge(source, blend, mask, Y=3, chroma=chrom) : blend

out = src_411 ? blend.ConvertToYUV411()
\ : src_420 ? blend.ConvertToYUV420()
\ : src_422 ? blend.ConvertToYUV422()
\ : src_444 ? blend.ConvertToYUV444()
\ : src_Y ? blend.ConvertToY()
\ : blend

return blend_rgb ? out : blend
}


Usage Default:
Overlay_MTools(source, over, mode="blend", opacity=1.0, chroma=false, blend_rgb=false)
or with clip mask
Overlay_MTools(source, over, mask=mask, mode="blend", opacity=1.0, chroma=false, blend_rgb=false)


Examples of what the script does. Only math
Source clip (aka base clip) - color changes in the X-axis
https://images2.imgbox.com/a0/20/UFoqoAVB_o.png
Overlay clip - color changes in the Y-axis
https://images2.imgbox.com/cd/3b/MNbLvyWb_o.png
Result
https://images2.imgbox.com/ad/da/uYP4joD3_o.png

Other Overlay scripts: UU_mt_blend (http://avisynth.nl/index.php/UU_mt_blend), Blend_MT_alpha3 (https://forum.doom9.org/showthread.php?p=1400434#post1400434), ex_blend (https://github.com/Dogway/Avisynth-Scripts/blob/9d2f113742a5a7fea3cb4945f78768132e1f69b3/ExTools.avsi), OverlayPlus (http://avisynth.nl/index.php/OverlayPlus) (in forum (https://forum.doom9.org/showthread.php?t=183185))

More information about Blend Modes:
https://en.wikipedia.org/wiki/Blend_modes
https://stackoverflow.com/questions/5919663/how-does-photoshop-blend-two-images-together
https://www.w3.org/TR/compositing/#blending
https://web.archive.org/web/20120728013719/http://jswidget.com/blog/2011/03/11/image-blending-algorithmpart-i
https://help.maxon.net/us/index.html#11718
https://ww2.mathworks.cn/matlabcentral/fileexchange/52513-image-blending-functions

kedautinh12
1st July 2021, 14:18
Thanks

Reel.Deel
1st July 2021, 21:16
@Arx1meD

About a month ago I started to port havsfuc Overlay function to AVS+. Then was away for some weeks and have not touch it since then. It is still unfinished and some of the modes in the script produce weird results but the x and y offsets work. Here's the script if you want to incorporate the x and y padding portion of it: https://gist.github.com/Reel-Deal/2f9f6e4bc388a60faa73a4b9906cf014

I will test out your script, it's nice to have the additional modes :).

poisondeathray
1st July 2021, 21:25
rr42 wrote something similar a few years back

http://avisynth.nl/index.php/UU_mt_blend
https://forum.doom9.org/showthread.php?t=170490

I think more blend modes are in this newer version

Reel.Deel
1st July 2021, 21:54
rr42 wrote something similar a few years back

http://avisynth.nl/index.php/UU_mt_blend
https://forum.doom9.org/showthread.php?t=170490

I think more blend modes are in this newer version

Also WorBry's Blend_MT_alpha3 back in 2010: https://forum.doom9.org/showthread.php?p=1400434#post1400434

But both of these earlier scripts only worked with 2 inputs and no mask clip.

kedautinh12
2nd July 2021, 00:18
Ex_blend from Dogway
https://github.com/Dogway/Avisynth-Scripts/blob/9d2f113742a5a7fea3cb4945f78768132e1f69b3/ExTools.avsi#L305

Arx1meD
2nd July 2021, 08:09
Thank you all for the comments!
I know about Ex_blend and UU_mt_blend.
I needed to overlay one clip on top of another with a mask and I couldn't use them. The Overlay filter in AviSynth gives a completely different result even in RGB color space than Photoshop. This is strange! So I decided to write another script.
My script is for some mode slower than Ex_blend, because the mask clip is used in the calculations.

Reel.Deel, thanks for a way to offset the overlay clip on the x and y axes.

Dogway
3rd July 2021, 02:19
Maybe you can add a check to skip lutxyz processing if mask is not defined.
What I observed at least with Multiply mode is that the output is a bit darker (blend_rgb=false). This might be an indication of doing PC levels blending for TV levels clips.

Arx1meD
3rd July 2021, 09:20
Maybe you can add a check to skip lutxyz processing if mask is not defined.
What I observed at least with Multiply mode is that the output is a bit darker (blend_rgb=false). This might be an indication of doing PC levels blending for TV levels clips.
Updated post #1. Now if there is no mask clip, the speed is almost the same as that of ex_blend.

kedautinh12
3rd July 2021, 10:56
Thanks

Reel.Deel
1st September 2021, 20:19
Hi Arx1meD,

For chromra you have it as default=true but it is in the actual script is set to false.

And one more thing, can you please update the OverlayPlus link to: http://avisynth.nl/index.php/OverlayPlus
I will post the link to the finished script there either today or tomorrow.

Arx1meD
2nd September 2021, 15:57
For chromra you have it as default=true but it is in the actual script is set to false.
I have corrected the error in the description and updated the link.