1

openGLでレンダリングしてレンダリングした画像をキャプチャしたいと思います。glReadPixelsを使用してから、CImgで画像を保存します。残念ながら、結果は間違っています。下記参照。左の画像は正しいです。GadWinPrintScreenでキャプチャしました。右の画像は正しくありません。glReadPixelsとCImgで作成しました。

ここに画像の説明を入力してください ここに画像の説明を入力してください

私は何が間違っているのかについて多くのWeb調査を行ってきましたが、私は追求する道がありません。ここに、画像をキャプチャするコードがあります。

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
4

2 に答える 2

5

フレームバッファから画像を取得していることは明らかですが、行の長さがずれているようです。パッキングの配置を設定します(良好)が、より多くの設定可能なパラメーターがあります。

  • GL_PACK_ROW_LENGTH
  • GL_PACK_SKIP_PIXELS
  • GL_PACK_SKIP_ROWS

密に梱包するには、0に設定します。また、glReadPixels()の後のglFinish()は不要です。glReadPixelsは非同期では機能しません。読み取りデータがターゲットバッファーにコピーされた後にのみ返されます(または、PBOに書き込む場合、PBOからデータをフェッチすると操作が終了するのを待ちます)。

于 2011-07-27T15:29:11.583 に答える
2

CImgはその色をインターリーブしません。つまり、3つの赤、緑、青のピクセルは次のように線形に格納されます。

R1、R2、R3、...、G1、G2、G3、...、B1、B2、B3、..。

ただし、OpenGLのglReadPixelとglDrawPixelは、次のようなインターリーブされたカラーコンポーネントを想定しています。

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

さらに、OpenGLは原点(0,0)を画像の左下隅に配置します。CImgは、原点が画像の左上にある、より多くのアプローチを使用します。

これが私が書いたルーチンで、インターリーブされた色を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);
于 2011-08-01T05:33:08.043 に答える