Welcome, Unregistered.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

Reply
Old 21-Jul-2004, 12:55   #1
asmatic
Junior Member
 
Join Date: Jul 2004
Posts: 21
Default Pixel Shaders: float & integer colors

Hello to everyone!

I'm using pixel shaders in order to do some very basic watermarking stuff with images.
I read a image as a A8R8G8B8 texture and mix it with another texture (same format) that contains the watermark data in a pixel shader,

However, in spite of being the two textures of integer format mi pixel shader must return a float4 value, not a int4 as I was testing or else I obtain artifacts in the final image. Even more, the original image must be sampled as a float, while sampling the watermark texture as a int or float gives the same results.

I'm worried because the integer data fits better with the needs of the watermarking and i'm fearing of loose information at de-watermarking stage.

Is there any way to work in a pixel shader as 100% integer data?

Thanks
asmatic is offline   Reply With Quote
Old 21-Jul-2004, 17:51   #2
Cryect
Member
 
Join Date: Jul 2004
Posts: 674
Default

Curious why does a watermarking algorithm need a method to remove the watermark. In theory, if you want someone to have the watermark free version you just give it to them instead of the algorithm to remove the watermark. Especially considering information is lost when a watermark is added.
Cryect is offline   Reply With Quote
Old 21-Jul-2004, 19:53   #3
asmatic
Junior Member
 
Join Date: Jul 2004
Posts: 21
Default

sorry, rather than de-watermarking I should have named the function "detecting watermark"

The main problem is that I have to make some integer ops to put and to detect the watermark.

The watermark texture consists in 0's and 1's, but if I try to sample it in the shader as

Code:
int4 pix2 = tex2D(text,In.uv);
I only obtain 0's
using:

Code:
float4 pix2 = tex2D(text,In.uv);
I obtain 0 for 0's and 0'0039 for 1's.

Tha main problem is that when I found a 1 in the watermark texture (sampler text) I have to write a odd Integer color to the ouput, or an even if it was a 0.

So i must work with integers rather than floats in the pixel shaders howaever, the shader seems to be forced to work with floats.

Sould I compile to 1.x to work with integers?



I'm using HLSL and compile with 2.0 targets.
asmatic is offline   Reply With Quote
Old 21-Jul-2004, 20:38   #4
Riff
Registered
 
Join Date: Mar 2004
Location: New Hope, MN
Posts: 6
Default

The specification states that color components are converted to floating point representation before being passed to the shader stage (at least this is the case in GLSL). These floating point components are always in the range [0.0, 1.0] so it should be no surprise when nearly all of the values get truncated to 0.0 if you store them to an integer variable. Most built-in functions don't care about the range of values passed into them as parameters. You are free to convert from floating point color components to integer color components, so long as you convert them back to floating point before they become shader stage outputs. If the color components are 8-bit, simply multiply your vector by (256.0, 256.0, 256.0, 256.0). This will map 0.0 to 0.0 and 1.0 to 256.0. Similarly, divide by the same vector to convert back to floating point.

The issue is that while integer data types are defined, there really arent any integer-specific operations defined. In most cases, there is no need to distinguish between integer and floating point values. Usually the only time it matters is when you want to use boolean logic requiring knowledge about how the value is represented internally. Until OpenGL and D3D support bitwise boolean operators I think its likely that you will have to simulate bitwise operations by using Floor, Ceiling, multiplication and division.

That being said, even if there were bitwise operators and a bigger distinction between floating point and integer representations, texture color components are still more than likely to remain passed in as floating point values.
Riff is offline   Reply With Quote
Old 22-Jul-2004, 01:12   #5
Cryect
Member
 
Join Date: Jul 2004
Posts: 674
Default

Just minor correction to point out shouldn't it be multiply by 255 not 256.
Cryect is offline   Reply With Quote
Old 22-Jul-2004, 07:23   #6
Chalnoth
 
Join Date: May 2002
Location: New York, NY
Posts: 12,681
Default

Quote:
Originally Posted by Cryect
Just minor correction to point out shouldn't it be multiply by 255 not 256.
Nope, 256. You're mapping 256 values between 0 and 255. I believe the proper interpretation of the fixed-point values is [0,1).
Chalnoth is offline   Reply With Quote
Old 22-Jul-2004, 09:36   #7
Simon F
Tea maker
 
Join Date: Feb 2002
Location: In the Island of Sodor, where the steam trains lie
Posts: 4,425
Default

Quote:
Originally Posted by Cryect
Just minor correction to point out shouldn't it be multiply by 255 not 256.
I'd agree with that. 255 is the correct value.
__________________
"Your work is both good and original. Unfortunately the part that is good is not original and the part that is original is not good." -(attributed to) Samuel Johnson

"I invented the term Object-Oriented, and I can tell you I did not have C++ in mind." Alan Kay
Simon F is offline   Reply With Quote
Old 22-Jul-2004, 12:48   #8
asmatic
Junior Member
 
Join Date: Jul 2004
Posts: 21
Default

Yes, thanks I noticed that it sould be 255.
I'm using now floor() and forcing convesions by dividing and multplying.
Sadly i have discovered now a seriously bug: pixel / texels not correctly aligned. I need to work on that.
asmatic is offline   Reply With Quote
Old 22-Jul-2004, 14:13   #9
Chalnoth
 
Join Date: May 2002
Location: New York, NY
Posts: 12,681
Default

No, it shouldn't be 255.

Multiplying by 256 would expand the [0,1) space between 0 and 255, as desired.

Multiplying by 255 would map 256 values onto 255 numbers. That wouldn't be good.
Chalnoth is offline   Reply With Quote
Old 22-Jul-2004, 14:41   #10
asmatic
Junior Member
 
Join Date: Jul 2004
Posts: 21
Default

But the space is [0, 1]. Because white color is {1,1,1} in the pixel shader and {255,255,255} in photoshop for example.

Regards
asmatic is offline   Reply With Quote
Old 22-Jul-2004, 15:41   #11
Chalnoth
 
Join Date: May 2002
Location: New York, NY
Posts: 12,681
Default

I believe {1,1,1} would be clamped to {255,255,255}, not an exact representation of that number.
Chalnoth is offline   Reply With Quote
Old 22-Jul-2004, 15:52   #12
Simon F
Tea maker
 
Join Date: Feb 2002
Location: In the Island of Sodor, where the steam trains lie
Posts: 4,425
Default

Quote:
Originally Posted by Chalnoth
No, it shouldn't be 255.

Multiplying by 256 would expand the [0,1) space between 0 and 255, as desired.
Chalnoth,
The range is [0,1], so 255 is the correct scale factor.
__________________
"Your work is both good and original. Unfortunately the part that is good is not original and the part that is original is not good." -(attributed to) Samuel Johnson

"I invented the term Object-Oriented, and I can tell you I did not have C++ in mind." Alan Kay
Simon F is offline   Reply With Quote
Old 22-Jul-2004, 18:43   #13
LeGreg
Member
 
Join Date: Nov 2003
Posts: 239
Default

I agree with every other one: multiply to 255..

Chalnoth, you're mistaken here.
if you multiply by 255 you still have 256 different integer values (you have to count zero as a value).

OT : What is funny though is because of that you don't have a correct integer representation of 0.5
LeGreg is offline   Reply With Quote
Old 22-Jul-2004, 21:30   #14
Chalnoth
 
Join Date: May 2002
Location: New York, NY
Posts: 12,681
Default

Well, the only problem I have with this argument now is, with on-chip support for higher precision fixed point, things just won't map properly.

That is, if you map 11 bits to a number between 0 and 2 (as is done with FX12), then the 8-bit input from a texture won't map directly unless it's mapped as [0,1).
Chalnoth is offline   Reply With Quote
Old 22-Jul-2004, 22:22   #15
Mintmaster
Senior Member
 
Join Date: Mar 2002
Posts: 3,896
Default

I've stumbled on this as well when thinking about this subject.

While I too agree that the factor is 255, I'm left wondering how the math is done. How do IHV's build their multipliers? 1x1=1, but taking the high eight bits of 255x255 gives you 254. Whatever solution you have, all the math must be consistent.

Anyone know the details?
Mintmaster is offline   Reply With Quote
Old 22-Jul-2004, 22:36   #16
Xmas
Off-season
 
Join Date: Feb 2002
Location: On the pursuit of happiness
Posts: 3,058
Default

NVidia details:
FX12 is [-2048/1024, 2047/1024]
FX9 is [-256/255, 255/255]

Add is straightforward, as well as FX12 mul. FX9 mul should add the MSB to the result.
Xmas is offline   Reply With Quote
Old 23-Jul-2004, 01:18   #17
asmatic
Junior Member
 
Join Date: Jul 2004
Posts: 21
Default

back to the original watermarking algoritm, i have made it work using floors, and scaling by 255 but only using Reference Rasterizer. Any attempt to use the algoritm with a HAL devide fails
asmatic is offline   Reply With Quote
Old 23-Jul-2004, 02:45   #18
bloodbob
Trollipop
 
Join Date: May 2003
Location: Australia
Posts: 1,630
Default

I believe DXNEXT may require signed 32 bit ints wait till then I guess.
__________________
Trolls find me soo tastey :P
bloodbob is offline   Reply With Quote
Old 24-Jul-2004, 12:11   #19
aranfell
Junior Member
 
Join Date: Apr 2004
Posts: 41
Default OpenGL's "fixed point" scale factor

I think that part of the confusion about the scale factor is due to the OpenGL spec sometimes using the term "fixed point" in a non-standard way. When producing an N-bit "fixed point" frame buffer value, OpenGL defines that the scale factor is (2^N)-1, not 2^N, so that the numbers [0..(2^N)-1] map to [0..1] (e.g., [0..255] map to [0.0..1.0]). This is explained in an obscure section at the end of one of the chapters of the OpenGL spec. The justification for this is simple: a pixel representation is not very useful if it can't exactly represent 1.0.

Arithmetic on these "fixed point" numbers has been handled a variety of ways in hardware, with varying degrees of accuracy. For example, one simple way to adjust the product of two such numbers is to treat them as true fixed point and then post-multiply by 256/255. That can be approximated by adding the high order bit of the result into the low order bit of the result, since 256/255 is approximately 1+1/256. Converting true fixed point to "fixed point" is simpler, since it requires multiplying by 255/256, which just requires a shift and a subtract.
aranfell is offline   Reply With Quote
Old 24-Jul-2004, 15:22   #20
ehart
Junior Member
 
Join Date: Sep 2003
Posts: 65
Default

Part of the confusion with the math here is that it is somewhat better to describe the math typically done for graphics in the range [0,1] as repeating fraction rather than fixed-point. Fixed point implies you are representing an exact number. Repeating fraction isn't exact, in that the digit sequence is logically repeated infinitely. (The number is rational, but it does not terminate, except in the 0 case.) I don't know that repeating fraction is the correct technical term, but it is the best one I have heard to differentiate this.

Now, back to the real problem.

Can you post a quick snip of the code? I imagine you are doing something like this for a single pixel in psuedo-C/GLSL:

ivec4 in; //input image
ivec4 out; //result
ivec4 mark; //watermark (no data except the last bit)

out = (in & 0xfe) | ( mark & 0x01);

I would advise trying to code it like this:

vec4 in;
vec4 out;
vec4 mark;

out = floor(in*127.0)/127.0 + mark;

I would probably also suggest folding the 1/127 into a multiply yourself, so you can control the operation more.

-Evan
ehart is offline   Reply With Quote
Old 25-Jul-2004, 15:10   #21
asmatic
Junior Member
 
Join Date: Jul 2004
Posts: 21
Default

Of course, this is the coda thet puts the watermark/message in the original texture:
Dx's HLSL code:
Code:
struct PS_INPUT {
    float2 uv : TEXCOORD0;
};

sampler image : register(s0);         // original image
sampler watermark :register(s1);   // texture containing the bit pattern of the watermark in the blue channel
     
float4 main (PS_INPUT In) : COLOR
{
  float4 pix1 = tex2D(image,In.uv);
  float4 pix2 = tex2D(watermark,In.uv); // read the bit
  float tmp = floor(pix1.b*255); // transform it to integer space
  if(pix2.b == 0)    // it is a 0?
  {
    pix1.b = ((int)tmp/(int)2)*2; // then put an even number in the output image's blue channel
  }
  else
  {
    pix1.b = ((int)tmp/(int)2)*2+1; // put an odd value
  }
  
  pix1.b = pix1.b/255; // un-transform to float
  return pix1;  //put value
};
this is the shaders that makes the detection of the watermark:

Code:
struct PS_INPUT {
    float2 uv : TEXCOORD0;
};

sampler image : register(s0);

float4 main (PS_INPUT In) : COLOR
{
  float4 pix1 = tex2D(image,In.uv);   // read texel
  pix1.b = floor(pix1.b*255);             // transform to integer
  float tmp = fmod(pix1.b,2);            // calculate module
  if(tmp == 0)                                 // if module was 0, the number was even
  {
    pix1 = 0;                                    // so put a {0,0,0,0} to the output 
  }
  else
  {
    pix1 = 1;                                    // it was a odd number: put white {1,1,1,1} to the output
  }
  return pix1;
};
It works perfectly when the device is the REF reference software rasterizer, however, fails when using HAL device. Sometimes it returns inverted bit patterns, and often completely fails and returns random bit patterns.

The watermark texture is a black A8R8G8B8 texture. His n-th texel has b = 255 if the n-th bit of the watermark is 1, or 0 otherwise.

With REF rasterizer, after the detection phase I should obtain a black texture with white texels where a even odd number (watermark = 1) was found. There sould be no clues of the original image, only a bit pattern.
However, with HAL device, after the dection phase the result texture is like this:



regards
asmatic is offline   Reply With Quote
Old 25-Jul-2004, 20:24   #22
ehart
Junior Member
 
Join Date: Sep 2003
Posts: 65
Default

I am guessing this is coming down to rounding rules etc. I would suggest a couple changes to your code to enhance your chances, and portabbility:
  1. Don't use any integer variables, DX allow these to be emulated as floats. I am not sure how much wiggle room it allows for the handling.
  2. Minimize your operations. Each one is adding error. You scale the numbers 4 times in your code. You only need to do it twice.

I would try this:

Code:
struct PS_INPUT { 
    float2 uv : TEXCOORD0; 
}; 

sampler image : register(s0);         // original image 
sampler watermark :register(s1);   // texture containing the bit pattern of the watermark in the blue channel 
      
float4 main (PS_INPUT In) : COLOR 
{ 
  float4 pix1 = tex2D(image,In.uv); 
  float4 pix2 = tex2D(watermark,In.uv); // read the bit 
  float tmp = floor(pix1.b*127.0); //clip the last bit

  pix1.b = tmp/127.0 + pix2.b/255.0; //add 8th bit based on watermark
  
  return pix1;  //put value 
};
Getting bit exact integer math is pretty hard with floats. Would you care if I stuck this in a piece of sample code?

Assuming it works, it is something that several developers would like to see.

-Evan
ehart is offline   Reply With Quote
Old 25-Jul-2004, 20:32   #23
Xmas
Off-season
 
Join Date: Feb 2002
Location: On the pursuit of happiness
Posts: 3,058
Default

I'd suggest this:
Code:
struct PS_INPUT {
    float2 uv : TEXCOORD0;
};

sampler image : register(s0);         // original image
sampler watermark :register(s1);   // texture containing the bit pattern of the watermark in the blue channel
     
float4 main (PS_INPUT In) : COLOR
{
  float4 pix1 = tex2D(image,In.uv);
  float4 pix2 = tex2D(watermark,In.uv); // read the bit
  pix1.b = (floor(pix1.b * 127.9) * 2 + pix2.b) / 255.0;
  return pix1;  //put value
};
Code:
struct PS_INPUT {
    float2 uv : TEXCOORD0;
};

sampler image : register(s0);

float4 main (PS_INPUT In) : COLOR
{
  float4 pix1 = tex2D(image,In.uv);   // read texel
  float tmp = pix1.b * 255;
  float bit = tmp - (floor(pix1.b * 127.9) * 2);                 return float4(bit);
};
Xmas is offline   Reply With Quote
Old 25-Jul-2004, 21:09   #24
Xmas
Off-season
 
Join Date: Feb 2002
Location: On the pursuit of happiness
Posts: 3,058
Default

Evan, nice to see you here

I hate to say it, but your LSB clipping code won't work. When you insert 2/255 as pix1.b, you will get 0/255 as result. 255/255 will result in 255/255, but should be 254/255, so you can add 1/255 without overflowing.

The correct scaling factor is 127.5, but for numerical reasons it is better to use 127.9
Xmas is offline   Reply With Quote
Old 25-Jul-2004, 21:24   #25
ehart
Junior Member
 
Join Date: Sep 2003
Posts: 65
Default

Yeah, after I read your post, I realized it. I think I have been staring at too much code this weekend.

-Evan
ehart is offline   Reply With Quote

Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
How long before a X800 wrapper (Ruby demo) appears? g__day 3D Technology & Algorithms 285 17-Jan-2005 10:08
shadermark 2.1 released tEd 3D Architectures & Chips 88 17-Oct-2004 02:06
NV40 poll Geeforcer 3D Architectures & Chips 56 24-Mar-2004 18:34
catalyst 4.3 fails in 3dmark2001 SE adv. pixel shader test?? Mendel 3D Hardware, Software & Output Devices 9 16-Mar-2004 23:52
nVIDIA Cg Compiler & Language Embraced By Industry Dave Baumann Press Releases 0 14-Jun-2002 21:27


All times are GMT +1. The time now is 20:14.


Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.