rgba_rpn v0.1

rgba_rpn/y8_rpn is an Avisynth filter for manipulating the pixels of RGB (and also YUV) clips.

Doom 9 discussion

Changelog
Input parameters
RPN extensions
Examples
y8_rpn
Caveats

Changelog

v0.1

Input parameters

rgba_rpn is slightly unusual in that in accepts unnamed parameters in any order.

Strings

rgba_rpn expects between one and four RPN formulae strings. These define the calculations to perform on each pixel.

Number of stringsAction
1Output is RGB24 (or Y8 if called as y8_rpn); input string is applied to each channel
2Output is RGB32; input string 1 is applied to R, G, and B channels; input string 2 is applied to the alpha channel
3Output is RGB24; input strings are applied to R, G, and B channels respectively
4Output is RGB32; input strings are applied to R, G, B, and alpha channels respectively

Integers

rgba_rpn accepts up to three integer parameters. The first controls the rounding of floating point values to pixels:

ValueMode
0Round (default): rounds to the nearest integer
1Ordered dither: applies an 8x8 ordered dither matrix
2Random noise (monochrome)
3Random noise (multicolour)

Dithering has been greatly exagerrated in the following image (note also that the drop shadowed overlay was added using rgba_rpn!):

The second integer parameter controls how values are clamped to the valid range for a pixel (0-255):

ValueMode
0Off: pixel values are not clamped. Negative values and values greater than 255 will wrap around.
1Fast (default): pixel values are clamped using integer registers (will work perfectly unless your output values exceed the range of a 32-bit integer, i.e. +/- approximately 2,000,000,000
2Full range: pixel values are clamped using floating-point registers (noticeably slower than default)

The third integer parameter controls how the range of YUV channels is handled.

ValueMode
0PC range: pixel values are read (and in the case of y8_rpn, written) directly to and from pixel data
1TV range (default): pixel values are expanded from 16-235 to 0-255 (unclamped) on read, and (when called as y8_rpn) clamped to 16-235 from 0-255 on write


To avoid having to remember the different defaults, a value of -1 maps to the default value for the integer parameters.

Clips

All clips must be the same size. Properties of the output clip are defined by the first input clip. A maximum of 255 clips may be specified.

Contrary to the filter's name, YUV clips may be used, but only the Y channel of those clips can be accessed.

Avisynth's "implicit last" does not work with rgba_rpn, but it may be used as part of a filter chain.

RPN extensions

Pixels

In addition to the basic RPN keywords, pixels can be referenced using the following notation:

[{channel letter}{image number}]

where the channel letter is r, g, b, a, c, or (YUV clips only) y.

For example, to refer to the red channel value of the current pixel in the second clip (clip 1; clips are numbered from 0):

[r1]

The letter c can be used to refer to the channel currently being calculated. For example, with one string parameter, each channel can be darkened with the following RPN string:

[c0] 0.5 *

Offset pixels

Pixels at fixed offsets from the current pixel may also be referred to using the following notiation:

[{channel letter}{image number}(x,y)]

For example, to refer to the red channel of the pixel 10 to the left and 3 below the current pixel, in the third clip:

[r2(-10,3)]

Built-in variables

rgba_rpn defines the following RPN variables (see here for more information about using variables):

VariableValue
xCurrent pixel x center coordinate (the leftmost pixel has an x value of 0.5)
yCurrent pixel y center coordinate (the topmost pixel has a y value of 0.5)
ax / width
by / height
cy / width (maintains aspect ratio with a)
nThe current frame number
tFractional time position in clip (0 <= t < 1)
wWidth
hHeight

Examples

To greyscale a single clip, with ordered dither:

colorbars.rgba_rpn("[r0] 0.3 * [g0] 0.59 * [b0] 0.11 *", 1)

To swap red and green channels, preserving blue:

colorbars.rgba_rpn("[g0]", "[r0]", "[b0]")

To apply a 5x5 gaussian blur to a clip:

colorbars.rgba_rpn(" [c0(-2,-2)] [c0(-1,-2)] 4 * [c0(0,-2)] 6 * [c0(1,-2)] 4 * [c0(2,-2)] + + + + [c0(-2,-1)] 4 * [c0(-1,-1)] 16 * [c0(0,-1)] 24 * [c0(1,-1)] 16 * [c0(2,-1)] 4 * + + + + [c0(-2,0)] 6 * [c0(-1,0)] 24 * [c0(0,0)] 36 * [c0(1,0)] 24 * [c0(2,0)] 6 * + + + + [c0(-2,1)] 4 * [c0(-1,1)] 16 * [c0(0,1)] 24 * [c0(1,1)] 16 * [c0(2,1)] 4 * + + + + [c0(-2,2)] [c0(-1,2)] 4 * [c0(0,2)] 6 * [c0(1,2)] 4 * [c0(2,2)] + + + + + + + + 256 / ")

To blend two clips (spatially), fading from left to right using the built-in variable a:

rgba_rpn("[c0] a * [c1] 1 a - * +", clip1, clip2)

To use a YUV image as a mask to blend two RGB images (using a variable to avoid accessing the mask pixel twice):

rgba_rpn("[c0] [y2] 255 / @M * [c1] 1 M - *", clip1, clip2, yuv_mask)

It should also be noted that rgba_rpn does not account for TV range black levels, and returns unaltered pixel values from YUV clips.

y8_rpn

The filter may also be called as y8_rpn, in which case only one RPN string is accepted, and output is a single-channel Y8 clip.

Caveats

rgba_rpn makes no attempt to be gamma-aware, but it can be made to be so by using appropriate RPN calculations. A passably fast approximation at mixing two RGB clips with gamma-awareness would be:

rgba_rpn("[c0] dup * [c1] dup * + 0.5 * sqrt")

dup * is a fast shortcut for raising to the power of 2.