Log in

View Full Version : OverlayPlus: layering script similar to Overlay with addidional modes.


Reel.Deel
2nd September 2021, 11:17
So I finally finished my OverlayPlus script. Most of it is a port of VapourSynth's havsfunc Overlay function. In addition, it includes 5 additional modes from Overlay_MTools (https://forum.doom9.org/showthread.php?t=183003), "multiply128" from FFmpeg (line #298) (https://ffmpeg.org/doxygen/trunk/libavfilter_2vf__blend_8c_source.html), "linearadd" and "linearsubtract" are modes I added based on Gimp's v2.10 add and subtract mode (https://gitlab.gnome.org/GNOME/gimp/-/issues/1872), "linearadd" is also known as "hypot" in Nuke (https://learn.foundry.com/nuke/content/comp_environment/merging/merge_operations.html).

Aside from that OverlayPlus works the same ways as the internal Overlay. The base and overlay clip do not have be the same dimensions and placement of the overlay clip can be adjusted, just like in overlay. All of OverlayPlus' parameters have the same meaning as Overlay, only difference is that Overlay's greymask parameter is called mask_first_plane in OverlayPlus.

As Arx1meD pointed out in the Overlay_MTools thread, internal Overlay does not produce results that are similar to Photostop and Gimp, etc (except for "blend" mode). That is because Overlay works internally in YUV and applies additional formulas on the U/V channels. Even in RGB some of the results are not too similar. In greyscale, most of the results are the same between the 2 functions.

Detailed documentation: http://avisynth.nl/index.php/OverlayPlus

Without further ado:
overlayplus.avsi (https://github.com/Reel-Deal/AviSynthPlus-Scripts/blob/main/overlayplus.avsi)

TO DO LIST:

Replace chroma parameters with a planes parameter (maybe);
Add hue and saturation modes;
Add some other modes from MATLAB (https://www.mathworks.com/matlabcentral/fileexchange/52513-image-blending-functions) (provided I can find formulas).
Fix any bugs that you guys find :D

kedautinh12
2nd September 2021, 11:26
Thanks, one man stand :D

Edit: can you up file to github for easy to monitor changes between versions??

Arx1meD
2nd September 2021, 16:11
Hi Reel.Deel
I noticed an error in your script:
In the OverlayPlus function, the "chroma" option is defined as bool:
function OverlayPlus (... bool "chroma" ...)
...
chroma = default(chroma, true)
Then you assign chroma the string:
chroma = (base.IsRgb || chroma==true) ? "process" : "copy"

StainlessS
2nd September 2021, 16:33
Then you assign chroma the string:
Nothing wrong with that, it was a bool, and then a string, [EDIT: is always bool before that point, and always string after that point in script]
just makes checking of function call easier [with a bool arg <no check needed at all>, instead of checking valid chroma arg as string].

But dont need eg

chroma = (base.IsRgb || chroma==true) ? "process" : "copy"


and instead of

Defined(msk)==false

Maybe
!Defined(msk)

Comparing with Global variables "true" and "false" is slow, and simply not needed when both chroma [at that point in script] is already a bool, and so is result of Defined().
Test of Bool True or False is done by parser and fast, whereas comparison with true or false globals is slow (has to find value of variable named "True" or "False" in Globals variable name table, after first searching Local variables name table).
True/False assigned to global vars early on in Avisynth startup, and so right at the end of Global variable list.

Above does not really matter, unless called many times from within runtime script. [EDIT: Also, I think name table access sped up some in AVS+]

Reel.Deel
2nd September 2021, 20:22
Hi Reel.Deel
I noticed an error in your script:
In the OverlayPlus function, the "chroma" option is defined as bool:

Then you assign chroma the string:

It just converts true or false to "process" and "copy" to feed mt_merge's chroma parameter . Similar to what you did in your script:

chrom = blend_rgb || chroma ? "process" : "copy"


and instead of

Defined(msk)==false

Maybe
!Defined(msk)


I will probably do some cosmetics later. But I guess it's just me but I like putting true or false, it makes it easier for me to follow.

StainlessS
2nd September 2021, 20:31
makes it easier for me to follow.
Is a bit like if(true==true), but I have been known to do it too, is nothing terribly wrong about it :)

Reel.Deel
10th September 2021, 20:18
I updated OverlayPlus, see first post. It includes a bug fix, added a chroma placement parameter, support for all interleaved colorspaces and a few other other minor things. OverlayPlus now accepts mismatched colorspaces as long as they are in the same color family. For example the base clip can be RGB32 and the overlay RGBP8 or vice versa. Or in YUV the base clip can be YUVA420P8 and the overlay clip can be YUV420P8, or base can be YUY2 and overlay YV16. If applicable, the alpha channel is discarded from the overlay and mask clip, only the base clip alpha channel is copied. Mask can be any colorspace if mask_first_plane=true, if not it must be the same as the base with or without an alpha channel..... Enjoy :)

Reel.Deel
27th September 2021, 09:28
I updated OverlayPlus, see first post. It includes a bug fix and some optimizations to try to increase speed. The cropping and padding stage is skipped when not needed and a single frame mask is used when a mask clip is not defined. From my test this increased the speed over 100fps on SD resolution and used less memory overall. Aside from that, now an RGB or YUV444 mask can be used and interchanged when the base clip is RGB or YUV. And last but not least the chroma parameter now defaults to false for YUV clips. Next version will have an RGB mode for YUV colorspaces, just undecided what to do with YUV420 or YUV422, downscale the luma channel to the size of the chroma or upscale the chroma to the luma....


I hope these changes makes the speed more comparable to ex_blend or Overlay_MTools :
# 100% ex_blend(a,mode="multiply")
# 92% Overlay_MTools(mode="multiply") # only in PC range
# 56% OverlayPlus(a,mode="multiply",chroma=false) # only in PC range
# 56% Overlay(mode="multiply") # only in PC range

@Dogway

What colorspace and dimensions did you use for that benchmark?

Dogway
27th September 2021, 17:04
I use 1080p@16-bit, with chroma false in 420.
I just retested latest version and is pretty much on par with ex_blend() within the margins of error.
OverlayPlus(a,mode="multiply",chroma=false) # 315
ex_blend(a,mode="multiply") # 319

pinterf
27th September 2021, 20:10
I see there is a bug in mt_merge chroma copy when luma is true?

Reel.Deel
27th September 2021, 21:08
I use 1080p@16-bit, with chroma false in 420.
I just retested latest version and is pretty much on par with ex_blend() within the margins of error.
OverlayPlus(a,mode="multiply",chroma=false) # 315
ex_blend(a,mode="multiply") # 319

Thank you for testing it again. I'm glad my changes increased the speed.

I see there is a bug in mt_merge chroma copy when luma is true?

Yes. I initially reported it here (https://forum.doom9.org/showthread.php?p=1951131#post1951131) but I think it was overlooked and then I forgot to follow up. So whenever luma=true it always processes the chroma planes, regardless of what chroma/u/v are set to. One can argue if you set luma=true you intend to process the chroma planes also but then u=2, v=3 is not possible since with luma=true it processes both planes. I don't know if this is the intended behavior but I think chroma/u/v should have priority. You can see what I'm talking about by setting luma to true and then false.

base = Blankclip(color=$FFFFFF, pixel_type="RGBP8")
base2 = Blankclip(color_yuv=$FF8080, pixel_type="YUV444P8")
over = Colorbars(pixel_type="RGBP8")
over2 = Colorbars(pixel_type="YUV444P8")
mask = Blankclip(color=$000000, pixel_type="RGBP8").Subtitle("AviSynth", size=150, align=5, text_color=$FFFFFF)
masky = mask.ShowRed("Y8")
mask2 = YToUV(masky,masky,masky)

# RGB
#mt_merge(base, over, mask, chroma="copy", luma=true)

#YUV
#mt_merge(base2, over2, mask2, chroma="copy", luma=false)
mt_merge(base2, over2, mask2, u=2, v=3, luma=true)

Edit:
I went back and read the old readme and I guess that is the intended behavior:

merge clip1 and clip2 according to the mask. If "luma" is true, only the luma
mask plane is used, and both chroma planes are processed with it - without needing
to specify u=v=3 or chroma="process"

Changed from alpha 21 to alpha 22 :
* added : bool "luma" parameter to mt_merge, which makes it use the luma mask for
all three planes, and which forces chroma modes to "process" ( u=v=3 )

I can't find any evidence in the source code but I don't why I was under the impression that luma defaults to true (only thing I found (https://github.com/pinterf/masktools/blob/16bit/masktools/filters/merge/merge.h#L293)). So this is a false alarm and not a bug but the intended behavior. Bummer.

Edit 2:
Added luma parameter notes in the wiki page (http://avisynth.nl/index.php/MaskTools2/Mt_merge) (luma, u/v, and chroma parameters), if something is wrong please let me know.

StvG
24th October 2022, 04:58
Thanks for the script.

I played with the function and found few issues. I used this: 1080p yv12 source
c=Crop(614, 314, 208, 498).SSHiQ2().GrainFactory3(g1str=1, g2str=1, g3str=1, g2size=0.9, g2shrp=60).Crop(64, 64, -64, -64)
OverlayPlus(c, x=678, y=378, chroma=false/true, mask_first_plane=true/false) # w/ and w/o mask
chroma and mask_first_plane shouldn't be allowed to be true at the same time, imo.
mask_first_plane is always true, even if chroma is true.
When chroma=true and mask is defined, the chroma of mask isn't take into account.
When overlay clip have to be padded and it colorspace is YUV 422/420, there could be green lines at the right border.

Here diff of the changes I made to fix above issues (https://www.diffchecker.com/gcyioH52) - left side is the original, right side is the modified. I didn't played with the other modes and colorspaces. I hope I didn't break them.

Reel.Deel
24th October 2022, 07:25
Hi StvG, thanks for the feedback. I have not tested your example or modified script yet (close to bedtime for me). But Overlay and mt_merge both work similar to OverlayPlus. In Overlay the chroma planes are always processed and greymask=true by default. In mt_merge when luma is set to true it automatically processes the U/V planes. In both cases the luma plane of the mask is used as the mask for the chroma planes, meaning that internally the mask Y plane gets resized to the appropriate subsampling. Same as OverlayPlus.

I will take a closer look later on, maybe I'm missing something. I did want to add a 'planes' parameter, maybe I can incorporate it into that, if anything.

StvG
24th October 2022, 18:52
Hi StvG, thanks for the feedback. I have not tested your example or modified script yet (close to bedtime for me). But Overlay and mt_merge both work similar to OverlayPlus. In Overlay the chroma planes are always processed and greymask=true by default. In mt_merge when luma is set to true it automatically processes the U/V planes. In both cases the luma plane of the mask is used as the mask for the chroma planes, meaning that internally the mask Y plane gets resized to the appropriate subsampling. Same as OverlayPlus.

I will take a closer look later on, maybe I'm missing something. I did want to add a 'planes' parameter, maybe I can incorporate it into that, if anything.

Yes, mt_merge(luma=true) implies chroma processing. mt_merge(u=3, v=3, luma=false) also is processing chroma but in different way than luma=true. When one have mt_merge(u=3, v=3, luma=true), luma=true takes precedence but the situation is a bit unclear (in what way chroma is processed - u/v=3 or luma=true) at the first look. That's why I added the assert code when both chroma and mask_first_plane are true.

Reel.Deel
25th October 2022, 08:35
I had some time to check out your example and yes, I saw the green stripe. It's because the mask is padded and then mt_merge(luma=true) resizes the luma to match the chroma. The resizing step blurs the edges of the padded areas in the mask and leads to that green stripe in subsampled formats. I updated OverlayPlus to pad and crop in the same colorspace as the base clip and got rid of luma=true in mt_merge by using my own mask scaling function. So now that there is no resizing after padding and cropping the mask, the green stripe is gone. I also added a chromaresample parameter, but it only has an effect when the mask clip is defined and with YUV420/422. I will leave the ability of setting chroma=true and mask_first_plane=true since I think it's useful but when mask is not defined mask_first_plane is ignored.

Here's the updated script: https://github.com/Reel-Deal/AviSynthPlus-Scripts/blob/main/overlayplus.avsi
And here's the diff in case you're interested: https://github.com/Reel-Deal/AviSynthPlus-Scripts/commit/9ba135a5027df762dfa250dd734d6a9df710a06d

If you see anything else that needs attention please let me know.

StvG
27th October 2022, 08:39
Thanks for the update. It's ok now.

PoeBear
25th February 2023, 00:33
What's the best modern image format to use with "mask" for 8-bit 4:2:0 video?

I always used a 24-bit bitmap with a solid black background and solid white mask parts with the built-in Overlay, but I'm trying to avoid the excess ConvertToYV12 and ConvertToRGB usage. Would any of the 4:2:0 capable formats, such as AVIF, be an option?

poisondeathray
25th February 2023, 02:15
What's the best modern image format to use with "mask" for 8-bit 4:2:0 video?

I always used a 24-bit bitmap with a solid black background and solid white mask parts with the built-in Overlay, but I'm trying to avoid the excess ConvertToYV12 and ConvertToRGB usage. Would any of the 4:2:0 capable formats, such as AVIF, be an option?



Is it an image sequence or 1 image?

Is there a reason for using an "image format" instead of a "video" ?

And why would you need 4:2:0 ? Are you using the Y (gray) channel for the mask only, or are you using the other channels as well ?

If single channel, one option is to use Y8 (gray) or Y16 (gray16le) tiff (with lzw compression if you wanted to reduce filesize) , and you can load it with ImageSource pixel_type="Y8" or "Y16"

An avif sequence cannot be loaded currently using imagesource, and only supports 8,10,12 bits

PoeBear
25th February 2023, 04:23
Is it an image sequence or 1 image?

Is there a reason for using an "image format" instead of a "video" ?

And why would you need 4:2:0 ? Are you using the Y (gray) channel for the mask only, or are you using the other channels as well ?

It's to remove a channel logo that's always in the same place, just a single image mask with light Photoshopped feathered edges needed to blend in slightly lower quality footage without logo, so it all looks better than just the logo

4:2:0 because the overlay is my first step in the script, where my videos are still in 4:2:0. All the filterings will be done at a later step. 4:4:4 is also fine if that's the limit, and I can overlay when I upscale. But not all my projects will be in 4:4:4, so I like to learn how to do 4:2:0 if possible

An avif sequence cannot be loaded currently using imagesource, and only supports 8,10,12 bits

Is OverlayPlus only able to use ImageSource? According to the wiki (http://avisynth.nl/index.php/OverlayPlus), it supports most planar formats. I was thinking if I could somehow turn my bitmap mask into an 8-bit 4:2:0 AVIF or similar file, I could load that with L-SMASH to load into OverlayPlus, which would be better as I wouldn't need to convert my clips to RGB and back, there would be no conversions

If single channel, one option is to use Y8 (gray) or Y16 (gray16le) tiff (with lzw compression if you wanted to reduce filesize) , and you can load it with ImageSource pixel_type="Y8" or "Y16"

This works, though for some reason only in Overlay, not OverlayPlus. OverlayPlus just displays the first clip. Still, enough to remove a couple of ConvertTos. Thank you!

Reel.Deel
25th February 2023, 05:29
Is OverlayPlus only able to use ImageSource? According to the wiki (http://avisynth.nl/index.php/OverlayPlus), it supports most planar formats. I was thinking if I could somehow turn my bitmap mask into an 8-bit 4:2:0 AVIF or similar file, I could load that with L-SMASH to load into OverlayPlus, which would be better as I wouldn't need to convert my clips to RGB and back, there would be no conversions


OverlayPlus is not dependent on any source filter. You supply a mask clip from whatever source you want. If you have a saved image that just a single mask load it with a source filter, something like this:


a = videoA
b = videoB
m = FFImageSource("mask.png") # here the red channel will be used as the mask,
# assuming all 3 channels are identical it should
# work as intended. If not then use ExtractR/G/B
# to get the mask from the appropriate channel

OverlayPlus(a,b,m)

Just remember that the mask must the same bitdepth as the other clips and must have the same dimensions as the b clip. I'm not sure what you mean by "turn my bitmap mask into an 8-bit 4:2:0 AVIF or similar file".

If the only mode you are using is "blend" there's really no advantage to using OverlayPlus.

poisondeathray
25th February 2023, 05:57
I think there is a bug in OverlayPlus1.3, using either YV12 or Y8 mask


cb=colorbars(pixel_type="YV12").trim(0,29).assumefps(24)
b=blankclip(30,640,480,"RGB24")

text=b.subtitle("TEXT", x=400,y=200,size=40).ConvertToYV12()

alpha=b.subtitle("TEXT", x=400,y=200,size=40,text_color=$FFFFFF, halo_color=$FFFFFF).ConvertToYV12(matrix="PC.601") #fullrange yv12
#also tested Y8

#overlay(cb, text, mask=alpha)
overlayplus(cb, text, mask=alpha)


overlay
https://i.postimg.cc/SR9nfzs8/overlay.png

overlayplus
https://i.postimg.cc/GpS90jTG/overlayplus.png

Reel.Deel
25th February 2023, 07:21
PDR, it's not a bug. Try with OverlayPlus(cb, text, mask=alpha, chroma=true) - If I do another update I will probably make it so that chroma=true as a default for blend mode only and false for the rest of the modes.