«GLSL で画像処理 (3) ワーピング 最新 GLSL で画像処理 (5) フレーム間差分»

床井研究室

※このブログは遅くとも 2027 年 3 月に管理者の定年退職により閉鎖します (移転先は管理者本人共々模索中)

■ 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 に入ります.これがその後にキャプチャされる画像から引かれます.

みかんぼうやの背景

いい加減なことをしているので,背景は真っ黒になってません.

乱入するみかんぼうや

次回はもっとまともなことが書けたらいいなぁ.


編集 «GLSL で画像処理 (3) ワーピング 最新 GLSL で画像処理 (5) フレーム間差分»