Examples :: Multi-color mask creation and manipulation

This example script creates combined colormasks of multiple colors and manipulates them in various ways. To demonstrate the applicability of color mask selection to moving objects, an animated source is constructed using the animation filters supplied by AVSLib.

First the script. In this example, colors are provided as R,G,B triplets in decimal, as it is common to show up in image editing applications. Typically in real video editing this will be the most convenient way to specify color values, since the values will have been read inside an image editing application from a group of sample frames of the video.

LoadPackage("avslib", "array")
LoadModule("avslib", "clip", "core")
LoadModule("avslib", "filters", "stack")
LoadModule("avslib", "filters", "animate")
LoadModule("avslib", "filters", "utility")

LoadPlugin("mt_masktools.dll")

# ------ create a source ---------

clp = BlankClip(pixel_type="YUY2", length=401)
clp = Overlay(clp, clp.BlankClip(color=color_red, width=100, height=100), x=100, y=100)
clp = Overlay(clp, clp.BlankClip(color=color_green, width=100, height=100), x=200, y=200)
clp = Overlay(clp, clp.BlankClip(color=color_blue, width=100, height=100), x=300, y=100)
clp = Overlay(clp, clp.BlankClip(color=color_magenta, width=100, height=100), x=300, y=300)

f = ArrayRange(0,400,50)
x = "0,120,240,120,0,120,240,120,0"
y = "0,80,0,-100,0,80,0,-100,0"
x = x.ArrayOpValue(Round(clp.Width / 2), "+")
y = y.ArrayOpValue(Round(clp.Height / 2), "+")

clp = clp.BlankClip().PolygonAnim(clp, f, x, y)
clp = clp.ConvertToRGB32.ResetMask()

Up to this point the script loads needed modules and plugins and constructs its animated source. This consists of a blank clip on top of which four colored rectangles are overlayed. The clip then is moved in a polygonal line such that the area occupied by the rectangles seems to collide and jump back from the borders of the clip like a particle in a box.

f, x, and y correspond to frame number, x position and y position of the moving clip. The call to ArrayOpValue is made to translate the x and y coordinates from the top-left corner of the clip to its center, as needed by the PolygonAnim filter.

# ------ apply color masks ---------

Function _to_RGB(string colors) { 
	old = ArrayDelimiterReset()
	ret = MakeRGBColor(colors.ArrayGet(0), colors.ArrayGet(1), colors.ArrayGet(2))
	old = ArrayDelimiterSet(old)
	return ret
}

Function _make_mask(int color, clip c) { 
	return c.ColorKeyMask(color, 20).ShowAlpha().Invert()
}

mask_colors = "255,0,0|0,128,0|0,0,255|255,0,255"

old = ArrayDelimiterSet("|")
colors = mask_colors.ArrayOpFunc("_to_RGB")
cmasks = colors.ArrayOpFunc("_make_mask", ArrayCreate(clp))
# quoted strings inside sum_args do not work; workaround with a global
global mode = "or"
msk = cmasks.ArraySum("ConvertToYV12", sum_func="mt_logic", sum_args="mode")
msk_if = msk.FilterChain("mt_inflate", 6, "u=2, v=2" \
		   ).FilterChain("Blur", 100, "1.25" \
		   ).FilterChain("mt_deflate", 6, "u=2, v=2")
rst = Overlay(clp, clp.BlankClip(color=color_gold), mask=msk, opacity=0.4)

StackToFit( \
	ArrayCreate(clp, msk.ConvertToRGB32, msk_if.ConvertToRGB32, rst), \
	4*240, 3*240)

To create the colors from the decimal R,G,B triplets a custom function is used that expects an array of RGB color triplets with the default (comma) array delimiter; the function then calls the MakeRGBColor to do the actual work. Current array delimiter is stored and restored before leaving the function, a practise that must be followed by any function that expects an array with a specific delimiter.

The colors array is then passed to _make_mask custom function to create the array of separate color masks. Because we want to act on what is inside the mask (ie we want to operate on masked colors and not to protect them) the Invert standard Avisynth filter is used inside _make_mask.

The separate mask clips are then summed up with mt_logic using "or" mode, with a call to ArraySum. Because mt_logic accepts only YV12 input, ConvertToYV12 is used as the elm_func argument of ArraySum to make the conversion.

The combined mask is then proccessed, with a series of calls to mt_inflate, Blur and mt_deflate filters, conveniently grouped in just a few lines through the use of the FilterChain filter. This is just to demonstrate the possibilities offered by AVSLib for irregular color key masks manipulations; here since our masked shape is highly regular the initial mask is better suited for subsequent operations.

Finally a simple color transformation of the source clip (color shift) is performed using the created mask. The original and modified clips along with the masks are stacked together in a specified frame size with the help of the StackToFit filter.