在 Raspberry Pi 中使用 OpenCV 和套接字通过 TCP 发送视频

Posted

技术标签:

【中文标题】在 Raspberry Pi 中使用 OpenCV 和套接字通过 TCP 发送视频【英文标题】:Send Video over TCP using OpenCV and sockets in Raspberry Pi 【发布时间】:2016-07-29 22:47:21 【问题描述】:

我一直在尝试将实时视频帧从我的客户端 (Raspberry Pi) 发送到托管在笔记本电脑上的服务器。这两个设备都连接到同一个网络。

服务器.py

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

HOST = '192.168.1.3'
PORT = 8083

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 = ""
payload_size = struct.calcsize("L")

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("L", 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.size
    # cv2.imshow('frame', frame)
    # cv2.waitKey(10)

客户端.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(('192.168.1.3', 8081))

while True:
    ret,frame = cap.read()
    data = pickle.dumps(frame)
    clientsocket.sendall(struct.pack("L", len(data)) + data)

我的笔记本电脑上的服务器没有收到任何数据。但是当我在同一设备上运行这个客户端和服务器时(例如笔记本电脑上的服务器和客户端),它就可以正常工作了。

我能够将数据从树莓派发送到笔记本电脑(针对 echo 应用程序进行了测试)。

谁能帮我解决这个问题?

【问题讨论】:

我不明白您为什么使用 TCP 进行视频流传输,而不是用于这种用途的 UDP 【参考方案1】:

使用相同的程序,我在我的树莓派上接收数据时遇到了问题。我发现这是因为在不同机器上使用 unsigned long 的“L”的方式不同。至少对我来说,它们在不同机器上的原生表示是不同的。我通过在格式字符串中添加“=”来解决此问题,以强制 struct 使用标准大小的“L”(4)解包。

payload_size = struct.calcsize("=L")

clientsocket.sendall(struct.pack("=L", len(data)) + data)

等等

【讨论】:

你是对的,在这个小改动生效后,谢谢!【参考方案2】:

使用下面的代码创建一个文件,在 Windows 上的 Powershell 中运行服务器代码,例如运行 python "C:\path\toFile\streamTestServer.py"

代码是:

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

HOST = '127.0.0.1'
PORT = 8083

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''
payload_size = struct.calcsize("L")

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("L", 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.size)
    cv2.imshow('frame', frame)
    cv2.waitKey(10)

然后在 Python IDLE 或 Powershell 的另一个窗口中运行客户端。 客户端代码是:

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(('127.0.0.1', 8083))

while True:
    ret,frame = cap.read()
    data = pickle.dumps(frame)
    clientsocket.sendall(struct.pack("L", len(data)) + data)

现在您正在从 localhost 客户端流式传输到 localhost 服务器。

【讨论】:

【参考方案3】:

经过数小时的分析为什么 server.py 和 client.py 不工作(即使在防火墙被禁用后),server.py 代码中出现错误:“单词不应该是字符串”。因此 word = "" (这是一个字符串)应该改为 word = b'' (这是两个单引号来表示一个字节)。

【讨论】:

你能分享完整的代码吗?我在你的 server.py 代码中没有看到“word=”【参考方案4】:

根据我的理解,您应该为客户端和服务器使用相同的端口,但是您使用的是两个不同的端口,8083 和 8081。

您是否检查过防火墙是否为所使用的端口打开?

【讨论】:

即使我的端口号相同,仍然是同样的问题。并且所有防火墙规则都允许该端口上的连接。 您是否检查过您的主机的实际 IP(通过 ipconfig 获得)与您在程序中使用的相同? ping 是否双向有效? 我遇到的问题是服务器中的“payload_size”正在获得一个非常大的值(7898745431321384897974964),因此程序处于无限循环中。

以上是关于在 Raspberry Pi 中使用 OpenCV 和套接字通过 TCP 发送视频的主要内容,如果未能解决你的问题,请参考以下文章

在 Raspberry PI 上使用 Python 和 OpenCV 进行图像处理 [关闭]

树莓派最新官方系统安装Opencv(Raspberry Pi 11)

OpenCV Raspberry Pi printf()不显示

使用 OpenCV 和 Raspberry Pi 进行实时图像处理

Raspberry Pi 上的 OpenCV 人脸检测速度很慢

Raspberry pi opencv 链接问题的交叉编译