如何使用Python中的tcp套接字发送和接收网络摄像头流?

2024-10-17 06:15:24 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试重新创建this project。我有一台服务器(我的电脑)和一台客户机(我的树莓皮)。我所做的与最初的项目不同的是,我尝试使用一个简单的网络摄像头而不是一个覆盆子pi相机将图像从我的rpi传输到服务器。我知道我必须:

  1. 从相机获取opencv图像帧。在
  2. 将帧(numpy数组)转换为字节。在
  3. 将字节从客户端传输到服务器。在
  4. 将字节转换回帧和视图。在

请举例说明。在

自我_驱动程序.py

import SocketServer
import threading
import numpy as np
import cv2
import sys


ultrasonic_data = None

#BaseRequestHandler is used to process incoming requests
class UltrasonicHandler(SocketServer.BaseRequestHandler):

    data = " "

    def handle(self):

        while self.data:
            self.data = self.request.recv(1024)
            ultrasonic_data = float(self.data.split('.')[0])
            print(ultrasonic_data)


#VideoStreamHandler uses streams which are file-like objects for communication
class VideoStreamHandler(SocketServer.StreamRequestHandler):

    def handle(self):
        stream_bytes = b''

        try:
            stream_bytes += self.rfile.read(1024)
            image = np.frombuffer(stream_bytes, dtype="B")
            print(image.shape)
            cv2.imshow('F', image)
            cv2.waitKey(0)

        finally:
            cv2.destroyAllWindows()
            sys.exit()


class Self_Driver_Server:

    def __init__(self, host, portUS, portCam):
        self.host = host
        self.portUS = portUS
        self.portCam = portCam

    def startUltrasonicServer(self):
        # Create the Ultrasonic server, binding to localhost on port 50001
        server = SocketServer.TCPServer((self.host, self.portUS), UltrasonicHandler)
        server.serve_forever()

    def startVideoServer(self):
        # Create the video server, binding to localhost on port 50002
        server = SocketServer.TCPServer((self.host, self.portCam), VideoStreamHandler)
        server.serve_forever()

    def start(self):
        ultrasonic_thread = threading.Thread(target=self.startUltrasonicServer)
        ultrasonic_thread.daemon = True
        ultrasonic_thread.start()
        self.startVideoServer()


if __name__ == "__main__":

    #From SocketServer documentation
    HOST, PORTUS, PORTCAM = '192.168.0.18', 50001, 50002
    sdc = Self_Driver_Server(HOST, PORTUS, PORTCAM)

    sdc.start()

视频_客户端.py

^{pr2}$

Tags: toimportselfportus服务器hostdata字节
1条回答
网友
1楼 · 发布于 2024-10-17 06:15:24

您不能只将接收到的每一个1-1024字节的缓冲区显示为一个图像;您必须将它们连接起来,并且只在缓冲区完成时显示一个图像。在

如果您知道,带外,您的图像将是一个固定的字节数,您可以这样做:

IMAGE_SIZE = 320*240*3

def handle(self):
    stream_bytes = b''

    try:
        stream_bytes += self.rfile.read(1024)
        while len(stream_bytes) >= IMAGE_SIZE:
            image = np.frombuffer(stream_bytes[:IMAGE_SIZE], dtype="B")
            stream_bytes = stream_bytes[IMAGE_SIZE:]
            print(image.shape)
            cv2.imshow('F', image)
            cv2.waitKey(0)
    finally:
        cv2.destroyAllWindows()
        sys.exit()

如果你不知道每帧发送一帧的大小,你就不知道每帧帧的大小了。在


接下来,如果只发送原始字节,没有任何数据类型、形状或顺序信息,则需要将数据类型和形状信息嵌入服务器中。如果你知道它应该是,比方说,一个特定形状的C顺序的字节,你可以手动执行:

^{pr2}$

…但如果没有,您也必须将该信息作为帧协议的一部分发送。在

或者,您可以将缓冲区的pickle.dumps发送给另一端的pickle.loads,或者将np.save发送给BytesIO和{}结果。不管怎样,这包括数据类型、形状、顺序和步幅信息以及原始字节,所以您不必担心它。在


下一个问题是,一旦显示一个图像,就退出。这真的是你想要的吗?如果不是…就不要那样做。在


但这又带来了另一个问题。您真的想用cv.waitKey来阻止整个服务器吗?您的客户机正在捕获图像并以最快的速度发送图像;当然,您要么希望让服务器在图像到达时立即显示图像,要么更改设计,使客户机只按需发送帧。否则,你只会得到一堆几乎完全相同的帧,然后在客户端被阻塞的时候有几秒长的间隔等待你清空缓冲区,然后重复。在

相关问题 更多 >