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

如何从TensorFlowJS目标检测模型输出中提取bounding box、类别与得分?

你调用的SSD MobileNet V2 TF.js版本返回的两个张量分别对应检测得分和候选框,需要额外做非极大值抑制(NMS)过滤,就能拿到你要的边界框、类别标签、得分三个参数,修改代码如下:

function getMethods(o) {
    return Object.getOwnPropertyNames(Object.getPrototypeOf(o))
        .filter(m => 'function' === typeof o[m]);
}

// COCO数据集类别标签映射,可根据需要补全全量90类标签
const COCO_CLASSES = [
    'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
    'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow'
    // 剩余类别可自行搜索COCO类别列表补全
]

const model = await tf.loadGraphModel("https://tfhub.dev/tensorflow/tfjs-model/ssd_mobilenet_v2/1/default/1", {fromTFHub: true});
console.log("Get methods");
console.log(getMethods(model));

const cat = document.getElementById('cat');
let tensor = tf.browser.fromPixels(cat);
tensor = tf.cast(tensor, 'int32');
let y_pred = await model.executeAsync({'image_tensor': tensor.expandDims(0)});

// 解构返回结果:第一个是得分张量,第二个是边界框张量
const [scoresTensor, boxesTensor] = y_pred;

// 去掉张量多余的空维度
const scores = tf.squeeze(scoresTensor);
const boxes = tf.squeeze(boxesTensor);

// 执行非极大值抑制,过滤重复、低置信度的候选框
const nmsResults = await tf.image.nonMaxSuppressionAsync(
    boxes, // 所有候选框
    tf.max(scores, 1), // 每个候选框的最高置信度
    20, // 最多返回的检测框数量
    0.5, // IOU过滤阈值
    0.5 // 最低置信度阈值
);

// 将张量转为普通JS数组方便后续处理
const boxesData = await boxes.array();
const scoresData = await scores.array();
const validIndices = await nmsResults.array();

// 遍历有效索引组装最终检测结果
const finalDetections = validIndices.map(idx => {
    const [ymin, xmin, ymax, xmax] = boxesData[idx];
    // 将归一化坐标转为图片实际像素坐标
    const imgWidth = cat.width;
    const imgHeight = cat.height;
    const bbox = {
        x: Math.round(xmin * imgWidth),
        y: Math.round(ymin * imgHeight),
        width: Math.round((xmax - xmin) * imgWidth),
        height: Math.round((ymax - ymin) * imgHeight)
    };
    const maxScore = Math.max(...scoresData[idx]);
    const classId = scoresData[idx].indexOf(maxScore);
    const className = COCO_CLASSES[classId] || 'unknown';
    return {
        bbox,
        className,
        score: maxScore
    }
});

console.log('最终检测结果:', finalDetections);

// 使用完成后释放张量内存,避免页面内存泄漏
tf.dispose([tensor, y_pred, scoresTensor, boxesTensor, scores, boxes, nmsResults]);

补充说明

  • 返回的第一个张量形状[1, 1917, 90],其中90对应COCO数据集的90个类别,每个候选框对应90个类别的置信度
  • 返回的第二个张量形状[1, 1917, 1, 4],最后一维的4个值是归一化的边界框坐标[ymin, xmin, ymax, xmax],范围在0~1之间,需要乘图片实际宽高才能得到对应像素坐标
  • 非极大值抑制是必须步骤,用来过滤模型输出的大量重复候选框,只保留置信度最高的有效结果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 12:51:03