前回、Socket通信でやりたいことがあった!!と記載しました。
elsammit-beginnerblg.hatenablog.com
それが、
”カメラキャプチャ画像をバイト列に変換して送信しストリーミング配信を行ってみる”
ことです。
無駄なことだと思いますが、どうしてもやってみたくて調べてみました!!
問題なく動作させることが出来たので、方法をまとめておこうと思います。
■環境
今回こちらの構成で動作させてみました!!
前回と同様、ネットワークサーバをRaspberry Pi側に構築し、クライアントをwindows PCを用いました。
今回はpythonを用いるのですが、バージョンはこちらの通りです。
・windows PC側Pythonバージョン:3.7.4
・Raspberry Pi側Pythonバージョン:3.7.3
またカメラですが、UCAM-C520FBBKを使用しました。
エレコム WEBカメラ マイク内蔵 200万画素 高精細ガラスレンズ ブラック UCAM-C520FBBK 新品価格 |
■サーバ側構築
ではまずはサーバ側の構築です。
全体のコードはこちらです。
import socketserver import cv2 import numpy import socket import sys class TCPHandler(socketserver.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024).strip() ret, frame=capture.read() jpegstring=cv2.imencode('.jpg', frame)[1].tostring() self.request.send(jpegstring) #hostとportを設定 HOST = 'host名' PORT = ポート番号 #カメラの設定 capture=cv2.VideoCapture(0) capture.set(3,320) capture.set(4,240) if not capture: print("Could not open camera") sys.exit() socketserver.TCPServer.allow_reuse_address = True server = socketserver.TCPServer((HOST, PORT), TCPHandler) server.capture=capture try: server.serve_forever() except KeyboardInterrupt: pass server.shutdown() sys.exit()
やっていることは、画像データをバイト列に変換し前回のsocket通信を実施しているのみです。
簡単には、
①データ受信により、TCPHandlerがコール
②画像データをバイト列に変換
jpegstring=cv2.imencode('.jpg', frame)[1].tostring()
③バイト列をレスポンス
self.request.send(jpegstring)
です。
■クライアント側構築
次にクライアント側の構築です。
コード全体はこちら。
import socket import numpy import cv2 def getimage(): #IPアドレスとポート番号は環境に応じて変更 HOST = '192.168.11.2' PORT = 8080 sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.connect((HOST,PORT)) sock.send(('a').encode("utf-8")) buf=b'' recvlen=100 while recvlen>0: receivedstr=sock.recv(1024) recvlen=len(receivedstr) buf +=receivedstr sock.close() narray=numpy.fromstring(buf,dtype='uint8') return cv2.imdecode(narray,1) while True: img = getimage() cv2.imshow('Capture',img) if cv2.waitKey(100) & 0xFF == ord('q'): break HOST = 'ホスト名' PORT = ポート番号 getimage()
こちらもsocket通信とバイト列から画像データ変換の組み合わせです。
具体的には、
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.connect((HOST,PORT)) sock.send(('a').encode("utf-8"))
でバイト列を要求し、
recvlen=100 while recvlen>0: receivedstr=sock.recv(1024) recvlen=len(receivedstr) buf +=receivedstr
にてバイト列を全て受信。
受信したバイト列を画像データに変換。
narray=numpy.fromstring(buf,dtype='uint8') return cv2.imdecode(narray,1)
以上です。
■動作確認
こちらを動作させてみましたが、、、
う~~ん。。。
遅延が目立ちますね。。。
コードは320×240だったのですが、画像サイズを数倍拡大させると
より遅延が目立つようになりました!!
バイトサイズが大きくなるにつれて遅延が大きくなってしまうようですね!!
しかも、jpgからbmpにencodeを変換すると、
数秒の遅延が発生してしまい、ビデオとしては、、、使い物にならないですね😅
制御が単純で分わかりやすいのですが、ちょっと使うシーンは限定されてしまう気がします。
使うとしても制限を守った使い方が必要そうですね。。