17

I'm trying to use glReadPixels to get color data from an image. I'm supposed to be using glReadPixels but I can't seem to figure it out. It's part of a much larger project, but right now all I want is to know how to properly use this.

I looked it up and got something like this:

    void glReadPixels(GLint x, 
       GLint y, 
       GLsizei width, 
       GLsizei height, 
       GLenum format, 
       GLenum type, 
       GLvoid* data);

But I'm not sure what I should be putting in as that last argument, and when I do, how I would even use it. Help would really be appreciated! (ie: a simple example of how to use it, or how to get the color)

genpfault
  • 51,148
  • 11
  • 85
  • 139
CustardBun
  • 3,457
  • 8
  • 39
  • 65

3 Answers3

27

data takes a pointer to some buffer you prepared for glReadPixels to put the data into. Like this:

switch(format) {
case GL_BGR:
case GL_RGB:
    components = 3; break;

case GL_BGRA:
case GL_RGBA:
    components = 4; break;

case GL_ALPHA:
case GL_LUMINANCE:
    components = 1; break;
}

GLubyte *data = malloc(components * width * height);
if( data ) {
    glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, data);
}
datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • 1
    Nicely done. I would add that the first two parameters (x and y) are almost always 0,0 because they specify the lower-left corner of the pixel area. – ahoffer Jan 12 '12 at 20:43
  • What about GL_PACK_ALIGNMENT? Or GL_PACK_ROW_LENGTH? – Zbyl Aug 18 '13 at 13:07
  • @Zbyl: GL_PACK_ALIGNMENT should be set, but the exact value depends on the target format. GL_PACK_ROW_LENGTH can be left 0, unless you want to update a subportion of the buffer pointed to by data. However for just reading a picture in whole this is not necessary. – datenwolf Aug 18 '13 at 14:25
  • How to you get the `format` for the default buffer? – Ciro Santilli OurBigBook.com Mar 26 '16 at 07:51
  • 1
    @CiroSantilli六四事件法轮功包卓轩: `format` is a conversion parameter. It asks OpenGL to convert the contents of the buffer to the specific format you ask for. – datenwolf Mar 26 '16 at 17:02
19

Usage example:

#include <GL/glut.h>
#include <iostream>

int mx = 0, my = 0;
void display()
{
    glClearColor( 0, 0, 0, 1 );
    glClear( GL_COLOR_BUFFER_BIT );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho( -10, 10, -10, 10, -1, 1 );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glScalef( 5, 5, 5 );
    glBegin( GL_TRIANGLES );
    glColor3ub( 255, 0, 0 );
    glVertex2f( -1, -1 );
    glColor3ub( 0, 255, 0 );
    glVertex2f( 1, -1 );
    glColor3ub( 0, 0, 255 );
    glVertex2f( 0, 1 );
    glEnd();

    // 4 bytes per pixel (RGBA), 1x1 bitmap
    unsigned char pixels[ 1 * 1 * 4 ] = { 0 };
    glReadPixels( mx, my, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels );
    std::cout << "r: " << static_cast< int >( pixels[ 0 ] ) << '\n';
    std::cout << "g: " << static_cast< int >( pixels[ 1 ] ) << '\n';
    std::cout << "b: " << static_cast< int >( pixels[ 2 ] ) << '\n';
    std::cout << "a: " << static_cast< int >( pixels[ 3 ] ) << '\n' << std::endl;

    glutSwapBuffers();
}

void mouse( int x, int y )
{
    mx = x;
    my = glutGet( GLUT_WINDOW_HEIGHT ) - y;
    glutPostRedisplay();
}

int main( int argc, char **argv )
{
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
    glutInitWindowSize( 800, 600 );
    glutCreateWindow( "glReadPixels() example" );
    glutDisplayFunc( display );
    glutPassiveMotionFunc( mouse );
    glutMainLoop();
    return 0;
}

Use the mouse to get the RGBA value for a pixel.

genpfault
  • 51,148
  • 11
  • 85
  • 139
  • 1
    I get crashes during the vector deallocation. I fixed it using: `unsigned char pixels[4];` – num3ric Dec 05 '12 at 03:50
  • I am trying to run this code but all I get are empty (NULL) values for the pixels. Any idea what might be causing this? I am using glut-3.7.6 – masad Nov 21 '13 at 19:24
  • 2
    @masad: Switch to [FreeGLUT](http://freeglut.sourceforge.net/) and/or try sticking a `glFinish()` before the `glReadPixels()` call. – genpfault Nov 21 '13 at 20:03
  • 1
    @genpfault many thanks! it worked!! I added the function call and changed my libraries to FREEGLUT – masad Nov 22 '13 at 16:39
  • @masad: Did FreeGLUT fix it or the `glFinish()`? Or were both required? – genpfault Nov 22 '13 at 16:55
  • 1
    @genpfault FREEGLUT fixed it. glFinish() does not change anything in the output. – masad Nov 26 '13 at 12:13
2

data is the pointer to the pixel data you're trying to read. Take a look at some example code, and look a few lines above that call to find out how they're initializing it. Usually it will just be an allocation of size something like x * y * depth. You'd pass it in as &data. Try reading a 1x1 pixel block of known color and see what kind of information it gives back.

Tim
  • 14,447
  • 6
  • 40
  • 63
  • 1
    "data is the pointer to the pixel data you're trying to read" - typo: _write_, not read. – Damon Jan 13 '12 at 14:54
  • I suppose my word ordering left something to be desired: "The pixel data you're trying to read is stored in `data`". They're *reading* the pixel into `data`. – Tim Jan 13 '12 at 20:46