園児ニアのメモ

ただのエンジニア。何でも屋みたいな扱い受けてます。

OpenCV for Unityでぼかし処理

このページではOpenCVをUnityで扱うためのAsset「OpenCV for Unity」を利用して画像加工を行う手順をメモしています。
こちらはUnity5.4.1で作業しました。

※修正点、改善点ありましたらコメントまたは編集リクエストをよろしくお願いします。

開発準備

  • 開発を行うためにAssetをImportしてください。
    madgenius.hateblo.jp
  • こちらのソースを使用して進めます。
    madgenius.hateblo.jp
  • ソースのSimpleScript.csのUpdate()メソッドにある「/* 画像加工開始 */」と「/* 画像加工終了 */」の間を修正していくのでその中身のみを書いていきます。
  • カメラ映像のMatはcvCamMatという変数で取得し、cvCamMatをTexture2Dに変換して描画しています。
  • 画面に映るデフォルトの状態はこちらです。
    わかりやすくするために描画部分のみ比べるようにします。
    f:id:nanokanato:20170412155523p:plain:w100 → f:id:nanokanato:20170412155642p:plain:w200

Median Blur

f:id:nanokanato:20170412155733p:plain:w300

Imgproc.medianBlur(cvCamMat, cvCamMat, 41);

第一引数:入力Mat
第二引数:出力Mat
第三引数:アパーチャサイズ(各ピクセル近傍領域の直径)
     ・大きくなるとぼかしが強くなる(1より大きな奇数)

ガウシアンフィルタ

f:id:nanokanato:20170412155754p:plain:w300

Imgproc.GaussianBlur(cvCamMat, cvCamMat, new Size(41, 41), 0.0, 0.0);

第一引数:入力Mat
第二引数:出力Mat
第三引数:ガウシアンカーネルのサイズ
     ・大きくなるとぼかしが強くなる(1より大きな奇数)
第四引数:X方向の標準偏差
第五引数:Y方向の標準偏差

ボックスフィルタ

f:id:nanokanato:20170412155905p:plain:w300

Imgproc.boxFilter(cvCamMat, cvCamMat, cvCamMat.depth(), new Size(41, 41));

第一引数:入力Mat
第二引数:出力Mat
第三引数:デプス(Matのデータ型)
第四引数:平滑化カーネルのサイズ
     ・大きくなるほどほかしが強くなる(1より大きな奇数)

バイラテラルフィルタ(失敗)

f:id:nanokanato:20170412155642p:plain:w300

Imgproc.cvtColor (cvCamMat, cvCamMat, Imgproc.COLOR_RGBA2BGR);
Mat bgrMat = new Mat();
Imgproc.bilateralFilter (cvCamMat, bgrMat, 41, 0.0, 0.0);
Imgproc.cvtColor(bgrMat, cvCamMat, Imgproc.COLOR_BGR2RGBA); 

第一引数:入力Mat
第二引数:出力Mat
第三引数:各ピクセル近傍領域の直径
     ・大きくなるほどほかしが強くなる
第四引数:色空間におけるフィルタシグマ
     ・大きくなるほど色的により遠くのピクセルが混ぜ合わさる
第五引数:座標空間におけるフィルタシグマ
     ・大きくなるほど距離的により遠くのピクセル同士が影響しあう

「Utils.setDebugMode(true);」でOpenCVのネイティブ側で発生したエラーの出力ができる。

imgproc::bilateralFilter_11() : /Users/satoo/opencv/mac/3.1/opencv-3.1.0/modules/imgproc/src/smooth.cpp:3228: error: (-215) (src.type() == CV_8UC1 || src.type() == CV_8UC3) && src.data != dst.data in function bilateralFilter_8u

第一引数と第二引数は同じMatだとダメみたいです。
別のMatを用意して再度実行したら処理は重くなりましたが、描画される画像に変化は見られませんでした。

ミーンシフトフィルタ(失敗)

f:id:nanokanato:20170412155642p:plain:w300

Imgproc.cvtColor (cvCamMat, cvCamMat, Imgproc.COLOR_RGBA2BGR);
Mat bgrMat = new Mat();
Imgproc.pyrMeanShiftFiltering(cvCamMat, bgrMat, 11, 11);
Imgproc.cvtColor(bgrMat, cvCamMat, Imgproc.COLOR_BGR2RGBA); 

第一引数:入力Mat
第二引数:出力Mat
第三引数:空間窓の半径?
第四引数:色空間窓の半径?

バイラテラルフィルタと同じく処理は重いが動作しない。
引数の数値が正しくないとかが原因かもしれない。

その他

他のバイラテラルフィルタや平均値シフト法でのぼかしも挑戦しましたが動作しないため現在記載しておりません。

  • 処理速度(上と同じ、ぼかし度:41、画像サイズ:750x750pxで比較)
順位 ぼかし方法 体感速度
1位 ボックスフィルタ ほぼリアルタイム
2位 ガウシアンフィルタ 2秒ほど遅れを感じる
3位 Median Blur 3秒ほど遅れを感じる

※バイラテラルフィルタは順位は4位だが変化がないため除外

ちゃんとぼかされていてある程度のリアルタイム性が必要であればボックスフィルタが有能?
引数や元Matサイズを調整することで変わることがあると思います。