I have a bit array representing an image mask, stored in a uint8_t[] container array, in row first order. Hence, for each byte, I have 8 pixels.
Now, I need to render this with OpenGL ( >= 3.0 ). A positive bit is drawn as a white pixel and a negative bit is drawn as a black pixel.
How could I do this? Please
The first idea that comes to mind is to develop a specific shader for this. Can anyone give some hints on that?
You definitely must write a shader for this. First and foremost you want to prevent the OpenGL implementation to reinterpret the integer bits of your B/W bitmap as numbers in a certain range and map them to [0…1] floats. Which means you have to load your bits into an integer image format. Since your image format is octet groups of binary pixels (byte is a rather unspecific term and can refer to any number of bits, though 8 bits is the usual), a single channel format 8 bits format seems the right choice. The OpenGL-3 moniker for that is GL_R8UI. Keep in mind that the "width" of the texture will be 1/8th of the actual width of your B/W image. Also for unnormalized access you must use a usampler (for unsigned) or an isampler (for signed) (thanks #derhass for noticing that this was not properly written here).
To access individual bits you use the usual bit manipulation operators. Since you don't want your bits to become filtered, texel fetch access must be used. So to access the binary pixel at integer location x,y the following would be used.
uniform usampler2D tex;
uint shift = x % 8;
uint mask = 1 << shift;
uint octet = texelFetch(tex, ivec2(x/8,y)).r;
value = (octet & mask) >> shift;
The best solution would be to use a shader, you could also hack something like this:
std::bitset<8> bits = myuint;
Then get the values of the single bits with bits.at(position) and finally do a simple point drawing.
Related
I'm trying to read image info from a dds file. I managed to get the DXT1 and DXT5 formats working fine, however I have a question concerning the alpha data of the DXT3 format (Also know as BC2).
When looking at the layout of a compressed BC2 block, it shows the alpha data for the 16-pixel block is stored in the first 8 bytes of the data, with each value taking up 4 bits.
Does this mean that, since the stored alpha value can only be 0-15, the actual alpha data is calculated as follows:
unsigned char bitvalue = GetAlphaBitValue(); // assume this works and gets the 4-bit value i am looking for
unsigned char alpha = (bitvalue / 15.0f) * 255;
Is this correct, or am I looking at it wrong?
That's what this specification seems to say:
The alpha component for a texel at location (x,y) in the block is
given by alpha(x,y) / 15.
Because the result there is supposed to be in [0 .. 1], not [0 .. 255].
Since 255 is divisible by 15, it's probably easier to think of the transformation to [0 .. 255] as
uint8_t alpha = bitvalue * 17;
It is now more obvious that what's going on is the usual "replicate" mapping (just like eg CSS short color codes) that gives a nice spreading of output values (allows both the minimum and the maximum values to be encoded, and has equal steps between all values).
I'm attempting to convert 12-bit RGGB color values into 8-bit RGGB color values, but with my current method it gives strange results.
Logically, I thought that simply dividing the 12-bit RGGB into 8-bit RGGB would work and be pretty simple:
// raw_color_array contains R,G1,G2,B in a bayer pattern with each element
// ranging from 0 to 4096
for(int i = 0; i < array_size; i++)
{
raw_color_array[i] /= 16; // 4096 becomes 256 and so on
}
However, in practice this actually does not work. Given, for example, a small image with water and a piece of ice in it you can see what actually happens in the conversion (right most image).
Why does this happen? and how can I get the same (or close to) image on the left, but as 8-bit values instead? Thanks!
EDIT: going off of #MSalters answer, I get a better quality image but the colors are still drasticaly skewed. What resources can I look into for converting 12-bit data to 8-bit data without a steep loss in quality?
It appears that your raw 12 bits data isn't on a linear scale. That is quite common for images. For a non-linear scale, you can't use a linear transformation like dividing by 16.
A non-linear transform like sqrt(x*16) would also give you an 8 bits value. So would std::pow(x, 12.0/8.0)
A known problem with low-gradient images is that you get banding. If your images has an area where the original value varies from say 100 to 200, the 12-to-8 bit reduction will shrink that to less than 100 different values. You get rounding , and with naive (local) rounding you get bands. Linear or non-linear, there will then be some inputs x that all map to y, and some that map to y+1. This can be mitigated by doing the transformation in floating point, and then adding a random value between -1.0 and +1.0 before rounding. This effectively breaks up the band structure.
After you clarified that this 12bit data is only for one color, here is my simple answer:
Since you want to convert its value to its 8 bit equivalent, it obviously means you lost some of the data (4bits). This is the reason why you are not getting the same output.
After clarification:
If you want to retain the actual colour values!
Apply de-mosaicking in the 12 Bit image and then scale the resultant data to 8 - Bit. So that the colour loss due to de-mosaicking will be less compared to the previous approach.
You say that your 12-bits represent 2^12 bits of one colour. That is incorrect. There are reds, greens and blues in your image. Look at the histogram. I made this with ImageMagick at the command line:
convert cells.jpg histogram:png:h.png
If you want 8-bits per pixel, rather than trying to blindly/statically apportion 3 bits to Green, 2 bits to Red and 3 bits to Blue, you would probably be better off going with an 8-bit palette so you can have 250+ colours of all variations rather than restricting yourself to just 8 blue shades, 4 reds an 8 green. So, like this:
convert cells.jpg -colors 254 PNG8:result.png
Here is the result of that beside the original:
The process above is called "quantisation" and if you want to implement it in C/C++, there is a writeup here.
I have data for every pixel red one byte, green one byte, blue one byte. I need to pack this to 8 bits bitmap, so I have only one byte for pixel. How to transform rgb (three bytes) to one byte for bitmap format ?
( I am using C++ and cannot use any external libraries)
I think you misunderstood how to form a bitmap structure. You do not need to pack (somehow) 3 bytes into one. That is not possible after all, unless you throw away information (like using special image formats GL_R3_G3_B2).
The BMP file format wiki page shows detailed BMP format : it is a header, followed by data. Now depending on what you set in your header, it is possible to form a BMP image containing RBG data component, where each component is one byte.
First you need to decide how many bits you want to allocate for each color.
3bit per color will overflow a byte (9bits)
2bits per color will underflow;
In three byte RGB bitmap you have one byte to represent each color's intensity. Where 0 is minimum and 255 is max intensity. When you convert it to 1 byte bitmap (assuming you will choose 2bits per color ) transform should be:
1-byte red color/64
i.e you will get only 4 shades out of a spectrum of 265 shades per color.
First you have to produce 256 colors palette that best fits your source image.
Then you need to dither the image using the palette you've generated.
Both problems have many well-known solutions. However, it's impossible to produce high-quality result completely automatic: for different source images, different approaches work best. For example, here's the Photoshop UI that tunes the parameters of the process:
I have an 8bit Image (stored in an Array) containing black(0) and white(255) pixels. Say I want to change all Black pixels in the image to grey(say 120) pixels. What is the fastest way I can change Black to Grey.
I thought of two approaches-
Start checking every single pixel in the image. As soon as a black pixel is found change it to grey. Continue till end of image. (Slower but easier)
Start checking pixels. When a black pixel is found maintain a counter to track it. Continue incrementing the counter till the next white pixel. Then goto the counter and use a fast function like memset to change a group of black pixels to grey. (Not sure but I think this may be faster)
I have a huge 1GB image therefore approach 1 is pretty slow. Is there a better(faster) way to change/edit pixels?
Probably quicker to do it a word at a time (using word aligned accesses).
You can just bitwise OR with 0x78787878 (assuming 32 bits). This will not affect white pixels but will set black pixels to the required value.
I think the problem with the first approach is that you read and write the same 32/64/x bits (depending on memory architecture/bus width) muliple times. It should be faster if you read and write the bits corresponding to the bus width once.
In the following snippet, getPixelsSizeOfLong returns the bites according to the width of the bus (say 4 bytes) and there reduces transfering bits between cache and cpu.
// Forward declaration:
unsigned long getPixelsSizeOfLong(byteInImage unsigned int);
void setPixelsSizeOfLong(byteInImage unsigned int, newBitValue unsigned long);
unsinged long l;
for (a=0; a+=sizeof(l); a<nof_pixels) {
l = getPixelsSizeOfLong(a);
l |= 120;
setPixelsSizeOfLong(a, l);
}
So I have a x8r8g8b8 formatted IDirect3DSurface9 that contains the contents of the back buffer. When I call LockRect on it I get access to a struct containing pBits, a pointer to the pixels I assume, and and integer Pitch (which I am very unclear about its purpose).
How to read the individual pixels?
Visual Studio 2008 C++
The locked area is stored in a D3DLOCKED_RECT. I haven't ever used this but the documentation says it is the "Number of bytes in one row of the surface". Actually people would normally call this "stride" (some terms explained in the MSDN).
For example, if one pixel has 4 bytes (8 bits for each component of XRGB), and the texture width is 7, the image is usually stored as 8*4 bytes instead of 7*4 bytes because the memory can be accessed faster if the data is DWORD-aligned.
So, in order to read pixel [x, y] you would have to read
uint8_t *pixels = rect.pBits;
uint32_t *mypixel = (uint32_t*)&pixels[rect.Pitch*y + 4*x];
where 4 is the size of a pixel. *myPixel would be the content of the pixel in my example.
Yep, you would access the individual RGB components of the pixel like that.
The first byte of the pixel is not used, but it is more efficient to use 4 Bytes per pixel, so that each pixel is aligned on a 32Bit boundary (that's also, why there's the pitch).
In your example, the x is not used, but note that there are lso other pixel formats, for example ARGB, which stores the alpha value (transparency) in the first byte. Sometimes the colors are also reversed (BGR instead of RGB). If you're unsure what byte corresponds to what color, a good trick is to create a texture which is entirely red, green or blue and then check which of the 4 bytes has the value 255.