Processing+OpenCVで背景差分

後輩からProcessingとOpenCVで背景差分を取りたいと相談を受けたため、そのプログラムをつくりました。

この記事ではProcessingとOpenCVを使って背景差分を取る方法について解説していきます。

大まかな流れ

  1. カメラで予め背景画像を取得する
  2. カメラで取得した画像を取得する
  3. 背景画像と取得画像をグレースケールに変換する
  4. 2枚のグレースケールの画像の差の絶対値を取得する
  5. 出来上がった差分画像をフィルターでノイズ処理する
  6. ある一定以上差が大きい部分を255, それ以外を0として2値化する

コード

import hypermedia.video.*;

OpenCV opencv; //OpenCVのオブジェクトです。
PImage binImage; // これが最終目標(変わった部分が白、変わらなかった部分が黒の二値画像)
boolean bLearnBgImage = true; // 背景画像を撮るフラグ

void setup(){
  size(640, 480);
  opencv = new OpenCV(this);
  opencv.capture(width, height);
}

void draw(){
  opencv.read(); // カメラから画像を取得
  opencv.flip(OpenCV.FLIP_HORIZONTAL); // 鏡写しにする

  if(bLearnBgImage){ // 背景撮るなら
    opencv.remember(OpenCV.SOURCE, OpenCV.FLIP_HORIZONTAL); // メモリーに画像を保存
    bLearnBgImage = false; // flagを切る。
  }

  opencv.absDiff();// 背景画像と今の画像の差の絶対値をとる
  opencv.convert(OpenCV.GRAY); // グレイスケールに変換
  opencv.blur(OpenCV.BLUR, 5); // ノイズを消すためにぼかす
  opencv.threshold(30); // スレッショルドを指定
  binImage = opencv.image(); // 最終目標!!!

  image(binImage, 0, 0); //表示
}

void keyPressed(){
  if(key == ' '){ // スペースキーが押されたら
    bLearnBgImage = true; // 背景を撮る
  }
}