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

显示界面如下:

相关推荐
董董灿是个攻城狮28 分钟前
大模型连载1:了解 Token
人工智能
雨中飘荡的记忆32 分钟前
ElasticJob分布式调度从入门到实战
java·后端
Se7en2581 小时前
推理平台全景
后端
大漠_w3cpluscom1 小时前
你学不会 CSS,不是笨,是方向错了
后端
花酒锄作田2 小时前
使用 pkgutil 实现动态插件系统
python
RoyLin3 小时前
沉睡三十年的标准:HTTP 402、生成式 UI 与智能体原生软件的时代
人工智能
cipher4 小时前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
needn5 小时前
TRAE为什么要发布SOLO版本?
人工智能·ai编程
毅航5 小时前
自然语言处理发展史:从规则、统计到深度学习
人工智能·后端