前端代码:
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 datetime
app = Flask(__name__)
# 初始化YOLOv8模型
model = YOLO("yolov8n.pt")
# 使用OpenCV打开摄像头
camera = cv2.VideoCapture(0)
# 实时目标信息
detected_objects = []
def gen_frames():
global detected_objects
while True:
success, frame = camera.read() # 从摄像头读取一帧
if not success:
break
else:
# 使用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)