close
使用 Flask 和 Picamera2 打造 YOLO 即時物件偵測網頁介面
前言
隨著物聯網(IoT)和人工智慧(AI)的普及,即時物件偵測已成為許多應用中的核心功能。今天,我將帶你在 Raspberry Pi 上使用 Flask 和 Picamera2 模組,搭配 YOLO 模型,實現即時影像偵測,並在網頁上顯示影像流和檢測資訊。
透過這篇教學,你將學會:
- 如何安裝 Flask 與 YOLO 環境。
- 使用 Picamera2 從 Raspberry Pi 相機捕捉影像。
- 將即時影像與 YOLO 偵測結果透過 Flask 提供網頁串流。
- 在網頁上加入按鈕來暫停/恢復影像流,以及顯示檢測資訊。
準備工作
硬體需求:
- Raspberry Pi 4 或 5
- Raspberry Pi 相機(支援 Picamera2 模組)
- 網路連接(本地網路)
軟體需求:
- Raspberry Pi OS(推薦最新版)
- Python 3(已預裝)
- Flask、OpenCV 和 YOLO 模型相關套件
步驟一:安裝必要的套件
首先,確保 Raspberry Pi 已更新系統軟體,並安裝所需的 Python 套件。
更新系統與套件:
sudo apt update
sudo apt upgrade -y
啟用虛擬環境
source venv/bin/activate
安裝 Python 套件:
pip install flask opencv-python numpy ultralytics picamera2
下載 YOLO 模型:
我們使用輕量級的 YOLO 模型 yolov8n.pt
。從 Ultralytics 官方 下載,並將模型放在專案目錄中。
步驟二:撰寫 Flask 和 YOLO 應用程式
我們的 Flask 應用會:
- 使用 Picamera2 從攝像頭捕捉影像。
- 使用 YOLO 模型進行物件偵測。
- 提供一個網頁介面顯示即時影像流。
- 顯示偵測資訊並提供按鈕來控制暫停和恢復功能。
完整程式碼:
from flask import Flask, Response, render_template_string, jsonify import cv2 import numpy as np from ultralytics import YOLO from picamera2 import Picamera2 import threading import time app = Flask(__name__) # Load the YOLOv8 model model = YOLO("yolov8n.pt") # Global variables for control and information sharing is_paused = False lock = threading.Lock() latest_info = [] # Function to initialize and start the camera def initialize_camera(): picam2 = Picamera2() picam2.configure(picam2.create_preview_configuration(main={"size": (640, 480)})) picam2.start() return picam2 # Generate video frames for streaming def generate_frames(): global is_paused, latest_info while True: with lock: if is_paused: time.sleep(0.1) # Sleep briefly to prevent tight loop when paused continue try: with initialize_camera() as camera: frame = camera.capture_array() # Check if the image has 4 channels and convert to 3 channels if necessary if frame.shape[2] == 4: frame = cv2.cvtColor(frame, cv2.COLOR_BGRA2BGR) results = model.predict(source=frame, stream=True) temp_info = [] for result in results: boxes = result.boxes.xyxy.numpy() for box, cls, conf in zip(boxes, result.boxes.cls.numpy(), result.boxes.conf.numpy()): x1, y1, x2, y2 = map(int, box) label = f"{model.names[int(cls)]}: {conf:.2f}" temp_info.append(label) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) with lock: latest_info = temp_info _, buffer = cv2.imencode('.jpg', frame) yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + buffer.tobytes() + b'\r\n') except RuntimeError as e: print(f"RuntimeError: {e}") time.sleep(1) # Wait before retrying to avoid rapid repeated failures # Main page route @app.route('/') def index(): return render_template_string(''' <!doctype html> <html> <head> <title>Live YOLOv8 Object Detection</title> <script> setInterval(() => { fetch('/latest_info') .then(response => response.json()) .then(data => { document.getElementById('info').innerText = "Detected: " + data.join(', '); }); }, 1000); function pause() { fetch('/pause', { method: 'POST' }).then(() => alert('Paused')); } function resume() { fetch('/resume', { method: 'POST' }).then(() => alert('Resumed')); } </script> </head> <body> <h1>Live YOLOv8 Object Detection</h1> <img src="/video_feed" width="640" height="480"> <div id="info">Detection Info: </div> <button onclick="pause()">Pause</button> <button onclick="resume()">Resume</button> </body> </html> ''') # Video feed route @app.route('/video_feed') def video_feed(): return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame') # Pause route @app.route('/pause', methods=['POST']) def pause(): global is_paused with lock: is_paused = True return jsonify({"status": "paused"}) # Resume route @app.route('/resume', methods=['POST']) def resume(): global is_paused with lock: is_paused = False return jsonify({"status": "resumed"}) # Latest info route @app.route('/latest_info') def latest_info_route(): with lock: return jsonify(latest_info) # Run the Flask app if __name__ == "__main__": app.run(host="0.0.0.0", port=5000, debug=True)
步驟三:運行應用程式
運行 Flask 伺服器:
python app.py
在瀏覽器中訪問:
打開瀏覽器,輸入 Raspberry Pi 的 IP 和埠號:
http://<Raspberry_Pi_IP>:5000
結果展示
- 影像流:網頁上顯示實時物件偵測畫面。
- 偵測資訊:在文字框中即時顯示 YOLO 偵測到的物件類別和置信度。
結語
透過 Flask 和 Picamera2,我們實現了一個功能齊全的 YOLO 物件偵測網頁應用。不僅可以即時顯示影像流,還加入了用戶互動功能,讓你能夠暫停/恢復檢測,並即時顯示檢測資訊。
全站熱搜