Log in

View Full Version : Alternative to the old Unpremultiply() plugin?


vampiredom
18th December 2012, 05:37
Hi all –

I need to unpremultiply some matted RGB32 clips. I am currently using the Unpremultiply() function (ca. 2008) but the results are not always good. It tends to add dark or bright speckles, particularly in near-transparent areas.

Does anyone know of a good alternative to this or perhaps some updated/re-tooled version?

I have tried using a series of Overlay operations with different modes ... but no luck. Perhaps there is some way with MaskTools or something similar?

Thx.

IanB
18th December 2012, 07:44
Assuming this source code unpremultiply.cpp (http://code.google.com/p/avisynth-unpremultiply/source/browse/trunk/unpremultiply.cpp) // Formula is: Cu = Cm / a
// Adding alpha/2 rounds instead of truncates the result of integer division
// This will cause horrible things to happen to your image if a color value
// is ever greater than the alpha value.
// This can happen if your source program used some kind of specular highlighting
*dstbpix = (srcbpix * 255 + srcapix / 2) / srcapix;
*dstgpix = (srcgpix * 255 + srcapix / 2) / srcapix;
*dstrpix = (srcrpix * 255 + srcapix / 2) / srcapix;
A rookie mistake in not clamping the intermediate results between 0 and 255.

Apply this patch or similarinline uint8_t uint8clamp(int x) {
if (x < 0) return 0;
if (x > 255) return 255;
return x;
}
....
*dstbpix = uint8clamp((srcbpix * 255 + srcapix / 2) / srcapix);
*dstgpix = uint8clamp((srcgpix * 255 + srcapix / 2) / srcapix);
*dstrpix = uint8clamp((srcrpix * 255 + srcapix / 2) / srcapix);

vampiredom
18th December 2012, 08:25
Nice find! Thank you. Any chance you would consider compiling this patched code into a new version? That would be fabulous.

IanB
27th December 2012, 09:10
Try the attached version.

Also changed to uses a fast 65K lookup table instead of the slow in place idiv's.

:Edit: See below for new version

vampiredom
30th December 2012, 04:32
Thanks so much! I will try it out and get back to you.

vampiredom
31st December 2012, 21:38
Hi --

There is something strange going on: It seems that areas that should be fully opaque turn to black.

This can be demonstrated with a simple test:

# This works properly, showing a white rectangle with a gray rectangle

a = BlankClip(width=1280, height=720, length=1, color=$808080, pixel_type="RGB32").ResetMask()
b = BlankClip(width=640, height=480, length=1, color=$FFFFFF, pixel_type="RGB32").ResetMask()

Layer(a, b, x=320, y=120)

# When Unpremultiply() is applied, the inner rectangle turns black

a = BlankClip(width=1280, height=720, length=1, color=$808080, pixel_type="RGB32").ResetMask()
b = BlankClip(width=640, height=480, length=1, color=$FFFFFF, pixel_type="RGB32").ResetMask().Unpremultiply()

Layer(a, b, x=320, y=120)

Can you please check this out? Thanks again.

IanB
31st December 2012, 23:07
Opps, :o The bottom row and right column of the lookup table are not being initialised.
for (int i=0; i< 255; i++) {
lookup[i<<8] = i;
for (int j=1; j<255; j++)
lookup[(i<<8)+j] = uint8clamp((i * 255 + j / 2) / j);
}
See attached :-

vampiredom
2nd January 2013, 19:51
Ah, much better! I have not tested it thoroughly but it seems to work well on some tests I have tried.

However, it seems to only work correctly when the matte color is black. I wish there were a way (similar to Adobe After Effects, for example) where you could choose the matte color to remove. Photoshop has a similar-but-simplified approach with "Matting > Remove Black Matte" and "Matting > Remove White Matte".

Unpremultiply() wreaks havoc on a white-matted clip.

IanB
2nd January 2013, 23:00
From our PM exchangeIf possible, I'd also like to be able to specify a matte color to override the function's automatic assumption.
The source I looked at didn't have any matte colour processing. It simply unmultiplied the source pixels by the alpha channel (without range checking).
Here is the original code :- // Formula is: Cu = Cm / a
// Adding alpha/2 rounds instead of truncates the result of integer division
// This will cause horrible things to happen to your image if a color value
// is ever greater than the alpha value.
// This can happen if your source program used some kind of specular highlighting
*dstbpix = (srcbpix * 255 + srcapix / 2) / srcapix;
*dstgpix = (srcgpix * 255 + srcapix / 2) / srcapix;
*dstrpix = (srcrpix * 255 + srcapix / 2) / srcapix;If you want to propose changes to allow selection of the matte colour, I am happy to consider compiling your modified version.


As for unpremultiplying based on a [255,255,255] white matte you could try this :-...source
Invert("RGB") # flip rgb channels
Unpremultiply() # Orgb = 255 - ( (255 - Irgb) * 255 / Ia )
Invert("RGB") # unflip rgb channels
..

A more general approach could be to split out the argb channels to yv12 clips and use mt_lutxy to do arbitrary 2 value function processing on the pixels. E.g....
Ya=ShowAlpha("YV12") # Copy alpha to Y plane
Ya3=Interleave(Ya, Ya, Ya)
Interleave( ShowRed("YV12"), ShowGreen("YV12"), ShowBlue("YV12") ) # Copy rgb's to Y planes
exprstr=mt_polish( "255 - ( ( ( 255 - X ) * 255 + Y / 2 ) / Y )" ) # "255 255 x - 255 * y 2 / + y / -"
Mt_LutXY(Ya3, yexpr=exprstr, y=3, u=1, v=1) # do Y, ignore U and V
MergeARGB( Ya, SelectEvery(3,0), SelectEvery(3,1), SelectEvery(3,2) ) # Reassemble Y's to ARGB

Gavino
28th June 2013, 17:06
...
Ya=ShowAlpha("YV12") # Copy alpha to Y plane
Interleave( ShowRed("YV12"), ShowGreen("YV12"), ShowBlue("YV12") ) # Copy rgb's to Y planes
exprstr=mt_polish( "255 - ( ( ( 255 - X ) * 255 + Y / 2 ) / Y )" ) # "255 255 x - 255 * y 2 / + y / -"
Mt_LutXY(Ya, yexpr=exprstr, y=3, u=1, v=1) # do Y, ignore U and V
MergeARGB( Ya, SelectEvery(3,0), SelectEvery(3,1), SelectEvery(3,2) ) # Reassemble Y's to ARGB

A neat way of using MaskTools on RGB input.
But don't you need to replicate the alpha channel three times as well, otherwise the wrong frames will be paired up in the mt_lutxy?
I think the Ya in the mt_lutxy call should be Interleave(Ya, Ya, Ya).
(unless you are assuming a single frame clip or a static image.)

IanB
28th June 2013, 22:59
Yes Oops :o