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

2024-05-06

我正在尝试重新创建这个项目 https://github.com/hamuchiwa/AutoRCCar。我拥有的是服务器(我的电脑)和客户端(我的树莓派)。我所做的与原始项目不同的是我尝试使用一个简单的网络摄像头而不是树莓派摄像头将图像从我的 rpi 流式传输到服务器。我知道我必须:

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

示例将不胜感激。

self_driver.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

import socket
import time
import cv2


client_sock = socket.socket()
client_sock.connect(('192.168.0.18', 50002))
#We are going to 'write' to a file in 'binary' mode
conn = client_sock.makefile('wb')

try:
    cap = cv2.VideoCapture(0)
    cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH,320)
    cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT,240)

    start = time.time()

    while(cap.isOpened()):
        conn.flush()
        ret, frame = cap.read()
        byteImage = frame.tobytes()
        conn.write(byteImage)


finally:
    finish = time.time()
    cap.release()
    client_sock.close()
    conn.close()

您不能仅将每个接收到的 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()

如果您不知道这一点,则必须添加某种帧协议,例如在每个帧之前以 uint32 形式发送帧大小,以便服务器可以知道每个帧要接收多少字节。


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

image = np.frombuffer(stream_bytes, dtype="B").reshape(320, 240, 3)

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

或者,您可以发送pickle.dumps缓冲区和pickle.loads它在另一边,或者np.save to a BytesIO and np.load结果。无论哪种方式,都包括数据类型、形状、顺序和步幅信息以及原始字节,因此您不必担心它。


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


但这又引发了另一个问题。你真的想用它来阻止整个服务器吗cv.waitKey?您的客户正在捕获图像并尽快发送它们;当然,您要么想让服务器在它们到达时立即显示它们,要么更改设计,以便客户端仅根据需要发送帧。否则,您只会得到一堆几乎相同的帧,然后在客户端被阻塞等待您耗尽缓冲区时出现一段长达数秒的间隙,然后重复。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • 在 Visual Studio 中查找所有与 == 进行比较的情况

    我犯了一个错误 使用 来比较 IP 地址 而不是使用 C 中 IPAddress 类的 equals 方法 这将导致比较的是引用而不是值 由于我目前正在研究的解决方案对于一个人项目来说非常大 gt 100 000 行源代码 因此我非常确定我
  • DbConnection 不带 Db,使用内存中的 DataSet(或类似的)作为源

    我正在尝试对一些 NET 类进行单元测试 这些类 出于良好的设计原因 需要 DbConnections 来完成其工作 对于这些测试 我在内存中有某些数据可以作为这些类的输入 内存中的数据可以很容易地表示为 DataTable 或包含该 Da
  • sed 在文本文件中换行?

    我是 Sed 的新手 我有一堆 ASCII 文件 其中包含如下所示的数据 Test Version 2 6 3 Model Manufacturer HR21 100 Test Version 2 6 3 Model Manufacture
  • 如何使用保存实例状态来保存活动状态?

    我一直在研究Android SDK平台 并且不太清楚如何保存应用程序的状态 因此 考虑到对 Hello Android 示例的这个小改动 package com android hello import android app Activi
  • cygwin winsymlinks:本机不起作用

    我现在和 cygwin 斗争了很长一段时间 我广泛搜索了如何让 cygwin 创建 Windows 风格的符号链接 我尝试了以下方法 export CYGWIN winsymlinks native export CYGWIN winsym
  • 如何通过列表中的属性值获取/查找对象

    我有一个关于通过使用 LINQ 搜索 字段名称来获取列表对象的问题 我编码简单Library and Book为此类 class Book public string title get private set public string
  • 如何验证字符串仅包含字母、数字、下划线和破折号? [复制]

    这个问题在这里已经有答案了 如果我迭代字符串中的所有字符 我知道如何做到这一点 但我正在寻找一种更优雅的方法 正则表达式只需很少的代码即可实现这一目的 import re if re match A Za z0 9 my little st
  • 将列拆分为多列

    对于下面给出的数据 data1 lt structure list var1 c 2 7 2 6 7 2 7 2 7 1 7 1 7 1 5 1 2 7 1 5 1 7 1 2 3 4 5 6 7 1 2 4 6 Names var1 cl
  • bash 或 sh 中的“=”和“==”运算符有什么区别

    我意识到 和 运算符都可以在 if 语句中使用 例如 var some string if var some string then doing something fi if var some string then doing some
  • 如何更改android上的hosts文件[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我已经成功root了我的三星Galaxy Mini android 2 2 1 并认为我可以改变任何东西 就像root通常可以的那样 我想更改 And
  • 从 dtype ('O') 转换为日期时间时出现问题

    我正在导入大量文本文件并将它们附加到 pandas 数据框中 有一个列包含我需要的一堆日期 但我无法将它们转换为日期时间 因为它被列为对象 这行代码适用于其他任何其他数据类型 但当我在这里运行它时 它会抛出错误 df Date pd to
  • 如何在 IntelliJ 中快速文档中换行文本?

    Ctrl Q 快速文档 后我看不到所有文本 我必须水平滚动才能看到所有内容 我无法使编辑器适合窗口 更新 问题只是符号定义 即 第一行 描述 块文本 正确换行 实际上 我不想调整此窗口的大小 因为我更喜欢将其保留在相同的位置以便快速参考 我
  • Android Market 公司注册

    抱歉 这个问题与编程无关 但我无处可问 我在 android 帮助中心和支持中询问 但没有任何回应 在 Android Market 开设公司帐户需要什么 我希望我的公司被视为卖家 他们将如何验证公司的身份 我需要向市场提供哪些文件 Tha
  • 如何在 Ruby 中获取网页的 HTML 源代码 [重复]

    这个问题在这里已经有答案了 在 Firefox 或 Safari 等浏览器中 打开网站后 我可以右键单击该页面 然后选择以下内容 查看页面源代码 或 查看源代码 这显示了该页面的 HTML 源代码 在 Ruby 中 是否有一个函数 也许是一
  • 自动生成序列号

    我编写了下面的计数代码 目的是让它为我的数据生成自动序列号 以代替删除行后的 MySQL 序列号 但是当我运行它时 我发现 MySQL 表中没有任何条目 后来我将代码更改为 Dreamweaver 插入记录 并观察到 SN 序列号 字段不需
  • 正则表达式 括号之间的匹配 (...)

    我正在尝试从一条简单的线中抓取 2 件物品 Title Description 编辑 实际上一个想要显示的网址称为描述 因为我希望它显示而不是实际解析 Trivium https www youtube com user trivium 在
  • 更改同一页面上的页面过渡

    我有一个带有两个内部页面 data role page 的html 其中一页显示日期以及与该日期相关的数据 当我向左或向右滑动时 日期应该会改变 我这里需要的是让页面过渡显示 看来我不能使用 mobile changePage 对于同一页面
  • printf 似乎忽略了字符串精度

    所以 我有点难受 根据man 3 printf在我的系统上 字符串格式 5s 应使用指定的精度来限制从给定字符串参数打印的字符数 man 3 printf PRINTF 3 BSD Library Functions Manual PRIN
  • ^ 和 _ 宏之后出现的数字(是:LaTeX 限制?)

    我在 LaTeX 中遇到了一个恼人的问题 我有一个大约 1000 行的 tex 文件 我已经有了一些数字 但是当我尝试添加另一个数字时 它会吐出 Undefined control sequence
  • 如何在Python中使用tcp套接字发送和接收网络摄像头流?

    我正在尝试重新创建这个项目 https github com hamuchiwa AutoRCCar 我拥有的是服务器 我的电脑 和客户端 我的树莓派 我所做的与原始项目不同的是我尝试使用一个简单的网络摄像头而不是树莓派摄像头将图像从我的