OpenCV live stream video over socket in Python 3

18,728

Solution 1

I'm the author of VidGear Video Processing python library that now also provides NetGear API, which is exclusively designed to transfer video frames synchronously between interconnecting systems over the network in real-time. You try it as follows:

A. Server End:(Bare-Minimum example)

Open your favorite terminal and execute the following python code:

Note: You can end streaming anytime on both server and client side by pressing [Ctrl+c] on your keyboard on server end!

# import libraries
from vidgear.gears import VideoGear
from vidgear.gears import NetGear

stream = VideoGear(source='test.mp4').start() #Open any video stream
server = NetGear() #Define netgear server with default settings

# infinite loop until [Ctrl+C] is pressed
while True:
    try: 
        frame = stream.read()
        # read frames

        # check if frame is None
        if frame is None:
            #if True break the infinite loop
            break

        # do something with frame here

        # send frame to server
        server.send(frame)
    
    except KeyboardInterrupt:
        #break the infinite loop
        break

# safely close video stream
stream.stop()
# safely close server
writer.close()

B. Client End:(Bare-Minimum example)

Then open another terminal on the same system and execute the following python code and see the output:

# import libraries
from vidgear.gears import NetGear
import cv2

#define netgear client with `receive_mode = True` and default settings
client = NetGear(receive_mode = True)

# infinite loop
while True:
    # receive frames from network
    frame = client.recv()

    # check if frame is None
    if frame is None:
        #if True break the infinite loop
        break

    # do something with frame here

    # Show output window
    cv2.imshow("Output Frame", frame)

    key = cv2.waitKey(1) & 0xFF
    # check for 'q' key-press
    if key == ord("q"):
        #if 'q' key-pressed break out
        break

# close output window
cv2.destroyAllWindows()
# safely close client
client.close()

NetGear as of now supports two ZeroMQ messaging patterns: i.e zmq.PAIR and zmq.REQ and zmq.REP and the supported protocol are: 'tcp' and 'ipc'

More advanced usage can be found here: https://abhitronix.github.io/vidgear/latest/gears/netgear/overview/

Solution 2

Late answer, but for those looking for live video transmission and reception over socket: Socket programming Here is the snapshot of results: enter image description here

server.py

import socket, cv2, pickle,struct

# Socket Create
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host_name  = socket.gethostname()
host_ip = socket.gethostbyname(host_name)
print('HOST IP:',host_ip)
port = 9999
socket_address = (host_ip,port)

# Socket Bind
server_socket.bind(socket_address)

# Socket Listen
server_socket.listen(5)
print("LISTENING AT:",socket_address)

# Socket Accept
while True:
    client_socket,addr = server_socket.accept()
    print('GOT CONNECTION FROM:',addr)
    if client_socket:
        vid = cv2.VideoCapture(0)
        
        while(vid.isOpened()):
            img,frame = vid.read()
            a = pickle.dumps(frame)
            message = struct.pack("Q",len(a))+a
            client_socket.sendall(message)
            
            cv2.imshow('TRANSMITTING VIDEO',frame)
            key = cv2.waitKey(1) & 0xFF
            if key ==ord('q'):
                client_socket.close()

client.py

import socket,cv2, pickle,struct

# create socket
client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host_ip = '192.168.1.20' # paste your server ip address here
port = 9999
client_socket.connect((host_ip,port)) # a tuple
data = b""
payload_size = struct.calcsize("Q")
while True:
    while len(data) < payload_size:
        packet = client_socket.recv(4*1024) # 4K
        if not packet: break
        data+=packet
    packed_msg_size = data[:payload_size]
    data = data[payload_size:]
    msg_size = struct.unpack("Q",packed_msg_size)[0]
    
    while len(data) < msg_size:
        data += client_socket.recv(4*1024)
    frame_data = data[:msg_size]
    data  = data[msg_size:]
    frame = pickle.loads(frame_data)
    cv2.imshow("RECEIVING VIDEO",frame)
    key = cv2.waitKey(1) & 0xFF
    if key  == ord('q'):
        break
client_socket.close()

Solution 3

It is because you are receiving small amount of data, and image is not complete. 8192 bytes is not enough in 99.99% of the time, because every image is larger than 8Kb. You'll need to grab ALL data sent by sender in order to convert it to image.

You can take a look at my code on github and change it acording to your need.

Long story short, easy option is to first send number of bytes to the client, and then send an image itself. In client code, after receiving length of image, loop until all bytes are received. for example:

...
img_len = 175428 # received by sender.py
e=0
data = ''
while e < img_len:
  d = sock.recv(1024)
  e += len(d)
  data += d

nparr = np.fromstring(data, np.uint8)
frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
cv2.imshow('frame', frame)
Share:
18,728

Related videos on Youtube

crtIT
Author by

crtIT

Updated on October 17, 2022

Comments

  • crtIT
    crtIT over 1 year

    I am trying to create a simple application to send live stream video over the socket in Python 3 with OpenCV. I am new to OpenCV and socket programming so if you can provide answer in detail I will be very grateful. Thank you.

    Here is sender.py

    import socket
    import time
    
    import cv2
    
    capture = cv2.VideoCapture(0)
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect(('192.168.1.10', 50505))
    
    while True:
        ret, frame = capture.read()
        data = cv2.imencode('.jpg', frame)[1].tostring()
        sock.sendall(data)
        time.sleep(2)
    

    Here is receiver.py

    import socket
    import cv2
    import numpy as np
    import time
    
    HOST = '192.168.1.10'
    PORT = 50505
    
    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()
    
    while True:
        data = conn.recv(8192)
        nparr = np.fromstring(data, np.uint8)
        frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
        cv2.imshow('frame', frame)
        time.sleep(2)
    

    and this is the error

     receiver.py", line 29, in <module>
            cv2.imshow('frame', frame)
        cv2.error: D:\Build\OpenCV\opencv-3.4.0\modules\highgui\src\window.cpp:339:
    error: (-215) size.width>0 && size.height>0 in function cv::imshow