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

显示界面如下:

相关推荐
寻星探路9 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
想用offer打牌10 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
Codebee10 小时前
能力中心 (Agent SkillCenter):开启AI技能管理新时代
人工智能
聆风吟º11 小时前
CANN runtime 全链路拆解:AI 异构计算运行时的任务管理与功能适配技术路径
人工智能·深度学习·神经网络·cann
KYGALYX11 小时前
服务异步通信
开发语言·后端·微服务·ruby
uesowys11 小时前
Apache Spark算法开发指导-One-vs-Rest classifier
人工智能·算法·spark
AI_567811 小时前
AWS EC2新手入门:6步带你从零启动实例
大数据·数据库·人工智能·机器学习·aws
掘了11 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
User_芊芊君子11 小时前
CANN大模型推理加速引擎ascend-transformer-boost深度解析:毫秒级响应的Transformer优化方案
人工智能·深度学习·transformer
ValhallaCoder11 小时前
hot100-二叉树I
数据结构·python·算法·二叉树