Opencv: meanshift＆CamShiftで遊んでみた♬その２；VGG16で物体識別

当然の発展として、物体識別であらかじめ識別してタグ付けした。

おまけに、fpsを画面に表示するようにしました。
ちなみに、７－８fps（1060）、29－30fps（1080）でした。

###コードは以下に置いた
[OpenCV / meanshift_recognizedByVGG16.py ](https://github.com/MuAuan/OpenCV/blob/master/meanshift_recognizedByVGG16.py)
###やったこと
機能として以下３つ追加した。
１．追跡する物体を決定したとき、物体識別をVGG16で実施
２．fpsを計測して画像の左上に表示
３．動画を保存する
###１．追跡する物体を決定したとき、物体識別をVGG16で実施
コードは以下のとおりで、先日のFlaskと同じくVGG16を利用したyomikomi()関数を使った。今回は引数として取得した画像を渡す。

```python
def yomikomi(img):
    batch_size = 2
    num_classes = 1000
    img_rows, img_cols=img.shape[0],img.shape[1]
    input_tensor = Input((img_rows, img_cols, 3))

    # 学習済みのVGG16をロード
    # 構造とともに学習済みの重みも読み込まれる
    model = VGG16(weights='imagenet', include_top=True, input_tensor=input_tensor)
    model.summary()
    
    # 引数で指定した画像ファイルを読み込む
    # サイズはVGG16のデフォルトである224x224にリサイズされる
    # 読み込んだPIL形式の画像をarrayに変換
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    #preds = model.predict(preprocess_input(x))
    preds = model.predict(x)
    results = decode_predictions(preds, top=1)[0]
    return str(results[0][1])
```
呼び出し側は以下のとおり、

```python
def main():     
    cap = cv2.VideoCapture(0)
    # 追跡する枠の座標とサイズ
    x = 100
    y = 100
    w = 224
    h = 224
    track_window = (x, y, w, h)
    # フレームの取得
    ret,frame = cap.read()
    cv2.waitKey(2) 
    # 追跡する枠を決定
    while True:
        ret,frame = cap.read()
        img_dst = cv2.rectangle(frame, (x,y), (x+w, y+h), 255, 2)
        cv2.imshow("SHOW MEANSHIFT IMAGE",img_dst)
        roi = frame[y:y+h, x:x+w]
        if cv2.waitKey(20)>0:
            txt=yomikomi(roi)
            break
```
追跡する物体が確定して、画像を取得したところでその画像を引数にしてyomikomi(img)に渡して物体識別をしてもらいます。その結果は、上記のように識別物体の名称str(results[0][1])として受け取ります。
こうして追跡している間中、名称を表示するようにしました。

###２．fpsを計測して画像の左上に表示
fpsの計測は以下のとおりです。

```python
   curr_time = timer()
   exec_time = curr_time - prev_time
   prev_time = curr_time
   accum_time = accum_time + exec_time
   curr_fps = curr_fps + 1
   if accum_time > 1:
        accum_time = accum_time - 1
        fps = "FPS: " + str(curr_fps)
         curr_fps = 0

   cv2.putText(img_dst, fps, (30,50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,0), 1)
```
最後の行で表示しています。表示文字の大きさは１としましたが、案外大きく表示されます。そして、物体識別したタグも同様に以下のように記載しました。

```python
img_dst = cv2.rectangle(frame, (x,y), (x+w, y+h), 255, 2)
            
cv2.putText(img_dst, txt, (x+3,y+10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,0), 1)
```
上で物体を四角で囲み、二行目でその左上に表示するようにしています。ここでは文字サイズ0.5としました。
###３．動画を保存する
これも以前やっていますが、img_dstを直接保存しようとしてもうまくいきません。
ということで当該部分を抜き出すと、以下のとおりでうまくいきます。

```python
OUT_FILE_NAME = "meanshift_result.mp4"
FRAME_RATE=8
out = cv2.VideoWriter(OUT_FILE_NAME, \
              cv_fourcc('M', 'P', '4', 'V'), \
              FRAME_RATE, \
              (w, h), \
              True)
img_dst = cv2.resize(img_dst, (int(h), w))
out.write(img_dst)    
```
ここで下から二番目の変換が重要なようです。これがないとうまく保存できません。
※元画像が大きすぎて保存できていない⇒（224,224）サイズに縮小でうまくいく
あとはおまじないの関数が必要です。

```python
def cv_fourcc(c1, c2, c3, c4):
        return (ord(c1) & 255) + ((ord(c2) & 255) << 8) + \
            ((ord(c3) & 255) << 16) + ((ord(c4) & 255) << 24)
```

###まとめ
・opencv.meanshiftに物体識別を行って、物体検出しつつ物体追跡をできるようにした
・fpsは７－８fps程度あり、追加により劣化はしていない。
・動画保存の機能を追加した

・説明は省いたが、前回のものに比較すると、最初の物体選択の画面を追跡画面と共通になるように変更した。これにより、Webでも追跡が開始できるようにできる
・複数物体もやれそうだが、次回以降にする