【问题标题】:Flipping RGBA output of glReadPixels (C++ OpenGL)翻转 glReadPixels 的 RGBA 输出(C++ OpenGL)
【发布时间】:2013-06-22 08:17:32
【问题描述】:

我想从 glReadPixel 翻转输出图像。我通过将 glReadPixels 的输出保存到文件中来检查它。图像是正确的,但它是颠倒的。

我尝试了什么

int patchSize = 50;
std::vector<unsigned char> rgbdata(4*patchSize*patchSize);
glReadPixels(x-(patchSize/2), y-(patchSize/2)/2), patchSize,patchSize,GL_RGBA,GL_UNSIGNED_BYTE, &rgbdata[0]);

std::vector< unsigned char > temp_rgbdata = rgbdata; // Create a copy of the data
    rgbdata.clear(); // Reset the array
    for (int i=patchSize-1; i >= 0; i--) // Count backwards in order to flip
    {
        for( int j = 0; j < patchSize; j++) {

            rgbdata.push_back(temp_rgbdata[i*patchSize+j*4]);
            rgbdata.push_back(temp_rgbdata[i*patchSize+j*4+1]);
            rgbdata.push_back(temp_rgbdata[i*patchSize+j*4+2]);
            rgbdata.push_back(temp_rgbdata[i*patchSize+j*4+3]);

        }
    }
    temp_rgbdata.clear(); // Clear the temporary array

怎么了

图片都错了:

感谢任何帮助和 cmets。谢谢。

解决方案(由 Boris 提供)

int patchSize = 50;
std::vector<unsigned char> rgbdata(4*patchSize*patchSize);
glReadPixels(x-(patchSize/2), y-(patchSize/2)), patchSize,patchSize,GL_RGBA,GL_UNSIGNED_BYTE, &rgbdata[0]);

std::vector< unsigned char > temp_rgbdata = rgbdata; // Create a copy of the data
    rgbdata.clear(); // Reset the array
    for (int i=patchSize-1; i >= 0; i--) // Count backwards in order to flip
    {
        for( int j = 0; j < patchSize; j++) {

            rgbdata.push_back(temp_rgbdata[(i*patchSize+j)*4]);
            rgbdata.push_back(temp_rgbdata[(i*patchSize+j)*4+1]);
            rgbdata.push_back(temp_rgbdata[(i*patchSize+j)*4+2]);
            rgbdata.push_back(temp_rgbdata[(i*patchSize+j)*4+3]);

        }
    }
    temp_rgbdata.clear(); // Clear the temporary array

【问题讨论】:

    标签: c++ opengl


    【解决方案1】:

    这是一个完整的例子,它建立在 Stypox 的伟大 sn-p 之上 - 这也可以完成实际的写作。当然,交换你的坐标系统是另一种解决方法 但我发现左上角的 0,0 更自然。

    // https://github.com/nothings/stb/blob/master/stb_image_write.h
    #include "stb_image_write.h"
    
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glReadBuffer(GL_BACK_LEFT);
    
    std::vector<uint8_t> pixels(3 * w * h);
    glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
    
    for(int line = 0; line != h/2; ++line) {
        std::swap_ranges(pixels.begin() + 3 * w * line,
                         pixels.begin() + 3 * w * (line+1),
                         pixels.begin() + 3 * w * (h-line-1));
    }
    
    int components = 3;
    stbi_write_png("out.png", w, h, components, pixels.data(), 3 * w);
    stbi_write_tga("out.tga", w, h, components, pixels.data());
    

    【讨论】:

      【解决方案2】:

      您确定从/向正确的坐标系进行读写吗?以下摘自OpenGL.org

      与具有左上角坐标系的 2D 渲染 API 相关的另一个常见缺陷是 2D 图像文件格式从顶部扫描线开始图像,而不是底部扫描线。默认情况下,OpenGL 假定图像从底部扫描线开始。如果在渲染时确实需要翻转图像,可以使用 glPixelZoom(1,-1).

      如果您保存的图像总是上下颠倒,这可能是问题所在。确保您知道 (0,0) 像素的位置(左上角或左下角),然后相应地调整图像算法。

      【讨论】:

      • +1 它没有回答为什么翻转代码不起作用,但首先消除了翻转的需要;-)
      • 事实上,glPixelZoom 不适用于 glRead,只能用于 glWrite,并且无论如何都已弃用。所以 +1 只是为了这个想法:尽量让图像不颠倒是最好的策略。
      • 好点。几周前我实际上发布了一个问题,在那里我遇到了同样的问题。我在倒置的物体上的纹理。我通过在顶点着色器中翻转图像来解决它,但是问题现在已经累积,所以我应该找到一种在加载时更改图像的方法。
      【解决方案3】:

      所有这些行都需要括号:

      temp_rgbdata[ (i*patchSize+j)*4 ]
      

      顺便说一句,您可以通过以下方式提高效率:

      1. 将倒置的图像放入临时数组(避免无用的复制)

      2. 初始化最终大小的rgbdata并一次复制整行:

      你会怎么做:

      int patchSize = 50;
      std::vector<unsigned char> temp_rgbdata(4*patchSize*patchSize);
      glReadPixels(x-(patchSize/2), y-(patchSize/2)),patchSize,patchSize,GL_RGBA,GL_UNSIGNED_BYTE, &temp_rgbdata[0]);
      
      std::vector< unsigned char > rgbdata(4*patchSize*patchSize);
      for (int i=0; i < patchSize; i++) // Doesn't matter the order now
          memcpy(&rgbdata[i*patchSize*4],                    // address of destination
                 &temp_rgbdata[(patchSize-i-1)*patchSize*4], // address of source
                 patchSize*4*sizeof(unsigned char) );        // number of bytes to copy
      
      temp_rgbdata.clear(); // Clear the temporary array
      

      【讨论】:

        【解决方案4】:

        使用 C++17 swap_ranges 翻转 glReadPixels 的输出的更简单方法,无需临时向量。下面的代码并不特定于所询问的内容,并且可以与 xywh 的任何值一起使用。

        std::vector<uint8_t> pixels(3 * w * h);
        glReadPixels(x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
        
        for(int line = 0; line != h/2; ++line) {
            std::swap_ranges(
                    pixels.begin() + 3 * w * line,
                    pixels.begin() + 3 * w * (line+1),
                    pixels.begin() + 3 * w * (h-line-1));
        }
        

        【讨论】:

        【解决方案5】:

        我用这句话来截屏,

        glReadPixels(0,0,SCR_WIDTH,SCR_HEIGHT,GL_RGB,GL_UNSIGNED_BYTE,buf);
        

        并且buf的类型是uint8_t*,

        所以我这样做

        void flip(uint8_t** buf)
        {
            int totalLength = SCR_HEIGHT*SCR_WIDTH*3;
            int oneLineLength = SCR_WIDTH*3;
            uint8_t* tmp = (uint8_t*)malloc(SCR_HEIGHT*SCR_WIDTH*3);
            memcpy(tmp,*buf,SCR_WIDTH*SCR_HEIGHT*3);
            memset(*buf,0,sizeof(uint8_t)*SCR_HEIGHT*SCR_WIDTH*3);
            for(int i = 0; i < SCR_HEIGHT;i++){
                memcpy(*buf+oneLineLength*i,tmp+totalLength-oneLineLength*(i+1),oneLineLength);
            }
          
        }
        

        【讨论】:

          猜你喜欢
          • 2012-02-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-11-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多