OpenCV plus Unityで画像の背景を動的に削除する方法
やりたいこと
らくがきARの様なアプリを作りたいと思ったので、今回は手始めにOpenCVを使ってUnityにインポートした画像の背景を削除(透明化)します。
ソースコードは以下にアップロードしてあります。
https://github.com/AzetaTakuya/MakeImageBackgroundTransparentUsingOpenCV
結果
こんな感じ
左から【元画像 -> グレースケール化 -> 二値化 -> マスク化 -> 背景削除】といった工程から画像の背景を透明化することができました。
実装
環境
- Windows10 Home
- Unity 2019.4.8f1
- OpenCV plus Unity 1.7.1
OpenCV plus Unity を試す
まずUnityプロジェクトを作成し、AssetStoreからOpenCV plus Unityをインポートします。
インポートが完了すると、エラー[ error CS0227: Unsafe code may only appear if compiling with /unsafe. Enable "Allow 'unsafe' code" in Player Settings to fix this error.]が出るかと思います。
unsafeコードを使用するので 【File -> BuildSettings -> PlayerSettings -> Player -> OtherSettings -> Allow 'unsafe' Code】 にチェックを入れます。
エラーがなくなったので、早速OpenCVplusUnityのデモを見てみます。
今回は画像の輪郭を抽出したりしたいので、それに近いデモである【Assets -> OpenCV+Unity -> Demo -> Identifiy_Contours_by_Shape -> ContoursByShapeScene.scene】を開きます。
実行結果はこんな感じ。
白黒画像に色とテキストが付きました。
このデモを元に画像の背景を透明化します。
画像の背景を削除
画像をインポート
Unityに画像ファイルをインポートします。そのままの状態では読み込めない為、Read/Write Enabledにチェックを入れます。
コード
元画像(m_texture)から
【元画像 -> グレースケール化画像 -> 輪郭抽出画像 -> マスク化画像 -> 背景透明化画像】を表示します。
namespace OpenCvSharp.Demo
{
using UnityEngine;
using System.Collections;
using OpenCvSharp;
using UnityEngine.UI;
using System.Threading.Tasks;
using System.Collections.Generic;
public class MakeImageBackgroundTransparentUsingOpenCV : MonoBehaviour
{
#region public members
public Texture2D m_texture;
public RawImage m_image_origin;
public RawImage m_image_gray;
public RawImage m_Image_binarization;
public RawImage m_image_mask;
public RawImage m_image_backgroundTransparent;
public double v_thresh = 180;
public double v_maxval = 255;
#endregion
private void Start()
{
#region load texture
Mat origin = Unity.TextureToMat(this.m_texture);
m_image_origin.texture = Unity.MatToTexture(origin);
#endregion
#region Gray scale image
Mat grayMat = new Mat();
Cv2.CvtColor(origin, grayMat, ColorConversionCodes.BGR2GRAY);
m_image_gray.texture = Unity.MatToTexture(grayMat);
#endregion
#region Find Edge
Mat thresh = new Mat();
Cv2.Threshold(grayMat, thresh, v_thresh, v_maxval, ThresholdTypes.BinaryInv);
m_Image_binarization.texture = Unity.MatToTexture(thresh);
#endregion
#region Create Mask
Mat Mask = Unity.TextureToMat(Unity.MatToTexture(grayMat));
Point[][] contours; HierarchyIndex[] hierarchy;
Cv2.FindContours(thresh, out contours, out hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxNone, null);
for(int i = 0; i < contours.Length; i++)
{
Cv2.DrawContours(Mask, new Point[][] { contours[i] }, 0, new Scalar(0, 0, 0), -1);
}
Mask = Mask.CvtColor(ColorConversionCodes.BGR2GRAY);
Cv2.Threshold(Mask, Mask, v_thresh, v_maxval, ThresholdTypes.Binary);
m_image_mask.texture = Unity.MatToTexture(Mask);
#endregion
#region TransparentBackground
Mat transparent = origin.CvtColor(ColorConversionCodes.BGR2BGRA);
unsafe
{
byte* b_transparent = transparent.DataPointer;
byte* b_mask = Mask.DataPointer;
float pixelCount = transparent.Height * transparent.Width;
for (int i = 0; i < pixelCount; i++)
{
if (b_mask[0] == 255)
{
b_transparent[0] = 0;
b_transparent[1] = 0;
b_transparent[2] = 0;
b_transparent[3] = 0;
}
b_transparent = b_transparent + 4;
b_mask = b_mask + 1;
}
}
m_image_backgroundTransparent.texture = Unity.MatToTexture(transparent);
#endregion
}
}
}
シーン
上のスクリプトをアタッチするGameObjectと5つのRawImageを用意します。
MakeImageBackgroundTransparentUsingOpenCVにインポートした画像とRawImageをアタッチします。
実行
実行すると【元画像 -> グレースケール化画像 -> 輪郭抽出画像 -> マスク化画像 -> 背景透明化画像】が表示されます。
※うまくいかなかった場合はv_threshの値を弄ってみてください。
まとめ
- ARアプリにガンガン使っていけそう。
- 白背景の画像以外も対応出来る様にする必要がある。
参考
Author And Source
この問題について(OpenCV plus Unityで画像の背景を動的に削除する方法), 我々は、より多くの情報をここで見つけました https://qiita.com/aazz/items/13aaa53f7bc8b2df943e著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .