webカメラからの動画を送信する

動機

パソコンの画像データを他のパソコンで見ることができるようにすることでリモートワークに何か役に立つのではないかと思い今回の実験をしました。 pythonで やります。

ソケット通信

WEBカメラがつないでいるコンピュータから動画を送信するときにwebカメラの画像をソケット通信で放送する方法を紹介します。サーバーとクライアントのがネットワークでつながっていることが前提です。(通信可能である)

ソースコード(送信)

import socket
import numpy as np
import cv2
import time
     
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#ソケットオブジェクト作成

s.bind(("10.231.249.146", 1025))    # サーバー側PCのipと使用するポート

print("接続待機中")  

s.listen(1)                     # 接続要求を待機

soc, addr = s.accept()          # 要求が来るまでブロック

print(str(addr)+"と接続完了")  
cap1 = cv2.VideoCapture(0)
cap2 = cv2.VideoCapture(1)
cap3 = cv2.VideoCapture(2)
cap4 = cv2.VideoCapture(3)
cap1.set(3,1920)
cap1.set(4,1080)
cap2.set(3,1920)
cap2.set(4,1080)
cap3.set(3,1920)
cap3.set(4,1080)
cap4.set(3,1920)
cap4.set(4,1080)
fourcc = cv2.VideoWriter_fourcc(*'XVID')

cap1.set(cv2.CAP_PROP_FOURCC,cv2.VideoWriter_fourcc('H','2','6','4'))
cap2.set(cv2.CAP_PROP_FOURCC,cv2.VideoWriter_fourcc('H','2','6','4'))
cap3.set(cv2.CAP_PROP_FOURCC,cv2.VideoWriter_fourcc('H','2','6','4'))
cap4.set(cv2.CAP_PROP_FOURCC,cv2.VideoWriter_fourcc('H','2','6','4'))
def image_hcombine(im_info1, im_info2):
    img1 = im_info1[0]                      
    img2 = im_info2[0]                       
    color_flag1 = im_info1[1]                
    color_flag2 = im_info2[1]                
 
    
    if color_flag1 == 1:
        h1, w1, ch1 = img1.shape[:3]         
    else:
        h1, w1 = img1.shape[:2]
 
    # 2つ目の画像に対しカラーかグレースケールかによって読み込みを変える
    if color_flag2 == 1:
        h2, w2, ch2 = img2.shape[:3]         # 画像のサイズを取得(グレースケール画像は[:2]
    else:
        h2, w2 = img2.shape[:2]
 
    # 2つの画像の縦サイズを比較して、大きい方に合わせて一方をリサイズする
    if h1 < h2:                              # 1つ目の画像の方が小さい場合
        h1 = h2                              # 小さい方を大きい方と同じ縦サイズにする
        w1 = int((h2 / h1) * w2)             # 縦サイズの変化倍率を計算して横サイズを決定する
        img1 = cv2.resize(img1, (w1, h1))    # 画像リサイズ
    else:                                    # 2つ目の画像の方が小さい場合
        h2 = h1                              # 小さい方を大きい方と同じ縦サイズにする
        w2 = int((h1 / h2) * w1)             # 縦サイズの変化倍率を計算して横サイズを決定する
        img2 = cv2.resize(img2, (w2, h2))    # 画像リサイズ
 
    img = cv2.hconcat([img1, img2])          # 2つの画像を横方向に連結
    return img
while (True):

  
    #time.sleep(0.5)            #フリーズするなら#を外す。
    ret1, frame1 = cap1.read()
  
    ret2, frame2 = cap2.read()
    ret3, frame3 = cap3.read()
    ret4, frame4 = cap4.read()
    print(ret1,ret2,ret3,ret4)
    check = ret1 and ret2 and ret3 and ret4      # 2つのフレームが共に取得できた時だけTrue(論理演算)
    if check == True:
        im_info1 = [frame1, True]                # 画像連結関数への引数1
        im_info2 = [frame2, True]                # 画像連結関数への引数2
 
        frame_mix = image_hcombine(im_info1, im_info2)  # 画像連結関数の実行
      
        ret3, frame3 = cap3.read()
        ret4, frame4 = cap4.read()
                                       # 2つのフレームが共に取得できた時だけTrue(論理演算)
    
        im_info3 = [frame3, True]                # 画像連結関数への引数1
        im_info4 = [frame4, True]                # 画像連結関数への引数2
 
        frame_mix2 = image_hcombine(im_info3, im_info4)  # 画像連結関数の実行
      
        img2 = cv2.vconcat([frame_mix, frame_mix2]) 
        
    img2 = img2.tostring()        #numpy行列からバイトデータに変換
    print(len(img2))
    #for i in range(60):
    #    soc.send(img2[i*61440:(i+1)*61440])              # ソケットにデータを送信
    soc.send(img2)
    #k = cv2.waitKey(1)         #↖ 
    ##if k== 13 :                #← ENTERキーで終了
    #    break                  #↙

cam.releace()     

socket.socket()内の第一引数socket.AF_INETはip4のアドレスを使いますという意味です。

受信

import socket
import numpy as np
import cv2
fps=30
size=(1280,480)
fourcc=cv2.VideoWriter_fourcc(*'XVID')
video=cv2.VideoWriter('output.avi',fourcc,fps,size)


soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#ソケットオブジェクト作成

soc.connect(("10.231.249.146", 1025))#サーバー側のipと使用するポート(ポートはサーバーと同じにする。)

print("接続完了")
buf=b''
while(1):
    data = soc.recv(207360)#引数は下記注意点参照
    #print(len(data))
    
    buf=buf+data
    if len(buf)>1843200:
        tmp = buf[1843200:]
        buf = buf[0:1843200]
        buf = np.fromstring(buf,dtype=np.uint8)#バイトデータ→ndarray変換
        #print(data.shape)
        buf = np.reshape(buf,(480,1280,3))#形状復元(これがないと一次元行列になってしまう。) reshapeの第二引数の(480,640,3)は引数は送られてくる画像の形状

        cv2.imshow("",buf)
        video.write(buf)
        buf=tmp



    if cv2.waitKey(20) & 0xFF ==ord('q'):
        break
video.release()

cv2.destroyAllWindows() # 作成したウィンドウを破棄   video.release()