2

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

怎么了

图像结果都是错误的:

尝试翻转图像的输出

任何帮助和意见表示赞赏。谢谢你。

解决方案(鲍里斯)

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

5 回答 5

4

这是一个完整的例子,建立在 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());
于 2020-04-29T14:13:08.960 回答
3

您确定您正在从正确的坐标系读取和写入吗?以下内容来自OpenGL.org

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

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

于 2013-06-22T08:36:03.670 回答
2

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

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
于 2013-06-22T08:25:20.590 回答
2

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

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));
}
于 2020-03-15T19:44:26.013 回答
0

我用这句话来截屏,

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);
    }
  
}
于 2021-11-21T12:24:07.277 回答