

2つのウェブカメラ(camera1,
camera2)から得られる動画を、別々の動画ファイルとして保存したいです。それと同時に行わなければいけない処理がもう1つあったため(音楽を再生するもの、musicと定義)、threadingを使うことを考えています。  
OpenCVのvideo.writeはメインスレッドで行わなければいけないと知り、毎フレームの情報をqueueで送ることを考えたのですが、カメラが2つあるせいなのか、あまり上手くいきません。下のコードは一応望み通りの動画ファイルが得られるのですが、camera1とcamera2の扱いが非対称で違和感・不安感があります(「###########」箇所参照)。  
この後行う処理の都合上、二つの映像の毎フレームの時間をできるだけ同期させる必要があるため、それぞれの映像のキャプチャ〜書き込みまでを順番に繰り返すというのは避けたいです。  
何か上手い方法はないでしょうか？ご教示いただきたいです。

### 試したこと

  * video1.writeとvideo2.writeを両方メインスレッド内で行う
  * video1.writeとvideo2.writeを両方t_cameraスレッド内で行う  
→一応カレントディレクトリに動画ファイルは作られるが、読み取れない。

  * camera1とcamera2のスレッドを分け、queueもcamera1用とcamera2用の2つ生成する  
→そもそもqを複数生成できない？  
→時間同期しづらい(Threading.EventやThreading.Conditionも試しましたが、精度は変わりませんでした)

**環境:**  
Windows 10  
Anaconda (Python 3.6)

### コード

[code]

    import time
    import threading
    import cv2
    import pyaudio
    import wave
    import sys
    import queue
    import time
    import asyncio
    
    # VIDEO SETTING
    camera1 = cv2.VideoCapture(1)
    camera2 = cv2.VideoCapture(2)
    fps1 = int(camera1.get(cv2.CAP_PROP_FPS))
    w1 = int(camera1.get(cv2.CAP_PROP_FRAME_WIDTH))
    h1 = int(camera1.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fourcc1 = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
    video1 = cv2.VideoWriter('camera1.mp4', fourcc1, fps1, (w1, h1))
    fps2 = int(camera2.get(cv2.CAP_PROP_FPS))
    w2 = int(camera2.get(cv2.CAP_PROP_FRAME_WIDTH))
    h2 = int(camera2.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fourcc2 = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
    video2 = cv2.VideoWriter('camera2.mp4', fourcc2, fps2, (w2, h2))
    
    frame_timing=[[],[]]
    init_time=time.time()
    
    # キュー生成
    q = queue.Queue()
    
    # thread内で行う処理(camera, music)定義
    def camera(q):
        #base_time_0 = time.time()
        #duration_0 = 0
        while True:
            #now_time_0 = time.time()
            #duration_0 = now_time_0 - base_time_0
            #print(duration_0)
            #print(time.time())
            ret1, frame1 = camera1.read() # フレームを取得
            frame_timing[0].append(time.time()-init_time)
            ret2, frame2 = camera2.read()
            frame_timing[1].append(time.time()-init_time)
            cv2.imshow("camera1_side", frame1)
            cv2.imshow("camera2_top", frame2)
            video1.write(frame1)
            ########### video2.write(frame2) ###########
            q.put([frame1,frame2])
            if cv2.waitKey(1) & 0xFF == ord('q'):
                print("Ctrl+C")
                break
    
    def music():
        time.sleep(10)
        # 適当に省略しました
    
    
    # スレッド生成、開始
    t_camera = threading.Thread(target=camera, args=(q, ))
    t_camera.setDaemon(True)
    t_music = threading.Thread(target=music)
    t_camera.start()
    t_music.start()
    
    # cameraの続きの保存処理
    base_time=time.time()
    duration=0
    while(duration<10):
        ############ video1.write(q.get()[0])###########
        video2.write(q.get()[1])
        now_time=time.time()
        duration=now_time-base_time
    
    camera1.release()
    camera2.release()
    video1.release()
    video2.release()
    cv2.destroyAllWindows()
    
[/code]


CC BY-SA 4.0
2021-06-05T15:53:38.817
77359
2021-06-06T12:32:37.803
2021-06-06T12:29:03.903
46692
46692
question
python windows opencv camera video
threadingを使って複数のウェブカメラからの動画を保存する方法


video.write()はスレッド内でも行うことができますが、スレッドを開始する前に

[code]

    camera1.release()
    camera2.release()
    video1.release()
    video2.release()
    cv2.destroyAllWindows()
    
[/code]

が行われてしまっており、カメラからの入力を読み取れていなかったために、再生不可能なファイルが生成されてしまっていたようです。  
よって、この前にt_music.join()を入れることで解決しました。


CC BY-SA 4.0
2021-06-06T12:32:37.803
77371
2021-06-06T12:32:37.803
46692
77359
answer