前端代码:
index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>YOLOv8 Video Stream</title><style>body {display: flex;justify-content: center;align-items: center;flex-direction: column;height: 100vh;margin: 0;background-color: #f0f0f0;}img {max-width: 100%;height: auto;border: 2px solid #ddd;border-radius: 8px;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);}table {width: 100%;border-collapse: collapse;margin-top: 20px;}table, th, td {border: 1px solid black;}th, td {padding: 10px;text-align: left;}th {background-color: #f2f2f2;}</style>
</head>
<body><h1>YOLOv8 实时检测</h1><img src="{{ url_for('video_feed') }}"><h2>检测到的目标信息</h2><table id="objects-table"><thead><tr><th>类别</th><th>坐标</th><th>置信度</th><th>时间</th></tr></thead><tbody></tbody></table><script>// 定时从后端获取检测到的目标信息function fetchDetectedObjects() {fetch('/get_detected_objects').then(response => response.json()).then(data => {// 获取表格的主体部分const tableBody = document.querySelector("#objects-table tbody");tableBody.innerHTML = ''; // 清空表格内容// 遍历检测到的对象并插入表格data.forEach(item => {const row = document.createElement("tr");row.innerHTML = `<td>${item.class}</td><td>[${item.coordinates.map(coord => coord.toFixed(2))}]</td><td>${(item.confidence * 100).toFixed(2)}%</td><td>${item.time}</td>`;tableBody.appendChild(row);});}).catch(error => console.error('Error fetching detected objects:', error));}// 每1秒更新一次目标信息表格setInterval(fetchDetectedObjects, 1000);</script>
</body>
</html>
后端代码
app.py
from flask import Flask, render_template, Response, jsonify
import cv2
from ultralytics import YOLO
import datetimeapp = Flask(__name__)# 初始化YOLOv8模型
model = YOLO("yolov8n.pt")# 使用OpenCV打开摄像头
camera = cv2.VideoCapture(0)# 实时目标信息
detected_objects = []def gen_frames(): global detected_objectswhile True:success, frame = camera.read() # 从摄像头读取一帧if not success:breakelse:# 使用YOLOv8模型进行目标检测results = model(frame)annotated_frame = results[0].plot() # 获取渲染后的检测结果图像# 获取检测结果并存储类别、坐标、置信度和当前时间detected_objects = []for box in results[0].boxes:# 获取检测到的类别、坐标和置信度class_name = results[0].names[int(box.cls[0])]xyxy = box.xyxy[0].cpu().numpy().tolist()confidence = float(box.conf[0]) # 获取置信度timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")detected_objects.append({"class": class_name,"coordinates": xyxy,"confidence": confidence,"time": timestamp})# 将检测结果转换为JPEG格式ret, buffer = cv2.imencode('.jpg', annotated_frame)frame = buffer.tobytes()# 使用yield生成器传输图像到前端yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')@app.route('/video_feed')
def video_feed():# 视频流路由return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')@app.route('/get_detected_objects')
def get_detected_objects():# 返回当前检测到的目标信息return jsonify(detected_objects)@app.route('/')
def index():# 主页面路由return render_template('index.html')if __name__ == '__main__':app.run(debug=True)