程序代码篇---esp32视频流处理



前言

ESP32摄像头模块可以通过Wi-Fi提供视频流,通常使用RTSP或HTTP协议。下面将简单介绍如何使用Python读取和处理ESP32摄像头的视频流。


一、ESP32摄像头设置

在开始之前,确保你的ESP32摄像头已经正确配置并可以输出视频流。常见的ESP32摄像头流媒体方式有:

1.HTTP视频流(最常见)

通常地址为 http://[ESP32_IP]/video
或 http://[ESP32_IP]/stream

2.RTSP视频流

通常地址为 rtsp://[ESP32_IP]:554/mjpeg/1

3.MJPEG流

通常地址为 http://[ESP32_IP]/mjpeg/1

二、使用OpenCV读取视频流

1. 读取HTTP视频流

import cv2

# ESP32摄像头的IP地址
esp32_ip = "192.168.1.100"  # 替换为你的ESP32 IP
stream_url = f"http://{esp32_ip}/video"

# 创建视频捕获对象
cap = cv2.VideoCapture(stream_url)

# 设置缓冲区大小为1以减少延迟
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)

while True:
    ret, frame = cap.read()
    if not ret:
        print("无法获取视频流,尝试重新连接...")
        cap.release()
        cap = cv2.VideoCapture(stream_url)
        continue
    
    # 显示视频
    cv2.imshow('ESP32 Camera Stream', frame)
    
    # 按'q'退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 释放资源
cap.release()
cv2.destroyAllWindows()

2. 读取RTSP视频流

import cv2

esp32_ip = "192.168.1.100"  # 替换为你的ESP32 IP
rtsp_url = f"rtsp://{esp32_ip}:554/mjpeg/1"

cap = cv2.VideoCapture(rtsp_url)

# 对于RTSP流,可能需要添加这些参数
cap.set(cv2.CAP_PROP_FPS, 30)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'MJPG'))

while True:
    ret, frame = cap.read()
    if not ret:
        print("RTSP流中断,尝试重新连接...")
        cap.release()
        cap = cv2.VideoCapture(rtsp_url)
        continue
    
    cv2.imshow('ESP32 RTSP Stream', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

三、使用requests库读取MJPEG流

对于MJPEG格式的视频流,可以使用requests库:
import cv2
import numpy as np
import requests
from io import BytesIO

esp32_ip = "192.168.1.100"  # 替换为你的ESP32 IP
stream_url = f"http://{esp32_ip}/mjpeg/1"

# 创建请求会话
session = requests.Session()
stream = session.get(stream_url, stream=True)

bytes_data = bytes()
for chunk in stream.iter_content(chunk_size=1024):
    bytes_data += chunk
    a = bytes_data.find(b'\xff\xd8')  # JPEG开始标记
    b = bytes_data.find(b'\xff\xd9')  # JPEG结束标记
    
    if a != -1 and b != -1:
        jpg = bytes_data[a:b+2]
        bytes_data = bytes_data[b+2:]
        
        # 转换为numpy数组
        img = cv2.imdecode(np.frombuffer(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
        
        if img is not None:
            cv2.imshow('ESP32 MJPEG Stream', img)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

cv2.destroyAllWindows()
session.close()

四、处理常见问题

1. 连接不稳定或断流

python
import time

def connect_to_stream(url, max_retries=5, retry_delay=1):
for i in range(max_retries):
cap = cv2.VideoCapture(url)
if cap.isOpened():
return cap
print(f"连接失败,尝试 {i+1}/{max_retries}…")
time.sleep(retry_delay)
return None

esp32_ip = “192.168.1.100”
stream_url = f"http://{esp32_ip}/video"

cap = connect_to_stream(stream_url)
if cap is None:
print(“无法连接到摄像头”)
exit()

while True:
ret, frame = cap.read()
if not ret:
print(“视频流中断,尝试重新连接…”)
cap.release()
cap = connect_to_stream(stream_url)
if cap is None:
break
continue

cv2.imshow('Stream', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
    break

cap.release()
cv2.destroyAllWindows()

2. 提高视频流性能

2.1降低分辨率

def resize_frame(frame, scale_percent=50):
    width = int(frame.shape[1] * scale_percent / 100)
    height = int(frame.shape[0] * scale_percent / 100)
    return cv2.resize(frame, (width, height))

2.2跳过部分帧

frame_counter = 0
frame_skip = 2  # 每3帧处理1帧

while True:
    ret, frame = cap.read()
    if not ret:
        # 处理断流...
        continue
    
    frame_counter += 1
    if frame_counter % (frame_skip + 1) != 0:
        continue
    
    # 处理帧
    frame = resize_frame(frame, 50)
    cv2.imshow('Optimized Stream', frame)
    
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

五、使用FFmpeg作为后端

对于某些ESP32摄像头流,使用FFmpeg作为后端可能更稳定:

import cv2
import subprocess

esp32_ip = "192.168.1.100"
stream_url = f"http://{esp32_ip}/video"

# 使用FFmpeg作为视频捕获后端
command = [
    'ffmpeg',
    '-i', stream_url,
    '-f', 'image2pipe',
    '-pix_fmt', 'bgr24',
    '-vcodec', 'rawvideo', '-'
]

pipe = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=10**8)

while True:
    # 读取原始视频数据
    raw_image = pipe.stdout.read(640*480*3)
    
    # 转换为numpy数组
    image = np.frombuffer(raw_image, dtype='uint8')
    if image.size == 0:
        break
    image = image.reshape((480, 640, 3))
    
    cv2.imshow('FFmpeg Stream', image)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

pipe.terminate()
cv2.destroyAllWindows()

六、使用PyAV库(高级选项)

import av
import cv2
import numpy as np

esp32_ip = "192.168.1.100"
stream_url = f"http://{esp32_ip}/video"

container = av.open(stream_url)

for frame in container.decode(video=0):
    img = frame.to_ndarray(format='bgr24')
    cv2.imshow('PyAV Stream', img)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

container.close()
cv2.destroyAllWindows()

七、实际应用示例 - 视频流处理

import cv2
import numpy as np

def process_frame(frame):
    """帧处理函数示例"""
    # 转换为灰度图
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    
    # 边缘检测
    edges = cv2.Canny(gray, 100, 200)
    
    # 转换为3通道以便与原图拼接
    edges = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
    
    # 水平拼接原图和边缘图
    processed = cv2.hconcat([frame, edges])
    
    return processed

esp32_ip = "192.168.1.100"
stream_url = f"http://{esp32_ip}/video"

cap = cv2.VideoCapture(stream_url)

while True:
    ret, frame = cap.read()
    if not ret:
        print("视频流中断")
        break
    
    # 处理帧
    result = process_frame(frame)
    
    # 显示FPS
    fps = cap.get(cv2.CAP_PROP_FPS)
    cv2.putText(result, f"FPS: {fps:.1f}", (10, 30), 
                cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
    
    cv2.imshow('Processed ESP32 Stream', result)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

八、注意事项

1.网络延迟

网络延迟:Wi-Fi视频流通常有100-500ms的延迟

2.带宽限制

带宽限制:高清视频流可能需要较大的带宽

3.认证

认证:如果ESP32摄像头需要认证,URL格式为 http://username:password@ip/video

4.编码格式

编码格式:确认ESP32摄像头的视频编码格式**(通常是MJPEG)**

5.稳定性

稳定性:无线连接可能不稳定,需要添加重连逻辑
通过以上方法,你可以灵活地使用Python读取和处理ESP32摄像头的视频流,并根据需要进行各种图像处理和分析


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值