翻转glReadPixels的RGBA输出(C ++ OpenGL)

时间:2013-06-22 08:17:33

标签: c++ opengl

我想从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

有什么问题

图像完全没错:

Output from trying to flip image

感谢任何帮助和评论。谢谢。

解决方案(鲍里斯)

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

4 个答案:

答案 0 :(得分:3)

您确定要从正确的坐标系读取和写入吗?以下摘自OpenGL.org

  

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

如果您保存的图像始终显示为颠倒,则可能出现问题。确保您知道(0,0)像素的位置(左上角或左下角),然后相应地调整图像算法。

答案 1 :(得分:2)

使用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));
}

答案 2 :(得分:2)

这是一个完整的示例,建立在Stypox的摘录片段之上-这也可以完成实际的编写。当然,交换协调系统是另一种解决方法 但我发现左上角的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());

答案 3 :(得分:1)

您需要在所有这些行中使用括号:

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

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

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

  2. 初始化最终尺寸的rgbdata并立即复制整行:

  3. 您将如何做:

    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