在Flask和YOLOv5结合的HTML网页开发场景中,摄像头画面能正常加载但检测框不显示是高频问题,需要从前后端全链路排查原因。

常见原因排查
1. 前端画布绘制逻辑错误
很多开发者会把摄像头画面渲染到video标签,但检测框需要绘制在覆盖video的canvas标签上,如果canvas尺寸和video不匹配,或者绘制时机错误,就会导致检测框看不到。
首先要确保canvas和video标签尺寸一致,且canvas覆盖在video上方:
<div class="video-container">
<video id="video" autoplay playsinline></video>
<canvas id="canvas"></canvas>
</div>
<style>
.video-container {
position: relative;
width: 640px;
height: 480px;
}
#video, #canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>2. 后端返回的检测框坐标格式错误
YOLOv5推理返回的检测框坐标通常是归一化的(0-1之间),如果直接把这类坐标传给前端绘制,就会因为数值太小看不到框。需要后端先转换为实际像素坐标。
下面是Flask后端处理YOLOv5检测结果的示例代码:
from flask import Flask, request, jsonify
import torch
import cv2
import numpy as np
app = Flask(__name__)
model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True)
@app.route('/detect', methods=['POST'])
def detect():
# 接收前端传来的帧数据
file = request.files['frame']
img_bytes = file.read()
nparr = np.frombuffer(img_bytes, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
# 获取画面尺寸
h, w = img.shape[:2]
# YOLOv5推理
results = model(img)
detections = results.pandas().xyxy[0].to_dict('records')
# 转换坐标为像素值,同时返回类别和置信度
formatted_detections = []
for det in detections:
formatted_detections.append({
'x1': int(det['xmin']),
'y1': int(det['ymin']),
'x2': int(det['xmax']),
'y2': int(det['ymax']),
'class': det['name'],
'conf': round(det['confidence'], 2)
})
return jsonify({'detections': formatted_detections})3. 前端绘制检测框的时机不对
检测框需要在每一帧画面渲染完成后立即绘制,如果绘制时机滞后于画面更新,就会出现框和画面不同步甚至看不到的情况。
正确的前端绘制逻辑示例:
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 设置canvas尺寸和video一致
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
// 每一帧都执行绘制
function drawFrame() {
// 先清空上一帧的框
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 这里可以调用接口获取当前帧的检测结果,假设已经拿到detections数组
if (window.currentDetections) {
window.currentDetections.forEach(det => {
// 绘制矩形框
ctx.strokeStyle = '#00ff00';
ctx.lineWidth = 2;
ctx.strokeRect(det.x1, det.y1, det.x2 - det.x1, det.y2 - det.y1);
// 绘制类别和置信度
ctx.fillStyle = '#00ff00';
ctx.font = '16px Arial';
ctx.fillText(`${det.class} ${det.conf}`, det.x1, det.y1 - 5);
});
}
requestAnimationFrame(drawFrame);
}
// 启动绘制循环
video.addEventListener('loadeddata', () => {
drawFrame();
});4. 跨域或接口数据未正确传递
如果前端和后端不在同一个域,可能会因为跨域问题导致检测结果无法正确获取,进而无法绘制框。需要在Flask中配置跨域:
from flask_cors import CORS app = Flask(__name__) CORS(app) # 允许所有跨域请求,生产环境可配置指定域名
问题定位步骤
可以按照以下步骤快速定位问题:
- 先在前端打印接口返回的检测结果,确认是否有正确的坐标数据
- 用固定坐标在canvas上绘制一个矩形,确认canvas绘制功能正常
- 检查video和canvas的尺寸是否完全一致,避免坐标偏移
- 确认绘制循环是否在每一帧都执行,没有被阻塞
按照以上步骤排查,基本可以解决大部分摄像头检测框不显示的问题,核心是保证前后端坐标格式统一、绘制逻辑正确、数据交互通畅。