読者です 読者をやめる 読者になる 読者になる

OpenCvSharpをつかう その9 (MSER)

OpenCvSharp

だんだんいい加減になっているこのシリーズですが、MSERのサンプルを作ってみたのでご紹介します。MSERの関数はOpenCV 2.0で追加されました。

MSER (Maximally Stable Extremal Regions)とは

今回も例によって勉強が足りず説明が苦しいのですが、Regionという単語が入っていることからもわかるようにこれは領域分割の手法です。領域分割の指標として画素値を用います。それぞれの画素の近傍で、画素値が近いところを連結していって領域とします。

詳しくは以下の論文を読んでみましょう。(私はまだAbstractと図しか見てませんが・・・)
http://cmp.felk.cvut.cz/~matas/papers/matas-bmvc02.pdf

OpenCVでのMSER

cvExtractMSER関数を使います。

// Extracts the contours of Maximally Stable Extremal Regions
CVAPI(void) cvExtractMSER( 
    CvArr* _img, CvArr* _mask, CvSeq** contours, CvMemStorage* storage,  CvMSERParams params );

contoursの要素は、ソースコード(src/cv/cvmser.cpp)を見たところではCvContour*のようです。contour、すなわち輪郭ということになっていますが、その中身を見る限りでは輪郭というよりは点の集合です。領域をそこに含まれる点すべてで表しています。


なお、C++ interfaceでは、cv::MSERというクラスが同等の機能を提供するようです。operator()が定義されていて、それがcvExtractMSERに相当します。

std::vector< std::vector<cv::Point> > dstcontours;
cv::MSER mser;
mser(image, dstcontours, NULL);

CvMemStorageが要らないのが楽です。

OpenCvSharpでのMSER

Cv.ExtractMSERメソッドが対応しています。出力がOpenCVとは少し違っていて、CvContourの配列で返されます。やはりCvSeqよりはマネージ配列の方が扱いやすいと思います。

public static class Cv
{
    public static void ExtractMSER(
        CvArr img, CvArr mask, out CvContour[] contours, CvMemStorage storage, CvMSERParams @params);
}

なおCvArrのインスタンスメソッドにもなっているので、img.ExtractMSER(...); と呼ぶこともできます。

コード

パラメータはよくわからないのでデフォルト値を使用しています。ありがたいことに何も指定しなくても全てデフォルト値が設定されています。

using (IplImage imgSrc = new IplImage("hoge.png", LoadMode.Color))
using (IplImage imgGray = new IplImage(imgSrc.Size, BitDepth.U8, 1))
using (IplImage imgDst = imgSrc.Clone())
using (CvMemStorage storage = new CvMemStorage())
{
    // グレースケールに変換
    Cv.CvtColor(imgSrc, imgGray, ColorConversion.BgrToGray);

    // MSER実行
    CvContour[] contours;
    CvMSERParams param = new CvMSERParams();
    Cv.ExtractMSER(imgGray, null, out contours, storage, param);

    // 領域ごとの輪郭データを得る
    foreach (CvContour c in contours)
    {
        // 各領域の点を別々の色で塗る
        CvColor color = CvColor.Random();
        for (int i = 0; i < c.Total; i++)
        {
            imgDst.Circle(c[i].Value, 1, color);
        }
    }

    // ウィンドウに表示
    using (new CvWindow("MSER src", imgSrc))
    using (new CvWindow("MSER gray", imgGray))
    using (new CvWindow("MSER dst", imgDst))
    {
        Cv.WaitKey();
    }
}

以下は、カメラキャリブレーション用のチェッカーボード画像にMSERを実行してみた例です。

マスごとに色が塗り分けられているのがわかります。ただ、角で繋がってしまったためか斜めで同じ色の部分もあります。

実践OpenCV 2.4―映像処理&解析

実践OpenCV 2.4―映像処理&解析