使用Flask在本地调用树莓派摄像头

发布时间:2026/10/28 9:39:01
使用Flask在本地调用树莓派摄像头

本文主要是记录如果在本地远程调用树莓派的摄像头,关于树莓派无线连接可以参考我另外一篇文章。

树莓派无线连接设置:树莓派4B无线设置


USB连接摄像头

本地环境为windows11操作系统,想通过网络远程调用树莓派上的摄像头(我这里的摄像头是通过USB连接在树莓派上的)

先在树莓派上新建一个video_steam.py的python脚本,代码如下。(这里的树莓派ip需要根据你实际情况进行配置,可以在树莓派中输入ifconfig进行查看设备ip)

# coding:utf-8 # video_stream.py - 在树莓派上运行 from flask import Flask, Response import cv2 import threading app = Flask(__name__) # 全局摄像头对象 camera = None frame_lock = threading.Lock() def init_camera(): """初始化摄像头""" global camera # 尝试不同的摄像头索引 for i in range(3): # 尝试0, 1, 2 print(f"尝试打开摄像头索引 {i}...") cap = cv2.VideoCapture(i) if cap.isOpened(): # 设置分辨率(可以调整) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) print(f"摄像头在索引 {i} 成功打开") camera = cap return True cap.release() print("错误:无法打开任何摄像头!") print("请检查:") print("1. 摄像头是否正确连接") print("2. 树莓派是否识别到摄像头(运行 ls /dev/video* 查看)") print("3. 如果有 /dev/video0,尝试修改代码中的摄像头索引") return False def generate_frames(): """生成视频帧的生成器函数""" global camera while True: with frame_lock: if camera is None: print("摄像头未初始化") break success, frame = camera.read() if not success: print("读取摄像头帧失败") break else: # 压缩图像以减小传输大小 ret, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 80]) if ret: # 转换为字节 frame_bytes = buffer.tobytes() # 使用MJPEG格式流 yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n') @app.route('/') def index(): """主页,显示一个简单的测试页面""" return """ <html> <head><title>树莓派摄像头</title></head> <body> <h1>树莓派摄像头实时视频</h1> <img src="/video_feed" width="640" height="480"> <p>如果看到这个图像,说明视频流服务器正在运行。</p> <p>在你的电脑上使用OpenCV程序连接这个视频流。</p> </body> </html> """ @app.route('/video_feed') def video_feed(): """视频流路由""" return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame') if __name__ == '__main__': print("正在初始化摄像头...") if init_camera(): print("摄像头初始化成功!") print(f"服务器将在 http://[你的树莓派IP]:5000 运行") print("按 Ctrl+C 停止服务器") try: # 启动Flask服务器 # 注意:在局域网中其他设备访问时,需要用树莓派的实际IP app.run(host='192.168.1.51', port=5000, debug=False, threaded=True) except KeyboardInterrupt: print("\n正在关闭服务器...") finally: # 释放摄像头资源 if camera is not None: camera.release() print("摄像头已释放") else: print("摄像头初始化失败,请检查连接!")

在树莓派上运行该代码:

python3 stream_server.py

此时出现以下内容说明运行成功:

pi@raspberrypi:~/Videos $ python3 stream_server.py 正在初始化摄像头... 尝试打开摄像头索引 0... 摄像头在索引 0 成功打开 摄像头初始化成功! 服务器将在 http://[你的树莓派IP]:5000 运行 按 Ctrl+C 停止服务器 * Serving Flask app "stream_server" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://192.168.1.51:5000/ (Press CTRL+C to quit)

然后你就可以本地电脑上输入以上地址来预览摄像头是否读取成功了。

以上是利用网页端进行测试查看在本地能否调用树莓派摄像头。

如果你希望使用opencv在本地调用树莓派摄像头,可在你本地新建一个python文件,输入以下代码,前提是必须保证你树莓派中stream_server.py始终在运行的。

import cv2 import requests import numpy as np PI_IP = "192.168.1.51" # 改成你的树莓派IP url = f"http://{PI_IP}:5000/video_feed" stream = requests.get(url, stream=True) bytes_buffer = bytes() print("按 'q' 退出") while True: for chunk in stream.iter_content(chunk_size=1024): bytes_buffer += chunk start = bytes_buffer.find(b'\xff\xd8') end = bytes_buffer.find(b'\xff\xd9') if start != -1 and end != -1: jpg = bytes_buffer[start:end + 2] bytes_buffer = bytes_buffer[end + 2:] frame = cv2.imdecode(np.frombuffer(jpg, dtype=np.uint8), cv2.IMREAD_COLOR) if frame is not None: cv2.imshow('树莓派摄像头', frame) if cv2.waitKey(1) & 0xFF == ord('q'): cv2.destroyAllWindows() exit(0)

显示界面如下:


CSI排线连接树莓派和摄像头

如果你使用CSI连接树莓派和摄像头,那么连接线是非常重要的!

1.树莓派端:金手指面向HDIM(背向网线口)

摄像头端:金手指面向电路板

2.连接树莓派,输入以下命令进行测试:

该命令会调用摄像头,然后本地保存一张图。

libcamera-still -o test.jpg -t 2000 --nopreview

如果无法保存,显示超时,重新接一下CSI线或者用橡皮擦把金手指擦一下。