この記事はPythonで動画に関するアプリを作る際に大変役立つと思います。
ネットにこれがっている同じような記事とは全然違います。
OpenCV2を使うと動画の表示とファイル作成簡単にできます。キモになる部分のコードはこれだけ。
while True:
ret, frame = camera.read() # フレームを取得
cv2.imshow('video', frame) # フレームを画面に表示
video.write(frame)
ループの中で
camera.read フレーム(静止画像)を取得して、 cv2.imshow 画像を表示して、
video.write 動画ファイルに書き出します。 個のループは1回回るのに数10msecです。
cv2.imshowフレームデータを渡すだけできちんと動画を表示します。 video.writeは セットされた条件でファイルに画像をかきみします。
これだと録画中にはなにもできません。唯一できるのはキーボード入力でロープを脱出することだけです。
自分で作成したウィジットで動画を表示する。 バックグラウンドで動画ファイルの生成をする。
これを実現しました。案外時間がかかりました。まず画面はこちら。

見た目はcv2.imshowと同じです。これに録画ボタンや録音経過時間などをいろいろ付けられます。cv2.imshowとは全然違うようにすることができます。
いろいろ調べるに時間がかかりましたが、ポイントとなるおいしい部分を公開します。
動画ファイルの書込み
while True:
ret, frame = camera.read() # フレームを取得
video.write(frame)
上記のようにすればベストかと思い、スレッドで対応する。
動画の表示
タイマーでスレッドで取得したフレームを表示する。
今回はクラスを使って作成しました。
import tkinter
import cv2
import PIL.Image, PIL.ImageTk
import time
from datetime import datetime
import threading
class videoApp:
def __init__(self, window, window_title, cameraId=0):
self.window = window
self.window.title(window_title)
self.cameraId = cameraId
# open video source (by default this will try to open the computer webcam)
self.cpatureDevice = MyVideoCapture(self.cameraId)
# Create a canvas that can fit the above video source size
self.canvas = tkinter.Canvas(window, width = self.cpatureDevice.width, height = self.cpatureDevice.height)
self.canvas.pack()
#スレッドの作成
self.threadVideo = threading.Thread(target=self.cpatureDevice.ThreadVideoCapture)
#スレッドの開始
self.threadVideo.start()
self.timer = 15 #msec単位
self.showFhoto()
self.window.mainloop()
self.cpatureDevice.terminate()
def showFhoto(self):
ret, frame = self.cpatureDevice.get_frame()
if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(frame))
self.canvas.create_image(0, 0, image = self.photo, anchor = tkinter.NW)
self.window.after(self.timer, self.showFhoto)
def __del__(self):
self.threadVideo.join()
class MyVideoCapture:
def __init__(self, cameraID=0):
# Open the video source
self.camera = cv2.VideoCapture(cameraID)
if not self.camera.isOpened():
raise ValueError("Unable to open video source", cameraID)
# Get video source width and height
self.width = self.camera.get(cv2.CAP_PROP_FRAME_WIDTH)
self.height = self.camera.get(cv2.CAP_PROP_FRAME_HEIGHT)
# Video Writer
self.fmt = cv2.VideoWriter_fourcc(*'XVID')
self.fps = 20
self.size = (640, 480)
self.videoWiter = cv2.VideoWriter("my_video.avi", self.fmt, self.fps, self.size)
self.quit = False
self.frame = None
self.thredRead = False
def terminate(self):
self.quit = True
def get_frame(self):
if self.thredRead:
return True, self.frame
return False, None
def ThreadVideoCapture(self):
while True:
try:
if self.quit == True:
break
ret, self.frame = self.camera.read()
gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)
self.thredRead = True
self.videoWiter.write(self.frame)
except:
break
print("terminate thread")
def __del__(self):
if self.camera.isOpened():
self.camera.release()
self.videoWiter.release()
if __name__ == '__main__':
videoApp(tkinter.Tk(), "Video Recording")
解説: videoAppクラスを作成し実行します。
self.cpatureDevice = MyVideoCapture(self.cameraId)
MyVideoCaptureのインスタンスを作成します。
スレッドの作成 self.threadVideo = threading.Thread(target=self.cpatureDevice.ThreadVideoCapture) #スレッドの開始 self.threadVideo.start()
スレッドの応答関数はself.cpatureDevice.ThreadVideoCaptureです。 class
MyVideoCapture:で定義されている関数です。
MyVideoCapture
ThreadVideoCapture() 画像ファイルの書込みをします。 例外処理でブレークする以外にself.quitでブレークするようにしています。
動画の表示
videoApp showFhoto() self.cpatureDevice.get_frame()
ThreadVideoCapture()が取得したデータを返します。 このフレームデータを取得して表示します。
いろいろわかったこと Windows10にUSBのwebカメラを接続すると、self.camera =
cv2.VideoCapture(cameraID)の処理が終わるまで20秒くらい掛かってハングアップしたかなと思いました。
動画に関係ないことですが、ラズベリーパイではwindowsを透明にできない。Windows10ならできる。Windowsとラズベリーパイでは同じに動作しない。
|