動機
パソコンの画像データを他のパソコンで見ることができるようにすることでリモートワークに何か役に立つのではないかと思い今回の実験をしました。 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()