キャプチャする

capture.png

OpenGLのレンダリング結果をpngで保存したい。
普通にキャプチャソフトでとってもいいのだけど、
図形だけで背景は透明とかできないかなと思い、
プログラム内部からキャプチャ画像を生成する方法を調べた。
そのうち、自動的にgif画像とか作りたいな。

glReadPixels()でフレームバッファからプロセッサのメモリにピクセルデータを読み込む

普通に書くとこうなる。

glReadPixels(0,0,width,height,GL_RGBA,GL_UNSIGNED_BYTE,読み込み先のポインタ);

もしこの場合だと、読み込み先の配列のサイズは

width*height*4

バイトになる。4なのはRGBAだから。
ダブルバッファリングしている場合は、事前にフロントバッファとバックバッファのどちらを読み込むのか指定する必要がある

glReadBuffer(GL_FRONT);// フロントを読み込む様に設定する

せっかくパソコンのメモリに落とし込んだフレームバッファの内容けど、
今度はそれをどうやってpngにアウトプットするかが大事。
tgaで出力ならば、glfwで標準でありそう。
それからImageMagickでpngに変換してもいいかも?
libpngも試してみたけど、私のWindows環境ではどうもうまくいかなかった。

背景透過で画像保存するには

また、OpenGLで描いたところだけ保存したいなら,
ウィンドウ生成時にちゃんとアルファチャンネルを使うことを明示する必要がある

glfwOpenWindow(300,300,0,0,0,8/*alpha*/,0,0, GLFW_WINDOW );

参照:glfwOpenWindow()

ImageMagickを使って画面キャプチャをとるコード

ImageMagickで受け入れてるもっとも簡単な画像フォーマットである.rgbaでまずバイナリ出力します。
.rgbaは赤、緑、青、アルファの順に数字が並んでるだけの画像フォーマットです。
それから、ImageMagickのコマンドでpngに変換します

    static void capture(GLFWwindow *window) {
        int width, height;
        glfwGetWindowSize(window, &width, &height);
        glReadBuffer(GL_FRONT);// フロントを読み込む様に設定する
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // 初期値は4
        //ImageMagickを使用してキャプチャする
        unsigned char* data =new unsigned char[width*height * 4];
        glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
        const char tempfilename[] = "output.rgba";
        ofstream ofs(tempfilename);
        ofs.write(reinterpret_cast<const char*>(data), width*height*4);
        ofs.close();
        stringstream command;
        command << "convert -size " << width << "x" << height << " -depth 8 "<< tempfilename<<" output.png";
        system(command.str().c_str());
        remove(tempfilename);
    }

OpenCVを使って画面キャプチャをとるコード

//OpenCV関係
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv2/core/core.hpp>
#pragma comment(lib,"opencv_highgui240d.lib")
#pragma comment(lib,"opencv_core240d.lib")
/**
 * @brief 現在の画面の状態をキャプチャしてpngに保存する
 */
void capture(GLFWwindow *window)
{
    int width, height;
    glfwGetWindowSize(window,&width, &height);
 
    cv::Mat cvmtx(cv::Size(width, height), CV_8UC4, cv::Scalar(0, 0, 0));//黒で初期化
                                                                         // 画像のキャプチャ
    glReadBuffer(GL_FRONT);// フロントを読み込む様に設定する
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // 初期値は4
    glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, (void*)cvmtx.data);
    //上下逆にする
    cv::flip(cvmtx, cvmtx, 0);
    /* 画像の書き出し */
    cv::imwrite("output.png", cvmtx);
}

サンプルプログラム

git/PNGCaptureにあります。
レンダリング結果をpngで出力するプログラム。
背景は透明。
キーボードのcを押すとキャプチャします。
output.pngという名前で出力されます。
外部ライブラリとして
OpenCV 2.X
glfw
が必要です。
その他の足りないヘッダはmiffyフォルダからとってください。


framebuffer screenshot

サポートサイト Wikidot.com framebufferscreenshot