■ 2014年08月05日 [OpenGL][GLSL] GLSL で画像処理 (4) 背景差分
2014年08月11日 17:31更新
晴れた
久しぶりに晴れましたけど,大雨であちらこちら大変なことになっているようで,被災された皆様にはお見舞い申し上げます.近年,雨がどんどん狂暴になってきているように感じます.
背景差分
画像間の演算の例として,もっとも簡単だと思われる背景差分を考えてみます.まず,二つのテクスチャを準備し,その内容を黒 (R, G, B がいずれも 0) で初期化します.テクスチャをクリアする glClearTexImage() や glClearTexSubImage() は OpenGL 4.4 の機能のため,MacOS X では使えません.代わりに FBO を使うなどいくつかの方法があるみたいなんですけど,ここでは考えるのがめんどくさいんで,そういうデータを作ってしまいます.
// 空のテクスチャを準備する std::vector<GLubyte> empty(capture_width * capture_height * 3, 0);
同じ形式のテクスチャメモリを二つ確保して,上のデータを転送します.
// テクスチャをテクスチャメモリに転送する GLuint image[2]; glGenTextures(2, image); for (int i = 0; i < 2; ++i) { glBindTexture(GL_TEXTURE_RECTANGLE, image[i]); glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGB, capture_width, capture_height, 0, GL_BGR, GL_UNSIGNED_BYTE, &empty[0]); glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); }
プログラムオブジェクトを作成して,サンプラに使う uniform 変数の場所を取り出しておきます.
// プログラムオブジェクトの作成 const GLuint program(ggLoadShader("simple.vert", "back.frag")); // uniform 変数のインデックスの検索(見つからなければ -1) const GLuint image0Loc(glGetUniformLocation(program, "image0")); const GLuint image1Loc(glGetUniformLocation(program, "image1"));
キャプチャに成功した時,直前にスペースキーをタイプしていれば 1 番目のテクスチャに,そうでなければ 0 番目のテクスチャにキャプチャしたデータを転送します.
// ウィンドウが開いている間繰り返す while (window.shouldClose() == GL_FALSE) { if (camera.grab()) { // キャプチャ映像から画像を切り出す cv::Mat frame; camera.retrieve(frame, 3); // 切り出した画像をテクスチャに転送する cv::Mat flipped; cv::flip(frame, flipped, 0); glBindTexture(GL_TEXTURE_RECTANGLE, image[window.getKey() == GLFW_KEY_SPACE ? 1 : 0]); glTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, 0, 0, frame.cols, flipped.rows, GL_BGR, GL_UNSIGNED_BYTE, flipped.data); }
あとは前回同様,この二つのテクスチャをマッピングして矩形を描画します.
フラグメントシェーダ
フラグメントシェーダで二つのテクスチャの差の絶対値を求めます.
#version 330 uniform sampler2DRect image0; uniform sampler2DRect image1; layout (location = 0) out vec4 fc; void main() { fc = abs(texture(image0, gl_FragCoord.xy) - texture(image1, gl_FragCoord.xy)); }
起動した直後は,image1 には黒 (0) が入っているので,普通にキャプチャ画像が表示されます.
スペースキーをタイプすると,その瞬間にキャプチャされた画像が image1 に入ります.これがその後にキャプチャされる画像から引かれます.
いい加減なことをしているので,背景は真っ黒になってません.
次回はもっとまともなことが書けたらいいなぁ.