Raspberry Piでキャプチャした画像を、リクエストのあったクライアントにJpeg画像で送るTCPサーバと、クライアントをPythonで作ってみる。
連続でJpeg画像を表示することによって動画として再生できるようにする。
サーバ側
import cv2
import numpy
class Getter:
cap: cv2.VideoCapture
avg: numpy.ndarray = None
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 100]
def __init__(self):
self.cap = cv2.VideoCapture(0)
def __del__(self):
self.cap.release()
def getImage(self):
ret, frame = self.cap.read()
rreturn cv2.imencode('.jpeg', frame, self.encode_param)[1]
Jpegイメージを取得するクラスを作成する。(getter.py)
import getter
import cv2
import socketserver
import sys
HOST = "192.168.0.2" # サーバのアドレス
PORT = 1234
class TCPHandler(socketserver.BaseRequestHandler):
gt = getter.Getter()
def handle(self):
while True:
recv = self.request.recv(1024).strip()
recvStr = recv.decode('utf-8')
if recvStr == "bye":
break
jpeg_bytes = self.gt.getImage()
if jpeg_bytes is None or not jpeg_bytes.any():
self.request.send((0).to_bytes(4, 'little'))
continue
self.request.send(len(jpeg_bytes).to_bytes(4, 'little'))
self.request.send(jpeg_bytes)
socketserver.TCPServer.allow_reuse_address = True
server = socketserver.TCPServer((HOST, PORT), TCPHandler)
try:
server.serve_forever()
except KeyboardInterrupt:
server.shutdown()
sys.exit()
サーバプログラム、TCP接続を受け入れたらなにかデータが送られてくるのを待つ。
送られてきたデータが文字列でbyeだった場合は通信を終了する。
byeでなければ画像を取得し、4byteでデータサイズを送信した後に、画像データを送信する。
一枚送信し終わったらまた受信待機して待つ。
クライアント側
import cv2
import numpy
import socket
HOST = "192.168.0.2"
PORT = 1234
sock = None
class Getter:
def __init__(self):
self.sock = sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((HOST, PORT))
def __del__(self):
self.sock.send('bye'.encode('utf-8'))
self.sock.close()
def getImage(self):
buf = []
recvlen = 180
image_size = 0
self.sock.send('img'.encode('utf-8'))
while True:
received = self.sock.recv(1024 * 8)
recvlen = len(received)
if recvlen <= 0:
if len(buf) <= 0:
print("No Data")
break
if image_size == 0:
image_size = int.from_bytes(received[:4], 'little')
if image_size == 0:
print("No image")
return None
received = received[4:]
buf += received
if len(buf) >= image_size:
break
if image_size == 0:
return None
recdata = numpy.array(buf, dtype='uint8')
return cv2.imdecode(recdata, 1)
def main():
getter = Getter()
while True:
img = getter.getImage()
if img is None:
continue
cv2.imshow('Capture', img)
if cv2.waitKey(5) & 0xFF == ord('q'):
break
if __name__ == '__main__':
main()
サーバ側のプログラム実行後に、クライアント側プログラムを実行するとクライアント側のマシンでも動画を見ることができるようになる。
このプログラムの場合、Jpeg画像をそのまま送っているので通信速度がそれなりに必要となる。