Sending live video frame over network in python opencv

Few things:

  • use sendall instead of send since you’re not guaranteed everything will be sent in one go
  • pickle is ok for data serialization but you have to make a protocol of
    you own for the messages you exchange between the client and the server, this
    way you can know in advance the amount of data to read for unpickling (see
    below)
  • for recv you will get better performance if you receive big chunks, so replace 80 by 4096 or even more
  • beware of sys.getsizeof: it returns the size of the object in memory, which is not
    the same as the size (length) of the bytes to send over the network ; for a
    Python string the two values are not the same at all
  • be mindful of the size of the frame you are sending. Code below supports a frame up to 65535. Change “H” to “L” if you have a larger frame.

A protocol example:

client_cv.py

import cv2
import numpy as np
import socket
import sys
import pickle
import struct ### new code
cap=cv2.VideoCapture(0)
clientsocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
clientsocket.connect(('localhost',8089))
while True:
    ret,frame=cap.read()
    data = pickle.dumps(frame) ### new code
    clientsocket.sendall(struct.pack("H", len(data))+data) ### new code

server_cv.py

import socket
import sys
import cv2
import pickle
import numpy as np
import struct ## new

HOST=''
PORT=8089

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print('Socket created')

s.bind((HOST,PORT))
print('Socket bind complete')
s.listen(10)
print('Socket now listening')

conn,addr=s.accept()

### new
data = ""
payload_size = struct.calcsize("H") 
while True:
    while len(data) < payload_size:
        data += conn.recv(4096)
    packed_msg_size = data[:payload_size]
    data = data[payload_size:]
    msg_size = struct.unpack("H", packed_msg_size)[0]
    while len(data) < msg_size:
        data += conn.recv(4096)
    frame_data = data[:msg_size]
    data = data[msg_size:]
    ###

    frame=pickle.loads(frame_data)
    print frame
    cv2.imshow('frame',frame)

You can probably optimize all this a lot (less copying, using the buffer interface, etc) but at least you can get the idea.

Leave a Comment