You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

树莓派PiCamera基于Python向同网Python服务器无线推流技术问询

我来给你一套针对性的解决方案,既能解决OpenCV帧率低的问题,又能实现无线推流,完全符合你不用VNC的要求。核心思路是利用树莓派PiCamera的硬件编码能力(避免OpenCV软件解码的性能损耗),结合Socket网络通信实现低延迟、高帧率的视频传输。

下面分两种可行方案,你可以根据需求选择:

方案1:Socket + MJPEG 实时推流(易调试、高帧率)

这个方案用PiCamera的视频端口(硬件加速)捕获帧,通过JPEG压缩后用Socket传输,帧率轻松达到30fps,延迟极低。

服务器端(接收视频的电脑)

先安装依赖:

pip install opencv-python numpy

然后运行以下Python代码作为服务器:

import socket
import cv2
import numpy as np

# 配置服务器监听地址和端口
HOST = '0.0.0.0'  # 监听本机所有网络接口
PORT = 8000

# 初始化Socket服务器
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))
server_socket.listen(1)
print(f"等待树莓派连接... 当前监听端口: {PORT}")

# 接受树莓派的连接请求
client_socket, addr = server_socket.accept()
print(f"已成功连接设备: {addr}")

# 循环接收并解码视频帧
data_buffer = b''
frame_size_bytes = 4  # 用4字节存储每一帧的大小

while True:
    # 先接收帧的大小信息
    while len(data_buffer) < frame_size_bytes:
        data_buffer += client_socket.recv(4096)
    
    # 解析帧大小
    packed_size = data_buffer[:frame_size_bytes]
    data_buffer = data_buffer[frame_size_bytes:]
    frame_size = int.from_bytes(packed_size, byteorder='big')
    
    # 接收完整的帧数据
    while len(data_buffer) < frame_size:
        data_buffer += client_socket.recv(4096)
    
    frame_data = data_buffer[:frame_size]
    data_buffer = data_buffer[frame_size:]
    
    # 解码JPEG帧并显示
    frame = cv2.imdecode(np.frombuffer(frame_data, dtype=np.uint8), cv2.IMREAD_COLOR)
    cv2.imshow('Raspberry Pi Video Stream', frame)
    
    # 按Q键退出程序
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 清理资源
client_socket.close()
server_socket.close()
cv2.destroyAllWindows()

客户端(树莓派)

先安装依赖(注意:如果是树莓派4B及以上,推荐用picamera2,这里先给传统picamera的代码):

pip install picamera[array] opencv-python

替换代码中的HOST为你的电脑在局域网内的IP地址,然后运行:

import socket
import cv2
from picamera import PiCamera
from picamera.array import PiRGBArray
import time

# 替换为你的电脑局域网IP
HOST = '192.168.1.100'
PORT = 8000

# 初始化PiCamera(启用硬件加速)
camera = PiCamera()
camera.resolution = (640, 480)  # 可根据需求调整,分辨率越低帧率越高
camera.framerate = 30
raw_capture = PiRGBArray(camera, size=(640, 480))
time.sleep(0.1)  # 等待摄像头预热完成

# 建立Socket连接
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, PORT))

# 循环捕获并发送视频帧
for frame in camera.capture_continuous(raw_capture, format='bgr', use_video_port=True):
    # 获取当前帧的数组数据
    image = frame.array
    
    # 编码为JPEG(压缩率可调,80是平衡画质和传输速度的取值)
    _, encoded_frame = cv2.imencode('.jpg', image, [cv2.IMWRITE_JPEG_QUALITY, 80])
    
    # 先发送帧的大小,再发送帧数据
    frame_size = len(encoded_frame).to_bytes(4, byteorder='big')
    client_socket.sendall(frame_size + encoded_frame.tobytes())
    
    # 清空缓冲区,准备下一帧
    raw_capture.truncate(0)
    
    # 按Ctrl+C终止程序
    try:
        pass
    except KeyboardInterrupt:
        break

# 清理资源
client_socket.close()
camera.close()

方案2:H.264 硬件编码推流(更低带宽占用)

如果你的局域网带宽有限,或者需要更高的帧率,可以用PiCamera的H.264硬件编码(比MJPEG压缩率更高),进一步降低网络负载。

服务器端(电脑)

同样安装opencv-python,代码如下:

import socket
import cv2

HOST = '0.0.0.0'
PORT = 8000

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))
server_socket.listen(1)
client_socket, addr = server_socket.accept()
print(f"已连接设备: {addr}")

# 将Socket流转换为OpenCV可读取的视频流
stream = client_socket.makefile('rb')
cap = cv2.VideoCapture(stream)

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    cv2.imshow('H.264 Video Stream', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 清理资源
cap.release()
cv2.destroyAllWindows()
client_socket.close()
server_socket.close()

客户端(树莓派)

无需额外安装依赖(picamera自带H.264编码),代码更简洁:

import socket
from picamera import PiCamera
import time

HOST = '192.168.1.100'  # 替换为你的电脑IP
PORT = 8000

camera = PiCamera()
camera.resolution = (640, 480)
camera.framerate = 30

# 直接将H.264流发送到服务器
camera.start_recording(
    socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((HOST, PORT)),
    format='h264'
)

# 可以设置录制时长,或者用循环保持连接
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    camera.stop_recording()

为什么你之前用OpenCV帧率低?

大概率是因为你没有启用PiCamera的use_video_port=True参数,默认用的是图片捕获端口(软件处理),帧率被限制在几fps;另外如果直接传输未压缩的帧,网络带宽不足也会导致帧率下降。上面的方案都用到了硬件加速和帧压缩,完美解决这个问题。

优化小技巧

  • 调整分辨率:如果需要更高帧率,可将分辨率降到(320, 240),帧率能达到60fps
  • 调整JPEG质量:方案1中的cv2.IMWRITE_JPEG_QUALITY可以设为60-90,数值越低压缩率越高,传输越快
  • 端口选择:如果8000端口被占用,可替换为其他未被使用的端口(比如8080)

内容的提问来源于stack exchange,提问作者JeyPay

火山引擎 最新活动