glReadPixels - 图像看起来抖动

发布于 2024-11-26 18:06:04 字数 1248 浏览 1 评论 0原文

我希望捕获在 openGL 中渲染的图像。我使用 glReadPixels,然后使用 CImg 保存图像。不幸的是,结果是错误的。见下文。左边的图像是正确的。我用 GadWin PrintScreen 捕获了它。右图不正确。我用 glReadPixels 和 CImg 创建它:

在此处输入图像描述 在此处输入图像描述

我已经对可能出现的问题进行了大量的网络研究,但我没有办法去追求。这里是捕获图像的代码:

void snapshot() {
    int width = glutGet(GLUT_WINDOW_WIDTH);
    int height = glutGet(GLUT_WINDOW_HEIGHT);
    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    int bytes = width*height*3; //Color space is RGB
    GLubyte *buffer = (GLubyte *)malloc(bytes);

    glFinish();
    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
    glFinish();

    CImg<GLubyte> img(buffer,width,height,1,3,false);
    img.save("ScreenShot.ppm");
    exit(0);
}

这是我调用快照方法的地方:

void display(void) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        drawIndividual(0);
        snapshot();
        glutSwapBuffers();
    }

根据评论,我获取了位深度并打印到控制台。结果如下:

redbits=8
greenbits=8
bluebits=8
depthbits=24

I wish to capture an image I rendered rendered in openGL. I use glReadPixels and then save the image with CImg. Unfortunately, the result is wrong. See below. The image on the left is correct. I captured it with GadWin PrintScreen. The image on the right is incorrect. I created it with glReadPixels and CImg:

enter image description here
enter image description here

I've done a lot of Web research on what might be wrong, but I'm out of avenues to pursue. Here the code the captures the image:

void snapshot() {
    int width = glutGet(GLUT_WINDOW_WIDTH);
    int height = glutGet(GLUT_WINDOW_HEIGHT);
    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    int bytes = width*height*3; //Color space is RGB
    GLubyte *buffer = (GLubyte *)malloc(bytes);

    glFinish();
    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
    glFinish();

    CImg<GLubyte> img(buffer,width,height,1,3,false);
    img.save("ScreenShot.ppm");
    exit(0);
}

Here is where I call the snapshot method:

void display(void) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        drawIndividual(0);
        snapshot();
        glutSwapBuffers();
    }

Following up on a comment, I grabbed the bit depth and printed to the console. Here are the results:

redbits=8
greenbits=8
bluebits=8
depthbits=24

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

为人所爱 2024-12-03 18:06:04

您显然是从帧缓冲区获取图像,但行长度似乎不对。您设置了打包对齐(很好),但还有更多可设置的参数:

  • GL_PACK_ROW_LENGTH
  • GL_PACK_SKIP_PIXELS
  • GL_PACK_SKIP_ROWS

将它们设置为 0 以实现紧密打包。 glReadPixels() 之后的 glFinish() 也是多余的。 glReadPixels 不能异步工作 - 它仅在读取数据复制到目标缓冲区后返回(或者在写入 PBO 的情况下,从 PBO 获取数据将等待操作完成)。

You're clearly getting the image from the framebuffer, but the row length seems off. You set the packing alignment (good), but there are more settable parameters:

  • GL_PACK_ROW_LENGTH
  • GL_PACK_SKIP_PIXELS
  • GL_PACK_SKIP_ROWS

set them to 0 for tight packing. Also the glFinish() after glReadPixels() is superflous. glReadPixels doesn't work asynchronously – it returns only after the read data has been copied into the target buffer (or in the case of writing to a PBO, fetching the data from the PBO will wait for the operation to finish).

挽梦忆笙歌 2024-12-03 18:06:04

CImg 不会交织其颜色。也就是说,3个红、绿、蓝像素将线性存储为:

R1,R2,R3,...,G1,G2,G3,...,B1,B2,B3,...

但是,OpenGL的glReadPixel和glDrawPixel 期望交错的颜色分量如下所示:

R1、G1、B1、R2、G2、B2...

此外,OpenGL 将原点 (0,0) 放在图像的左下角。 CImg 使用 more 方法,其中原点位于图像的左上角。

这是我编写的一个例程,用于将交错颜色转换为 CImg 的面向通道的格式。

void convertToNonInterleaved(int w, int h, unsigned char* tangled, unsigned char* untangled) {
    //Take string in format R1 G1 B1 R2 G2 B2... and re-write it 
    //in the format format R1 R2 G1 G2 B1 B2... 
    //Assume 8 bit values for red, green and blue color channels.
    //Assume there are no other channels
    //tangled is a pointer to the input string and untangled 
    //is a pointer to the output string. This method assumes that 
    //memory has already been allocated for the output string.

    int numPixels = w*h;
    int numColors = 3;
    for(int i=0; i<numPixels; ++i) {
        int indexIntoInterleavedTuple = numColors*i;
        //Red
        untangled[i] = tangled[indexIntoInterleavedTuple];
        //Green
        untangled[numPixels+i] = tangled[indexIntoInterleavedTuple+1];
        //Blue
        untangled[2*numPixels+i] = tangled[indexIntoInterleavedTuple+2];
    }
}

我可能应该添加代码来解释原点的变化,但我感到懒惰并决定使用 CImg 来做到这一点。一旦运行此例程,此代码就会创建图像对象:

unsigned char* p = (unsigned char *)malloc(bytes);
convertToNonInterleaved(width, height, buffer, p);
CImg<unsigned char> img(p, width, height,1,3);
free(p);
img.mirror('y');
CImgDisplay main_disp(img,"Snapshot");
while (!main_disp.is_closed() ) {
    main_disp.wait();
}

据我所知,我不必设置任何打包参数。下面是我用来从 OpenGL 渲染目标获取像素的代码:

bytes = width*height*3; //Color space is RGB
if(buffer) 
    free(buffer);
buffer = (GLubyte *)malloc(bytes);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);

CImg does not interleave its colors. That is, 3 red, green, blue pixels would be stored linearly as:

R1, R2, R3, ..., G1, G2, G3, ..., B1, B2, B3, ...

However, OpenGL's glReadPixel and glDrawPixel expect interleaved color components like this:

R1, G1, B1, R2, G2, B2, ...

Additionally, OpenGL puts the origin (0,0) at the lower left corner of an image. CImg uses the more approach where the origin is at the top left of the image.

Here is a routine I wrote convert the interleaved colors to CImg's channel-oriented format.

void convertToNonInterleaved(int w, int h, unsigned char* tangled, unsigned char* untangled) {
    //Take string in format R1 G1 B1 R2 G2 B2... and re-write it 
    //in the format format R1 R2 G1 G2 B1 B2... 
    //Assume 8 bit values for red, green and blue color channels.
    //Assume there are no other channels
    //tangled is a pointer to the input string and untangled 
    //is a pointer to the output string. This method assumes that 
    //memory has already been allocated for the output string.

    int numPixels = w*h;
    int numColors = 3;
    for(int i=0; i<numPixels; ++i) {
        int indexIntoInterleavedTuple = numColors*i;
        //Red
        untangled[i] = tangled[indexIntoInterleavedTuple];
        //Green
        untangled[numPixels+i] = tangled[indexIntoInterleavedTuple+1];
        //Blue
        untangled[2*numPixels+i] = tangled[indexIntoInterleavedTuple+2];
    }
}

I should have probably added the code to account for the change in origin, but I felt lazy and decided to use CImg to do that. Once this routine is run, this code creates the image object:

unsigned char* p = (unsigned char *)malloc(bytes);
convertToNonInterleaved(width, height, buffer, p);
CImg<unsigned char> img(p, width, height,1,3);
free(p);
img.mirror('y');
CImgDisplay main_disp(img,"Snapshot");
while (!main_disp.is_closed() ) {
    main_disp.wait();
}

And as far as I can tell, I do not have to set any packing parameters. Here is the code I use to grab the pixels from the OpenGL render target:

bytes = width*height*3; //Color space is RGB
if(buffer) 
    free(buffer);
buffer = (GLubyte *)malloc(bytes);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文