OpenCvSharpを使う その3 (グレースケールに変換)

今回は読み込んだカラー画像をグレースケールに変換します。OpenCVの関数にはグレースケール画像しか受け付けないというものが相当数存在するので、これは重要な処理です。
(最初からLoadMode.GrayScaleにしてグレースケールで読み込めばいいじゃないか、というのは無しの方向で。自分でグレースケールにする場面は結構あります。)

using System;
using OpenCvSharp;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            using (IplImage src = Cv.LoadImage("penguin.png", LoadMode.Color))
            using (IplImage dst = Cv.CreateImage(new CvSize(src.Width, src.Height), BitDepth.U8, 1))
            {
                Cv.CvtColor(src, dst, ColorConversion.BgrToGray);

                using (new CvWindow("src", src))
                using (new CvWindow("dst", dst))
                {
                    Cv.WaitKey();
                }
            }
        }
    }
}


出力先画像の生成

Cv.CreateImageを使って、読み込んだ画像と同じサイズの画像を生成します。ここにグレースケール化した画像を入れることになります。

IplImage dst = Cv.CreateImage(new CvSize(src.Width, src.Height), BitDepth.U8, 1);

第2引数は要素のビット深度を指定しています。符号なし8ビットを表すBitDepth.U8を指定することが多いですが、これは行う画像処理によって決まってくるので、リファレンスを見て適当なものを指定します。
第3引数は要素ごとのチャンネル数です。カラー画像は赤緑青で3チャンネル、グレースケール画像は1チャンネルです。


なお、Cv.CreateImageもIplImageのコンストラクタとして呼び出すことができます。

IplImage dst = new IplImage(new CvSize(src.Width, src.Height), BitDepth.U8, 1);

また、new CvSize(src.Width, src.Height) と書くのは面倒なので、サイズを取得するSizeプロパティが用意してあります。

IplImage dst = new IplImage(src.Size, BitDepth.U8, 1);

グレースケール化

Cv.CvtColorを使い、色空間を変更します。

Cv.CvtColor(src, dst, ColorConversion.BgrToGray);

グレースケールのほかにも、HSVやCIE L*a*b*などに変換することもできますので色々試してみましょう。


なお、インスタンスメソッドとして呼び出すこともできます。

src.CvtColor(dst, ColorConversion.BgrToGray);

引数が1個減るだけなので、あまり旨味はありません。本当は、

dst = src.CvtColor(ColorConversion.BgrToGray);

のようにできるとC#らしいのですが、その場合はラッパ側でdstの形式を推定してcvCreateImageをして、そしてcvCvtColorに投げなければなりません。これがかなり困難なため諦めています。

従って、OpenCvSharpを利用する際は、ネイティブのOpenCV同様、出力画像をあらかじめ全部用意しておく必要があります。メソッドの返り値として出力画像が出てくるということはほとんどありませんのでご注意ください。

まとめ

// 入力画像の読み込みと、出力画像の準備
using (IplImage src = new IplImage("penguin.png", LoadMode.Color))
using (IplImage dst = new IplImage(src.Size, BitDepth.U8, 1))
{
    // グレースケールに変換
    Cv.CvtColor(src, dst, ColorConversion.BgrToGray);

    // ウィンドウに画像を表示
    using (new CvWindow("src", src))
    using (new CvWindow("dst", dst))
    {
        Cv.WaitKey();
    }
}

おまけ

自分で使っていて思ったのが、画像を見たい時にいちいち

using (new CvWindow("src", src))
using (new CvWindow("dst", dst))
{
    Cv.WaitKey();
}

のように書くのが長ったらしいということでした(これでもかなり短いとは思いますが)。そこでCvWindow.ShowImagesというものを用意しました。

CvWindow.ShowImages(src, dst);

引数は可変長で、表示したい画像を好きなだけ指定することができます。このメソッドが呼ばれると、内部で適当なウィンドウ名を付けてすべて表示してくれます。ウィンドウ名は指定できませんが、画像を見れば明らかにどれがどれかわかるという場面なら困らないと思います。


画像処理とパターン認識入門 - 基礎からVC#/VC++ .NETによるプロジェクト作成まで

画像処理とパターン認識入門 - 基礎からVC#/VC++ .NETによるプロジェクト作成まで