Unity + OpenCVsharp3 でガンマ・コントラスト調整


ちょっと必要になって Unity + OpenCVsharp3 でガンマとコントラスト調整用の関数(グレースケール用)を書いたので、忘れないように自分用メモ。

// コントラスト調整
void contrust(Mat src, Mat dst, float contrust)
{
	byte[] lut = new byte[256];
	for (int i = 0; i < lut.Length; i++)
	{
		lut[i] = (byte)(255 /(1.0f + Math.Exp(-contrust * (i - 128) / 255)));
	}
	Cv2.LUT(src, lut, dst);
}

// ガンマ調整
void ganma(Mat src, Mat dst, float ganma)
{
	byte[] lut = new byte[256];
	for (int i = 0; i < lut.Length; i++)
	{
		lut[i] = (byte)(Math.Pow((float)i / 255, 1.0f / ganma) * 255);
	}
	Cv2.LUT(src, lut, dst);
}

今回は赤外線カメラの画像からあれこれやるため調整するのに必要だったので単一チャンネルの画像処理で済みましたが、カラー画像(マルチチャンネル)の場合はそれぞれのチャンネルに下記の処理を行えばいいのかな?(要調査)

ちなみに OpenCVsharp3 を Unity で使用するには Windows の場合、ここにある OpenCVsharp のお好きな自分の環境に合ったバーションをダウンロードしてきて、プロジェクト > Assets > Plugin に、OpenCvSharp.dll, OpenCvSharp.Blob.dll, OpenCvSharpExtern.dll と、公式インストーラで OpenCV 3.x にインストールされる opencv_world310.dll, opencv_world310d.dll(OpenCV 3.1.0 の場合)を突っ込んでおけばとりあえず動きます。(Mac はいろいろめんどくさそうだったのでパスw)

あとついでに Mat と Texture2D の相互変換用のクラスもついでに作ったのでこれで変換すれば、スクリプトで Texture2D の動的な画像修正もできるかもしれません。

■ Mat と Texture2D の相互変換用のクラス
※ このクラスは Parallel.For を使用しているため、要 Uk.Org.Adcock.Parallel。
https://github.com/qian256/OpenCVSharp3Unity のサンプルソース内にあります)

using UnityEngine;
using OpenCvSharp;
using Uk.Org.Adcock.Parallel;

public class ImageUtil {

    // Input image size
    private int _imWidth;
    private int _imHeight;

    // MatType
    private MatType _matType;

    // Convert Textur2D <> Mat 
    private Mat _videoSourceImage;
    private Vec3b[] _videoSourceImageData;
    private Vec3b[] _processedImageData;
    private Texture2D _processedTexture;

    // Init
    public ImageUtil(int imWidth, int imHeight, MatType matType)
    {
        _imWidth = imWidth;
        _imHeight = imHeight;
        _matType = matType;

        _videoSourceImage = new Mat(_imHeight, _imWidth, MatType.CV_8UC3);
        _videoSourceImageData = new Vec3b[_imHeight * _imWidth];

        _processedImageData = new Vec3b[_imHeight * _imWidth];
        _processedTexture = new Texture2D(_imWidth, _imHeight, TextureFormat.RGBA32, true, true);

    }

    // Texture2D → Mat CV_8UC3
    public Mat TextureToMat(Texture2D tex2D)
    {
        Color32[] c = tex2D.GetPixels32();
		
        // parallel for loop
        Parallel.For(0, _imHeight, i => {
            for (var j = 0; j < _imWidth; j++)
            {
                var col = c[j + i * _imWidth];
                var vec3 = new Vec3b
                {
                    Item0 = col.b,
                    Item1 = col.g,
                    Item2 = col.r
                };
                _videoSourceImageData[j + i * _imWidth] = vec3;
            }
        });

        _videoSourceImage.SetArray(0, 0, _videoSourceImageData);
        return _videoSourceImage;
    }


    // Mat CV_8UC3 → Texture2D
    public Texture2D MatToTexture(Mat mat)
    {
        mat.GetArray(0, 0, _processedImageData);
        Color32[] c = new Color32[_imHeight * _imWidth];

        // parallel for loop
        Parallel.For(0, _imHeight, i => {
            for (var j = 0; j < _imWidth; j++)
            {
                Vec3b vec3 = _processedImageData[j + i * _imWidth];
                var color32 = new Color32
                {
                    r = vec3.Item0,
                    g = vec3.Item1,
                    b = vec3.Item2,
                    a = 255
                };
                c[j + i * _imWidth] = color32;
            }
        });

        _processedTexture.SetPixels32(c);
        _processedTexture.Apply();
        return _processedTexture;
    }
}

■ 今回参考にさせていただいたページ
http://gori-naru.blogspot.jp/2012/11/blog-post_8647.html
https://github.com/qian256/OpenCVSharp3Unity