🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

8001閲覧

openCVで、リアルタイムに動画に対して重い処理をしつつ元動画の録画も行う方法

Ryomax

総合スコア68

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

2グッド

1クリップ

投稿2019/11/25 09:29

前提・実現したいこと

現在、python+openCV+pytorchを用いて、WEBカメラからの画像に対してリアルタイムに画像処理を行い、保存するプログラムを作成しています。ただ、pytorchによる画像処理は非常に重く、それなりのスペックのPCを使用していますが、FPSはせいぜい10前後といったところです。

できれば、処理を行う前のrawな状態のWEBカメラ動画も保存しつつ、処理した後の動画も保存したいのですが、while内に処理前動画の
をいれても、画像処理に時間がかかることから、飛び飛び状態の動画しか保存できず困っています。処理後の動画に関しては飛び飛びでも問題はないのですが、処理前の元動画は処理落ちのない状態で保存したいのですが、どのようなプロセスにすれば可能でしょうか?

おそらくmultiprocessに処理をすればなんとかできるのではないか思ってはいるのですが、あまり詳しくないのと、もっとシンプルに解決する方法がないかと思い、質問させて頂きました。

詳しい方がいましたら、よろしくお願いします。

該当のソースコード

python

1def video(output_path=""): 2 vid = cv2.VideoCapture(0, cv2.CAP_DSHOW) 3 video_FourCC = cv2.VideoWriter_fourcc(*'XVID') 4 video_fps = vid.get(cv2.CAP_PROP_FPS) 5 video_size = 1920 , 1080 6 7 isOutput = True if output_path != "" else False 8 if isOutput: 9 out = cv2.VideoWriter(output_path, video_FourCC, video_fps, video_size) 10 11 while True: 12 return_value, frame = vid.read() 13 result_img = video_process(frame) #フレームに対する処理(pytorchによる処理) 14 15 result_add = cv2.hconcat([frame, result_img]) 16 cv2.namedWindow("result", cv2.WINDOW_KEEPRATIO | cv2.WINDOW_NORMAL) 17 cv2.imshow("result", result_add) 18 if isOutput: 19 out.write(result_img) 20 if cv2.waitKey(1) & 0xFF == ord('q'): 21 break 22 23if __name__ == '__main__': 24 25 output_dir = "./movie.avi" 26 video(output_dir)

補足情報(FW/ツールのバージョンなど)

  • Windows10+Anaconda
  • Python 3.6.8
  • opencv-python 4.1.1.26
  • pytorch 1.2.0
tiffany, tachikoma👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tachikoma

2019/11/25 12:17

multithreadでPyTorchでの処理を実行させつつ、メインのループでは保存をする。Pythonのqueueをスレッド間での処理の受け渡しに使うと便利です。もしくはconcurent.futureからworkerを1つだけ持つPoolを作成して、そちらに重い処理を投げてしまう。とかですかね。
Ryomax

2019/11/25 12:25

なるほど、やはり現状ではmultithreadで処理するのがbetterのようですね。ご指摘頂いたPythonのqueueやconcurent.futureなど全然理解していないので、いろいろ試行錯誤してやってみようと思います。ありがとうございました。
guest

回答1

0

ベストアンサー

GPU で行われるディープラーニングの処理が重たい原因と思われ、CPU で行う処理で並列化できる要素が質問のコードの範囲ではないため、マルチプロセスにしても速度は変わらないでしょう。
カウンタを1つ用意して重たい処理は数フレームに1回だけおこなうようにすればよいかと思います。

python

1def video(output_path=""): 2 vid = cv2.VideoCapture(0, cv2.CAP_DSHOW) 3 video_FourCC = cv2.VideoWriter_fourcc(*"XVID") 4 video_fps = vid.get(cv2.CAP_PROP_FPS) 5 video_size = 1920, 1080 6 7 isOutput = True if output_path != "" else False 8 if isOutput: 9 out = cv2.VideoWriter(output_path, video_FourCC, video_fps, video_size) 10 11 i = 0 12 while True: 13 return_value, frame = vid.read() 14 if i % 10 == 0: 15 result_img = video_process(frame) 16 result_add = cv2.hconcat([frame, result_img]) 17 18 cv2.namedWindow("result", cv2.WINDOW_KEEPRATIO | cv2.WINDOW_NORMAL) 19 cv2.imshow("result", result_add) 20 21 if isOutput: 22 out.write(result_img) 23 if cv2.waitKey(1) & 0xFF == ord("q"): 24 break 25 26 i += 1 27 28 29if __name__ == "__main__": 30 31 output_dir = "./movie.avi" 32 video(output_dir)

追記

Python ではあまりマルチスレッドをやったことがないので、やり方が間違っているかもしれませんが、以下のようにしてみてはどうでしょうか。

メインスレッド→子スレッド、子スレッド→メインスレッドの2つのキューを用意して、

  1. 「メインスレッド→子スレッドのキュー」が空ならメインスレッドから子スレッドへフレームを送る。
  2. 子スレッド側でそれを受け取り、処理して、「子スレッド→メインスレッドのキュー」で結果を送る。
  3. 「子スレッド→メインスレッドのキュー」が空でないなら、結果を受け取る。

python

1import time 2from multiprocessing import Process, Queue 3 4import cv2 5 6 7def process_frame(parent_to_child, child_to_parent): 8 while True: 9 # メインスレッドからフレームがある場合は受け取る。 10 frame = parent_to_child.get() 11 # print("recieved frame from main thread") 12 13 # なにか処理する。 14 time.sleep(1) 15 16 # メインスレッドへ処理した結果を送る。 17 # print("send result to main thread") 18 child_to_parent.put(frame) 19 20 21def video(output_path=""): 22 cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) 23 24 video_fourcc = cv2.VideoWriter_fourcc(*"XVID") 25 video_fps = int(cap.get(cv2.CAP_PROP_FPS)) 26 video_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) 27 video_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) 28 out = cv2.VideoWriter( 29 output_path, video_fourcc, video_fps, (video_width, video_height) 30 ) 31 32 parent_to_child = Queue() 33 child_to_parent = Queue() 34 process = Process(target=process_frame, args=(parent_to_child, child_to_parent)) 35 process.start() 36 37 result = None 38 while True: 39 # 1フレームずつ取得する。 40 ret, frame = cap.read() 41 42 # メインスレッドから子スレッドへフレームを送る。 43 if parent_to_child.empty(): 44 # print("send frame to child thread") 45 parent_to_child.put(frame) 46 47 # 処理結果がある場合は受け取る。 48 if not child_to_parent.empty(): 49 result = child_to_parent.get() 50 # print("recieved result from child thread") 51 52 if result: 53 cv2.imshow("result", result) 54 55 # 動画保存処理 56 out.write(frame) 57 if not ret or cv2.waitKey(1) & 0xFF == ord("q"): 58 break 59 60 cap.release() 61 cv2.destroyAllWindows() 62 63 print("process finished.") 64 65 66video("out.avi")

投稿2019/11/25 10:01

編集2019/11/25 14:22
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ryomax

2019/11/25 11:09

回答ありがとうございます。御指摘の通り、GPUによるディープラーニング処理に時間がかかり、その処理自体が並列化でも高速化できないことは把握しております。 入力元のWEBカメラからは60fps程度で入力されており、VideoWriterによる動画保存とdeep learningによる画像処理を同一プログラム内で走らせると、画像処理に時間がかかっている間の4-5frameほどがskipされてしまいます。処理後の画像がframe落ちすることに関しては問題ないのですが、できればもともとの60fpsの処理落ちしていないrawな状態の動画も一緒に保存したいと思っています。 pytorchの処理はGPU上で主に処理されていると思うので、CPU自体自体にはある程度余裕があると思うので、できればdeep learningとは別のスレッドで動画をキャプチャーするだけのプログラムを走らせることができないかと思っています。 まあ、WEBカメラからの信号を分配し、動画を録画するためだけのPCを別に用意すればいいだけなんですが、1台のPCで解決できないかと思いまして。わかりづらい質問で申し訳ありません。
tiitoi

2019/11/25 14:25

Process でディープラーニングの処理を行う子スレッドを作成して、Queue を利用してスレッド間の情報のやり取りを行ってはどうでしょうか。 ちなみに imshow() のようなウィンドウに関係する関数はメインスレッド以外から呼ぶと、アプリケーションがクラッシュするので、マルチスレッドを利用する場合はメインスレッドから必ず呼ぶようにする点はご注意ください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問