動画のダイジェスト画像

#はじめに
この動画ファイルなんだっけ？と思うことが良くあり、
一発で確認できないものかと動画ファイルをダイジェスト的に画像を
並べて表示するものを作ってみました。

#プログラム

```videocap.py
import numpy as np
import cv2
import sys

# 画像の右下にテキストを描画
def drawTextRightBottom(image, text) :
    hmargin = 5
    color = (0,0,0)
    thickness   = 1
    fontFace    = cv2.FONT_HERSHEY_SIMPLEX
    fontScale   = 0.5
    image_size = image.shape[:2]

    # テキストの描画サイズ取得
    sz  = cv2.getTextSize(text, fontFace, fontScale, thickness)

    # テキスト描画位置
    x = image_size[1] - sz[0][0] - hmargin
    y = image_size[0] - sz[1]

    # 矩形描画位置
    rx = x 
    ry = image_size[0] - sz[0][1] - sz[1]

    cv2.rectangle(image, (rx, ry), (image_size[1]-1, image_size[0]-1), (255, 255, 255), -1, cv2.LINE_AA)
    cv2.putText(image, text, (x, y), fontFace, fontScale, color, thickness, cv2.LINE_AA)


cap = cv2.VideoCapture('D0002100117_00000_V_000.mp4')
if not cap.isOpened():
    sys.exit()

#動画プロパティ取得
v_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))    # 縦の大きさ
v_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))   # 横の大きさ
fps = cap.get(cv2.CAP_PROP_FPS)                 # フレームレート
fcnt =  cap.get(cv2.CAP_PROP_FRAME_COUNT)       # フレーム数

div_horizontal = 5  # タイリング横個数
div_vertical = 5    # タイリング縦個数

# 1タイル画像の縮小率
sc = min(1 / div_horizontal, 1 / div_vertical)
print("w=%d h=%d fps=%f fcnt=%d total=%f" % (v_w, v_h, fps, fcnt, fcnt/fps ))

loop_cnt = div_horizontal * div_vertical
resimage = np.zeros((v_h, v_w, 3),np.uint8)
resize_width = int(v_w * sc)
resize_height = int(v_h * sc)

for i in range(0, loop_cnt):
    # フレーム位置算出
    if i == 0:
        # 初回
        fpos = 0
        fpos2 = int((i+1 * fcnt) / loop_cnt)
        # 先頭だけ5秒を読み込み
        fpos1 = int(5.1 * fps)
        if fpos2 < fpos1 :
            fpos = int(fpos2 / 2)
        else:
            fpos = fpos1
    else:
        fpos = int(i * fcnt / loop_cnt)

    # フレームシーク 読み出し位置指定
    cap.set(cv2.CAP_PROP_POS_FRAMES, fpos)
    ret, frame = cap.read()

    # 画像縮小
    resize_img = cv2.resize(frame, None, fx=sc, fy=sc, interpolation=cv2.INTER_CUBIC)

    # 画像の描画位置計算
    iy = i // div_horizontal
    ix = i % div_horizontal
    y = iy * resize_height
    x = ix * resize_width

    # 画像の時間を右下に描画
    totalsec = fpos // fps
    mi = totalsec // 60
    se = totalsec % 60
    text = '%3d:%02d' % (mi, se)
    drawTextRightBottom(resize_img, text)

    # 画像転送
    resimage[y:y+resize_height, x:x + resize_width, :] = resize_img

    # 画像ファイル出力
    cv2.imwrite('resimage.jpg', resimage)

# 画像ファイル表示
cv2.imshow('Scene Tiling',resimage)
cv2.waitKey(0)

cap.release()
cv2.destroyAllWindows()

```

#プログラム説明
特に難しいところは無いと思います。
OpenCVでビデオデータのシーク（シークと呼んでよいやら）
といいますか指定フレームを読みだすランダムアクセスについては、
ちょっと調べました。
フレーム番号をセットして読み込めば該当フレーム画像が読み込めます。
下記は、fposはフレーム番号

```
cap.set(cv2.CAP_PROP_POS_FRAMES, fpos)
ret, frame = cap.read()
```



各画像の右隅に経過時間を表示するようにしています。
timeモジュールを使えば、時間を計算しなくて良かったのでしょうが、
面倒だったので計算でやっつけました。

```
totalsec = fpos // fps
mi = totalsec // 60
se = totalsec % 60
```


#動作環境
Anaconda
Python 3.7.4
OpenCV 3.4.1


#結果画像
NHK CREATIVE LIBRARYの動画でテストを行いました。

##結果画像 その1 天の橋立
![天野橋立.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391380/600c427e-513c-550a-5e73-fb6a8aaa6d59.jpeg)


##結果画像 その2 日没
![日没.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391380/64006e8e-6e1a-bb08-60b1-46a7bafc3be7.jpeg)


#まとめ
サンプルとしてはこんなところかと思います。
実用的に使用とすればGUIがあれば便利で、私はtkinterで画面作って使っています。


#参照
[NHK CREATIVE LIBRARY](https://www.nhk.or.jp/archives/creative/material/)