OpenCVを用いてアムステルダム駅を通る人を認識するのはびっくりするほど簡単だった。

#最終目的
僕はマーケティングが好きなのでこのような人体認識を機械にさせるところから始まり、最終的にはマーケティングなどに使えるツールを自作できるようにしたいなと考えている第一歩として、OpenCVを触ってみた。

この一歩目が正しいかはわからないが...

Jupyter Notebook上でコードは回した。

##この記事の内容
OpenCVを使って、動画解析をするというのは非常に簡単ではあるが、初心者として詰まったところなどを紹介していきながら執筆していこうと思う。

##実際の動画
**アムステルダム駅で人体認識をOpenCVを用いて実行してみた。**
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/fiGLOCT_iwg/0.jpg)](http://www.youtube.com/watch?v=fiGLOCT_iwg)
#コード
```python:detect.ipyb
import cv2
import os

#setting cascade file
f_cascade = cv2.CascadeClassifier('./haarcascade_fullbody.xml')
#Capture the target movie
cap = cv2.VideoCapture('./amsterdam.mp4')

#catch the details of the movie
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)

#set data format to save movie
fourcc = cv2.VideoWriter_fourcc(*'H264')
writer = cv2.VideoWriter("amsterdam_detected_1.avi", fourcc, fps, (width, height))

while(True):
    #catch every frames. ret indicates wether reading is succeeded, return must be True or False
    ret, frame = cap.read()
    print(ret)
    
    #detect body
    facerect = f_cascade.detectMultiScale(frame, scaleFactor=1.2, minNeighbors=2, minSize=(1, 1))
    
    if ret:
         #make rectangles around detected body
        for rect in facerect:
            cv2.rectangle(frame, tuple(rect[0:2]), tuple(rect[0:2] + rect[2:4]), (255,255,255), thickness=2)

            text = 'Detected'
            font = cv2.FONT_HERSHEY_PLAIN
            cv2.putText(frame, text ,(rect[0],rect[1]-10),font, 2, (255, 255, 255), 2, cv2.LINE_AA)
        
        #save frames to movie
        writer.write(frame)  
        
        cv2.imshow("Show Result", frame)

        k = cv2.waitKey(1)
        if k == ord('q'):
            break
        
writer.release()
cap.release()
cv2.destroyAllWindows()
```

#構成
コードが短いように構成は非常にシンプルでした。
まずすでに用意されているカスケード学習器であるhaarcascade_fullbody.xmlを用意します。
この中にフレーム内にあるBodyを検出するための学習済み特徴が入っています。

そしてその後、OpenCVを用いて動画を用意します。動画パスを渡します。その上で、fpsや動画の高さ、幅なども用意しておくと動画を保存する時に楽です。

```
f_cascade = cv2.CascadeClassifier('./haarcascade_fullbody.xml')
#Capture the target movie
cap = cv2.VideoCapture('./amsterdam.mp4')

#catch the details of the movie
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)
```
今回は動画を保存したかったのでOpenCVを用いて動画を書き込むということもしました。出力は.aviファイルで行いました。fourccというのは出力フォーマットを指定するための4つの記号というような認識でしょうか。ここで先ほど入手したwidth height fpsなどを使います。出力の際の詳細情報を書き込む必要があるからです。

```
fourcc = cv2.VideoWriter_fourcc(*'H264')
writer = cv2.VideoWriter("amsterdam_detected_1.avi", fourcc, fps, (width, height))
```
その後、発見したBodyに対して長方形の白い囲みとDetected

```
for rect in facerect:
            cv2.rectangle(frame, tuple(rect[0:2]), tuple(rect[0:2] + rect[2:4]), (255,255,255), thickness=2)

            text = 'Detected'
            font = cv2.FONT_HERSHEY_PLAIN
            cv2.putText(frame, text ,(rect[0],rect[1]-10),font, 2, (255, 255, 255), 2, cv2.LINE_AA)
```

まあ後はやめる処理です。qを押したら処理を終了しようという処理は真似させていただきました。waitKeyの中のintとかはきをつけてください

```
 k = cv2.waitKey(1)
        if k == ord('q'):
            break
```

#手こずったところ・手こずっているところ
実は4点いまだに解決していないところがあるので,もし読んでくれた方でわかる人がいたら教えていただきたいです。
###1.認識精度を向上させるには
認識精度をここから向上させる方法がイマイチつかめません。カスケード学習器を自作して認識精度をあげるのがいいのでしょうか？
それとも今回は少し手ブレが動画に入ってしまっているのでしっかい固定したりすれば駅の塔を誤認したりしなくなるのでしょうか？
次の改善ステップを聞きたいです。

###2.動画を最後まで処理できない
お気付きの方もいるかもしれませんが、今回print(ret)で動画の読み込みがしっかりできているかoutputで確認しています。が、途中(10秒)くらい目のframeまで行くとあとは全部Falseになっちゃうんですよ。なぜかわからない

###3.MP4で出力ができなかった
もともと.aviファイルで出力したくなくて、書き込み設定もmp4でできるようにfourccもMP4Vを試したりだとかしたんですけど、書き込んだ後の.mp4ファイルは正常に書き込めていないのかなぜか開いても動画を再生できなかったんですよね。これも謎でした。

###4.qでやめる処理をしたけど、実際に画面止まったりしなかった
qを押したらbreakして処理終わって、画面とか全部閉じるようにコーディングしたと思ったのですが実際にはPython No reponseみたいになってしまっていっつも出力動画を強制終了させていました。


以上のことが手こずった点です。誰か助けてぇ〜〜〜