【问题标题】:Send webcam stream from server in Python using sockets使用套接字从 Python 中的服务器发送网络摄像头流
【发布时间】:2020-04-22 12:35:54
【问题描述】:

我正在尝试使用 Python 套接字将网络摄像头流从 server.py 文件发送到 client.py 文件。我让它在另一个方向工作,但想要翻转它(当客户端连接到服务器时,服务器会将网络摄像头数据从服务器提供给客户端)。但是,尝试运行此类会导致错误,并且只会显示流的第一帧,然后崩溃......我该怎么做才能解决这个问题?

server.py

import cv2
import io
import socket
import struct
import time
import pickle
import zlib

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((socket.gethostname(), 1234))
s.listen(5)

cam = cv2.VideoCapture(0)

cam.set(3, 320);
cam.set(4, 240);

img_counter = 0

encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 100]

while True:
    client_socket, address = s.accept()
    print(f"Connection from {address} has been established!")

    ret, frame = cam.read()
    result, frame = cv2.imencode('.jpg', frame, encode_param)

    data = pickle.dumps(frame, 0)
    size = len(data)

    print("{}: {}".format(img_counter, size))
    client_socket.send(struct.pack(">L", size) + data)
    print("ooga")
    img_counter += 1

cam.release()

client.py

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

HOST=''
PORT=8485

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((socket.gethostname(),1234))

data = b""
payload_size = struct.calcsize(">L")
print("payload_size: {}".format(payload_size))
while True:
    while len(data) < payload_size:
        print("Recv: {}".format(len(data)))
        data += s.recv(4096)

    print("Done Recv: {}".format(len(data)))
    packed_msg_size = data[:payload_size]
    data = data[payload_size:]
    msg_size = struct.unpack(">L", packed_msg_size)[0]
    print("msg_size: {}".format(msg_size))
    while len(data) < msg_size:
        data += s.recv(4096)
    frame_data = data[:msg_size]
    data = data[msg_size:]

    frame=pickle.loads(frame_data, fix_imports=True, encoding="bytes")
    frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
    cv2.imshow('ImageWindow',frame)
    cv2.waitKey(1)

【问题讨论】:

    标签: python image sockets opencv raspberry-pi


    【解决方案1】:

    以下内容可以满足您的要求。在服务器端(在本例中为树莓派),您绑定到端口并等待连接:

    #!/bin/python
    import io, struct
    import picamera
    import socket
    
    STREAMING_PORT = 8887
    
    with picamera.PiCamera() as camera:
    
        stream = io.BytesIO()
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server_socket.bind(('0.0.0.0', STREAMING_PORT))
        server_socket.listen(2)
    
        while True:
            client_conn, client_address = server_socket.accept()
            connection = client_conn.makefile('wb')
    
            print ("Accepted connection")
            for _ in camera.capture_continuous(stream, 'jpeg', use_video_port = True):
                try:
                    connection.write(struct.pack('<L', stream.tell()))
                    connection.flush()
                    stream.seek(0)
                    connection.write(stream.read())
                    stream.seek(0)
                    stream.truncate()
               
                except:
                    break
                    
        connection.close()
        server_socket.close()
    

    在桌面端(客户端),您打开与服务器的连接并获取流式传输。当然你必须知道你的服务器的地址。

    #!/bin/python
    import socket
    import cv2
    import numpy as np
    
    PI_IP = "192.168.0.100"
    STREAMING_PORT = 8887
    
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect((PI_IP, STREAMING_PORT))
    
    client_socket.settimeout(5)
    client_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
            
    rfile = client_socket.makefile('rb')
    stream_bytes = b' '
    
    while True:
        stream_bytes += rfile.read(1024)
                
        if len(stream_bytes) == 0:
            break
    
        first = stream_bytes.find(b'\xff\xd8')
        last = stream_bytes.find(b'\xff\xd9')
                
        if first != -1 and last != -1:
    
            jpg = stream_bytes[first:last+2]
            stream_bytes = stream_bytes[last+2:]
    
            image = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
            cv2.imshow('image', image)
    
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
    
    cv2.destroyAllWindows()
    rfile.close()
    client_socket.close()
    

    您可能还对在客户端创建生成器感兴趣,例如,如果您正在中继流。

                    yield b'--frame\r\n'
                    yield b'X-Timestamp: %s\r\n' % str(time.time()).encode()
                    yield b'Content-Length: %s\r\n' % str(len(jpg)).encode()
                    yield b'Content-Type: image/jpeg\r\n\r\n' 
                    yield jpg
                    yield b'\r\n'
    
    

    【讨论】:

      【解决方案2】:

      下面是一个可行的例子:

      客户端.py

      import cv2
      import numpy as np
      import socket
      import sys
      import pickle
      import struct
      
      cap=cv2.VideoCapture(0)
      clientsocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
      clientsocket.connect(('localhost',8089))
      
      while True:
          ret,frame=cap.read()
          # Serialize frame
          data = pickle.dumps(frame)
      
          # Send message length first
          message_size = struct.pack("L", len(data)) ### CHANGED
      
          # Then data
          clientsocket.sendall(message_size + data)
      

      服务器.py

      import pickle
      import socket
      import struct
      
      import cv2
      
      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()
      
      data = b'' ### CHANGED
      payload_size = struct.calcsize("L") ### CHANGED
      
      while True:
      
          # Retrieve message size
          while len(data) < payload_size:
              data += conn.recv(4096)
      
          packed_msg_size = data[:payload_size]
          data = data[payload_size:]
          msg_size = struct.unpack("L", packed_msg_size)[0] ### CHANGED
      
          # Retrieve all data based on message size
          while len(data) < msg_size:
              data += conn.recv(4096)
      
          frame_data = data[:msg_size]
          data = data[msg_size:]
      
          # Extract frame
          frame = pickle.loads(frame_data)
      
          # Display
          cv2.imshow('frame', frame)
          cv2.waitKey(1)
      

      希望这能满足您的需求!!

      【讨论】:

      • 您好!虽然这段代码可以解决问题,including an explanation 解决问题的方式和原因确实有助于提高帖子的质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请edit您的回答添加解释并说明适用的限制和假设。
      猜你喜欢
      • 1970-01-01
      • 2015-07-28
      • 1970-01-01
      • 2018-04-05
      • 2021-01-27
      • 2020-04-06
      • 2015-05-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多