使用 Python 和 OpenCV 实现树莓派与客户端的视频流传输与显示
在计算机视觉和物联网领域,经常需要将树莓派作为视频流服务器,通过网络将摄像头画面传输到客户端进行处理和显示。本文将详细介绍如何利用picamera2
库、Flask 框架以及 OpenCV 库,实现树莓派端的视频流推送和客户端的视频流接收与显示。
一、前期准备
硬件准备
树莓派(建议树莓派 3 及以上版本),确保已安装操作系统(如 Raspbian)。
树莓派摄像头模块,正确连接到树莓派的 CSI 接口。我这里使用的是Zero 2W和Camera Module 3
客户端电脑,操作系统可以是 Windows、MacOS 或 Linux。
软件准备
在树莓派上:
确保系统已更新到最新版本,在终端执行sudo apt update
和sudo apt upgrade -y
。
安装picamera2
库,执行pip install picamera2
。
安装 Flask 框架,执行pip install flask
。
安装Pillow
库(用于图像格式转换),执行pip install pillow
。
在客户端电脑上:
安装 Python 环境,建议使用 Python 3.x 版本。
安装OpenCV
库,对于不同操作系统安装方式略有不同:
在 Windows 上,打开命令提示符,执行pip install opencv - python
。
在 MacOS 上,打开终端,执行pip install opencv - python
。
在 Linux 上,根据不同发行版,可能需要使用sudo apt - get install python3 - opencv
等命令安装。
二、树莓派端操作
树莓派服务器端代码(使用 picamera2 库和 Flask 框架)
树莓派作为视频流服务器,利用picamera2
库获取摄像头画面,并通过 Flask 框架将视频流以 HTTP 的形式提供给客户端。
import io
from flask import Flask, Response
from picamera2 import Picamera2
app = Flask(__name__)
def generate_frames():
picam2 = Picamera2()
# 将格式改为RGB888,后续再转换为JPEG
picam2.configure(picam2.create_preview_configuration(main={"format": "RGB888", "size": (640, 480)}))
picam2.start()
while True:
stream = io.BytesIO()
buffer = picam2.capture_array()
from PIL import Image
img = Image.fromarray(buffer)
img.save(stream, format='JPEG')
stream.seek(0)
yield b'--frame\r\nContent-Type: image/jpeg\r\n\r\n' + stream.read() + b'\r\n'
stream.close()
@app.route('/video_feed')
def video_feed():
return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, threaded=True)
代码说明:
导入库 :导入io
、Flask
、Response
、Picamera2
等必要的库。io
用于处理字节流,Flask
和Response
用于构建 Web 服务器,Picamera2
用于控制树莓派摄像头。
摄像头配置与初始化 :使用Picamera2
创建摄像头对象picam2
,配置其输出格式为RGB888
,分辨率为(640, 480)
,并启动摄像头。
生成视频帧 :在generate_frames
函数中,通过picam2.capture_array
获取摄像头的图像数组,使用PIL
库将数组转换为图像对象并保存为 JPEG 格式到字节流stream
中,然后将字节流数据以特定格式作为视频帧输出。
定义路由 :使用@app.route
装饰器定义/video_feed
路由,返回由generate_frames
函数生成的视频流响应。
启动 Flask 应用 :在if __name__ == '__main__':
条件下,启动 Flask 应用,监听所有 IP 地址(host='0.0.0.0
),端口为5000
。
操作步骤
打开树莓派的终端。
使用文本编辑器(如nano
)创建一个新的 Python 文件,例如video_server.py
,命令为nano ``video_server.py
。
将上述代码逐行复制粘贴到video_server.py
文件中。
按下Ctrl + X
,然后按Y
,再按Enter
保存并退出文件。
在终端中执行python3 ``video_server.py
运行该程序。此时树莓派开始通过摄像头采集视频流,并通过 Flask 应用将其提供在http://0.0.0.0:5000/video_feed
地址上。注意记录树莓派的 IP 地址,可在终端执行hostname -I
查看。
三、电脑端操作
客户端代码(使用 OpenCV 和 urllib 库)
客户端电脑通过 Python 的cv2
(OpenCV)库和urllib.request
库从树莓派服务器获取视频流并进行显示。
python
import cv2
import urllib.request
import numpy as np
# 视频流的URL,即树莓派的IP地址
url = 'http://192.168.3.90:5000/video_feed'
# 打开URL
stream = urllib.request.urlopen(url)
# 用于存储视频流数据的字节数组
bytes_data = bytearray()
while True:
# 读取视频流数据
bytes_data += stream.read(1024)
# 查找帧的起始位置
a = bytes_data.find(b'\xff\xd8')
b = bytes_data.find(b'\xff\xd9')
if a != -1 and b != -1:
# 提取一帧图像数据
frame_data = bytes_data[a:b+2]
# 从字节数据中删除已处理的部分
bytes_data = bytes_data[b+2:]
# 将字节数据转换为numpy数组
frame = np.asarray(bytearray(frame_data), dtype=np.uint8)
# 解码图像帧
frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
# 显示图像帧
cv2.imshow('Video Stream', frame)
# 等待按键事件,25毫秒
if cv2.waitKey(25) & 0xFF == ord('q'):
break
# 关闭窗口
cv2.destroyAllWindows()
代码说明:
导入库 :导入cv2
、urllib.request
、numpy
库。cv2
用于图像和视频处理,urllib.request
用于网络请求,numpy
用于处理数组数据。
设置视频流 URL :将url
变量设置为树莓派服务器提供的视频流 URL。需将http://192.168.3.90:5000/video_feed
中的 IP 地址替换为树莓派实际的 IP 地址。
打开 URL :使用urllib.request.urlopen
打开 URL,获取视频流数据的流对象stream
。
读取和处理视频流数据 :循环读取stream
中的数据并添加到bytes_data
中,查找 JPEG 图像帧的起始和结束标记(\xff\xd8
和\xff\xd9
),提取一帧图像数据,转换为numpy
数组并使用cv2.imdecode
解码为 OpenCV 可处理的格式。
显示视频帧 :使用cv2.imshow
显示解码后的图像帧,并通过cv2.waitKey
等待按键事件,按下q
键时退出循环。
关闭窗口 :循环结束后,使用cv2.destroyAllWindows
关闭所有 OpenCV 窗口。
操作步骤
- 通过 Python 代码接收视频流
打开客户端电脑的命令行终端(Windows 下为命令提示符或 PowerShell,MacOS 和 Linux 下为终端)。
使用文本编辑器(如 Windows 的 Notepad++、MacOS 的 TextEdit 需设置为纯文本模式、Linux 的gedit
等)创建一个新的 Python 文件,例如video_client.py
。
将上述代码逐行复制粘贴到video_client.py
文件中,特别注意将url
变量中的 IP 地址替换为树莓派的实际 IP 地址。
保存video_client.py
文件。
在终端中切换到保存video_client.py
文件的目录,执行python ``video_client.py
(如果使用的是 Python 3,可能需要执行python3 ``video_client.py
)。此时客户端电脑将从树莓派服务器获取视频流,并在 OpenCV 窗口中显示树莓派摄像头捕捉到的画面。按q
键可关闭视频显示窗口。
- 通过浏览器查看视频流
打开客户端电脑上的任意浏览器,如 Chrome、Firefox 等。
在浏览器地址栏中输入树莓派的视频流地址,格式为http://树莓派IP地址:5000/video_feed
。例如,如果树莓派的 IP 地址是192.168.1.100
,则输入http://192.168.1.100:5000/video_feed
。
按下回车键,浏览器将尝试加载树莓派摄像头的视频流画面。如果网络连接正常且树莓派服务器运行正常,应该能看到实时的视频画面。
部分浏览器可能会对视频流显示有兼容性问题。如果遇到无法正常显示的情况,可以尝试更换浏览器,或者检查浏览器是否阻止了某些内容加载。另外,确保树莓派服务器的防火墙设置允许外部访问端口5000
。如果树莓派开启了防火墙,可能需要执行sudo ufw allow 5000
命令(适用于使用ufw
防火墙的情况)来允许外部访问该端口。
在实际应用中,确保树莓派和客户端电脑处于同一网络环境,并且客户端电脑能够访问树莓派的 IP 地址。通过上述代码及操作步骤,即可实现树莓派到客户端的视频流传输与显示功能。