Color Lookup Tables and Filtering

Yes it always does takes 2x2 texels. The difference is that at texture coordinate 0.5, the 2 texels “inside” the texture will both have a weight of 0.5 (max weight), and the two border texels (above or below, does not matter) will have a weight of 0.0 => result is like 1D sampling.

x00.5+x10.5+00.0+00.0

Oh, thanks, now I see.

Ah, I see… thanks for the explanation, ZbuffeR.

Incidentally, I ended-up creating my own very simple filtering function.

// Filter function
float simpleFilter(in sampler samp, in float x, in float lutWidth, in int ch) {
	float fractX = fract(x);
	float y = 0.5;
	float result = (fractX > 0.0) ?
			mix(	unpremultiply(sample(samp, vec2(max(0.0,x-1.0), y)))[ch],
				unpremultiply(sample(samp, vec2(min(lutWidth,x+1.0), y)))[ch],
				fractX ) :
			unpremultiply(sample(samp, vec2(x, y)))[ch];
	return result;
}

kernel vec4 tb_applyLUT_customFilter(sampler Image, __table sampler LUT)
{
	// Sample input image
	vec4 pix = unpremultiply(sample(Image, samplerCoord(Image)));
	
	// Width of LUT
	float lutWidth = samplerSize(LUT).x - 1.0;
	
	// Apply LUT
	vec3 outPix;
	outPix.r = simpleFilter(LUT, pix.r * lutWidth, lutWidth, 0);
	outPix.g = simpleFilter(LUT, pix.g * lutWidth, lutWidth, 1);
	outPix.b = simpleFilter(LUT, pix.b * lutWidth, lutWidth, 2);

	// Return pixel color using original alpha
	return vec4(outPix, pix.a);
}

Seems to work OK, as far as I can tell. I don’t have any material with higher than 8bpc to test it on, though. Does it look like it should work to you?

Thanks again for all your help and advice, guys,

a|x

Sound good.

I would advise against the condition around fract > 0.0, performance wise conditionals should be avoided unless they are actually useful. To be benchmarked I guess.

Not sure if you need the unpremultiply before doing the mix() ?

Cool, cheers!

I would advise against the condition around fract > 0.0, performance wise conditionals should be avoided unless they are actually useful. To be benchmarked I guess.

Good point. I was trying to avoid doing the extra lookup and mix if the lookup-position wasn’t fractional, but do you think it’s better just to remove the conditional and always mix the neighbouring pixels?

Not sure if you need the unpremultiply before doing the mix() ?

I’m never sure about that one either. I’ll try without it and see if it makes any difference. It may be I need it to cope with non-opaque images (or portions of images), given that Core Image samplers come into the Kernel with their colour-channels pre-multiplied with their alpha.

Thanks again,

a|x

Indeed you should drop the conditional, for 2 reasons :

  1. a lot of hardware have to evaluate both sides of conditional (when blocks are small like in your case) anyway so it means 3 samples instead of 2 which lowers performance
  2. not useful : in practice, a float is almost never strictly equal to 0.0
    But as I said, test and time the results, it will give you a more precise idea of what happens on your hardware.

About unpremultiply you are probably right to do it before filtering.
A tangential question : what happens when alpha=0.0 ???

OK, sounds like good advice. I will try and do some benchmarking on my system and see what happens.

About unpremultiply you are probably right to do it before filtering.
A tangential question : what happens when alpha=0.0 ???

I assume the values in each colour-channel will also be 0. I can test that quite easily, in fact.

Done. As I suspected: if you reduce the alpha of an image to 0.0, then extract the colour information from the image, without unpremultiplying, you get nothing (or 0.0 in all RGB channels).

Interestingly, if you unpremultiply, you also get zero (which makes sense, I suppose, since no colour can be extracted from 0 information). But, if you increase the input alpha to any number above 0, you get the original colour, as you’d expect.

So, essentially, you can’t extract any colour information if the alpha is exactly 0.0. Not an issue in most scenarios, but could be I guess if you wanted to use an image as a 4-channel lookup texture, as in this case you’d lose the ability to lookup values in the RGB channels if alpha was 0.0 for that pixel.

I guess you could add a tiny offset to the alpha as a workaround (though the offset amount might have to vary with the bit-depth of the image used).

a|x

Incidentally, it just occurred to me that, since I’m creating the LUT, I can be sure that alpha will be 1.0, anyway, so I can miss out the unpremultiply in the filter function.

I’ll still need to do it in the image-lookup though.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.