I'm using Processing(Java) to write shaders that do lots of fancy code art.
In my shader code I'm trying to get 2 integers (x,y positions) into an RGBA so I can send this colored pixel back to my Java program - and from there decode this color to get back the original integers.
As far a I know, I cant use bitwise operations in GLSL, or least I'd have to re-write a lot of code.
So I need to get 2 numbers into an RGBA, or 1 number into 2 bytes (RG) and the other in another 2 bytes (BA) - something like that.. without bitwise.. Help!!
First we must take into account the MSB/LSB order on CPU side and internal format of GPU render buffer. The simplest way to check the order is to set color in GLSL with different channels and read it on CPU side as hex number so:
in GLSL set color to vec4(0.1,0.2,0.3,0.4); (r,g,b,a)
read the color on CPU side and print it as HEX
the channels are:
chn float BYTE
[dec] [hex]
r = 0.1 -> 255*0.1 -> 19h
g = 0.2 -> 255*0.1 -> 33h
b = 0.3 -> 255*0.1 -> 4Ch
a = 0.4 -> 255*0.1 -> 66h
Your output was 0x6619334C which identifies the order of r,g,b,a as:
MSB ....... LSB
66 19 33 4C hex (4xBYTE)
0.4 0.1 0.2 0.3 dec (4xfloat)
a r g b
so we can encode x,y for example like this:
MSB ....... LSB
a r g b
Yh Yl Xh Xl
In case your a channel is not correct check if your render buffer has allocated 8 bits for alpha channel during OpenGL context creation (look for pixel format descriptor) and repair if not.
In case you are using this for different render targets each can have different internal format so you need to check this for each separately.
Another problem is that your color on GLSL side is most likely a vec4 and not integer type so you need to use floats ... Also % requires extention so to avoid that compute it by / like this:
unsigned int x,y; // 2x16 bit integer
vec4 xy; // 4xfloat (32 bit color)
unsigned int h,l; // temp
h=x/256u; l=x-(256u*h);
xy.b=float(l)/255.0;
xy.g=float(h)/255.0;
h=y/256u; l=y-(256u*h);
xy.r=float(l)/255.0;
xy.a=float(h)/255.0;
Now the extraction of x,y back on CPU side:
unsigned int rgba; // input 32 bit color
unsigned int x,y; // output 16 bit x,y
y=(rgba>>16)&0x0000FFFF;
x=(rgba )&0x0000FFFF;
Related
I render to a texture which is in the format GL_RGBA8.
When I render to this texture I have a fragment shader whose output is set to color = (1/255, 0, 0, 1). Triangles are overlapping each other and I set the blend mode to (GL_ONE, GL_ONE) so for example if 2 triangles overlap for a given fragment, the resulting pixel at that fragment position will have value (2/255.0).
I then use this texture in a second pass (applied to a quad filling up the screen). My goal at this point when I read the values back from the texture is to convert the values (which are in floating point format in the range [0:1]) back to integers in the range [0:255]. If I look at the pixel that add value (2.0/255.0) I should have the result (2.0/255.0) * 255.0 = 2.0 but I don't.
If I do
float a = (texture(colorTexture, texCoord).x * 255);
float b = (a == 2) ? 1.0 : 0;
color = vec4(0, b, 0, 1);
I get a black image. If I do
float a = (texture(colorTexture, texCoord).x * 255);
float b = (a > 1.999 && a <= 2) ? 1.0 : 0;
color = vec4(0, b, 0, 1);
I get the expected result. So in summary it seems like the convention back to [0:255] suffers from floating precision issues.
precision highp float;
Doesn't make a difference. I also turned filtering off (and no mipmaps).
This would work:
float a = ceil(texture(colorTexture, texCoord).x * 255);
Though in general that doesn't like very robust as a solution (why would ceil work and not floor for example, why is the value 1.999999 rather than 2.00001 and can I be sure it will always be that way?). People must have done that before so I am sure there's a much better way to guaranteeing you get an accurate result without doing too much fiddling with the numbers. Any hints would be greatly appreciated.
EDIT
As pointed in 2 comments, it's right from the way floating point numbers are encoded that you can't get a guarantee that you will get a "integer" number back even if the number is even (that's good to be reminded of this important point). So I reformulate my question which is then, is there a preferred way in GLSL to clamp number to its closest integer values?
And that would be round:
float a = round(texture(colorTexture, texCoord).x * 255);
Hope this can help other people in the future though.
I have a program that generates an grayscale image. The grayshading for every pixel is set with the following code sniped:
//loop over all pixel
*PixelColorPointer = Number * 0x010101;
in this case the Number is an integer number between 0 and 255. Which generates all grayscale colors from black to white.
What I try to do is have an colored image (in order to have false colors), but I don't really understand the calculation with the hex value. I figured out if I assign e.g. Number * 0xFFFFFF I have a gradient/variety from white to yellow.
Can someone explain me how the calculation of this colors is working? Please remember that (as said already) I want/have to pass the Number variable to get variety.
RGB color are stored byte by byte (0 to 255).
When you say 0x010203 it is (in hex) 01 red, 02 green, and 03 blue. It can also be inverted (03 red, 02 green, 01 blue) depending on your Endianness.
Here you have to separate your 3 colors. Then you shoud multiply every color by it's coefficient.
You can store your color in an union, it's the easiest way.
union Color
{
struct
{
unsigned char b;
unsigned char g;
unsigned char r;
unsigned char a; // Useless here
};
unsigned int full;
};
Color c;
c.full = 0x102030;
unsigned char res = 0.229 * c.r + 0.587 * c.g + 0.114 * c.b;
Color grey;
grey.r = grey.g = grey.b = res;
0.229, 0.587 and 0.114 are the Relative luminance.
Remember, you might need to invert the rgba order and move the a place :)
You need to give a little more information. What library of function are you using to do this??
But by just seeing the problems I think the hexadecimal number refers to the color in the Color-hex code, the Number would refer to the brightness 0 being blank and 255 max color intensity (white)
EDIT: Actually I think the whole number resulting from:
Number * 0x010101
Is the hexadecimal color code, in the particular case of 0x010101 the Number works as the intensity. But any other hexadecimal would give you some weird result.
Use an Color-hex code table choose any random color and just input :
*PixelColorPointer = 0XHEXCODE;
if the output is the desired color then I'm right
I used method:
val = 0.299 * R + 0.587 * G + 0.114 * B;
image.setRGBA(val, val, val, 0);
to convert bitmap (24-bit RGB888 and 32-bit RGBA8888) to grayscale successfully.
Example: BMP 24-bit: 0E 0F EF (BGR) --> 51 51 51 (Grayscale) // using above method
But can't apply for bitmap 16-bit RGBA4444.
Example: BMP 16-bit: 'A7 36' (BGRA) --> 'CE 39' (Grayscale) // ???
Anyone know how?
Are you sure you need RGBA4444 format? Maybe you need an old format where green channel gets 6 bits while red and blue get 5 bits (total 16 bits)
In case of 5-6-5 format - the answer is simple.
Just do
R = (R>>3); G = (G>>2); B = (B>>3); to reduce the 24 bits into 16. Now just combine them using | operation.
Here is a sample code in C
// Combine RGB into 16bits 565 representation. Assuming all inputs are in range of 0..255
static INT16 make565(int red, int green, int blue){
return (INT16)( ((red << 8) & 0xf800)|
((green << 2) & 0x03e0)|
((blue >> 3) & 0x001f));
}
The method above uses roughly the same structure as the regular ARGB construction method but squeezes the colors to 16 bits instead of 32 like in the following example:
// Combine RGB into 32bit ARGB representation. Assuming all inputs are in range of 0..255
static INT32 makeARGB(int red, int green, int blue){
return (INT32)((red)|(green << 8)|(blue<<16)|(0xFF000000)); // Alpha is always FF
}
If you do need RGBA4444 then the method would be a combination of the two above
// Combine RGBA into 32bit 4444 representation. Assuming all inputs are in range of 0..255
static INT16 make4444(int red, int green, int blue, int alpha){
return (INT32)((red>>4)|(green&0xF0)|((blue&0xF0)<<4)|((alpha&0xF0)<<8));
}
I've implemented rgb->ycrcb and ycrcb->rgb conversion using JPEG conversion formulae from
http://www.w3.org/Graphics/JPEG/jfif3.pdf
(the same at: http://en.wikipedia.org/wiki/YCbCr (JPEG conversion)).
When checking whether results are correct (original->YCrCb->RGB), some of pixels differ by one, e.g 201->200.
Average percent of precision errors is 0.1%, so it's not critical.
/// converts RGB pixel to YCrCb using { en.wikipedia.org/wiki/YCbCr: JPEG conversion }
ivect4 rgb2ycrcb(int r, int g, int b)
{
int y = round(0.299*r + 0.587*g + 0.114*b) ;
int cb = round(128.0 - (0.1687*r) - (0.3313*g) + (0.5*b));
int cr = round(128.0 + (0.5*r) - (0.4187*g) - (0.0813*b));
return ivect4(y, cr, cb, 255);
}
/// converts YCrCb pixel to RGB using { en.wikipedia.org/wiki/YCbCr: JPEG conversion }
ivect4 ycrcb2rgb(int y, int cr, int cb)
{
int r = round(1.402*(cr-128) + y);
int g = round(-0.34414*(cb-128)-0.71414*(cr-128) + y);
int b = round(1.772*(cb-128) + y);
return ivect4(r, g, b, 255);
}
I use round formula:
floor((x) + 0.5)
When using other types of rounding, e.g. float(int), or std::ceil(), results are even worse.
So, does there exist the way to do YCrCb <-> RGB conversion without loss in precision?
The problem isn't rounding modes.
Even if you converted your floating point constants to ratios and used only integer math, you'd still see different values after the inverse.
To see why, consider a function where I tell you I'm going to shift the numbers 0 through N to the range 0 through N-2. The fact is that this transform is just doesn't have an inverse. You can represent it more or less exactly with a floating point computation (f(x) = x*(N-2)/N), but some of the neighboring values will map to the same result in integer math (pigeonhole principle!). This is a simplification and "compresses" the range, but the same thing happens in arbitrary affine transforms like this one you are using.
If you had r, g, b in floating point, and kept it that way until you quantized to integer, that would be a different story - but in integers you will necessarily always see some difference between the original and the inverse.
Only about 60% of all RGB values can be represented in YCbCr space when using the same amount of bits for both triplets. This means the most damage happens in RGB->YCbCr when you take a 3*8 bit RGB triplet, convert and round it back to 3*8 bits of precision. The trick is to store the YCbCr triplet at a higher precision until it's time to do forward DCT. There, the data needs to be scaled up anyway, so you can do e.g. 16 bit * 16 bit -> MSB16 multiplies, which are well supported by various SIMD instruction sets.
At the decoder it's the reverse: The results of inverse DCT have to be stored at higher precision until it's time to do the YCbCr->RGB conversion.
This doesn't make the process lossless, but for JPEG, it may buy a few dB of PSNR at the extreme high end of the quality scale, i.e. where the difference can't be seen with a naked eye but can be measured.
Yes, supposedly JPEG XR defines a color conversion that is reversible. The code is open source if you want to investigate in depth how they're doing it. The method is loosely described on the Wiki-page I linked to.
Also this SO post might give you some insights.
Another problem is that there is not a 1 to 1 mapping between rgb and YCbCR. There are YCbCr values with no corresponding RGB value and RBG values with no corresponding YCbCR values.
So I've successfully access pixel data in a frame using the c++ frame access wrapper on the opencv webpage
template<class Frame>
class Frame_Data {
IplImage *imgp;
public:
Frame_Data (IplImage *img=0) {imgp = img;}
~Frame_Data () {imgp = 0;}
void operator=(IplImage *img) {imgp=img;}
inline Frame* operator[] (int rowIndex) {
return ((Frame*)(imgp->imageData + rowIndex*imgp->widthStep));
}
};
typedef struct {
unsigned char b,g,r;
} RgbPixel;
typedef struct {
float b,g,r;
} RgbPixelFloat;
typedef Frame_Data<RgbPixel> RgbImage;
Im then using 2 for loops to go through the frame pixel array such as:
for (int i = ymin; i < ymax; i++)
{
for (int j = xmin; j < xmax; j++)
{
int r = image[i][j].r;
int g = image[i][j].g;
int b = image[i][j].b;
So lets say I want to throw in an IF statement to check pixel data colors. I've seen some websites list them as stuff like
image[i][j].r=0xFF;
or if g < 0x20
Im not used to the hex looking values, i tried to look them up but can't find any refernece, im used to cvscalars, so what do these mean? Like what does 0x20 stand for? or what about 0xFF?
thanks
The range from 0x00 ... 0xFF that you are seeing is one byte which can hold a value between 0 and 255 which is how pixel color data is stored, generally in 3 or 4 bytes consisting of Red, Blue, Green and optionally Alpha.
The CvScalar is just a convenience container of 1, 2, 3 or 4 doubles which can be used to hold these values in a slightly different form.
For example:
cv.RGB(1.0, 0.5, 0.3) sets the red component of the color to 1.0 or 100%, the green component to 0.5 or 50% and the blue component to 0.3 or 30%. When the actual color structure is created each of these components will be made up of exactly one byte so this is analagous to setting the
R (red component) to 1.0 * 0xFF = 0xFF
G (green component) to 0.5 * 0xFF = 0x7F
B (blue component) to 0.3 * 0xFF = 0x26
The alpha is automatically set to 1.0 or 0xFF
Hexidecimal is just another representation of a number (base 16).
It's not too hard to get used to, you just need to learn how to convert to and from regular base 10 numbers.
Open up your favourite windows/mac calculator, switch to Hex mode, and type in FF. (the 0x prefix just tells the code that it's it's hexidecimal number)
Switch to Dec[imal] and the number will change to 255.
Type 32 in, in Decimal mode, then click hex, you'll see the number change to 20 (or 0x20 as it is in your code)
Now you can go from hexidecimal to decimal, you can go from decimal to scalar quite easily; Just convert the range;
float Scalar = static_cast<float>( Decimal ) / 255.f; // 255 being the largest value for your byte-colour
Enjoy Hex! You'll find it a very useful, neat and important way of looking at data.