Amazon Linux 2 上に導入した OpenCV 3.4 で動画を出力する

## はじめに

この記事は EC2 に構築した Amazon Linux 2 LTS RC 環境に OpenCV 3.4 を導入し動画を出力できるようになるまでの方法を記録したものである。

作業を開始する前に以下を実行しておく。

```bash
$ sudo yum update
$ sudo yum groups install "Development Tools"
```

## Python 3.6 のインストール

OpenCV には C, C++, Python 言語用のインターフェースが用意されている。今回は Python 3.6 から OpenCV を使いたいので、最初に Python 3.6 をインストールしておく。Amazon Linux 2 の標準リポジトリでは Python 3.6 は提供されていないが、`amazon-linux-extras` コマンドによりインストールできる。

```bash
# install python3.6
$ sudo amazon-linux-extras install python3
$ sudo yum install python3-devel

# check installed version
$ python3.6 --version
```

OpenCV のインストール実行時に `numpy` の有無が確認されるのでここで入れておく。

```bash
# install numpy
$ sudo pip3.6 install numpy
```

## FFmpeg のインストール

Linux 上の OpenCV で動画の出力を行うためには FFmpeg が必要とのこと。今回は AVI (XVID) 形式で出力したいため、まず libxvidcore をインストールしてから FFmpeg 本体をインストールする。なお、MP4 (H.264) 形式などで出力したい場合には別途 libx264 などのライブラリをインストールする必要があるので、https://trac.ffmpeg.org/wiki/CompilationGuide/Centos を参考に各自で実施してほしい。

```bash
# install libxvidcore
$ wget https://downloads.xvid.com/downloads/xvidcore-1.3.5.tar.gz
$ tar zxf xvidcore-1.3.5.tar.gz
$ cd xvidcore/build/generic
$ ./configure
$ make -j$(nproc)
$ sudo make install
```

引き続き FFmpeg 本体のインストールを行う。`--enable-libavresample` は必須かどうかわからないが、OpenCV の `cmake` 実行時に有無が確認されるため念のため有効化している。libxvidcore 以外のライブラリを追加した場合は `./configure` に与えるオプションを追加する必要がある。

```bash
# install nasm
$ sudo yum install nasm

# install ffmpeg
$ wget http://ffmpeg.org/releases/ffmpeg-3.4.1.tar.bz2
$ tar jxf ffmpeg-3.4.1.tar.bz2
$ cd ffmpeg-3.4.1
$ ./configure \
    --enable-avresample \
    --enable-gpl \
    --enable-libxvid \
    --enable-postproc \
    --enable-pthreads \
    --enable-shared
$ make -j$(nproc)
$ sudo make install
```

## GStreamer のインストール

OpenCV で動画の出力を行うためにはこれも必要とのこと。`yum` でインストールできる。

```bash
# install gstreamer
$ sudo yum install gstreamer-devel gstreamer-plugins-base-devel
```

## OpenCV 3.4 のインストール

1. `cmake` コマンドをインストールする。

    ```bash
# install cmake
$ sudo yum install cmake
```

1. OpenCV 3.4 本体をインストールする。環境変数 `PKG_CONFIG_PATH` を指定しないと FFmpeg に付属するライブラリ (libavcodec, libavformat など) を見つけてくれない。

    ```bash
    # set pkg-config path
    $ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

    # install opencv
    $ wget https://github.com/opencv/opencv/archive/3.4.0.tar.gz
    $ tar zxf 3.4.0.tar.gz
    $ cd opencv-3.4.0
    $ mkdir build
    $ cd build
    $ cmake ..
    ```

1. `cmake` 実行後に表示される Configuration のサマリーで Video I/O の FFMPEG および GStreamer 以下の要素がすべて YES と表示されていることを確認する。また、Python 3 以下の各要素が正しく表示されていることを確認する。表示されない場合は `CMakeCache.txt` を削除してから再度 `cmake` を実行する。

    ```
    --   Video I/O:
    --     DC1394:                      NO
    --     FFMPEG:                      YES
    --       avcodec:                   YES (ver 57.107.100)
    --       avformat:                  YES (ver 57.83.100)
    --       avutil:                    YES (ver 55.78.100)
    --       swscale:                   YES (ver 4.8.100)
    --       avresample:                YES (ver 3.7.0)
    --     GStreamer:                   
    --       base:                      YES (ver 1.10.4)
    --       video:                     YES (ver 1.10.4)
    --       app:                       YES (ver 1.10.4)
    --       riff:                      YES (ver 1.10.4)
    --       pbutils:                   YES (ver 1.10.4)
    --     libv4l/libv4l2:              NO
    --     v4l/v4l2:                    linux/videodev2.h
    --     gPhoto2:                     NO

    --   Python 3:
    --     Interpreter:                 /usr/bin/python3 (ver 3.6.2)
    --     Libraries:                   /lib64/libpython3.6m.so (ver 3.6.2)
    --     numpy:                       /usr/lib64/python3.6/site-packages/numpy/core/include (ver 1.14.0)
    --     packages path:               lib/python3.6/site-packages
    ```

1. 確認できたらインストールを続行する。

    ```bash
    $ make -j$(nproc)
    $ sudo make install
    ```

1. `/etc/ld.so.conf` を以下のように修正して `sudo ldconfig` を実行する。

    ```diff
      include ld.so.conf.d/*.conf
    + /usr/local/lib
    + /usr/local/lib64
    ```

1. Python から `import` できるようにライブラリをコピーする。

    ```bash
    $ sudo cp /usr/local/lib/python3.6/site-packages/cv2.cpython-36m-x86_64-linux-gnu.so /usr/lib/python3.6/site-packages/cv2.so
    ```

## 動作確認 (C++)

TIFF 画像から 1 秒間の動画を AVI (XVID) 形式で出力する以下の C++ プログラム `video_generator.cpp` を作成した。

```cpp
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/core.hpp"

#include <stdio.h>
#include <iostream>

using namespace std;
using namespace cv;

int main() {

    int fourcc = VideoWriter::fourcc('X', 'V', 'I', 'D');
    VideoWriter writer("output.avi", fourcc, 30.0, Size(512, 512));

    if (!writer.isOpened()) {
        puts("VideoWriter is not opened");
        exit;
    }

    Mat image = imread("lena_std.tif");

    for (int i = 0; i < 30; i++) {
        writer << image;
    }
}
```

ビルドして実行する。実行したディレクトリに用意してある画像ファイル `lena_std.tif` から 1 秒間の動画 `output.avi` が出力される。

```bash
# build video_generator
$ g++ video_generator.cpp \
    -o video_generator \
    -I/usr/local/include \
    -lopencv_core \
    -lopencv_highgui \
    -lopencv_videoio \
    -lopencv_imgcodecs

# execute video_generator
$ ./video_generator
```

## 動作確認 (Python)

上と同様の処理を行う Python スクリプト `video_generator.py` を作成した。

```python3
import cv2
import sys

fourcc = cv2.VideoWriter_fourcc(*'XVID')
writer = cv2.VideoWriter('output.avi', fourcc, 30.0, (512, 512))

if not writer.isOpened():
    print('VideoWriter is not opened')
    sys.exit(1)

image = cv2.imread('lena_std.tif')

for i in range(1, 30):
    writer.write(image)
```

実行する。実行したディレクトリに用意してある画像ファイル `lena_std.tif` から 1 秒間の動画 `output.avi` が出力される。

```bash
# execute video_generator
$ python3.6 video_generator.py
```

## 注意

+ t2.micro などスペックの低い T2 ファミリーのインスタンスを使用した場合、CPU クレジットの枯渇により FFmpeg や OpenCV のビルドに予想以上に時間がかかることがある。