PDA

View Full Version : Problems with glReadPixel



dancvogel
10-03-2008, 06:49 PM
I am attempting to create a thumbnail of an image I am displaying. I would like the thumbnail version to be stored separately in a much smaller data array. I have the following code to accomplish this.

If I could have figured out how to tag the following as code I would have. I'm new to this forum and don't know how, sorry.

public ushort[] CreateThumbnail()
{

if (DisplayedImage == null) return null;

ushort[] data = new ushort[136 * 198];
float ScaleX = (float)136 / DisplayedImage.XSize;
float ScaleY = (float)198 / DisplayedImage.YSize;

Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);

Gl.glRasterPos2i(0, 0);
Gl.glBitmap(0, 0, 0, 0, 0, 0, null);
Gl.glPixelZoom(ScaleX, ScaleY);

Gl.glDrawPixels(DisplayedImage.XSize, DisplayedImage.YSize, Gl.GL_LUMINANCE, Gl.GL_UNSIGNED_SHORT, DisplayedImage.DataArray);

Gl.glFlush();

Gl.glReadBuffer(Gl.GL_BACK_LEFT);
Gl.glReadPixels(0, 0, 136, 198, Gl.GL_LUMINANCE, Gl.GL_UNSIGNED_SHORT, data);

return data;
}

Using the same data set(DisplayedImage.DataArray), when run through this code the first time, the result of the glReadPixels is all zeros, but the second time I get the expected values. IT IS THE EXACT SAME DATA, WHY IS IT DOING THIS? PLEASE HELP!

The original image is being displayed in a Paint function outside of this CreateThumbnail function.

This is coded in c# using the Tao framework for the OGL.

V-man
10-04-2008, 07:42 AM
Could be because of this
http://www.opengl.org/wiki/index.php/Common_Mistakes#The_Pixel_Ownership_Problem

dancvogel
10-06-2008, 11:28 AM
I looked into your suggestion, and tried to create a FBO. However, I don't think my graphics card supports the EXT_frambuffer_object. When calling glGenFramebuffersEXT I get a NULL pointer exception.

Any thoughts?

ZbuffeR
10-06-2008, 01:54 PM
Do you know how to use opengl entry points beyond gl1.1 and extensions ?
Try using glee or glew to ease this.

if EXT_frambuffer_object appears somewhere here then your card supports it :
glubyte* extString = glGetString(GL_EXTENSIONS); // to do within a valid opengl context.

Even old hardware can support this through modern drivers.

dletozeun
10-06-2008, 02:07 PM
Check if EXT_framebuffer_object is in the extension string. If you use opengl 3.0, I don't if it is still relevant.

The null pointer problem is caused because you don't retrieve the function call entry point dynamically, like explained here (http://www.opengl.org/resources/faq/technical/extensions.htm).

If you don't want to bother with these kind of details you can use tools like GLEW (http://www.opengl.org/sdk/libs/GLEW/) or GLee (http://www.opengl.org/sdk/libs/GLee/) that do this job for you.

ps: for code tags, paste your between
tags or switch to full reply mode and click on the '#' icon.

ps2: ok I am very slow tonight... :)

dancvogel
10-06-2008, 02:12 PM
I've tried:
string extString = Gl.glGetString(Gl.GL_EXTENSIONS);
the resulting string does not contain "EXT_framebuffer_object".

I don't know anything about glee or glew.

What about pbuffers? Would that work? Where can I find a good tutorial on how to use them?

dletozeun
10-06-2008, 02:22 PM
What is your hardware, fbo are quite often supported.

I am not very familiar with your problem, but I think that pBuffers would work if the solution is just offline rendering. But pBuffers are OS dependent. What is your platform?

dancvogel
10-06-2008, 02:25 PM
I've just realized that the glReadPixels is returning all zeros when it is being called from a helper thread, and the correct values when called from the main thread.

Is this a context issue?

I guess it might help to say that I am using c# and the Tao framework for my openGL.

dancvogel
10-06-2008, 02:37 PM
I am bound to a machine with an integrated graphics card (Intel 82945G Express Chipset) and Windows XP.

Since my objective is to basically just scale down my image data so that a thumbnail of the image can be stored, these operations never have to be displayed on the screen so pbuffers probably would work. I just need to figure out how to use them.

dletozeun
10-06-2008, 03:05 PM
Ok, It need a verified, but if I remember well, you can only do opengl calls in the thread that created the context, an other one that want to deal with opengl should ask the first one to do so.
To deal with opengl in two threads, you need to create two rendering contexts. This explains what you have noticed in your last post.

Now, I think that for image resizing, pbuffers are like bring out the big toolbox :). You will will have a lot of pain to make working them on different platforms. Moreover the way you do this, it would not be hardware accelerated, so opengl is not very useful in this case resizing manually may be more relevant and easier.

dancvogel
10-06-2008, 03:13 PM
How would I resize manually then?

Do you mean, outside of the code? If that is what you mean, then I cannot do it manually.

_NK47
10-07-2008, 08:02 AM
you can resize them manually on cpu. though it require some understanding like what filter to use (linear/nearest) and other things i dont remember. DevIL library might be helpful.

dletozeun
10-07-2008, 01:48 PM
Yes I was talking about resizing yourself in a program. Anyway, the way you are doing this with glDrawPixels/glReadPixels is not resizing but just "changing the image size without changing the scale its content" (don't know if there an english word to sum up this).
Moreover, this way, you don't benefit of any 2D filtering, because you don't use texture and then fbos. So, in your case, without fbo support, you better have to resize images yourself on cpu.

You can look at bilinear filtering and mipmapping on wikipedia, it is easy to implement on cpu and quite nice at the beginning.

_NK47
10-08-2008, 03:27 AM
"changing the image size without changing the scale its content" -
its kindof you take a portion of your image but its not the whole image its just a fraction of the whole thing. a subregion.

to make a POT image half of its size (mipmap) you need to ineterate through the pixels, take 4 pixels at a time, add them together and devide by 4. this gives the avarage pixel color.
you can continue this process till 1x1.
byte final_color = (pvalue1 + pvalue2 + pvalue3 + pvalue4) / 4;

dancvogel
10-08-2008, 10:02 AM
Thanks, this has helped!