Unityで画像処理をするためのライブラリを公開しました


顛末

なんか画像処理の研究をすることになったけど,Unity+C#以外の環境でスクリプトが書ける気がしない...

なんでUnity+C#で画像処理しちゃいかんの?ライブラリ書いたるわ!

初めに

ということでUnityで画像処理ができるライブラリ,ImageProcessingLibraryforUnityを作りました.
他のUnityで画像処理している記事は主に画面描画におけるポストプロセスの工程でのブラーの実装とかをしていますが,本ライブラリはTexture2DやTextureに対するものです.

ComputeShaderで書いているのでGPUがちゃんとしている環境ではまあまあ早いです.
画像処理ライブラリといったらOpenCVですが,Unityでこれが使えるAssetはこれとかこれとかいくつかありますが,速度比較をしたところ自分のライブラリの方が早かったです.
そのデータ紛失したので自信もって言えませんが...

一番の特徴としては,LINQのようにメソッドチェーンの方式で書くことができます.
これによって直感的に記述することができ,雰囲気で画像処理ができます.うれしいですね.

使い方

基本的にGitHubのリポジトリページにあるReadMeに書いてあります.

Unityのプロジェクトに本unitypackageを導入後,利用したいシーンにShaderSettingsのprefabを置いてください.これで準備完了です.

var renderTexture = texture.ToRenderTexture();

と書くことで,Texture2DやTexture型の画像をComputeShaderで扱える画像フォーマットであるRenderTextureに変換できます.

そのあとは,

renderTexture.GaussianFilter5X5().ExtractEdge().TransAlpha(true).MoveChannel(Color.white);

といった感じで行いたい処理のメソッドを後ろに追記していくだけで画像処理ができます.

機能紹介

フィルタ関数

便利機能

  • 解像度変更
  • マスク処理
  • 色変換
  • 透過度変換
  • 2画像の足し合わせ

自分が画像処理の研究をするにあたり必要な機能を実装していっただけなので,現在ある機能は結構偏ったものとなっていますが,後々色々と追加していこうと思っています.

動作例


この画像に対し,この処理

// デノイズ処理を行い,その結果からエッジを抽出
texture.ToRenderTexture().GaussianFilter5X5().ExtractEdge();

を実行した結果がこちらになります.

ちゃんとエッジが抽出されているのが分かると思います.

System.Diagnostics.Stopwatch のストップウォッチを利用し時間計測をした結果13msとなりました.
この処理時間のほとんどはCPU-GPU間のデータ転送時間であり,もっと複雑な処理をしてもあまり増加しません.

おわりに

今回色々なフィルタ関数を実装してみて,この程度の処理ならUnityでも十分な速度が出ることが分かりました.
今後も機能追加をしていこうと思っています.

今後の課題

既知のバグとして,コードを書いていると時々アセンブリのコピーがうまくできないという現象があります.Unityを再起動することで修復されますが,すごくウザいので原因究明を行っています.

また,現在はRenderTextureを用いてGPUとのデータのやり取りを行っています.
そのため,画像表示を行うとUnity標準のガベージコレクションでは扱えないゴミが出るため,定期的にこちらからリソースの整理命令を出しています.
常にRenderTextureでやり取りをすると常に画像を可視化できデバッグなどとてもやりやすいのですが,ComputeBufferでGPUとのやり取りをして,必要に応じてRenderTextureに変換する,というやり方もあります.
どちらがよいのか検証しようと思っていますが,めんどくさいので現状このままになっています.知見のある方がおられましたらご指南をお願いします.

4/9編集:日本語が変だったので修正しました