簡體   English   中英

翻轉 glReadPixels 的 RGBA 輸出(C++ OpenGL)

[英]Flipping RGBA output of glReadPixels (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

怎么了

圖像結果都是錯誤的:

嘗試翻轉圖像的輸出

任何幫助和評論表示贊賞。 謝謝你。

解決方案(由鮑里斯)

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

您確定要從/向正確的坐標系讀取和寫入嗎? 以下內容來自OpenGL.org

與具有左上角坐標系的 2D 渲染 API 相關的另一個常見缺陷是 2D 圖像文件格式從頂部掃描線而不是底部掃描線開始圖像。 默認情況下,OpenGL 假定圖像從底部掃描線開始。 如果在渲染時確實需要翻轉圖像,可以使用 glPixelZoom(1,-1)。

如果您保存的圖像總是上下顛倒,這可能是哪里出了問題。 確保您知道 (0,0) 像素的位置(左上角或左下角),然后相應地調整圖像算法。

所有這些行中都需要括號:

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

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

這是一個完整的例子,建立在 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());

我用這句話來截屏,

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM