概要
物体検出で用いられる Non Maximum Suppression の仕組み及び実装について紹介します。
Non Maximum Suppression
物体検出を行うと、1 つの物体に対して複数回検出されることがあります。そのため、物体検出では重複した検出結果を 1 つに統合するために、Non Maximum Suppression という後処理がよく用いられます。
矩形の表現
短形の左上の座標を 、右下の座標を 、幅及び高さを とします。
から を求めるには、、 逆に から を求めるには、 となることに注意してください。

Overlap Ratio
2 つの矩形 があったとき、 で計算される値を Overlap Ratio といいます。2 つの矩形が完全に一致していれば 、全く重なっていなければ となります。
Non Maximum Suppression の処理
入力としてスコア付きの矩形が渡され、以下のアルゴリズムで動作します。
- 入力からスコアが一番高い矩形を選択し、出力に移す。
- 選択した矩形と入力に残っている各矩形の IOU を計算し、閾値以上のものを入力から削除する。(選択した矩形とある程度重なっている矩形は同じ物体であると判断する)
- 入力が空になるまで 1、2 を繰り返す。
- 入力が空になったら、出力にある矩形を結果出力とする。
閾値の設定
重複と判断して削除する Overlap Ratio の閾値を の範囲で適切な値に設定する必要があります。 値が大きいほど重複と判断する基準が厳しくなり、同一物体に複数の矩形が残ってしまう可能性があります。 逆に、値が低いほど重複と判断する基準が緩くなり、異なる物体を示している矩形が同じ物体を示していると判断され、削除される可能性があります。
実装
例として、テンプレートマッチングの重複した検出結果を Non Maximum Suppression の入力として使用します。

入力画像

テンプレート画像
テンプレートマッチングを行う
テンプレートマッチングを行い、類似度が 0.9 以上の矩形を検出されたと判定します。
検出結果を描画する
この時点で検出結果を描画すると、以下のようになります。 1 つの物体として検出されているように見えますが、実際には複数の矩形が重なっています。

number of boxes 16
Non Maximum Suppression を実装する
Non Maximum Suppression を適用する。
Non Maximum Suppression を適用します。その結果、複数あった検出結果が 1 つに統合されていることが確認できます。

number of boxes 1
cv2.groupRectangles で矩形のクラスタリング
Non Maximum Suppression 以外にも、cv2.groupRectangles()
を使用して矩形のクラスタリングを行うことができます。
引数 groupThreshold
はクラスタリングを行う際に、クラスタに属する矩形の数が groupThreshold + 1
未満のクラスタは結果から棄却されます。
例えば、groupThreshold=1
を指定した場合、クラスタに属する矩形の数が 2 個未満のクラスタは棄却されます。
[[120 99 260 283]]

number of boxes 1
コメント
コメント一覧 (0件)
①「テンプレートマッチングを行う」を実行してから、②「検出結果を描画する」の最後に
cv2.imwrite(’ファイル名’ , dst) と追記して実行しますと、sample画像に16ヶの矩形が表示
された画像が保存されました。
その後に、
③「Non Maximum Suppression を実装する」 def non_max_suppression・・・・
④「Non Maximum Suppression を適用する」 boxes = non_ max_・・・・
をそのまま追記し、cv2.imwrite()~の()内を①②実行時と同名のファイル名でその表記位置
のままにして、③④を実行しましすと、sample画像に1ヶの矩形が表示されました。
②の直後に記したcv2.imwrite()~はそのままの位置なのに、何故その結果が変わるのか
が解らないのですが、3つ目のdef分(def non_max_suppression・・・)以下最後までのコードは、
2つ目のdef分(def draw_boxes・・・)よりも前に実行されるのでしょうか?
コメントありがとうございます。本ブログのコード部分はコードの上の In [番号] を上から順番に実行していくことを想定しております。
本記事の場合、上から ln[1]、ln[2]、ln[3]、ln[4] の順番で実行します。
> cv2.imwrite()~はそのままの位置なのに、何故その結果が変わるのか
が解らないのですが、
Jupyter Notebook で実行していますでしょうか。その場合、前の実行結果がそのまま残るので、セルの位置が変わらなくても2回目は実行結果が変わる可能性があります。
セルを上から順番に実行すると、ブログと同じ結果になると思います。
—-
矩形を1つにしたあとの結果を画像に保存したい場合は、以下のようにしてみてください。