物体検出を軽〜く入門する

この記事は[近畿大学 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/kindai)の15日目の記事です．
この記事では，物体検出についてざっくりと書こうと思います．
サーベイ論文「[Object Detection in 20 Years: A Survey](https://arxiv.org/abs/1905.05055)」の内容を参考にして書いています．

# 1. 物体検出(Object Detection)とは

物体検出は， 画像やビデオ内から，クラスやセマンティックオブジェクトのインスタンスを検出するタスクです．classify(分類)とsemantic(位置推定)という2種類の指針があるため， 昔は精度を出すのは難しいタスクでした．近年では，他のCV分野のタスクと同じく，ディープラーニングの力によって目まぐるしい速度で精度を上げ続けています．

## 1.1 最新の物体検出手法は？

[Object Detection on COCO test-dev](https://paperswithcode.com/sota/object-detection-on-coco)でSOTA（State-of-the-Art)な手法を調べることができます．

![スクリーンショット 2019-11-13 16.48.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249063/f7d08d73-f5ad-7b5e-6ca9-dea2152c85f5.png)

執筆時（2019/11/13)のSOTAは，[CBNet: A Novel Composite Backbone Network Architecture for Object Detection](https://arxiv.org/abs/1909.03625)を用いたCascade Mask R-CNN(Triple-ResNeXt152, multi-scale)」で， mAP 53.3(COCO)となっています．

CV分野では競争が激しいので，3ヶ月から半年ですぐに更新されています．2019年1月ごろにSOTAだった[M2Det](https://arxiv.org/abs/1811.04533v3)はmAP 44.2(COCO)なので，1年で10ポイント近く伸びています．ディープラーニングを用いた最新の物体検出について学ぶには，hoya012さんの論文まとめ（https://github.com/hoya012/deep_learning_object_detection） が参考になります． 

# 2. 物体検出の歴史

物体検出の歴史は大きく2タームに区切られます．2001年~2013年頃までの「ディープラーニング襲来前」と2014年~の「ディープラーニング襲来後」です．ニューラルネットは，近年のマシンスペックの向上やGPUの活用などによって近年ブームになっていますが，それらと連動して物体検出も進化を遂げています．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249063/0e98175a-2d9b-78a8-34e4-3276e16da07f.png)
図は[Object Detection in 20 Years: A Survey](https://arxiv.org/abs/1905.05055)より引用．

ディープラーニング襲来前は，画像の数値を見て特徴を抽出する処理を考えることで物体検出を行っていましたが，襲来後はニューラルネットの構成や仕組みを考え調整するようになっています．（もちろん，特徴を抽出する処理を学ぶことは重要です）

>SNSでは，これまで特徴抽出芸人と呼ばれてきた人材が必要とされていました．ディープの世界になるとハイパーパラメータ調整芸人と呼ばれる人材が必要とされています[要出典]

以下では各タームの主要技術について簡単に説明します．

## 2.1 ディープ襲来前
ディープ襲来前の物体検出は，特徴を抽出し，領域を示すウインドウを移動させて判定するスライドウインドウ検出によって行われてきました．以下は代表的な手法です．

### VJ Det(2000)

Viola Jones Detectorと呼ばれる，人間の顔のリアルタイム検出器です．明暗差に注目したHaar-like特徴量を抽出し，カスケード分類をスライドウインドウによって行うタイプの検出器です．
Haar-like特徴量とは，簡単にいうとある領域のピクセルの加算値です．
「[Harr Cascadesを使った顔検出](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_objdetect/py_face_detection/py_face_detection.html#face-detection)」では，顔検出の手法について書かれており，OpenCVでカスケード検出を行う場合のサンプルコードが書かれています．

ピクセルの加算値を計算して，パターンが合致しているかどうかを確かめていくような操作になります．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249063/103d8aff-523f-9e86-9248-91e448b1fc39.png)


ここで検出器の学習結果(xml)をダウンロードすることができます．
https://github.com/opencv/opencv/tree/master/data/haarcascades

OpenCVのインストールはビルドしなければこんな感じ．

```
pip install opencv-python opencv-contrib-python
```

VJDetector自体はこんな感じで利用することができます．

```python
import cv2
img = cv2.imread("input.jpg")
detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml"）
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
face = detector.detectMultiScale(gray_img,scaleFactor=1.1, minNeighbors=3, minSize=(30, 30))
for (x, y, w, h) in face:
  cv2.rectangle(img, (x, y), (x+w, y+h), (0, 0, 300), 4)
cv2.imwrite("output.jpg", img)
```

cv2.CascadeClassifierにｘｍｌファイルを投げるだけで簡単に利用ができます．

実際に使ってみた例がこれ．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249063/fb6bd634-8a9e-2efd-f151-4aa17fba0615.png)
大統領の顔を認識してモザイクかけていますね！（これで国際問題にならないか心配）

### HOG Det(2006)

輝度の勾配方向の分布に注目したHOG特徴量を抽出し，スライドウインドウを行いながらSVMによって分類する検出器です．
人検出などでは，明暗差のHaar特徴量よりも輪郭情報を捉えることができるHOG特徴量の方が良いとされています．
OpenCVでは，cv2.HOGDescriptorとして実装されています．コードはこんな感じです．

```python
import cv2
img = cv2.imread("input.jpg")
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
hogParams = {'winStride': (8, 8), 'padding': (32, 32), 'scale': 1.05}
human, r = hog.detectMultiScale(img, **hogParams)
for (x, y, w, h) in human:
  cv2.rectangle(img, (x, y), (x+w, y+h), (0, 0, 300), 4)
cv2.imshow("results human detect by def detector", img)
cv2.waitKey(0)
```

## 2.2 ディープ襲来後

ディープ到来後，物体検出の分野は劇的に精度が向上されました．CNNの登場，VGGの登場，ResNetの登場など様々な技術タームがあります．これらの技術は基本的に画像分類タスクによって派生したタスクで，それをもとに物体検出のタスクも向上していく傾向にあります．
手法は，分類と位置推定の2つのプロセスの扱いによって手法が分けられています．両方同時に行うone-shot Detectorと位置推定を行ってから分類を行うtwo-shot Detectorです．
<img width="893" alt="スクリーンショット 2019-12-15 0.05.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249063/d01c1e20-9b05-9606-ed16-5ceb1b7a34c5.png">
一般的には，One-shot Detectorは検出速度に優れ，Two-shot Detectorは検出精度に優れています．
（最新の手法では，正直あまり差がないように感じています）

### One-shot Detector
One-shot Detectorは，画像分類と位置検出を同時に行う検出の手法のことです．多くの場合，YOLO系とSSD系に分類することができます．検出速度に優れるOne-shot Detectorの中でもSSD系の方が早いことが多く，検出精度はYOLO系が優れていると言われることが多いです．

* [YOLO](https://arxiv.org/abs/1506.02640) 

* [SSD](https://arxiv.org/abs/1512.02325)

### Two-shot Detector

2段階分類では，RCNNから始まる技術が主に使用されています．近年では，ピクセル単位で分類を行うセマンティックセグメンテーションを行うこともあり，精度の面ではOne-shot Detectorを超えることが多い印象です．（もちろん，それを支えるラベリング済みデータセットが下地になっています）

* [RCNN](https://arxiv.org/abs/1311.2524)

# 3. ディープなライブラリ

基本的にGPUを使用して処理能力を稼ぐ傾向にあるので，どのライブラリもだいたいCUDAとの連携をとる必要があります．（CPUのみの利用ももちろん可能）
正直その辺のバージョン合わせをするのがマジで苦行です．

### tensorflow

Google様が開発しているライブラリです．すごい勢いでバージョンアップが進んでいて，CUDAとのバージョン合わせが大変になります．割と容赦無くAPIを変更するのやめてくれ（小声）

### pytorch

tensorflowとバトルしているイメージのライブラリです．最近のつよつよ論文の再現実装などは，pytorchが多い印象があります．特に若者に人気（勝手なイメージ）

### chainer

最近，PFNがアップデートをやめたライブラリです．割と好きなんだけど，新しく使っていくには厳しい選択肢になると思います．

### keras

tensorflowなどをバックエンドにして動くライブラリです．抽象度が非常に高く，ディープラーニング初心者でも簡単にCNNを用いた画像分類のネットワークを作ることができます．しかし，分類よりも高度なことを扱おうとすると，tensorflowのコードを書かなくてはいけなかったり，損失関数の定義が面倒になったりします．

# 4. ディープの環境を支えるツール

ディープな開発環境を支えるのに役立ちそうなツールのキーワードを上げておきます．個人的にオススメなのはnvidia-docker + nativeのpython + pip + etc..です．

### Docker (kubernetes)

仮想コンテナを用いることで，環境を保存可能にしたすごいツールです（語彙力）
v19からは，ネイティブでGPU対応しました．それ以前はnvidia-dockerをインストールすることでGPUを利用するコンテナを作成することができます．特にCUDAとのバージョン合わせが簡単になることと，ライブラリの環境の再現が簡単になることがメリットです．デメリットはDockerの学習コストです...

### Anaconda

科学技術計算する時に使われたりするpythonのバージョン，ライブラリ管理ツールです．ターミナルを汚染したりするので，偶に宗教上の理由で排斥されがちです．

### pyenv

Pythonのライブラリ管理ツールは様々あって，宗派に分かれています.(私はvirtualenvとｐyenvの違いがいまいちわかっていません)

# 5． 終わりに

CV分野のタスクはどれも激しい競争にあるので，すごいスピードで進化しています．基礎研究として参入するにはホットな業界なのでオススメしませんが，これらの技術を使った応用としてはまだまだ挑戦できるタスクだと思います．
特に論文の再現実装を行うと，論文に書かれていない処理をどうするかや論文に書いている処理時間を出せなかったり，そもそもライブラリにない処理を書いたりする必要があって，とても勉強になります．時間があるときにはオススメです．
これまでにあったリソースや処理時間などの問題が解決されつつあり，とても簡単に扱えるようになってきているので，ぜひ皆さんも挑戦してみてはどうでしょうか．

途中で力尽きたので，今後追記するかも．

# 参考文献
* [Object Detection in 20 Years: A Survey](https://arxiv.org/abs/1905.05055): 物体検出の歴史と手法について細かに書かれているので，興味のある方はぜひ読んでみてください．
* [Deep Learning for Generic Object Detection: A Survey](https://arxiv.org/ads/1809.02165): ディープラーニングを用いた手法について主に書かれています．
* [OpenCV-Pythonチュートリアル](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_tutorials.html)
* [SSD:Single Shot multi-box Detector](https://arxiv.org/abs/1512.02325)
* [物体検出についての歴史まとめ](https://qiita.com/mshinoda88/items/9770ee671ea27f2c81a9)