OpenCVを触ってみる 〜動画表示編〜

前回、Kotlin + OpenCVの開発環境が出来たので、OpenCVのユーティリティを用いて動画から画像を1フレームずつ取り出し、ウィンドウに表示してみる事にする。
解析しながら何度も画像を確認する事になるので、この辺のユーティリティも使いこなす必要があると思っている。

ところで何をしようとしているの?

格ゲーの動画を解析したいなと思っています。
どういう技で良くダメージを受けているのか?などが解析できたら面白いなと思ってます。

グラブルVS、たのちぃ。|ストーム久保|note
格ゲー(グラブルVS)の画面

動画の最初の1フレームを表示する処理を書く

こんな感じのコードを書いた。

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME)

        val m = Mat()
        val capture = VideoCapture()
        capture.exceptionMode = true

        capture.open("/home/kuni/Videos/2020-04-08 13-25-27.mp4")
        capture.grab()
        capture.retrieve(m)

        val name = "test"
        HighGui.namedWindow(name, HighGui.WINDOW_AUTOSIZE)
        HighGui.imshow(name, m)
        HighGui.waitKey()
        System.exit(0)

コンパイルはできるが、実行すると以下のエラーが出た。
ライブラリが見つからんとの事。

Exception in thread "main" java.lang.UnsatisfiedLinkError: no opencv_java430 in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib]

以下の様にbuild.gradle.ktsでライブラリのパスを通す必要があった。

application {
    applicationDefaultJvmArgs = listOf("-Djava.library.path=/home/kuni/Documents/opencv-4.3.0/build/lib")
}

これでイケるだろうと再実行したが、またエラーが発生。
今度はプラグインが見つからないとのこと。
ffmpegがどうのこうの言ってるな・・・

[ INFO:0] global /home/user/Documents/opencv-4.3.0/modules/videoio/src/backend_plugin.cpp (342) getPluginCandidates VideoIO pluigin (FFMPEG): glob is 'libopencv_videoio_ffmpeg*.so', 1 location(s)

ffmpegとは?

動画と音声を記録・変換・再生するためのフレームワーク。
ふーん。なるほど?
たぶん動画を読み込む時に使うのでしょう。

プラグインが見つからない原因を調べる

ふとOpenCVをビルドした時の、cmakeのログを眺めていると以下の様な記述を見つけた。
どうやら、ffmpeg関連で必要なパッケージが見つからない状態でビルドしてしまっていた様子。

Video I/O:
    DC1394:                      NO
    FFMPEG:                      NO
      avcodec:                   NO
      avformat:                  NO
      avutil:                    NO
      swscale:                   NO
      avresample:                NO
    GStreamer:                   NO
    v4l/v4l2:                    YES (linux/videodev2.h)

ffmpeg関連のパッケージをインストールする。

sudo apt install -y libavcodec-dev libavformat-dev libavutil-dev libswscale-dev 

cmakeの設定変更も必要だった。
以下の画像の様にVIDEOIO_PLUGIN_LISTffmpeg,gstreamer を設定した。
https://github.com/conda-forge/opencv-feedstock/issues/155#issuecomment-487081345
設定変更後、再ビルドした。

cmakeでVIDEOIO_PLUGIN_LISTを設定している図

で、アプリをビルド&実行すると、無事、動画の1フレーム目が表示された!

OpenCVで動画の1フレームを表示した図

全フレームを連続で表示する処理を書く

コードはこんな感じ。
思ったより泥臭い感じになった笑
用意されているユーティリティが画像の連続表示は想定していないっぽくて、ユーティリティの実装を眺めながら必要な処理だけ抜き出して連続表示出来るようにした。

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME)

        val m = Mat()
        val capture = VideoCapture()
        capture.exceptionMode = true

        capture.open("/home/kuni/Videos/2020-04-08 13-25-27.mp4")
        capture.grab()
        capture.retrieve(m)

        val name = "test"
        HighGui.namedWindow(name, HighGui.WINDOW_AUTOSIZE)
        val win = HighGui.windows[name]!!
        win.setMat(m)
        val frame = HighGui.createJFrame(name, HighGui.WINDOW_AUTOSIZE)
        frame.isVisible = true
        frame.defaultCloseOperation = JFrame.EXIT_ON_CLOSE
        val icon = ImageIcon(HighGui.toBufferedImage(m))
        val lbl = JLabel(icon)
        win.setFrameLabelVisible(frame, lbl)
        try {
            while (capture.grab()) {
                capture.retrieve(m)
                lbl.icon = ImageIcon(HighGui.toBufferedImage(m))
            }
        } catch (e: CvException) {
            if (e.message === null) {
                throw e
            }

            if (!e.message!!.contains("Unspecified error")) {
                throw e
            }
        }
        System.exit(0)

実行するとこんな感じ。
マシンパワーの許す限りのスピードで処理するので再生速度が鬼早い。

OpenCVで動画の全フレームを連続表示している図

所感

そんな訳で今日はここまで。
「今日は」と言いつつ、実はこの記事書くのに3日ぐらい掛かっている。というのも、ライブラリやプラグインが読み込めないあたりでめちゃめちゃハマったから。
ドキュメントに記載されている手順はOpenCV 3系がベースになっているようで、今回4系にしてしまったのでちょこちょこ差分があるっぽい。

参考資料

こちらの本を参考に進めてます!

「OpenCVを触ってみる 〜動画表示編〜」への2件のフィードバック

コメントする