You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ONNX.js处理目标检测模型输出获取边界框与置信度?

解析ONNX.js目标检测模型的输出结果

我完全理解你的困扰——ONNX.js相关的目标检测输出解析资料确实远不如Python生态丰富,不过别担心,我来帮你一步步拆解怎么从模型输出里提取 bounding box 坐标和置信度。

首先要明确:不同的目标检测模型(比如YOLO系列、Faster R-CNN/SSD系列)输出结构差异很大,我们先从最常见的两种情况入手,再给你调试建议。

第一步:先明确你的模型类型

先在代码里加一行,打印输出张量的维度,这能帮你快速判断模型类型:

console.log("输出张量维度:", outputData.dims);

比如YOLOv5/v8的输出维度通常是[1, 25200, 85](1是batch数,25200是检测框数量,85是每个框的信息:4个坐标+1个置信度+80个类别分数);而Faster R-CNN/SSD类模型会输出多个张量,你需要从outputMap里按键名取出对应的boxes、scores、labels。


情况1:YOLO系列模型(YOLOv5/v8等)

如果你的输出维度是[1, N, 5+num_classes],那可以用下面的代码解析:

const outputArray = outputData.data; // 获取float32类型的原始数据
const [batchSize, numBoxes, boxInfoLength] = outputData.dims;

// 遍历所有检测框,过滤低置信度的结果
for (let i = 0; i < numBoxes; i++) {
  const startIdx = i * boxInfoLength;
  // 提取YOLO格式的原始输出:中心坐标、宽高、置信度
  const xCenter = outputArray[startIdx];
  const yCenter = outputArray[startIdx + 1];
  const boxWidth = outputArray[startIdx + 2];
  const boxHeight = outputArray[startIdx + 3];
  const confidence = outputArray[startIdx + 4];

  // 过滤置信度低于阈值的框(这里用0.5,你可以自己调整)
  if (confidence < 0.5) continue;

  // 将YOLO的中心坐标+宽高,转换成左上角(xMin,yMin)和右下角(xMax,yMax)
  // 注意:YOLO的输出是归一化到[0,1]的,需要乘以输入图像的尺寸
  const inputSize = imageSize; // 你的输入图像尺寸(和预处理时一致)
  const xMin = (xCenter - boxWidth / 2) * inputSize;
  const yMin = (yCenter - boxHeight / 2) * inputSize;
  const xMax = (xCenter + boxWidth / 2) * inputSize;
  const yMax = (yCenter + boxHeight / 2) * inputSize;

  // 提取类别分数,找到置信度最高的类别
  const classScores = outputArray.slice(startIdx + 5, startIdx + boxInfoLength);
  const classIndex = classScores.indexOf(Math.max(...classScores));
  const classScore = classScores[classIndex];

  // 打印结果,或者存入数组后续处理
  console.log(`检测到目标:
    置信度:${confidence.toFixed(2)}
    类别索引:${classIndex}
    坐标:(${xMin.toFixed(0)}, ${yMin.toFixed(0)}) → (${xMax.toFixed(0)}, ${yMax.toFixed(0)})`);
}

情况2:Faster R-CNN/SSD系列模型

这类模型的输出通常是多个独立的张量,你需要从outputMap中按键名取出(键名可能是detection_boxes、detection_scores、detection_classes,具体要看模型导出时的设置):

// 从输出映射中取出对应的张量
const boxesTensor = outputMap.get('detection_boxes');
const scoresTensor = outputMap.get('detection_scores');
const labelsTensor = outputMap.get('detection_classes');

if (!boxesTensor || !scoresTensor) {
  console.error("未找到检测框或置信度张量,请检查模型输出键名");
  return;
}

const boxes = boxesTensor.data;
const scores = scoresTensor.data;
const labels = labelsTensor.data;
const numBoxes = boxesTensor.dims[0];

for (let i = 0; i < numBoxes; i++) {
  const score = scores[i];
  if (score < 0.5) continue; // 过滤低置信度

  // 注意:这类模型的坐标通常是[yMin, xMin, yMax, xMax]的顺序,且归一化到[0,1]
  const yMin = boxes[i * 4] * imageSize;
  const xMin = boxes[i * 4 + 1] * imageSize;
  const yMax = boxes[i * 4 + 2] * imageSize;
  const xMax = boxes[i * 4 + 3] * imageSize;
  const label = labels[i];

  console.log(`检测到目标:
    置信度:${score.toFixed(2)}
    类别:${label}
    坐标:(${xMin.toFixed(0)}, ${yMin.toFixed(0)}) → (${xMax.toFixed(0)}, ${yMax.toFixed(0)})`);
}

关键调试技巧

  1. 确认输出键名:如果是多输出模型,打印outputMap.keys()看看所有可用的键:
    console.log("所有输出键名:", Array.from(outputMap.keys()));
    
  2. 匹配预处理逻辑:确保你的preprocess函数和模型训练时的预处理一致(比如是否将图像归一化到0-1,是否转换了RGB/BGR通道),否则输出的坐标和置信度会不准确。
  3. 坐标反归一化:几乎所有模型的输出坐标都是归一化到[0,1]的,一定要乘以输入图像的实际尺寸才能得到真实像素坐标。

内容的提问来源于stack exchange,提问作者Aakash Bhadana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 16:53:15