こんにちは、私は画像とAIに関する研究をしている大学院生です!
「物体検出に興味がある」「物体検出に使われるアルゴリズムを学びたい」と、考えている方は是非この記事を読んでみてください。
今回は、物体検出において重要な役割を担うアルゴリズムであるNMS(Non-Maximum Suppression)について基礎的な仕組みとPythonを用いた実装例を解説していきます。
Contents
【使用例】NMS(Non-Maximum Suppression)を使用すると?

左側の画像がNMSを使用する前の、「cat」というテキストの物体検出結果になります。
物体検出の検出結果は基本的にバウンディングボックスと呼ばれる四角形のボックスで出力されます。理想的には、検出対象の物体に対して1つずつバウンディングボックスが出力されてほしいですよね。しかし、Faster R-CNNなどの物体検出モデルでは、重複を許して、物体らしいバウンディングボックスを過剰に出力する設計になっているため、左の画像のように複数のバウンディングボックスが出力されてしまいます。
そこで、NMSというアルゴリズムを用いることで、最も「物体らしさ」の高いバウンディングボックスのみが残るように処理することができ、右の画像のような結果を得ることができます。
以降では、まずFaster R-CNNなどの物体検出モデルが過剰にバウンディングボックスを出力する理由について説明した後、「NMS」について説明していきたいと思います。
Faster R-CNNが過剰にバウンディングボックスを出力する理由
Faster R-CNNは、物体検出の分野で高い精度を誇るモデルですが、そのプロセスの中で非常に多くのバウンディングボックスを出力する特徴があります。この現象は、モデルの設計上の性質と高精度な物体検出を実現するための工夫が影響しています。
Region Proposal Network(RPN)とアンカーボックス
Faster R-CNNの中核であるRegion Proposal Network (RPN)は、画像内のオブジェクト候補領域を生成する役割を担っています。このRPNは、画像全体をスライディングウィンドウのように走査しながら、各位置でアンカーボックス(Anchor Boxes)と呼ばれる矩形領域を作成します。アンカーボックスは、以下の特徴を持っています:
- 多様性のあるアンカーの生成
各位置で異なるスケールやアスペクト比(縦横比)のアンカーボックスを生成します。これにより、小さな物体や大きな物体、縦長・横長など、さまざまな形状のオブジェクトに対応可能になります。 - 冗長性の許容
モデルが重要なオブジェクトを見逃さないよう、あえて多くの候補を生成します。この冗長性によって、物体検出の精度を高める設計となっています。
なぜ過剰になるのか?
このようにRPNは膨大な数のアンカーボックスを生成し、それぞれに「物体らしさ」をスコア付けします。しかし、スコアリングの精度や閾値の調整次第では、オブジェクトではない領域や重複する候補が多く残ってしまいます。これが、過剰なバウンディングボックス出力の原因となっています。
高精度のためのトレードオフ
過剰な候補を出力することで一見無駄が多いように見えますが、これは重要なオブジェクトの検出漏れが無いようにするための意図的な設計です。適切な候補を残しつつ冗長なものを削減するためには、本記事でのメインであるNMS(Non-Maximum Suppression)などのプロセスが重要な役割を果たしています。
まとめると、Faster R-CNNの設計は、精度を最大化するためのバランスが取られており、その冗長性が高い検出能力を支えています。バウンディングボックスの多さこそが、このモデルが正確に物体を検出する鍵となっています。
NMS(Non-Maximum Suppression)のアルゴリズム
1. NMSとは
NMSは、バウンディングボックスが重複した際に、最も「物体らしさ」が高いボックスのみを残し、他のバウンディングボックスを排除するというアルゴリズムです。
この「物体らしさ」というのは、各バウンディングボックスに対して割り当てられている数値であり、モデルが検出した物体がどれだけ「正しい」と思っているかを示すスコアのことです。簡単に言うと、その領域にその物体が実際に存在する確率のことです。
つまり、NMSを使用することで、検出したい物体が最も存在する可能性の高いバウンディングボックスのみを選抜できるというわけです。
2. NMSのアルゴリズムの概要
NMSは以下のステップで実行されます。
- すべてのバウンディングボックスの中から最も「物体らしさ」の高いボックスを選択し、ラベル「1」を付与。
- 重複率(IoU: Intersection over Union)が一定の値以上のバウンディングボックスにラベル「0」を付与。
- ラベルが付いていないボックスについてこの処理を繰り返す。
具体例を用いて上記のステップを説明していきます。
例えば、以下の画像で黄色の枠で示したバウンディングボックスが最も「物体らしさ」が高いとします。ここでの物体らしさは、0.6と仮定しています。
黄色の枠にラベル「1」を付与します(手順1)。

黄色いバウンディングボックスと一定の面積以上重複しているボックスにラベル「0」を付与します(手順2)。ここでは、わかりやすくするため、ラベル「0」のバウンディングボックスを除去しています。

手順1、手順2を実行すると、余分なバウンディングボックスは除去され、最も「物体らしさ」の高いバウンディングボックスのみが残りました。これらの作業を繰り返し行っていくイメージです。
実際には、最終的なラベルが「1」のバウンディングボックスのみを結果として出力します。
3. IoU: Intersection over Unionとは
IoU(Intersection over Union)とは、2つのボックスがどれだけ重複しているかを計算する指標です。
NMSでは、このIoUという指標に基づき、最も「物体らしさ」の高いボックスとのIoUが一定以上のバウンディングボックス、つまり、重複率が高いバウンディングボックスを除去していきます。
次の章では、IoUの計算方法などNMSのアルゴリズムについて具体例を示しながら解説していきます。
NMSのアルゴリズムの詳細
1. IoU(Intersection over Union)の計算方法
IoUの計算式は以下のように示せます。
\( IoU=\frac{(Area\; of\; Intersection)}{(Area\; of\; Union)} \)・Area of Intersection:2つのボックスが重なっている面積
・Area of Union:2つのボックスの合計面積から重なっている面積を引いた残りの面積

IoUの計算式をPython関数として定義すると以下のように表せます。
def iou(box1, box2):
"""
IoU(Intersection over Union)を計算する関数
:param box1: [x1, y1, x2, y2]形式の矩形ボックス
:param box2: 同じ形式の矩形ボックス
:return: IoUスコア
"""
# ボックスの座標から交差領域を計算
x1_inter = max(box1[0], box2[0])
y1_inter = max(box1[1], box2[1])
x2_inter = min(box1[2], box2[2])
y2_inter = min(box1[3], box2[3])
# 交差領域の面積を計算
inter_area = max(0, x2_inter - x1_inter) * max(0, y2_inter - y1_inter)
# 各ボックスの面積を計算
box1_area = (box1[2] - box1[0]) * (box1[3] - box1[1])
box2_area = (box2[2] - box2[0]) * (box2[3] - box2[1])
# Unionの面積を計算
union_area = box1_area + box2_area - inter_area
# IoUスコアを計算
return inter_area / union_area
2. NMSを実装してみよう
NMSのアルゴリズムをおさらいすると
- すべてのバウンディングボックスの中から最も「物体らしさ」の高いボックスを選択。
- 重複率(IoU: Intersection over Union)が閾値以上のボックスを除去。
- 残ったボックスについてこの処理を繰り返す。
以上のような手順でした。では実際にPythonで実装してみたいと思います!
プログラムを実行すると、左側にNMS処理を行う前のバウンディングボックスが、右側にNMS処理を行ったあとのバウンディングボックスが表示されます。
左側の図では、重複しているボックスがいくつかありますが、NMS処理をした後の右側の図では、重複しているボックスが全て除去されたと思います。
IoUの閾値(IoU_threshold)を変更することで、NMS処理をした後に残るバウンディングボックスが変わってきます。
初期値は0.2に設定してあるので、0から1.0の間で数字を変化させてみてください(0.3や0.5など)。値を大きくすると重複率(IoU)が高くても削除されないようになり、逆に、小さくするとIoUが小さいボックスでも削除されるようになります。
是非試してみてください!
まとめ
今回の記事ではNMS(Non-Maximum Suppression)の基本的な仕組みとそのアルゴリズムの詳細を解説し、Pythonを用いた実装例を紹介しました。NMSを使いこなすことで、より効果的な物体検出が可能になりますので、ぜひお試しください。