Raspberry Piでパラパラアニメ風の動画を撮影してみる

Raspberry Piで2FPSの動画を作ろうとして`fswebcam`を使用したのですが撮影に時間がかかってしまい2FPSの撮影ができませんでした。画像処理と言ったらOpenCVと思い使ってみました。
2020.02.29

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちはCX事業本部のさかじです。
Raspberry Piで2FPSの動画を作ろうとしてfswebcamを使用したのですが撮影に時間がかかってしまい2FPSの撮影ができませんでした。画像処理と言ったらOpenCVと思い使ってみました。

環境

  • MacBook Pro(macOS Mojave 10.14.6)
  • Raspberry Pi 3 Model B+
  • webカメラ
  • Python 3.5.3
  • Open CV 4.1.1

事前準備

$ pip3 --version
pip 9.0.1 from /usr/lib/python3/dist-packages (python 3.5)
$ pip3 install --upgrade pip
$ pip3 --version
pip 20.0.2 from /home/pi/.local/lib/python3.5/site-packages/pip (python 3.5)

$ sudo apt install libhdf5-dev libhdf5-serial-dev libhdf5-100
$ sudo apt install libqtgui4 libqtwebkit4 libqt4-test python3-pyqt5
$ sudo apt install libatlas-base-dev
$ sudo apt install libjasper-dev
$ python3 -m pip install opencv-python

通常撮影のプログラム

以下のプログラムでデフォルト設定の撮影ができます。

ソースコード

import cv2

print(cv2.__version__)

cap = cv2.VideoCapture(0)
print('width :', cap.get(cv2.CAP_PROP_FRAME_WIDTH))
print('height :', cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print('fps :', cap.get(cv2.CAP_PROP_FPS)) #FPS

while (cap.isOpened()):
    ret, frame = cap.read()
    cv2.imshow('frame', frame)
    if cv2.waitKey(1) != -1:
        break
cap.release()
cv2.destroyAllWindows()

実行

Raspberry Piのデスクトップで実行すると画面が表示されます。

$ python3 cam.py
4.1.1
width : 640.0
height : 480.0
fps : 30.0

コマ撮りしたい

今回は2fpsの撮影したいので設定を変えてみましょう。

ソースコード(差分のみ)

cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FPS, 2)

実行

$ python3 cam.py
4.1.1
width : 640.0
height : 480.0
fps : 30.0

設定を変えても有効にならないようです。使用しているwebカメラのせいでしょうか?仕方ないので、自分でコマ撮り出来るように作ってみました。

1フレームの処理時間

使用しているカメラは30fpsに対応しているようです。

    ret, frame = cap.read()

で次のフレームのが取得できますので処理時間を確認してみます。

ソースコード (差分のみ)

import time
    t1 = time.time() * 1000
    ret, frame = cap.read()
    t2 = time.time() * 1000
    cv2.imshow('frame', frame)
    print("diff : {0}[ms], ret : {1}".format((t2 - t1), ret))

実行

$ python3 cam.py
4.1.1
width : 640.0
height : 480.0
fps : 30.0

diff : 564.839111328125[ms], ret : True
diff : 11.472900390625[ms], ret : True
diff : 13.27197265625[ms], ret : True
diff : 11.17578125[ms], ret : True
diff : 12.062255859375[ms], ret : True
diff : 13.162841796875[ms], ret : True
diff : 11.621337890625[ms], ret : True
diff : 17.267333984375[ms], ret : True
diff : 22.738525390625[ms], ret : True
diff : 23.575927734375[ms], ret : True
diff : 29.06298828125[ms], ret : True
diff : 21.141845703125[ms], ret : True
diff : 24.453857421875[ms], ret : True
diff : 27.63427734375[ms], ret : True
diff : 24.210693359375[ms], ret : True
diff : 13.812255859375[ms], ret : True
diff : 23.103515625[ms], ret : True

起動直後は時間がかかるようですが、概ね10~30msの間に収まっているようです。このカメラは30FPSということですので33ms以内に描画できればいいので大丈夫そうです。

2PFSで撮影してみる(失敗編)

ソースコード(差分のみ)

while (cap.isOpened()):
  time.sleep(0.5)

結果

動画が送れるようになりました。単純にsleepするとバッファされている画像が残っているため、再生がもたつくように見えます。

2FPSで撮影してみる

ソースコード(一部)

import math
t = time.time()
next_show = math.ceil(t) # 次の0秒から開始

while (cap.isOpened()):
    t1 = time.time() * 1000
    ret, frame = cap.read()
    t2 = time.time() * 1000
    now = time.time()
    if now >= next_show:
        cv2.imshow('frame', frame)
        next_show += 0.5
        print('now :', now, 'next :', next_show)

実行結果

now : xxxx next : xxxxと表示されている時にだけcv2.imshow()を実施していますので0.5秒ごと(2PFS)は実現できているようです。

pi@ykg-video-dev1:~/tmp/blog $ python3 ./cam.py 
4.1.1
width : 640.0
height : 480.0
fps : 30.0
now : 1582965124.5596235 next : 1582965124.5
now : 1582965124.968592 next : 1582965125.0
now : 1582965125.0104537 next : 1582965125.5
now : 1582965125.60014 next : 1582965126.0
now : 1582965126.0907393 next : 1582965126.5

参考サイト

https://docs.opencv.org/

最後に

今回は雑にパラパラ動画を作ってみました。実際動かしてみると処理時間などを意識する必要があり、単純にできないことがわかりました。取得時間を意識はしましたが別のカメラだとうまく行かない可能性もあります。自分が使うカメラの性能を知っておくのも必要ですね。