動画ファイルからサイズ情報やサムネイルをPythonのOpenCVで取得

OpenCVというライブラリがあり、これで動画ファイルを扱えるようです。OpenCVを使って、動画ファイルからサイズ情報やサムネイルを取得してみました。


# OpenCVをインストール

この記事の内容を試すには以下のコマンドのみで十分でした。Python環境整備済みのLinuxの前提です。

```console
$ pip install opencv-python
```

私の環境で`pipenv`でインストールしたら、バージョンは以下のようになりました。

```console
$ pipenv install opencv-python

$ pipenv run pip list
Package       Version
------------- --------
numpy         1.19.5
opencv-python 4.5.1.48
pip           20.3.3
setuptools    51.0.0
wheel         0.36.2
```


# 動画サイズや長さなどの情報を取得

動画ファイルから縦横サイズ、再生時間、コーデックの情報を取得します。

```python
# OpenCVをインポート
import cv2

# サンプル動画ファイル
videoPath = "./sample.mp4"

cap = cv2.VideoCapture(videoPath)

# 横幅
print(f"width: {cap.get(cv2.CAP_PROP_FRAME_WIDTH)}")
# width: 600.0

# 高さ
print(f"height: {cap.get(cv2.CAP_PROP_FRAME_HEIGHT)}")
# height: 360.0

# フレームレート
print(f"fps: {cap.get(cv2.CAP_PROP_FPS)}")
# fps: 30.0

# フレーム数
print(f"frame_count: {cap.get(cv2.CAP_PROP_FRAME_COUNT)}")
# frame_count: 639.0

# 再生時間
print(f"length: {cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS)} s")
# length: 21.3 s

print("fourcc: " + int(cap.get(cv2.CAP_PROP_FOURCC)).to_bytes(4, "little").decode("utf-8"))
# fourcc: avc1
# コーデックの種類を4文字で表すコード
```

コーデックの種類を表すコードはfourccという4文字のコードです。

- [Video Codecs by FOURCC - fourcc.org](https://www.fourcc.org/codecs.php)


# 最初のフレームから画像ファイルを作成

動画ファイルの最初のフレームをNumpy配列で取得し、それを画像ファイルで書き出します。

```python
import cv2

def buildVideoCaptures(videoPath, outputPath):
    cap = cv2.VideoCapture(videoPath)
    if not cap.isOpened(): return

    # 最初のフレームを読み込む
    _, img = cap.read()
    # imgは読み込んだフレームのNumpy配列でのピクセル情報(BGR)
    # imgのshapeは (高さ, 横幅, 3)

    # 画像ファイルで書き出す
    # 書き出すときの画像フォーマットはファイル名から自動で決定
    cv2.imwrite(outputPath, img)

buildVideoCaptures("./sample.mp4", "./thumbnail.jpg")

# PNG出力もOK
#buildVideoCaptures("./sample.mp4", "./thumbnail.png")
```


# 最初のフレームからサムネイルを作成

次は画像をリサイズして、サムネイルとして画像ファイルを作成します。`cv2.resize`というメソッドでリサイズできます。

```python
import cv2

def buildVideoCaptures(videoPath, outputPath):
    cap = cv2.VideoCapture(videoPath)
    if not cap.isOpened(): return

    _, img = cap.read()
    # imgは読み込んだフレームのNumpy配列でのピクセル情報(BGR)
    # imgのshapeは (高さ, 横幅, 3)

    # 画像サイズを取得
    width = img.shape[1]
    height = img.shape[0]

    # 縮小後のサイズを決定
    newWidth = 100
    newHeight = int(height * newWidth / width)

    # リサイズ
    img = cv2.resize(img, (newWidth, newHeight))

    # 画像ファイルで書き出す
    cv2.imwrite(outputPath, img)


buildVideoCaptures("./sample.mp4", "./thumbnail.jpg")
```

# 動画の途中からもサムネイルを作成

最初のフレームだけではなく、途中のフレームからも画像を取得します。再生時間を10分割して、10個のサムネイルを作成します。

```python
import cv2

def buildVideoCaptures(videoPath, outputPath):
    cap = cv2.VideoCapture(videoPath)
    if not cap.isOpened(): return

    # フレーム数を取得
    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

    for i in range(10):
        # フレーム位置を設定
        cap.set(cv2.CAP_PROP_POS_FRAMES, i * frame_count / 10)

        _, img = cap.read()
        # imgは読み込んだフレームのNumpy配列でのピクセル情報(BGR)
        # imgのshapeは (高さ, 横幅, 3)

        # 画像サイズを取得
        width = img.shape[1]
        height = img.shape[0]

        # 縮小後のサイズを決定
        newWidth = 100
        newHeight = int(height * newWidth / width)

        # リサイズ
        img = cv2.resize(img, (newWidth, newHeight))

        # 画像ファイルで書き出す
        # ファイル名には連番を付ける
        cv2.imwrite(outputPath % i, img)

buildVideoCaptures("./sample.mp4", "./thumbnail%d.jpg") # 出力ファイル名には連番を付ける
```