OpenGL pixels drawn with each horizontal pair swapped - opengl

I'm somewhat new to OpenGL though I'm fairly sure my problem lies in the pixel format being used, or how my texture is being generated...
I'm drawing a texture onto a flat 2D quad using a 16bit RGB5_A1 pixel format, though I don't make use of any alpha at this stage. The problem I'm having is that each pair of horizontal pixel values have been swapped.
That is... if the pixels positions should be in this order (assume 8x2 image)
0 1 2 3
4 5 6 7
they are instead drawn as
1 0 3 2
5 4 7 6
Or, more clearly from this image (below).
Left is what I get... Right is what I should get.
.
The question is... How have I ended up with this? Is there something wrong with the pixel format? Unlikely since the colours all appear correct, and I would expect all kinds of nasty if it were down to endian-ness. Suggestions greatly appreciated.
Update: Turns out the problem was in my source renderer. Interestingly, I've avoided the problem entirely by using 32-bit textures (haven't tried 24-bit at this point).

This may be unrelated, and you have found a workaround, but it could be related to OpenGL unpack alignment. Have you tried with the following call ? To instruct the alignment of every image row to 1 byte (default is 4).
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

Related

Converting 12 bit color values to 8 bit color values C++

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.

Textures and pixel storage

Right now I have an application that renders a geometry and allows you to select a PNG and overlay it. My question is this:
I have a scenario where I select a PNG where the width is not a multiple of 4 (the dimensions are 2719 x 1277).
My understanding is that if you try to store an image into a 2D texture who's dimensions aren't multiples of 4 this shouldn't work. At least if your GL_UNPACK_ALIGNMENT is 4, which mine is.
I'm storing my texture with an internal format of RGB so one row if pixels would be 2719 * 3 (8157). I've seen problems people have had where they're trying to do the same thing I am where their image width is not in a multiple of 4, and they haven't been able to use the texture, until they've set the unpack alignment to 1, but in my case it works if I use 4. I just wanna understand why this is.
I used this link as my primary learning source.
https://www.opengl.org/wiki/Pixel_Transfer

Compressing BMP methods

I am working on a project to losslessly compress a specific style of BMP images that look like this
I have thought about doing pattern recognition, to find repetitive blocks of N x N pixels but I feel like it wont be fast enough execution time.
Any suggestions?
EDIT: I have access to the dataset that created these images too, I just use the image to visualize my data.
Optical illusions make it hard to tell for sure but are the colors only black/blue/red/green? If so, the most straightforward compression would be to simply make more efficient use of pixels. I'm thinking pixels use a fixed amount of space regardless of what color they are. Thus, chances are you are using 12x as many pixels as you really need to be. Since a pixel can be a lot more colors than just those four.
A simple way to do that would be to do label the pixels with the following base 4 numbers:
Black = 0
Red = 1
Green = 2
Blue = 3
Example:
The first four colors of the image seems to be Blue-Red-Blue-Blue. This is equal to 3233 in base 4, which is simply EF in base 16 or 239 in base 10. This is enough to define what the red color of the new pixel should be. The next 4 would define the green color and the final 4 define what the blue color is. Thus turning 12 pixels into a single pixel.
Beyond that you'll probably want to look into more conventional compression software.

C++: How to interpret a byte array representation of an image?

I'm trying to work with this camera SDK, and let's say the camera has this function called CameraGetImageData(BYTE* data), which I assume takes in a byte array, modifies it with the image data, and then returns a status code based on success/failure. The SDK provides no documentation whatsoever (not even code comments) so I'm just guestimating here. Here's a code snippet on what I think works
BYTE* data = new BYTE[10000000]; // an array of an arbitrary large size, I'm not
// sure what the exact size needs to be so I
// made it large
CameraGetImageData(data);
// Do stuff here to process/output image data
I've run the code w/ breakpoints in Visual Studio and can confirm that the CameraGetImageData function does indeed modify the array. Now my question is, is there a standard way for cameras to output data? How should I start using this data and what does each byte represent? The camera captures in 8-bit color.
Take pictures of pure red, pure green and pure blue. See what comes out.
Also, I'd make the array 100 million, not 10 million if you've got the memory, at least initially. A 10 megapixel camera using 24 bits per pixel is going to use 30 million bytes, bigger than your array. If it does something crazy like store 16 bits per colour it could take up to 60 million or 80 million bytes.
You could fill this big array with data before passing it. For example fill it with '01234567' repeated. Then it's really obvious what bytes have been written and what bytes haven't, so you can work out the real size of what's returned.
I don't think there is a standard but you can try to identify which values are what by putting some solid color images in front of the camera. So all pixels would be approximately the same color. Having an idea of what color should be stored in each pixel you may understand how the color is represented in your array. I would go with black, white, reg, green, blue images.
But also consider finding a better SDK which has the documentation, because making just a big array is really bad design
You should check the documentation on your camera SDK, since there's no "standard" or "common" way for data output. It can be raw data, it can be RGB data, it can even be already compressed. If the camera vendor doesn't provide any information, you could try to find some libraries that handle most common formats, and try to pass the data you have to see what happens.
Without even knowing the type of the camera, this question is nearly impossible to answer.
If it is a scientific camera, chances are good that it adhers to the IEEE 1394 (aka IIDC or DCAM) standard. I have personally worked with such a camera made by Hamamatsu using this library to interface with the camera.
In my case the camera output was just raw data. The camera itself was monochrome and each pixel had a depth-resolution of 12 bit. Therefore, each pixel intensity was stored as 16-bit unsigned value in the result array. The size of the array was simply width * height * 2 bytes, where width and height are the image dimensions in pixels the factor 2 is for 16-bit per pixel. The width and height were known a-priori from the chosen camera mode.
If you have the dimensions of the result image, try to dump your byte array into a file and load the result either in Python or Matlab and just try to visualize the content. Another possibility is to load this raw file with an image editor such as ImageJ and hope to get anything out from it.
Good luck!
I hope this question's solution will helps you: https://stackoverflow.com/a/3340944/291372
Actually you've got an array of pixels (assume 1 byte per pixel if you camera captires in 8-bit). What you need - is just determine width and height. after that you can try to restore bitmap image from you byte array.

How to magnify/stretch a texture with Matlab Psychtoolbox (OpenGL)?

Update: This only seems to be a problem at some computers. The normal, intuitive code seems to work fine one my home computer, but the computer at work has trouble.
Home computer: (no problems)
Windows XP Professional SP3
AMD Athlon 64 X2 3800+ Dual Core 2.0 GHz
NVIDIA GeForce 7800 GT
2 GB RAM
Work computer: (this question applies to this computer)
Windows XP Professional SP3
Intel Pentium 4 2.8 Ghz (dual core, I think)
Intel 82945G Express Chipset Family
1 GB RAM
Original post:
I'm trying to apply a very simple texture to a part of the screen using Psychtoolbox in Matlab with the following code:
win = Screen('OpenWindow', 0, 127); % open window and obtain window pointer
tex = Screen('MakeTexture', win, [255 0;0 255]); % get texture pointer
% draw texture. Args: command, window pointer, texture pointer, source
% (i.e. the entire 2x2 matrix), destination (a 100x100 square), rotation
% (none) and filtering (nearest neighbour)
Screen('DrawTexture', win, tex, [0 0 2 2], [100 100 200 200], 0, 0);
Screen('Flip', win); % flip the buffer so the texture is drawn
KbWait; % wait for keystroke
Screen('Close', win); % close screen
Now I would expect to see this (four equally sized squares):
But instead I get this (right and bottom sides are cut off and top left square is too large):
Obviously the destination rectangle is a lot bigger than the source rectangle, so the texture needs to be magnified. I would expect this to happen symmetrically like in the first picture and this is also what I need. Why is this not happening and what can I do about it?
I have also tried using [128 0 1152 1024] as a destination rectangle (as it's the square in the center of my screen). In this case, all sides are 1024, which makes each involved rectangle a power of 2. This does not help.
Increasing the size of the checkerboard results in a similar situation where the right- and bottommost sides are not showed correctly.
Like I said, I use Psychtoolbox, but I know that it uses OpenGL under the hood. I don't know much about OpenGL either, but maybe someone who does can help without knowing Matlab. I don't know.
Thanks for your time!
While I don't know much (read: any) Matlab, I do know that textures are very picky in openGL. Last I checked, openGL requires texture files to be square and of a power of two (i.e. 128 x 128, 256 x 256, 512 x 512).
If they aren't, openGL is supposed to pad the file with appropriate white pixels where they're needed to meet this condition, although it could be a crapshoot depending on which system you are running it on.
I suggest making sure that your checkerboard texture fits these requirements.
Also, I can't quite make sure from your code posted, but openGL expects you to map the corners of your texture to the corners of the object you are intending to texture.
Another bit of advice, maybe try a linear filter instead of nearest neighbor. It's heavier computationally, but results in a better image. This probably won't matter in the end.
While this help is not Matlab specific, hope it is useful.
Without knowing a lot about the Psychtoolbox, but having dealt with graphics and user interfaces a lot in MATLAB, the first thing I would try would be to fiddle with the fourth input to Screen (the "source" input). Try shifting each corner by half-pixel and whole-pixel values. For example, the first thing I would try would be:
Screen('DrawTexture', win, tex, [0 0 2.5 2.5], [100 100 200 200], 0, 0);
And if that didn't seem to do anything, I would next try:
Screen('DrawTexture', win, tex, [0 0 3 3], [100 100 200 200], 0, 0);
My reasoning for this advice: I've noticed sometimes that images or GUI controls in my figures can appear to be off by a pixel, which I can only speculate is some kind of round-off error when scaling or positioning them.
That's the best advice I can give. Hope it helps!