【OpenCV for Unity】texture2DToMatは絶対に必要なので忘れないように


OpenCV for Unityを使い始めました。基本的な画像処理で間違ったためメモします。

画像によって、うまくいかない現象が起きる

基本的な画像処理”チャネル入れ替え”の処理を作ったのですが、うまくいく画像といかない画像の2パターンがでてきました。

■うまくいった画像

■うまくいかない画像

画像の設定で何か問題があるのかなぁ…と思い、設定を全て揃えたのですが、うまくいかず…

原因:texture2DToMatがないから

うまくいかないコードがこちらです。

RGB2BGR.cs
    void Start()
    {
        Texture2D srcTex = Resources.Load("imori") as Texture2D;

        Mat srcMat = new Mat(srcTex.height, srcTex.width, CvType.CV_8UC4);
        Mat dstMat = new Mat(srcTex.height, srcTex.width, CvType.CV_8UC4);

        Imgproc.cvtColor(srcMat, dstMat, Imgproc.COLOR_RGBA2BGRA);
        Texture2D dstTex = new Texture2D(dstMat.cols(), dstMat.rows(), TextureFormat.RGBA32, false);
        Utils.matToTexture2D(dstMat, dstTex, false);

        Sprite texture_sprite = Sprite.Create(dstTex, new UnityEngine.Rect(0, 0, dstTex.width, dstTex.height), new Vector2(-0.25f, 0.5f));
        GetComponent<SpriteRenderer>().sprite = texture_sprite;
    }

原因は致命的で、texture2DToMatがなかったためです。new Mat()だけでは初期化しかしていないので、うまくいかないのも当然であります。

修正したコードはこちらになります!

RGB2BGR.cs
    void Start()
    {
        Texture2D srcTex = Resources.Load("imori") as Texture2D;

        //ここではmatの入れ物を用意するだけ
        Mat dstMat = new Mat(srcTex.height, srcTex.width, CvType.CV_8UC4);

        //テクスチャ→Mat
        Utils.texture2DToMat(srcTex, dstMat);

        //チャネル入替
        Imgproc.cvtColor(dstMat, dstMat, Imgproc.COLOR_RGBA2BGRA);

        //Mat→テクスチャ
        Texture2D dstTex = new Texture2D(dstMat.cols(), dstMat.rows(), TextureFormat.RGBA32, false);
        Utils.matToTexture2D(dstMat, dstTex);

        //テクスチャ→sprite→表示
        Sprite texture_sprite = Sprite.Create(dstTex, new UnityEngine.Rect(0, 0, dstTex.width, dstTex.height), new Vector2(-0.25f, 0.5f));
        GetComponent<SpriteRenderer>().sprite = texture_sprite;
    }

ちゃんとチャネル変換されていることがわかります。

大きな違いはUtils.texture2DToMatがあるかどうかです。うまくいっている処理は、texture2DToMatがあります。

あくまでも仮説にはなりますが、Utils.texture2DToMatなしでもうまくいったのは、Mat srcMat = new Mat(srcTex.height, srcTex.width, CvType.CV_8UC4)で元々のテクスチャをMat変換+TextureやMatの型が合致したからかもしれません。

もしOpenCV for UnityでMat変換するときは、必ずUtils.texture2DToMatを用いた方が良さそうです。
(原因が仮説段階のため、断定はしていません。もし詳細がわかる方いらっしゃりましたら、コメントいただけると嬉しいです!)

追記:2019/5/9
原因はtexture2DToMatがなかったためです。new Mat(~,~,~)でも処理が動いたのは、openCV以外の原因(キャッシュが残るなど)、他が原因になります。

コメントしてくださった@utibenkeiさん、本当にありがとうございました!!!

参考リンク