【機械学習】Selective Searchを使って物体検出を行ってみる

# SelectiveSearchとは
画像の中から、"物体らしい"箇所を検出するタスク。おおまかな流れとして、矩形を複数用意し、画像の上をスライディングさせていき、"物体らしい"箇所を見つけ出す。物体が何であるかや特定の物体だけを検出するわけではない点に注意。例えば画像の中から車だけを見つけ出すことはできない。
物体検出手法で有名なR-CNNでも使われている有名なタスクであるが、調べてみると意外にも記事が少なかったので本記事でまとめた。

# 環境
- Ubuntu16.04.3 LTS
- Python:3.6
- opencv-python:3.3.1.11

# インストール
pip を使って簡単にインストールできる

```
pip install selective-search
```
opencvもpipでインストールしておく


# 対象画像
以下4つの画像を対象に実行してみる。なお画像はPascalVOC。 

|  車  |  犬  |家具  |
| ---- | ---- |---- |
|  ![000071.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/67d107ba-0bb8-b0d1-b5a7-537f48a78512.jpeg) |  ![000108.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/175d7d09-d9dd-3bc4-5d1c-6d46ab3a03e2.jpeg) | ![000102.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/fd6d5fa7-8321-1811-7e6f-6e3eb1d0fe25.jpeg)|


# パタメーター設定

### random
randomパラメータが存在するが、リファレンスに以下が書かれている

If random set to True, function will carry out pseudo random sorting. It only alters sequences of bounding boxes, instead of locations, which prevents heavily emphasis on large regions as combing proposals from up to 80 different strategies[1]. This only has a significant impact when selecting a subset of region proposals with high rankings, as in RCNN.

どうやらselectivesearchでは大きい矩形が優先されて提示されるらしい。RCNNなどを使って物体検出を行う際には、小さい物体の認識が行えなくなるため、randomを設定することで、大きい物体ばかりになることを防ぐ。


### mode
selectivesearchには3つのモードが存在する

- single
- fast
- quality

リファレンスによると次のような違いがある。
![mode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/91ad455a-f854-020f-aca3-1dad0fcdfb3e.png)

すなわち、single,fast,qualityとなるに連れて、矩形の数、言い換えると試行の数が増える。一方で速度が落ちてしまうという問題もあり。以下が試行結果。


|  モード |  車  | 家具   |犬  |
| ---- | ---- | ---- |---- |
| single | ![000071.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/47e5a8f4-645b-48b6-2ebc-f77c96701ceb.jpeg)|  ![000102.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/cbdf7e5e-1fb2-0971-b9c2-b3c785a3b6c8.jpeg)|![000108.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/0e8a5b86-80f9-2608-18bf-ec0708ef226a.jpeg)|
| fast |![000071.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/d43d925b-1862-7c43-9247-fedff6f79415.jpeg)|![000102.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/63babf45-9d7f-39d5-33c2-8ae762a01370.jpeg)|![000108.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/f5f520b2-061e-8c5b-0973-b94612a0a967.jpeg)|
| quality |![000071.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/ccdc2b77-a31b-6811-dcfe-a1af8048e23a.jpeg)|![000102.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/9db3e948-b4fa-6478-b818-5e8f99c5c6c9.jpeg)|![000108.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/6988c643-2993-fb72-9228-be7f4879c04a.jpeg)|

single,fast,qualityとなるに連れ、推定されるオブジェクトが増えるが、これだけ多くの矩形を必要とするケースはほぼ無い。基本はsingleで実装すれば十分だと考えられる。

なおsingleを設定したとしても矩形が多すぎるため、今回実装する際には一定の大きさが無い矩形は出力を抑制することとした。


# 実装


ディレクトリ構成

```
├── pic #オリジナル画像
├── result　#結果画像
│   ├── fast
│   ├── quality
│   └── single
└── exe.py　#実行ファイル
```

実行ファイル

```python
import cv2
import glob
from selective_search import selective_search


### パラメータ設定
MODE="single"
#MODE="fast"
#MODE="quality"
MINH=100
MINW=100


### 入出力ディレクトリ設定
ORGDIR="./pic/"
RSTDIR="./result/"+MODE+"/"


def search():

    ### 入力ファイルパス読み込み
    tgtpaths=glob.glob(ORGDIR+"*")

    for tgtpath in tgtpaths:

        ### 出力ファイルパス設定
        rstpath=tgtpath.replace(ORGDIR,RSTDIR)

        ### 対象画像読み込み
        tgtimg = cv2.imread(tgtpath, cv2.IMREAD_COLOR)

        ### SelectiveSearch実行
        boxes = selective_search(tgtimg, mode=MODE,random=False)

        for box in boxes:

            ### 一定の長さが無い矩形表示しない
            if abs(box[2]-box[0]) < MINW or abs(box[3]-box[1])<MINH:
                continue

            ### 矩形描画
            cv2.rectangle(tgtimg, (box[0],box[1]), (box[2],box[3]), (0,255,0), thickness=1)

        ### 出力
        print(rstpath)
        cv2.imwrite(rstpath, tgtimg)



if __name__=="__main__":
    search()
```

# 結果

|  車  |  家具  |犬  |
| ---- | ---- |---- |
|![000071.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/e3212def-c09f-d5a5-2b5c-524b71f6ffbe.jpeg)|![000102.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/0b29eec2-8c12-3a81-c837-9017990b8389.jpeg)|![000108.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/093e43bf-1220-9d58-a5a1-de85243f5d2c.jpeg)|

selectivesearchにより”物体らしい”箇所が提示された。RCNNなどではこれらの候補を分類器にかけることで物体検出を行う。


# 参考 
- https://pypi.org/project/selective-search/