うにてぃブログ

主にUnityとC#に関する記事を書いていきます

【Unity】テクスチャの輪郭を抽出する

こちら を参考に輪郭抽出アルゴリズムを用いて

テクスチャの輪郭を抽出できるライブラリを作成しました

github.com

いらすとや」さんの素材をお借りして、ライブラリを使うと

f:id:hacchi_man:20211130231309p:plain:w250

このように上記画像の輪郭を抜き出したり、輪郭を合成することができます

f:id:hacchi_man:20211130231346p:plain:w250f:id:hacchi_man:20211130231400p:plain:w250

以下のアルゴリズムと使い方を記述します

アルゴリズム

下のテクスチャをもとにアルゴリズムを記述します

f:id:hacchi_man:20211130174218p:plain:w300

左上から探索して対象のピクセルにヒットするまで探索する

f:id:hacchi_man:20211130174317p:plain:w300

開始地点に行くまで、対象ピクセルから周りのピクセルを反時計周りに探索を繰り返す

f:id:hacchi_man:20211130174454p:plain

この際に探索する位置は初回は左下から反時計回り

f:id:hacchi_man:20211130175059p:plain

それ以降はヒットした位置 + 6 が探索開始位置になる

  • 1 でヒットすれば次は 7 から
  • 3 でヒットすれば次は 1 から

これを繰り返すことで最終的には以下の輪郭が抽出できる

f:id:hacchi_man:20211130175305p:plain:w300

複数輪郭のアルゴリズム

上記のアルゴリズムは、輪郭が一つの場合はこれでいいが輪郭が複数あった場合はこれだけでは動作しません

そのため、以下の画像を参考に複数輪郭の抽出についても記述します

f:id:hacchi_man:20211130180011p:plain:w300

今まで通り輪郭の抽出を行う

輪郭の抽出を行うと左が先に検知できるためこのようになります

f:id:hacchi_man:20211130180045p:plain:w300

先程の検出した輪郭はスキップして次の対象ピクセルを探す

再度探索を開始する際に見つけたところはスキップ、つまり次の開始は (2, 1) ですが (2, 1) はすでに探索済みなので、(3, 1) から探索を開始する

f:id:hacchi_man:20211130180915p:plain:w300

(4, 1) で未探索にヒットするためそこから、輪郭を抽出する

f:id:hacchi_man:20211130180822p:plain:w300

輪郭を抽出後再度探索を開始すると以下のように (4, 4) でまたヒットするので輪郭を抽出する

f:id:hacchi_man:20211130181005p:plain:w300

これを最後のピクセルまで繰り返すことで複数の輪郭を抽出できる

使い方

private void TraceConTour(Texture2D src, Color color, float threshold)
{
    // テクスチャをインスタンスに渡す
    var contour = new Contour(src);

    // 輪郭を探す色を指定して輪郭を探す
    if (!contour.Search(color))
    {
        return;
    }

    // 輪郭が見つかった場合輪郭テクスチャを取得できる
    var texture = contour.GetContourTexture(Color.black);

    // 輪郭のピクセル座標を取得することもできる
    contour.Points
} 
 
// 2値化して輪郭探索
private void SaveBinarizationTexture(Texture2D src, float threshold)
{
    // テクスチャをインスタンスに渡す
    var contour = new Contour(src);
    // 必要に応じて2値化する
    contour.ToBinarization(threshold);

    // 元々のテクスチャに輪郭を追加して出力
    var blendTexture = contour.BlendContourTexture(src, Color.black) :
    // 2値化したテクスチャを取得
    var binarizationTexture = contour.GetBinarizationTexture();
}