Memorandum about OpenCV, Jupyter and Matplotlib (FuncAnimation version).
OpenCV と Jupyter を使ってリアルタイムのビデオキャプチャ表示をしようとすると、いつもそのやり方が分からなくなって、半日近く試行錯誤することになるので、備忘録としてまとめておくことにしました。
そもそも Matplotlib は難しくて、何も参考にせずにスラスラとコードを書ける人は、あまりいないのではないでしょうか。多くの方が、Stack Overflow などを見ながらコードを書いているのではないか、と想像します。
まずは動くコード
最初に、動くコードを示してしまおうと思います。ちなみに、私は Jupyter や Matplotlib の権威でもなんでもなく、上に書いたように、Stack Overflow を見ながら苦心してなんとか動くコードを書けた、というくらいのレベルです。なお、今回使用したバージョンは以下の通りです。
- macOS 10.15.7(Catalina)
- Python 3.9.11
- opencv-python==4.6.0.66
- matplotlib==3.5.3
- notebook==6.4.12(Jupyter Notebook)
%matplotlib notebook
import cv2
from matplotlib import animation
from matplotlib import pyplot as plt
CAMERA_ID = 0 # 必要に応じて変えてください
def capread_rgb():
ret, frame = cap.read()
if ret:
ret_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
else:
ret_frame = None
return ret, ret_frame
def init():
return (im,)
def animate(dummy):
ret, frame = capread_rgb()
im.set_data(frame)
return (im,)
cap = cv2.VideoCapture(CAMERA_ID)
if not cap.isOpened():
print("Cannot open camera")
exit()
fig, ax = plt.subplots()
ret, frame = capread_rgb()
im = plt.imshow(frame)
anim = animation.FuncAnimation(
fig, animate, init_func=init, interval=1, blit=True
)
plt.show()
さて、コードの説明(備忘録)です。
%matplotlib notebook
Jupyter セッション(セル)中に動画を表示するためには必須です。%matplotlib inline ではうまく動きません。
CAMERA_ID = 0
後で出てくる cv2.VideoCapture() のための引数です。デフォルトのカメラは 0 ですが、適宜変更の必要があるかも知れません。
capread_rgb()
OpenCV で取り込まれる画像は BGR の配列になっているので、Matplotlib で表示できるよう、これを RGB に変換します。
init(), animate()
後で FuncAnimation() に渡すための関数です。blit=True で使うので、いずれも (im,) を返す必要があります。
plt.show()
Jupyter 内で動かすときは、この行は不要ですが、Python アプリケーションコードとして動かす場合に必要なので、混乱を避けるために、書いておいたほうが良さそうです。
参考文献
以下のブログや Q&A を参考にさせて頂きました。ありがとうございました。Thanks for the helpful blogs and discussions below.
- GitHub: jrobchin/Computer-Vision-Basics-with-Python-Keras-and-OpenCV: Full tutorial of computer vision and machine learning basics with OpenCV and Keras in Python. (OpenCV と機械学習を組み合わせたい人のための、必読資料です。)
- OpenCV: Getting Started with Videos(OpenCV 本家の Python チュートリアルです。)
- python – How to update matplotlib’s imshow() window interactively? – Stack Overflow
(Matplotlib の imshow() で、画像を動的にアップデートする方法に関する議論です。ただし、Jupyter でも動作するような決定打はあまりないようで、私は結局 FuncAnimation() を使うことにしました。) - python – Inline animations in Jupyter – Stack Overflow
(Jupyter 内で FuncAnimation するときは、backend に notebook を指定する必要がありますよ、という議論です。)
今日はここまで。