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

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

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


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

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

python 复制代码
# 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("摄像头初始化失败,请检查连接!")

树莓派上运行该代码:

bash 复制代码
python3 stream_server.py

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

bash 复制代码
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始终在运行的。

python 复制代码
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)

显示界面如下:

相关推荐
AIFQuant1 小时前
2026 全球股市实时行情数据 API 对比指南
python·websocket·金融·数据分析·restful
南梦浅1 小时前
Flask+Gunicorn+Nginx 校园众筹项目部署全流程(生产环境)
nginx·flask·gunicorn
3DVisionary1 小时前
告别传统检具:蓝光3D扫描开启精密模具“数字化质检”新模式
人工智能·3d·数字化转型·质量控制·蓝光3d扫描·精密模具·可溯源
deephub1 小时前
RAG 检索模型如何学习:三种损失函数的机制解析
人工智能·深度学习·损失函数·信息检索·rag
方见华Richard2 小时前
伦理量子信息学:九元原子的量子信息实现
人工智能·经验分享·交互·原型模式·空间计算
Elastic 中国社区官方博客2 小时前
Elasticsearch:监控 LLM 推理和 Agent Builder 使用 OpenRouter
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
高频交易dragon2 小时前
Hawkes LOB Market从论文到生产
人工智能·算法·金融
CoderIsArt2 小时前
AI代码编辑器详细实现步骤
人工智能·编辑器
无心水2 小时前
2、Go语言源码文件组织与命令源码文件实战指南
开发语言·人工智能·后端·机器学习·golang·go·gopath