マスク付きテンプレートマッチングでスプラトゥーン3のイカランプを認識させる
openCVのcv2.matchTemplate()によるテンプレートマッチングでは、アルファ値が使えないことで有名ですが、実はマスク付きテンプレートマッチングで透過処理もどきが可能です。
公式ドキュメント:https://docs.opencv.org/4.x/de/da9/tutorial_template_matching.html
オライリー・ジャパンから出版されてるあの「詳解OpenCV 3」にもこのことは書かれて無かったので知らなかった・・・😇
かなり便利なのですが、よくあるopenCVの基礎だけを簡単に解説した記事などでは取り上げられてないので本記事でご紹介したいと思います。
cv2.matchTemplate()にテンプレート画像を同じサイズのマスクを渡すことで、「透明なピクセル」のような扱いが可能なようです。アルファ値ではないため半透明を取り扱うことはできませんが、マスクの取り方としきい値である程度調整可能かと思います。
マスクを掛けることで自由な形状のテンプレート画像でマッチングさせることができます。
(icons.png) @2022 任天堂 スプラトゥーン3
こちらはスプラトゥーンの、8人のプレイヤーの使用ブキを表したアイコン通称「イカランプ」の画像です。
ここからスプラシューターのアイコンを検出したいと思います。
(splashooter.png) @2022 任天堂 スプラトゥーン3
こちらにこのようなテンプレートと、
(splashooter_mask.png)
マスク画像
を引数に指定してマッチングさせてみたいと思います。
import cv2
import numpy as np
img = cv2.imread(r"icons.png")
template = cv2.imread(r"splashooter.png")
mask = cv2.imread(r"splashooter_mask.png", 0)
res = cv2.matchTemplate(img, template, cv2.TM_CCORR_NORMED, mask=mask)
loc = np.where(res >= 0.95) # しきい値
for pt in zip(*loc[::-1]):
cv2.rectangle(img, pt, (pt[0] + template.shape[1], pt[1] + template.shape[0]), (0,0,255), 1)
cv2.imshow("img", img)
cv2.waitKey() # キー入力で終了
・結果
@2022 任天堂 スプラトゥーン3
おおお背景色によらずマッチングさせることができました!!
前からこういう画像検出をやってみたかったんですがついに実現して感動しました・・!
というかマスクなしのテンプレートマッチングってほぼ役に立たないような・・矩形でない形状の検出をしたいケースって山ほどありますし。
画像処理が本職の人たちって今までどうしてたんやろか?🤔
ちなみに余談ですが、cv2.matchTemplate()が返すRECTのリストですが、位置が重複したものを複数返してくるので重複を取り除く処理が必要になります。
検出結果の画像の赤い四角形の線が太いものになっているのは重複したRECTをすべて描画しているため太い線のように見えています。
今回のケース、本来であれば2つのRECTを取得できるのが適切な処理です。
本記事では取り扱いませんが、重複除去の手法である**Non Maximum Suppression(NMS)**について
紹介してる記事のリンク貼っておきます。お役に立てればと。
Discussion