由于项目需要需要将树莓派摄像头捕获的图像通过局域网传输给PC上位机做图像处理。之前使用过mjpg-stream进行图像传输但由于树莓派系统更新较难应用并且传输分辨率有所限制。通过查阅Picamera2手册发现官方有该应用示例代码,清晰度低延迟性能都很好分享给大家。
import io
import logging
import socketserver
from http import server
from threading import Condition
from picamera2.encoders import Quality
from picamera2 import Picamera2
from picamera2.encoders import JpegEncoder
from picamera2.outputs import FileOutput
PAGE = """\
<html>
<head>
<title>picamera2 MJPEG streaming demo</title>
</head>
<body>
<h1>Picamera2 MJPEG Streaming Demo</h1>
<img src="stream.mjpg" width="3280" height="2464" />
</body>
</html>
"""
class StreamingOutput(io.BufferedIOBase):
def __init__(self):
self.frame = None
# 定义Condtion 用于线程同步
self.condition = Condition()
def write(self, buf):
with self.condition:
self.frame = buf
# 唤醒其余被阻塞线程
self.condition.notify_all()
# 定义 StreamingHandler处理类 继承server.BaseHTTPRequestHandler
class StreamingHandler(server.BaseHTTPRequestHandler):
# 定义do_GET 方法用于 处理GET请求
def do_GET(self):
if self.path == '/':
self.send_response(301)
self.send_header('Location', '/index.html')
self.end_headers()
elif self.path == '/index.html':
content = PAGE.encode('utf-8')
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.send_header('Content-Length', len(content))
self.end_headers()
self.wfile.write(content)
# 访问192.168.137.100:8000/stream.mjpg 则尝试从output.frame中获取帧数据 并传输数据流到客户端
elif self.path == '/stream.mjpg':
self.send_response(200)
self.send_header('Age', 0)
self.send_header('Cache-Control', 'no-cache, private')
self.send_header('Pragma', 'no-cache')
self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
self.end_headers()
try:
while True:
with output.condition:
output.condition.wait()
frame = output.frame
# 如果分辨率小的话可以用 opencv 做一些图像处理功能frame
self.wfile.write(b'--FRAME\r\n')
self.send_header('Content-Type', 'image/jpeg')
self.send_header('Content-Length', len(frame))
self.end_headers()
self.wfile.write(frame)
self.wfile.write(b'\r\n')
except Exception as e:
logging.warning(
'Removed streaming client %s: %s',
self.client_address, str(e))
else:
self.send_error(404)
self.end_headers()
# 创建SteamingServer类 继承socketserver.ThreadingMixIn server.HTTPServer
class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
# 允许服务器地址重用
allow_reuse_address = True
# 使用守护线程
daemon_threads = True
# 初始化 Picamera2
picam2 = Picamera2()
# 设置相机为视频捕获模式 分辨率 设置为3240 2464
picam2.configure(picam2.create_video_configuration(main={"size": (3240, 2464)}))
# 定义编码器视频输出对象
output = StreamingOutput()
# 启动摄像头编码 jpeg格式 输出到output对象 输出质量最高
picam2.start_recording(JpegEncoder(), FileOutput(output),quality=Quality.VERY_HIGH)
try:
#ip改为树莓派ip
address = ('192.168.137.100', 8000)
# 启动服务器 并监听指定地址请求 使用StreamingHandler来处理请求
server = StreamingServer(address, StreamingHandler)
server.serve_forever()
finally:
# 关闭编码输出
picam2.stop_recording()
在浏览器输入ip:8000即可预览视频窗口,使用opencv可以打开相应视频流。
cap.open("http://192.168.137.110:8000/stream.mjpg"); // 打开相机设备,0代表默认相机设备
cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));
示例代码链接:https://github.com/raspberrypi/picamera2/blob/main/tests/mjpeg_server.py
Picamera2 手册 picamera2-manual.pdf (raspberrypi.com)