How To Access The GrayScale Texture Pixel Value i

Hi all, I have to admit that i am a newbie to GLSL - -. what I want to do is to access the exact pixel value(type: unsigned short, ranging from 0 to 65535) of a medical grayscale image in glsl frag shader. So that I can display a certain range of value in the image. The image is sent to the shader as a texture image.

At first, I use:
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, pack->width, pack->height, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, pack->texture);

prerequisite:
I have used the function:
glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D,0,GL_TEXTURE_INTERNAL_FORMAT,actual_format);
to validate that GL_LUMINANCE16 is available on my box.

In the frag shader:
vec4 color = texture2D(myTexture, vTexCoord);
int pixel_value = int(color.g * 65535.0); //precision lost here
if(pixel_value <= 0 || pixel_value > 1500)//display range from 0 to 1500
{
color = vec4(1.0,1.0,1.0,1.0);
}
else
{
float value = float(pixel_value) / 1500.0;
color = vec4(value,value, value,1.0);
}
But as a result, the pixel value recovery have precision lost, for the fact that simpler will normalize the value of the pixel from 0.0 to 1.0. So I can not get the correct effect…

Form V-man’s suggestion on gamedev, I took a look at an opengl extension called “EXT_texture_integer”, I change the code to:
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16UI_EXT, pack->width, pack->height, 0,GL_LUMINANCE_INTEGER_EXT, GL_UNSIGNED_SHORT, pack->texture);
In frag shader:
vec4 color = texture2D(myTexture, vTexCoord);
int pixel_value = int(color.r);
if(pixel_value <= 0 || pixel_value > 1500)
{
color = vec4(1.0,1.0,1.0,1.0);
}
else
{
float value = float(pixel_value) / 1000;
color = vec4(value,value, value,1.0);
}
But it still have any effect…why???

Can Anyone give me any suggestion??? thx in advance…

See the previous answer to this question.

a 16bit value normalized to 0…1 cant be exactly represented in a float value,
so multiplying by 65535 doesn’t result in the original value again,
so u need proper rounding.

i think only using casts to int rounds towards neg infinity (or zero?)

try:

int pixel_value = int(floor(color.g*65535.0+0.5));

and be sure to use GL_NEAREST

Thank you for replying ^^.
I finally managed to find out that the exact cause of huge precision lost is the data itself contaminated,not the sampler…
How STUPID I am to waste so much time on the wrong target!! - -

[quote=“vs987”]

a 16bit value normalized to 0…1 cant be exactly represented in a float value,
so multiplying by 65535 doesn’t result in the original value again,
so u need proper rounding.

i think only using casts to int rounds towards neg infinity (or zero?)

try:

int pixel_value = int(floor(color.g*65535.0+0.5));

and be sure to use GL_NEAREST [/QUOTE]

Great Suggestion!!!
I will try that in my implementation!!!^ ^

a 16bit value normalized to 0…1 cant be exactly represented in a float value,

Actually, it can. So long as it’s a 32-bit float, that gives 23 bits of mantissa, which is well more than 16 bits.

The problem is the conversion. The multiply + round operation. And, as you point out, the very necessary use of GL_NEAREST.

I’d try to avoid using “floor” if possible. Try it with just GL_NEAREST (unless you were using it already) and see if it will work without the “floor” operation.

Actually, it can NOT.

even a 8-bit normalized value cant be exactly represented in a 32bit-float or even a 64bit-float

this is because:

normalization takes an integer 16-bit value in the range [0-65535] and multiplies it with 1.0/65535.0 (this value cant be represented exactly in fp32 or fp64)
so if u multiply again with 65535.0 u get a value near the original integer, but not the exact one.

korval, if u want to check for urself,
here is a little example code:


main()
{
  int q;
  float tab[256],err;
  for(q=0;q<256;q++)
    tab[q]=q/255.0;
  for(q=0;q<256;q++)
  {
    err=tab[q]*255.0-q;
    if(err != 0.0) printf("value %d not exactly representable, error: %f
",q,err);
  }
}

it shows u the error introduced due to 8bit-normalization
i used an array to stop the compiler from doing optimization and merging fp operations.

so u have to use proper rounding (rounding to nearest integer) to get the exact original integer values.

if normalization would multiply by 1/65536.0 (1.0/2^16) the fp32 format would be able to hold the exact integer, but then u have no 1.0

a real number that is representable by a machine is called a machine number. Lots of real numbers are also machine numbers, but some aren’t, like irrational numbers, or even simple fractions like 1/10. Not all numbers between 0 and 1/65536 are machine numbers, but it’s likely that a few are.

http://docs.sun.com/source/806-3568/ncg_goldberg.html

Back to my sunday muffins…

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