使用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)

显示界面如下:

相关推荐
北京耐用通信16 分钟前
全域适配工业场景耐达讯自动化Modbus TCP 转 PROFIBUS 网关轻松实现以太网与现场总线互通
网络·人工智能·网络协议·自动化·信息与通信
火山引擎开发者社区19 分钟前
TRAE × 火山引擎 Supabase:为你的 AI 应用装上“数据引擎”
人工智能
小a彤1 小时前
GE 在 CANN 五层架构中的位置
人工智能·深度学习·transformer
前端若水1 小时前
会话管理:创建、切换、删除对话历史
前端·人工智能·python·react.js
Upsy-Daisy1 小时前
AI Agent 项目学习笔记(八):Tool Calling 工具调用机制总览
人工智能·笔记·学习
企学宝1 小时前
企学宝5月专题课程丨《OpenClaw AI 智能体实战营:从零基础部署到全场景自动化落地》
人工智能·ai·企业培训
冬奇Lab2 小时前
让 AI Agent 更可靠:Harness Engineering 与多 Agent 系统工程实践
人工智能·llm·agent
放下华子我只抽RuiKe52 小时前
React 从入门到生产(四):自定义 Hook
前端·javascript·人工智能·深度学习·react.js·自然语言处理·前端框架
想你依然心痛2 小时前
HarmonyOS 6(API 23)实战:基于悬浮导航、沉浸光感与HMAF的“文思智脑“——PC端AI智能体沉浸式智能写作工作台
人工智能·ar·harmonyos·ai写作
冬奇Lab2 小时前
一天一个开源项目(第108篇):Andrej Karpathy Skills - 用一个 CLAUDE.md 文件修复 LLM 编码的四个顽疾
人工智能·开源·资讯