跳转到内容

YOLO 推理结果

更新: 2026/3/2 字数: 0 字 时长: 0 分钟

YOLOResults 类是 YOLO 推理的核心返回对象,封装了所有推理结果及其相关操作方法。它支持目标检测、实例分割、图像分类、姿态估计和旋转框检测等多种任务,并提供数据转换、可视化、文件导出等丰富功能。

YOLOResults

YOLOResults, YOLO推理的结果集合, 通过Yolo.predict()方法返回的对象。 YOLOResults"继承"于数组,实际上是一个YOLOObject的数组,因此可以使用数组的函数和属性,例如使用size()方法获取YOLOResults的大小,使用forEach函数来遍历YOLOResults。 例如,采用forEach遍历屏幕上所有的文本控件并打印出文本内容的代码为:

js
var yoloResults = yolo.predict(image);
yoloResults.forEach(function(yoloObject){
    console.log("类别:", yoloObject.cls, "置信度:", yoloObject.conf);
});

例如,使用 for 循环来遍历结果并打印内容的示例代码

js
var yoloResults = yolo.predict(image);
for (var i = 0; i < yoloResults.size(); i++) {
    var yoloObject = yoloResults.get(i);
    console.log("类别:", yoloObject.cls, "置信度:", yoloObject.conf);
}

YOLOResults.path

  • path {string}

图像文件路径或标识符

YOLOResults.origShape

  • origShape {number[]}

原始图像尺寸数组 [height, width]

YOLOResults.names

  • names {string[]}

类别名称数组

YOLOResults.speed

推理速度统计信息

YOLOResults.isEmpty()

  • 返回 {boolean}

检查结果是否为空(无检测目标)

js
var yoloResults = yolo.predict(image);
if (yoloResults.isEmpty()) {
    console.log("未检测到任何目标");
}

YOLOResults.size()

  • 返回 {number}

返回检测目标数量

js
console.log("检测到 " + yoloResults.size() + " 个目标");

YOLOResults.get(index)

获取指定索引的目标对象。请确保索引在 [0, yoloResults.size()-1] 范围内。

js
for (var i = 0; i < yoloResults.size(); i++) {
    var obj = yoloResults.get(i);
    console.log("类别:", obj.cls, "置信度:", obj.conf);
}

⚠️ 若索引越界,会抛出异常。建议循环使用 size() 控制范围。


YOLOResults.iterator()

返回迭代器,支持 for-each 遍历

js
for (var obj of yoloResults) {
    console.log("类别:", obj.cls, "置信度:", obj.conf);
}

YOLOResults.getYoloObjects()

返回原始推理目标对象数组(可能为空数组,如果推理失败则数组长度为 0),用于一次性获取所有目标对象

js
var yoloObjects = yoloResults.getYoloObjects();
for (var i = 0; i < yoloObjects.length; i++) {
    var obj = yoloObjects[i];
    console.log("类别:", obj.cls, "置信度:", obj.conf);
}

YOLOResults.isSuccess()

  • 返回 {boolean}
    • true → 推理成功(可能未检测到任何目标)
    • false → 推理失败(模型加载失败或传入参数异常)

判断 YOLO 推理是否成功执行

⚠️ 此方法主要用于调试和异常检测。熟悉 YOLO API 后,可直接使用 YOLOResults.getYoloObjects() 遍历结果,无需每次判断。

js
if (!yoloResults.isSuccess()) {
    console.error("推理异常,请检查模型或参数");
}

💡 说明:

  • getYoloObjects() 永远返回数组,不会返回 null,避免 JS 端多余的 null 判断
  • 遍历时可直接用 for-of 或数组索引
  • isSuccess() 提供显式推理状态判断

YOLOResults.summary([options])

  • options {object} 配置,可选
    • normalize {boolean} 是否归一化,默认false
    • decimals {number} 小数位数,默认5
  • 返回 {Summary[]}

获取摘要对象数组

js
var summaries = yoloResults.summary({
    normalize: true,
    decimals: 3
});
// 遍历摘要信息
for (var i = 0; i < summaries.length; i++) {
  var summary = summaries[i];

  console.log("目标: " + summary.name + " (置信度: " + summary.confidence + ")");

  if (summary.box) {
    console.log("边界框: (" + summary.box.x1 + ", " + summary.box.y1 + ") - (" + summary.box.x2 + ", " + summary.box.y2 + ")");
  }
}

YOLOResults.boxes()

获取边界框检测结果(目标检测任务)非目标检测、实例分割、姿态估计任务时返回 null

js

var boxes = yoloResults.boxes();
if (boxes) {
  var xyxy = boxes.xyxy(); // 获取所有框的坐标,格式 [[x1, y1, x2, y2], ...]
  var classes = boxes.cls(); // 获取所有类别ID,格式 [0, 1, 0, ...]
  var confidences = boxes.conf(); // 获取所有置信度,格式 [0.87, 0.92, ...]

  for (var i = 0; i < xyxy.length; i++) {
    var box = xyxy[i];
    console.log(
      "框 #" +
        i +
        ": [" +
        box[0] +
        ", " +
        box[1] +
        ", " +
        box[2] +
        ", " +
        box[3] +
        "]" +
        " 类别: " +
        classes[i] +
        " 置信度: " +
        confidences[i]
    );
  }
} else {
    console.error("非目标检测、实例分割、姿态估计任务");
}

YOLOResults.masks()

获取分割掩码结果(实例分割任务)。非实例分割任务时返回 null

js
var masks = yoloResults.masks();
if (masks) {
  var xy = masks.xy(); // 获取原始坐标,格式 [[[x1, y1], [x2, y2], ...], ...]
  var xyn = masks.xyn(); // 获取归一化坐标,格式 [[[x1, y1], [x2, y2], ...], ...]

  for (var i = 0; i < xy.length; i++) {
    console.log("掩码 #" + i + ":");
    console.log("原始坐标:\n", JSON.stringify(xy[i], null, 4)); // 打印原始像素坐标
    console.log("归一化坐标:\n", JSON.stringify(xyn[i], null, 4)); // 打印归一化坐标
  }
} else {
  console.error("非实例分割任务");
}

YOLOResults.keypoints()

获取关键点检测结果(姿态估计任务)。非姿态估计任务时返回 null

js
var keypoints = yoloResults.keypoints();
if (keypoints) {
  var xy = keypoints.xy(); // [[ [x,y], ... ], ...]
  var conf = keypoints.conf(); // [[0.9, 0.85, ...], ...]

  for (var i = 0; i < xy.length; i++) {
    // 遍历每个目标
    console.log("目标 #" + i + " 关键点信息:");
    for (var j = 0; j < xy[i].length; j++) {
      // 遍历该目标的关键点
      console.log("  关键点 #" + j + ": [" + xy[i][j][0] + ", " + xy[i][j][1] + "]" + " 置信度: " + conf[i][j]);
    }
  }
} else {
  console.error("非姿态估计任务");
}

YOLOResults.obb()

  • 返回 {OBB | null}

获取旋转框检测结果(旋转框检测任务)。非旋转框检测任务时返回 null

js
var obb = yoloResults.obb();
if (obb) {
  var xywhr = obb.xywhr(); // 获取旋转框中心点、宽高和旋转弧度,格式 [[x, y, w, h, r], ...]
  var corners = obb.xyxyxyxy(); // 获取四个角点坐标,顺序: 右下 -> 右上 -> 左上 -> 左下,格式 [[ [x1,y1], [x2,y2], [x3,y3], [x4,y4] ], ...]

  for (var i = 0; i < xywhr.length; i++) {
    var radians = xywhr[i][4];

    // 弧度 → 角度
    var deg = (radians * 180) / Math.PI;

    console.log(
      "旋转框 #" +
        i +
        ": " +
        "中心点=(" +
        xywhr[i][0] +
        ", " +
        xywhr[i][1] +
        "), " +
        "宽=" +
        xywhr[i][2] +
        ", " +
        "高=" +
        xywhr[i][3] +
        ", " +
        "弧度=" +
        radians +
        ", " +
        "角度=" +
        deg.toFixed(2) +
        "°"
    );

    var c = corners[i];
    console.log("四角坐标 (右下 → 右上 → 左上 → 左下):");
    console.log("  右下: (" + c[0][0] + ", " + c[0][1] + ")");
    console.log("  右上: (" + c[1][0] + ", " + c[1][1] + ")");
    console.log("  左上: (" + c[2][0] + ", " + c[2][1] + ")");
    console.log("  左下: (" + c[3][0] + ", " + c[3][1] + ")");
    console.log("--------------------------------------------------");
  }
} else {
  console.error("非旋转框检测任务");
}

YOLOResults.probs()

获取分类概率结果(图像分类任务)。非图像分类任务时返回 null

js
var probs = yoloResults.probs();
if (probs) {
    var top1 = probs.top1();         // 获取 Top1 类别 ID
    var top1name = probs.top1name(); // 获取 Top1 类别名称
    var top1conf = probs.top1conf(); // 获取 Top1 置信度
    console.log("分类结果:", top1name, "置信度:", top1conf);
} else {
    console.error("当前任务不是分类任务,无分类结果");
}

YOLOResults.plot([options])

  • options {object}(可选)绘图配置
    • lineWidth {number} 边框线宽
    • fontSize {number} 字体大小
    • kptRadius {number} 关键点半径
    • showBoxes {boolean} 是否显示边界框
    • showLabels {boolean} 是否显示标签
    • showConf {boolean} 是否显示置信度
    • showMasks {boolean} 是否显示掩码
    • showKptLine {boolean} 是否显示关键点连线
    • classPalette {float[][]} 类别调色板
    • posePalette {float[][]} 姿态调色板
    • skeleton {int[][]} 骨架连接
    • limbColor {int[]} 骨骼颜色
    • kptColor {int[]} 关键点颜色
    • save {boolean} 是否保存图像
    • fileName {string} 保存的文件名
  • 返回 {Image | null}
    绘制检测结果并返回图像包装器
js
// 简单绘制
var img = yoloResults.plot();
js
// 带配置绘制
var img = yoloResults.plot({
  lineWidth: 10,
  fontSize: 28,
  showLabels: true,
  showConf: false,
  save: true,
  fileName: "plot.png",
});

YOLOResults.show()

  • 返回 {FloatImage}
    显示检测结果(悬浮窗显示)
js
var floatImage = yoloResults.show();
floatImage.setTitle("YOLO 推理");
floatImage.setPosition(100, 100);
floatImage.setSize(device.width * 0.8, device.height * 0.8);
sleep(2000);
floatImage.close();

YOLOResults.save([path])

  • path {string}(可选)保存路径
  • 返回 {boolean}

保存检测结果图像

保存到默认路径

js

yoloResults.save();

保存到指定路径

js
yoloResults.save("/sdcard/output/detection.png");

YOLOResults.orig()

  • 返回 {Image | null}
    获取原始图像的Image对象
js
var origImg = yoloResults.orig();

YOLOResults.recycleOrig()

回收检测结果对应的原始图像资源,释放内存占用

注意

  1. images.captureScreen() 截屏获取的 Image 对象为自动回收资源,禁止调用此方法,否则会触发运行时错误
  2. 非截屏场景的自定义图像资源,建议在使用完毕后及时调用此方法释放,避免内存泄漏
js
yoloResults.recycleOrig();

YOLOResults.recycle()

回收检测结果图像资源(由 YOLO 框架创建的绘制图),释放内存占用

使用要求: 当满足以下任一条件时,会生成绘制图Image对象资源,使用完毕后必须调用此方法回收,避免内存泄漏:

  1. 推理选项中设置 show: truesave: true
  2. 主动调用 YOLOResults.plot() 生成绘制图
  3. 主动调用 YOLOResults.show() 显示绘制图
  4. 主动调用 YOLOResults.save([path]) 保存检测结果图
js
yoloResults.recycle();

YOLOResults.recyclePlot()

回收检测结果图像资源,释放内存占用,和YOLOResults.recycle()一样

YOLOResults.recycleAll()

回收原图 + 绘制图的图像资源,释放内存占用,是多场景下的快捷回收方法。

相当于YOLOResults.recycleOrig()+YOLOResults.recyclePlot()

适用场景: 本地/网络图片推理、视频帧推理、相机帧推理场景,可一次性完成所有图像资源回收,简化代码编写

js
yoloResults.recycleAll();

提示

系统截屏 images.captureScreen() 推理场景禁止调用YOLOResults.recycleAll()方法,否则会因回收系统托管的原图触发错误,此类场景仅需调用 YOLOResults.recycle() 即可

YOLOResults.verbose()

  • 返回 {string}
    获取简洁的结果摘要字符串
js
console.log(yoloResults.verbose());
// 输出: "4 persons, 1 car, 2 traffic lights"

YOLOResults.verbosePredict()

  • 返回 {string}

获取详细预测结果字符串

js
console.log(yoloResults.verbosePredict());
// 输出: "640x480 4 persons, 1 car, 2 traffic lights, 184.9ms"

YOLOResults.verboseSpeed()

  • 返回 {string}

获取速度统计字符串

js
console.log(yoloResults.verboseSpeed());
// 输出: "Speed: 184.9ms preprocess, 45.6ms inference, 12.3ms postprocess per image at shape (1, 3, 640, 480)"

YOLOResults.verboseSaved()

  • 返回 {string}

获取保存成功信息

js
console.log(yoloResults.verboseSaved());
// 输出: "Results saved to /sdcard/YOLO/runs/detect/exp"

YOLOResults.verboseCamera()

  • 返回 {string}

获取相机详细的预测结果字符串

js
console.log(yoloResults.verboseCamera());
// 输出: 0: 640x480 1 person, 1 cell phone 123.4ms

YOLOResults.saveTxt([options])

  • options {Object} 可选

    • path {string} 可选,保存的文件路径,默认为 results.txt
    • saveConf {boolean} 可选,是否保存置信度,默认为 false
  • 返回 {boolean}

将数据保存为 YOLO 格式标签文件.txt

每行表示一个检测目标:class centerX centerY width height [confidence]

js

yoloResults.saveTxt({
    path: "/sdcard/results.txt",
    saveConf: true
});

YOLOResults.toDf([options])

  • options {object}(可选)DataFrame配置
    • normalize {boolean} 是否归一化坐标,可选,默认false
    • decimals {number} 小数位数,可选,默认5
  • 返回 {DataFrame}

转换为DataFrame格式

js
// 默认像素坐标
var df = yoloResults.toDf();
console.log("\nCSV (pixel):\n" + df.toCsv()); // 输出实际像素坐标

// 使用归一化坐标
var df2 = yoloResults.toDf({ normalize: true, decimals: 3 });
console.log("\nCSV (normalize):\n" + df2.toCsv()); // 输出归一化坐标(0~1)

YOLOResults.toJson()

  • 返回 {Array}

转换为JSON格式。

js
// 获取JSON数组
var json = yoloResults.toJson();
console.log(json);

YOLOResults.toJson(path)

  • path {string} 保存的文件路径。

  • 返回 {boolean}

JSON格式的数据保存到指定文件。

js
// 保存到文件
yoloResults.toJson("/sdcard/results.json");

YOLOResults.toCsv([options])

  • options {object} 配置,可选
    • normalize {boolean} 是否归一化坐标,可选,默认false
    • decimals {number} 小数位数,可选,默认5
    • index: CSV 表格中是否显示行索引列,可选,默认true
  • 返回 {string}

转换为 CSV 格式字符串。

js
var csv = yoloResults.toCsv({
  normalize: false,
  index: false,
  decimals: 2,
});
console.log(csv);

YOLOResults.toCsv(options)

  • options {object} 配置
    • path: 保存的路径
    • normalize {boolean} 是否归一化坐标,可选,默认false
    • decimals {number} 小数位数,可选,默认5
    • index: CSV 表格中是否显示行索引列,可选,默认true
  • 返回 {boolean}

保存为 CSV 文件。

js
yoloResults.toCsv({
    path: "/sdcard/results.csv",
    normalize: true,
    index: true
});

YOLOResults.toXml([options])

  • options {object} 配置,可选
    • normalize {boolean} 是否归一化坐标,可选,默认false
    • decimals {number} 小数位数,可选,默认5
    • index: XML 表格中是否显示行索引列,可选,默认true
  • 返回 {string}

转换为 XML 格式字符串。

js
var xml = yoloResults.toXml({
    normalize: false,
    index: true
});
console.log(xml)

YOLOResults.toXml(options)

  • options {object} 配置
    • path: 保存的路径
    • normalize {boolean} 是否归一化坐标,可选,默认false
    • decimals {number} 小数位数,可选,默认5
    • index: XML 表格中是否显示行索引列,可选,默认true
  • 返回 {boolean}

保存为 XML 文件。

js
yoloResults.toXml({
    path: "/sdcard/results.xml",
    normalize: true,
    index: true
});

YOLOResults.toHtml([options])

  • options {object} 配置,可选
    • normalize {boolean} 是否归一化坐标,可选,默认false
    • decimals {number} 小数位数,可选,默认5
    • index: HTML 表格中是否显示行索引列,可选,默认true
  • 返回 {string}

转换为 HTML 格式字符串。

js
var html = yoloResults.toHtml({
    normalize: false,
    index: true
});
console.log(html)

YOLOResults.toHtml(options)

  • options {object} 配置
    • path: 保存的路径
    • normalize {boolean} 是否归一化坐标,可选,默认false
    • decimals {number} 小数位数,可选,默认5
    • index: HTML 表格中是否显示行索引列,可选,默认true
  • 返回 {boolean}

保存为 HTML 文件。

js
yoloResults.toHtml({
    path: "/sdcard/results.html",
    normalize: true,
    index: true
});

YOLOResults.toSql([options])

  • options {object}(可选)数据库配置
    • path: 保存的路径,可选,默认results.db
    • tableName: 表名,可选,默认results
    • normalize {boolean} 是否归一化坐标,可选,默认false
    • decimals {number} 小数位数,可选,默认5
  • 返回 {boolean}

保存到SQLite数据库

js
yoloResults.toSql({
    path: "/sdcard/results.db",
    tableName: "detections"
});

Speed

Speed 类存储 YOLO 推理各阶段的时间统计信息。 由 YOLOResults.speed 得到

⚡ 提示:想要进一步提高推理性能,请参考 推理速度 章节中的优化建议。

示例

js
// 访问速度信息
var yoloResults = yolo.predict(image);
var speed = yoloResults.speed;

// 格式化输出
console.log(speed);
// 输出: "Speed(preprocess=12.30ms, inference=48.50ms, postprocess=9.20ms, total=70.00ms)"

console.log("预处理时间:", speed.preprocess + "ms");
console.log("推理时间:", speed.inference + "ms");
console.log("后处理时间:", speed.postprocess + "ms");
console.log("总耗时:", (speed.preprocess + speed.inference + speed.postprocess) + "ms");

Speed.preprocess

  • preprocess

图像预处理耗时(毫秒),包括图像加载、缩放、归一化等

Speed.inference

  • inference

模型推理耗时(毫秒),指在所选推理后端(CPU 或 GPU)上执行模型计算的时间

Speed.postprocess

  • postprocess

后处理耗时(毫秒),包括 NMS、结果解码、坐标转换等

Boxes

Boxes 类表示边界框检测结果。

示例

js
var boxes = yoloResults.boxes();

if (boxes) {
  console.log("=== Boxes.size() ===");
  console.log("目标数量: " + boxes.size());

  console.log("\n=== Boxes.xyxy() ===");
  var allXYXY = boxes.xyxy();
  for (var i = 0; i < allXYXY.length; i++) {
    var xyxy = allXYXY[i];
    console.log("框 #" + i + ": [" + xyxy[0] + ", " + xyxy[1] + ", " + xyxy[2] + ", " + xyxy[3] + "]");
  }

  console.log("\n=== Boxes.xyxy(index) ===");
  for (var i = 0; i < boxes.size(); i++) {
    var xyxy = boxes.xyxy(i);
    console.log("框 #" + i + ": [" + xyxy[0] + ", " + xyxy[1] + ", " + xyxy[2] + ", " + xyxy[3] + "]");
  }

  console.log("\n=== Boxes.xyxyn() ===");
  var allXYXN = boxes.xyxyn();
  for (var i = 0; i < allXYXN.length; i++) {
    var xyn = allXYXN[i];
    console.log("框 #" + i + " 归一化: [" + xyn[0] + ", " + xyn[1] + ", " + xyn[2] + ", " + xyn[3] + "]");
  }

  console.log("\n=== Boxes.xyxyn(index) ===");
  for (var i = 0; i < boxes.size(); i++) {
    var xyn = boxes.xyxyn(i);
    console.log("框 #" + i + ": [" + xyn[0] + ", " + xyn[1] + ", " + xyn[2] + ", " + xyn[3] + "]");
  }

  console.log("\n=== Boxes.xywh() ===");
  var allXYWH = boxes.xywh();
  for (var i = 0; i < allXYWH.length; i++) {
    var xywh = allXYWH[i];
    console.log("框 #" + i + " 中心+宽高: [" + xywh[0] + ", " + xywh[1] + ", " + xywh[2] + ", " + xywh[3] + "]");
  }

  console.log("\n=== Boxes.xywh(index) ===");
  for (var i = 0; i < boxes.size(); i++) {
    var xywh = boxes.xywh(i);
    console.log("框 #" + i + ": [" + xywh[0] + ", " + xywh[1] + ", " + xywh[2] + ", " + xywh[3] + "]");
  }

  console.log("\n=== Boxes.xywhn() ===");
  var allXYWHN = boxes.xywhn();
  for (var i = 0; i < allXYWHN.length; i++) {
    var xywhn = allXYWHN[i];
    console.log("框 #" + i + " 归一化中心+宽高: [" + xywhn[0] + ", " + xywhn[1] + ", " + xywhn[2] + ", " + xywhn[3] + "]");
  }

  console.log("\n=== Boxes.xywhn(index) ===");
  for (var i = 0; i < boxes.size(); i++) {
    var xywhn = boxes.xywhn(i);
    console.log("框 #" + i + ": [" + xywhn[0] + ", " + xywhn[1] + ", " + xywhn[2] + ", " + xywhn[3] + "]");
  }

  console.log("\n=== Boxes.cls() ===");
  var allCls = boxes.cls();
  for (var i = 0; i < allCls.length; i++) {
    console.log("框 #" + i + " 类别ID: " + allCls[i]);
  }

  console.log("\n=== Boxes.cls(index) ===");
  for (var i = 0; i < boxes.size(); i++) {
    console.log("框 #" + i + ": 类别ID " + boxes.cls(i));
  }

  console.log("\n=== Boxes.conf() ===");
  var allConf = boxes.conf();
  for (var i = 0; i < allConf.length; i++) {
    console.log("框 #" + i + " 置信度: " + allConf[i]);
  }

  console.log("\n=== Boxes.conf(index) ===");
  for (var i = 0; i < boxes.size(); i++) {
    console.log("框 #" + i + ": 置信度 " + boxes.conf(i));
  }
} else {
  console.error("当前任务不是目标检测、实例分割、姿态估计任务");
}

Boxes.size()

  • 返回 {number}

获取边界框数量

Boxes.xyxy()

  • 返回 {float[][]}

获取所有边界框的 [x1, y1, x2, y2] 坐标

Boxes.xyxy(index)

  • index {number} 目标索引
  • 返回 {float[]}

获取单个边界框的 [x1, y1, x2, y2] 坐标

Boxes.xyxyn()

  • 返回 {float[][]}

获取归一化的 [x1, y1, x2, y2] 坐标

Boxes.xyxyn(index)

  • index {number} 目标索引
  • 返回 {float[]}

获取单个目标的归一化 [x1, y1, x2, y2] 坐标

Boxes.xywh()

  • 返回 {float[][]}

获取 [x_center, y_center, width, height] 坐标

Boxes.xywh(index)

  • index {number} 目标索引
  • 返回 {float[]}

获取单个边界框的 [x_center, y_center, width, height] 坐标

Boxes.xywhn()

  • 返回 {float[][]}

获取归一化的 [x_center, y_center, width, height] 坐标

Boxes.xywhn(index)

  • index {number} 目标索引
  • 返回 {float[]}

获取单个目标的归一化 [x_center, y_center, width, height] 坐标

Boxes.cls()

  • 返回 {number[]}

获取所有类别ID数组

Boxes.cls(index)

  • index {number} 目标索引
  • 返回 {number}

获取单个目标的类别ID

Boxes.conf()

  • 返回 {float[]}

获取所有置信度数组

Boxes.conf(index)

  • index {number} 目标索引
  • 返回 {float}
    获取单个目标的置信度

Masks

Masks 类表示分割掩码结果。

示例

js
var masks = yoloResults.masks();

if (masks) {
  // 1. 打印掩码总数(核心基础信息)
  console.log("=== 掩码基础信息 ===");
  console.log("掩码数量: " + masks.size());

  // 2. Masks.xy() - 所有目标原始轮廓坐标(仅打印前5个点)
  console.log("\n=== Masks.xy() 所有目标原始轮廓坐标 ===");
  var allXY = masks.xy();
  for (var i = 0; i < allXY.length; i++) {
    var xy = allXY[i];
    console.log("目标 #" + i + " 轮廓坐标(总点数:" + xy.length + "):");
    for (var j = 0; j < xy.length; j++) {
      if (j >= 5) {
        // 仅打印前5个点
        console.log("  (省略剩余 " + (xy.length - 5) + " 个点)");
        break;
      }
      console.log("  点" + j + ": [" + xy[j][0] + ", " + xy[j][1] + "]");
    }
  }

  // 3. Masks.xy(index) - 按索引获取单个目标原始轮廓坐标(仅打印前5个点)
  console.log("\n=== Masks.xy(index) 按索引获取原始轮廓坐标 ===");
  for (var i = 0; i < masks.size(); i++) {
    var xy = masks.xy(i);
    console.log("目标 #" + i + " 轮廓坐标(总点数:" + xy.length + "):");
    for (var j = 0; j < xy.length; j++) {
      if (j >= 5) {
        // 仅打印前5个点
        console.log("  (省略剩余 " + (xy.length - 5) + " 个点)");
        break;
      }
      console.log("  点" + j + ": [" + xy[j][0] + ", " + xy[j][1] + "]");
    }
  }

  // 4. Masks.xyn() - 所有目标归一化轮廓坐标(仅打印前5个点,保留4位小数)
  console.log("\n=== Masks.xyn() 所有目标归一化轮廓坐标 ===");
  var allXYN = masks.xyn();
  for (var i = 0; i < allXYN.length; i++) {
    var xyn = allXYN[i];
    console.log("目标 #" + i + " 归一化坐标(总点数:" + xyn.length + "):");
    for (var j = 0; j < xyn.length; j++) {
      if (j >= 5) {
        // 仅打印前5个点
        console.log("  (省略剩余 " + (xyn.length - 5) + " 个点)");
        break;
      }
      // 归一化坐标保留4位小数,精简显示
      console.log("  点" + j + ": [" + xyn[j][0].toFixed(4) + ", " + xyn[j][1].toFixed(4) + "]");
    }
  }

  // 5. Masks.xyn(index) - 按索引获取单个目标归一化轮廓坐标(仅打印前5个点)
  console.log("\n=== Masks.xyn(index) 按索引获取归一化轮廓坐标 ===");
  for (var i = 0; i < masks.size(); i++) {
    var xyn = masks.xyn(i);
    console.log("目标 #" + i + " 归一化坐标(总点数:" + xyn.length + "):");
    for (var j = 0; j < xyn.length; j++) {
      if (j >= 5) {
        // 仅打印前5个点
        console.log("  (省略剩余 " + (xyn.length - 5) + " 个点)");
        break;
      }
      console.log("  点" + j + ": [" + xyn[j][0].toFixed(4) + ", " + xyn[j][1].toFixed(4) + "]");
    }
  }

  // 6. 轮廓绘制
  console.log("\n=== Masks.draw([img]) 轮廓绘制 ===");

  var originalImg = images.read("/sdcard/assets/image/bus.jpg");
  var drawnImg = masks.draw(originalImg);
  drawnImg.saveTo("/sdcard/drawnImg.png");
  console.log("✅ 轮廓已绘制并保存至: /sdcard/drawnImg.png");
  originalImg.recycle();
  drawnImg.recycle();
} else {
  console.error("❌ 当前任务不是实例分割,无掩码数据");
}

Masks.size()

  • 返回 {number}

获取掩码数量

Masks.xy()

  • 返回 {float[][][]}

获取所有轮廓的原始坐标

Masks.xy(index)

  • index {number} 目标索引
  • 返回 {float[][]}

获取单个目标的轮廓坐标

Masks.xyn()

  • 返回 {float[][][]}

获取所有轮廓的归一化坐标

Masks.xyn(index)

  • index {number} 目标索引
  • 返回 {float[][]}

获取单个目标的归一化轮廓坐标

Masks.draw(img)

  • img {Image | Bitmap} 要绘制轮廓的目标图像
  • 返回 {Image}

在指定图像上绘制分割轮廓,并返回绘制后的新图像对象。

返回的 Image 对象为新实例,使用完毕后必须手动调用 Image.recycle() 回收资源,避免内存泄漏。

Keypoints

Keypoints 类表示关键点检测结果。

示例

js
var keypoints = yoloResults.keypoints();

if (keypoints) {
  // 1. 打印关键点目标总数
  console.log("=== 关键点基础信息 ===");
  console.log("目标数量: " + keypoints.size());

  // 2. Keypoints.xy() - 所有目标关键点原始坐标(逐行打印)
  console.log("\n=== Keypoints.xy() 所有目标关键点原始坐标 ===");
  var allXY = keypoints.xy();
  for (var i = 0; i < allXY.length; i++) {
    var kpArray = allXY[i];
    console.log("目标 #" + i + " 关键点(共" + kpArray.length + "个):");
    for (var j = 0; j < kpArray.length; j++) {
      console.log("  关键点" + j + ": [" + kpArray[j][0] + ", " + kpArray[j][1] + "]");
    }
  }

  // 3. Keypoints.xy(index) - 按索引获取单个目标关键点原始坐标(逐行打印)
  console.log("\n=== Keypoints.xy(index) 按索引获取关键点原始坐标 ===");
  for (var i = 0; i < keypoints.size(); i++) {
    var kpArray = keypoints.xy(i);
    console.log("目标 #" + i + " 关键点(共" + kpArray.length + "个):");
    for (var j = 0; j < kpArray.length; j++) {
      console.log("  关键点" + j + ": [" + kpArray[j][0] + ", " + kpArray[j][1] + "]");
    }
  }

  // 4. Keypoints.xyn() - 所有目标归一化关键点坐标(逐行打印,原始数值)
  console.log("\n=== Keypoints.xyn() 所有目标归一化关键点坐标 ===");
  var allXYN = keypoints.xyn();
  for (var i = 0; i < allXYN.length; i++) {
    var kpArray = allXYN[i];
    console.log("目标 #" + i + " 归一化关键点(共" + kpArray.length + "个):");
    for (var j = 0; j < kpArray.length; j++) {
      // 完全保留原始数值,不做任何小数位数处理
      console.log("  关键点" + j + ": [" + kpArray[j][0] + ", " + kpArray[j][1] + "]");
    }
  }

  // 5. Keypoints.xyn(index) - 按索引获取单个目标归一化关键点坐标(逐行打印)
  console.log("\n=== Keypoints.xyn(index) 按索引获取归一化关键点坐标 ===");
  for (var i = 0; i < keypoints.size(); i++) {
    var kpArray = keypoints.xyn(i);
    console.log("目标 #" + i + " 归一化关键点(共" + kpArray.length + "个):");
    for (var j = 0; j < kpArray.length; j++) {
      console.log("  关键点" + j + ": [" + kpArray[j][0] + ", " + kpArray[j][1] + "]");
    }
  }

  // 6. Keypoints.conf() - 所有目标关键点置信度(逐行打印,原始数值)
  console.log("\n=== Keypoints.conf() 所有目标关键点置信度 ===");
  var allConf = keypoints.conf();
  for (var i = 0; i < allConf.length; i++) {
    var confArray = allConf[i];
    console.log("目标 #" + i + " 关键点置信度(共" + confArray.length + "个):");
    for (var j = 0; j < confArray.length; j++) {
      // 完全保留原始数值,不做任何小数位数处理
      console.log("  关键点" + j + "置信度: " + confArray[j]);
    }
  }

  // 7. Keypoints.conf(index) - 按索引获取单个目标关键点置信度(逐行打印)
  console.log("\n=== Keypoints.conf(index) 按索引获取关键点置信度 ===");
  for (var i = 0; i < keypoints.size(); i++) {
    var confArray = keypoints.conf(i);
    console.log("目标 #" + i + " 关键点置信度(共" + confArray.length + "个):");
    for (var j = 0; j < confArray.length; j++) {
      console.log("  关键点" + j + "置信度: " + confArray[j]);
    }
  }
} else {
  console.error("当前任务不是姿态估计,无关键点数据");
}

Keypoints.size()

  • 返回 {number}

获取目标数量

Keypoints.xy()

  • 返回 {float[][][]}

获取所有关键点的原始坐标

Keypoints.xy(index)

  • index {number} 目标索引
  • 返回 {float[][]}

获取单个目标的关键点坐标

Keypoints.xyn()

  • 返回 {float[][][]}

获取所有关键点的归一化坐标

Keypoints.xyn(index)

  • index {number} 目标索引
  • 返回 {float[][]}

获取单个目标的归一化关键点坐标

Keypoints.conf()

  • 返回 {float[][]}

获取所有关键点的置信度

Keypoints.conf(index)

  • index {number} 目标索引
  • 返回 {float[]}

获取单个目标的关键点置信度

OBB

OBB 类表示旋转框检测结果,包含获取旋转框角点、尺寸、类别等信息的方法。

示例

js
var obb = yoloResults.obb();

if (obb) {
  console.log("=== OBB.size() ===");
  console.log("旋转框数量: " + obb.size());

  console.log("\n=== OBB.xywhr() ===");
  var allXYWHR = obb.xywhr();
  for (var i = 0; i < allXYWHR.length; i++) {
    var arr = allXYWHR[i];
    console.log(
      "旋转框 #" +
        i +
        ": [x_center=" +
        arr[0] +
        ", y_center=" +
        arr[1] +
        ", w=" +
        arr[2] +
        ", h=" +
        arr[3] +
        ", r=" +
        arr[4] +
        "]"
    );
  }

  console.log("\n=== OBB.xywhr(index) ===");
  for (var i = 0; i < obb.size(); i++) {
    var arr = obb.xywhr(i);
    console.log(
      "旋转框 #" +
        i +
        ": [x_center=" +
        arr[0] +
        ", y_center=" +
        arr[1] +
        ", w=" +
        arr[2] +
        ", h=" +
        arr[3] +
        ", r=" +
        arr[4] +
        "]"
    );
  }

  console.log("\n=== OBB.xyxyxyxy() ===");
  var allCorners = obb.xyxyxyxy();
  for (var i = 0; i < allCorners.length; i++) {
    var cornerArr = allCorners[i];
    var str = "旋转框 #" + i + " 四角: [";
    for (var j = 0; j < cornerArr.length; j++) {
      str += "[" + cornerArr[j][0] + ", " + cornerArr[j][1] + "]";
      if (j < cornerArr.length - 1) str += ", ";
    }
    str += "]";
    console.log(str);
  }

  console.log("\n=== OBB.xyxyxyxy(index) ===");
  for (var i = 0; i < obb.size(); i++) {
    var cornerArr = obb.xyxyxyxy(i);
    var str = "旋转框 #" + i + " 四角: [";
    for (var j = 0; j < cornerArr.length; j++) {
      str += "[" + cornerArr[j][0] + ", " + cornerArr[j][1] + "]";
      if (j < cornerArr.length - 1) str += ", ";
    }
    str += "]";
    console.log(str);
  }

  console.log("\n=== OBB.xyxyxyxyn() ===");
  var allCornersN = obb.xyxyxyxyn();
  for (var i = 0; i < allCornersN.length; i++) {
    var cornerArr = allCornersN[i];
    var str = "旋转框 #" + i + " 归一化四角: [";
    for (var j = 0; j < cornerArr.length; j++) {
      str += "[" + cornerArr[j][0] + ", " + cornerArr[j][1] + "]";
      if (j < cornerArr.length - 1) str += ", ";
    }
    str += "]";
    console.log(str);
  }

  console.log("\n=== OBB.xyxyxyxyn(index) ===");
  for (var i = 0; i < obb.size(); i++) {
    var cornerArr = obb.xyxyxyxyn(i);
    var str = "旋转框 #" + i + " 归一化四角: [";
    for (var j = 0; j < cornerArr.length; j++) {
      str += "[" + cornerArr[j][0] + ", " + cornerArr[j][1] + "]";
      if (j < cornerArr.length - 1) str += ", ";
    }
    str += "]";
    console.log(str);
  }

  console.log("\n=== OBB.xyxy() ===");
  var allXY = obb.xyxy();
  for (var i = 0; i < allXY.length; i++) {
    var arr = allXY[i];
    console.log("旋转框 #" + i + " 轴对齐框: [x1=" + arr[0] + ", y1=" + arr[1] + ", x2=" + arr[2] + ", y2=" + arr[3] + "]");
  }

  console.log("\n=== OBB.xyxy(index) ===");
  for (var i = 0; i < obb.size(); i++) {
    var arr = obb.xyxy(i);
    console.log("旋转框 #" + i + " 轴对齐框: [x1=" + arr[0] + ", y1=" + arr[1] + ", x2=" + arr[2] + ", y2=" + arr[3] + "]");
  }
  console.log("\n=== OBB.conf() ===");
  var confs = obb.conf();
  for (var i = 0; i < confs.length; i++) {
    console.log("旋转框 #" + i + " 置信度: " + confs[i]);
  }

  console.log("\n=== OBB.conf(index) ===");
  for (var i = 0; i < obb.size(); i++) {
    console.log("旋转框 #" + i + " 置信度: " + obb.conf(i));
  }

  console.log("\n=== OBB.cls() ===");
  var clsArr = obb.cls();
  for (var i = 0; i < clsArr.length; i++) {
    console.log("旋转框 #" + i + " 类别ID: " + clsArr[i]);
  }

  console.log("\n=== OBB.cls(index) ===");
  for (var i = 0; i < obb.size(); i++) {
    console.log("旋转框 #" + i + " 类别ID: " + obb.cls(i));
  }
} else {
  console.error("当前任务不是旋转框检测");
}

OBB.size()

  • 返回 {number}

获取旋转框的数量。

OBB.xywhr()

  • 返回 {float[][]}

获取旋转框的 [x_center, y_center, width, height, radians] 格式,表示旋转框的中心坐标、尺寸和旋转弧度。

其中:

  • radians 为弧度(radians)
  • 角度 = radians × 180 / Math.PI

OBB.xywhr(index)

  • index {number}:目标索引。
  • 返回 {float[]}

获取指定索引的旋转框 [x_center, y_center, width, height, radians] 格式。

OBB.xyxyxyxy()

  • 返回 {float[][][]}

获取旋转框的四个角点坐标,顺序为:右下 -> 右上 -> 左上 -> 左下。

OBB.xyxyxyxy(index)

  • index {number}:目标索引。
  • 返回 {float[][]}

获取指定索引的旋转框的四个角点坐标,顺序为:右下 -> 右上 -> 左上 -> 左下。

OBB.xyxyxyxyn()

  • 返回 {float[][][]} 获取归一化的四个角点坐标,顺序为:右下 -> 右上 -> 左上 -> 左下。

OBB.xyxyxyxyn(index)

  • index {number}:目标索引。
  • 返回 {float[][]}

获取指定索引的归一化四个角点坐标,顺序为:右下 -> 右上 -> 左上 -> 左下。

OBB.xyxy()

  • 返回 {float[][]}

获取轴对齐边界框的左上和右下坐标。

OBB.xyxy(index)

  • index {number}:目标索引。
  • 返回 {float[]}

获取指定索引的轴对齐边界框左上和右下坐标。

OBB.conf()

  • 返回 {float[]}

获取每个旋转框的置信度数组。

OBB.conf(index)

  • index {number}:目标索引。
  • 返回 {float}

获取指定索引的旋转框的置信度。

OBB.cls()

  • 返回 {number[]}

获取每个旋转框的类别ID数组。

OBB.cls(index)

  • index {number}:目标索引。
  • 返回 {number}

获取指定索引的旋转框的类别ID。

Probs

Probs 类表示分类概率结果。

示例

js
var probs = yoloResults.probs();
if (probs) {
  console.log("=== Probs 测试示例 ===");

  // 1. Top1 ID
  var top1Id = probs.top1();
  console.log("Top1 类别ID: " + top1Id);

  // 2. Top1 名称
  var top1Name = probs.top1name();
  console.log("Top1 类别名称: " + top1Name);

  // 3. Top1 置信度
  var top1Conf = probs.top1conf();
  console.log("Top1 置信度: " + top1Conf);

  // 4. Top1 完整对象
  var top1Obj = probs.top1Object();
  if (top1Obj) {
    console.log("Top1 完整对象信息:");
    console.log("  cls: " + top1Obj.cls);
    console.log("  conf: " + top1Obj.conf);
  } else {
    console.log("Top1 对象为空");
  }

  // 5. Top5 ID 数组
  var top5Ids = probs.top5();
  console.log("Top5 类别ID数组: " + top5Ids);

  // 6. Top5 名称数组
  var top5Names = probs.top5name();
  console.log("Top5 类别名称数组: " + top5Names);

  // 7. Top5 置信度数组
  var top5Confs = probs.top5conf();
  console.log("Top5 置信度数组: " + top5Confs);

  // 8. 输出 Top5 详细信息
  console.log("\n=== Top5 分类详细信息 ===");
  for (var i = 0; i < top5Ids.length; i++) {
    console.log(
      "Top" + (i + 1) + ": ID=" + top5Ids[i] + ", 名称=" + top5Names[i] + ", 置信度=" + (top5Confs[i] * 100).toFixed(2) + "%"
    );
  }

  // 9. Probs.summary() 简要摘要
  var summary = probs.summary();
  console.log("\n分类摘要: " + summary);
} else {
  console.error("当前任务不是分类任务,无概率结果");
}

Probs.top1()

  • 返回 {number}

获取Top1类别ID

Probs.top1name()

  • 返回 {string}

获取Top1类别名称

Probs.top1conf()

  • 返回 {float}

获取Top1置信度

Probs.top1Object()

获取Top1完整对象

Probs.top5()

  • 返回 {number[]}

获取Top5类别ID数组

Probs.top5name()

  • 返回 {string[]}

获取Top5类别名称数组

Probs.top5conf()

  • 返回 {float[]}

获取Top5置信度数组

Probs.summary()

  • 返回 {string}

获取简要摘要字符串

DataFrame

DataFrame 类提供结构化数据操作和文件导出功能,适用于处理 YOLO 推理结果。

示例

js
// 创建 DataFrame

var df = yoloResults.toDf({
  normalize: false, // 是否归一化
  decimals: 2, // 小数保留位数
});

console.log("=== DataFrame.shape() ===");
var shape = df.shape(); // 返回 [行数, 列数]
console.log("行数: " + shape[0] + ", 列数: " + shape[1]);

console.log("\n=== DataFrame.head(n) ===");
var head = df.head(5); // 获取前 5 行
console.log(head);
for (var i = 0; i < head.length; i++) {
  var summary = head[i];
  console.log("目标 #" + i + ": cls=" + summary.cls + ", name=" + summary.name + ", confidence=" + summary.confidence);
  // 其他数据参阅 Summary,例如 box, obbBox, keypoints, segments 等
}

console.log("\n=== DataFrame.toJson() ===");
var jsonStr = df.toJson(); // 转换为 JSON 字符串
console.log(jsonStr);
var jsonSave = df.toJson({ path: "/sdcard/results.json" }); // 保存 JSON 文件
console.log("保存 JSON 文件结果:", jsonSave);

console.log("\n=== DataFrame.toCsv() ===");
var csvStr = df.toCsv({ index: true }); // 转换为 CSV 字符串,显示行索引
console.log(csvStr);
var csvSave = df.toCsv({ path: "/sdcard/results.csv", index: true }); // 保存 CSV 文件
console.log("保存 CSV 文件结果:", csvSave);

console.log("\n=== DataFrame.toHtml() ===");
var htmlStr = df.toHtml({ index: true }); // 转换为 HTML 字符串
console.log(htmlStr);
var htmlSave = df.toHtml({ path: "/sdcard/results.html", index: true }); // 保存 HTML 文件
console.log("保存 HTML 文件结果:", htmlSave);

console.log("\n=== DataFrame.toXml() ===");
var xmlStr = df.toXml({ index: true }); // 转换为 XML 字符串
console.log(xmlStr);
var xmlSave = df.toXml({ path: "/sdcard/results.xml", index: false }); // 保存 XML 文件,不显示行索引列
console.log("保存 XML 文件结果:", xmlSave);

console.log("\n=== DataFrame.toSql() ===");
var sqlSave = df.toSql({
  path: "/sdcard/results.db",
  tableName: "detection_results",
});
console.log("保存 SQLite 数据库结果:", sqlSave);

DataFrame.shape()

  • 返回 {number[]}

获取 DataFrame 形状 [行数, 列数]

DataFrame.head([n])

  • n {number}(可选)行数,默认5
  • 返回 {Summary[]}

获取前 n 行数据。

DataFrame.saveTxt(path[, saveConf])

  • path {string} 保存的文件路径。

  • saveConf {boolean} 可选,是否保存置信度,默认为 false

  • 返回 {boolean}

将数据保存为 YOLO 格式标签文件.txt

DataFrame.saveTxt([options])

  • options {Object} 包括:

    • path {string} 可选,保存的文件路径,默认为 results.txt
    • saveConf {boolean} 可选,是否保存置信度,默认为 false
  • 返回 {boolean}

将数据保存为 YOLO 格式标签文件.txt

DataFrame.toJson()

  • 返回 {Array}

转换为JSON格式。

DataFrame.toJson(path)

  • path {string} 保存的文件路径。

  • 返回 {boolean}

JSON格式的数据保存到指定文件。

DataFrame.toCsv([index])

  • index {boolean} 是否显示行索引列,可选,默认true
  • 返回 {string}

转换为 CSV 格式字符串。

DataFrame.toCsv(path[, index])

  • path {string} 保存的文件路径。
  • index {boolean} CSV 表格中是否显示行索引列,可选,默认true
  • 返回 {boolean}

保存为 CSV 文件。

DataFrame.toCsv(options)

  • options {object} 配置
    • path: 保存的路径,可选,默认results.csv
    • index: CSV 表格中是否显示行索引列,可选,默认true
  • 返回 {boolean}

保存为 CSV 文件。

DataFrame.toXml([index])

  • index {boolean} 是否显示行索引列,可选,默认true
  • 返回 {string}

转换为 XML 格式字符串。

DataFrame.toXml(path[, index])

  • path {string} 保存的文件路径。
  • index {boolean} XML 表格中是否显示行索引列,可选,默认true
  • 返回 {boolean}

保存为 XML 文件。

DataFrame.toXml(options)

  • options {object} 配置
    • path {string} 保存的路径,可选,默认results.xml
    • index {boolean} XML 表格中是否显示行索引列,可选,默认true
  • 返回 {boolean}

保存为 XML 文件。

DataFrame.toHtml([index])

  • index {boolean} 是否显示行索引列,可选,默认true
  • 返回 {string}

转换为 HTML 格式字符串。

DataFrame.toHtml(path[, index])

  • path {string} 保存的文件路径。
  • index {boolean} HTML 表格中是否显示行索引列,可选,默认true
  • 返回 {boolean}

保存为 HTML 文件。

DataFrame.toHtml(options)

  • options {object} 配置
    • path {string} 保存的路径,可选,默认results.html
    • index {boolean} HTML 表格中是否显示行索引列,可选,默认true
  • 返回 {boolean}

保存为 HTML 文件。

DataFrame.toSql(path[, tableName])

  • path {string} 保存的路径
  • tableName {string} 表名,可选,默认results
  • 返回 {boolean}

将数据保存到 SQLite 数据库。

DataFrame.toSql([options])

  • options {object}(可选)数据库配置
    • path: 保存的路径,可选,默认results.db
    • tableName: 表名,可选,默认results
  • 返回 {boolean}

将数据保存到 SQLite 数据库。

Summary

Summary 表示单个检测目标的摘要信息,包含通用字段和各任务专属字段,字段为动态存在(非当前任务的字段为null)。

示例

js

// 获取摘要数组
var summaries = yoloResults.summary();
// 遍历摘要信息
if (summaries.length > 0) {
  for (var i = 0; i < summaries.length; i++) {
    var summary = summaries[i];
    console.log("=== 目标 #" + i + " ===");
    console.log("类别名称: " + summary.name + ",类别ID: " + summary.cls);
    console.log("置信度: " + summary.confidence);

    // 边界框信息(Box)
    if (summary.box) {
      if ([0, 1, 3].includes(yolo.task)) {
        // 目标检测、实例分割、姿态估计(轴对齐边界框)
        console.log(
          "边界框 (Axis-Aligned Box): 左上=(" +
            summary.box.x1 +
            ", " +
            summary.box.y1 +
            "), " +
            "右下=(" +
            summary.box.x2 +
            ", " +
            summary.box.y2 +
            ")"
        );
      } else if (yolo.task === 4) {
        // 旋转框四角
        console.log("旋转框四角点 (右下 → 右上 → 左上 → 左下):");
        console.log(
          "  右下: (" +
            summary.box.x1 +
            ", " +
            summary.box.y1 +
            ")\n" +
            "  右上: (" +
            summary.box.x2 +
            ", " +
            summary.box.y2 +
            ")\n" +
            "  左上: (" +
            summary.box.x3 +
            ", " +
            summary.box.y3 +
            ")\n" +
            "  左下: (" +
            summary.box.x4 +
            ", " +
            summary.box.y4 +
            ")"
        );
      }
    }

    // 分割掩码信息 (Segments) - 掩码是目标轮廓的坐标点集合,用于精准定位目标边缘
    if (summary.segments) {
      // 获取掩码的X坐标数组和Y坐标数组
      var xs = summary.segments.x;
      var ys = summary.segments.y;

      // 先打印掩码坐标点的总数,让用户知道完整数据量
      console.log("分割掩码坐标点总数: " + xs.length + " 个");
      console.log("分割掩码前5个坐标点(避免输出过多数据):");

      // 遍历坐标点,逐个打印
      for (var s = 0; s < xs.length; s++) {
        // 核心判断:如果当前索引>=5(即已经打印了前5个点),直接跳出循环停止打印
        if (s >= 5) {
          // 打印提示信息,告知用户已停止打印
          console.log("  提示:已打印前5个坐标点,剩余 " + (xs.length - 5) + " 个点不再展示");
          break; // 跳出循环,终止后续打印
        }

        var segX = xs[s]; // 当前点的X坐标
        var segY = ys[s]; // 当前点的Y坐标
        console.log("  坐标点 #" + (s + 1) + ": (" + segX + ", " + segY + ")");
      }
    }

    // 关键点信息 (Keypoints)
    if (summary.keypoints) {
      var xs = summary.keypoints.x;
      var ys = summary.keypoints.y;
      var visible = summary.keypoints.visible;

      for (var k = 0; k < xs.length; k++) {
        console.log("关键点 #" + k + ": (x=" + xs[k] + ", y=" + ys[k] + ", 可见性=" + visible[k] + ")");
      }
    }

    console.log("--------------------------------------------------");
  }
} else {
  console.error("未检测到目标或摘要为空");
}

Summary.cls

  • {number}

类别ID

Summary.name

  • {string}

类别名称

Summary.confidence

  • {float}

置信度(0~1)

Summary.box

  • box {Object | null} 边界框信息
    • x1, y1, x2, y2 {float} 矩形框,轴对齐边界框坐标
    • x1, y1, x2, y2, x3, y3, x4, y4 {float} 旋转框,4个角点坐标

Summary.segments

  • segments {Object | null}
    • x {float[]} 分割轮廓的 x 坐标数组
    • y {float[]} 分割轮廓的 y 坐标数组 分割轮廓信息

Summary.keypoints

  • keypoints {Object | null}
    • x {float[]} 关键点 x 坐标数组
    • y {float[]} 关键点 y 坐标数组
    • visible {float[]} 关键点 可见性(置信度)数组

姿态的关键点信息

YOLOObject

单个推理对象

示例

js
// 遍历每一个 YOLOObject(目标检测结果)
for (var i = 0; i < yoloResults.size(); i++) {
  var yoloObject = yoloResults.get(i);

  // 打印目标的基本信息
  console.log("目标 " + (i + 1) + ":");
  console.log("  类别ID: " + yoloObject.cls);
  var name = yoloResults.names[yoloObject.cls];
  console.log("  类别名称: " + name);
  console.log("  置信度: " + yoloObject.conf);

  // 打印目标的位置信息(坐标和尺寸)
  if ([0, 1, 3].includes(yolo.task)) {
    // 目标检测、实例分割、姿态估计(轴对齐边界框)
    console.log("  检测框:");
    console.log("    左上角: x=" + yoloObject.x + ", y=" + yoloObject.y);
    console.log("    宽度=" + yoloObject.w + ", 高度=" + yoloObject.h);
  } else if (yolo.task === 4) {
    // 旋转框
    console.log("  旋转框:");
    console.log("    中心点: x=" + yoloObject.x + ", y=" + yoloObject.y);
    console.log("    宽度=" + yoloObject.w + ", 高度=" + yoloObject.h);
    console.log("    旋转角度=" + yoloObject.angle + "°");
  }

  // 打印关键点信息(如果有)
  if (yoloObject.keypoints && yoloObject.keypoints.length > 0) {
    console.log("  关键点数量: " + yoloObject.keypoints.length);
    for (var j = 0; j < yoloObject.keypoints.length; j++) {
      var keypoint = yoloObject.keypoints[j];
      console.log("    关键点 " + (j + 1) + ": x=" + keypoint.x + ", y=" + keypoint.y + ", 可见性/置信度=" + keypoint.conf);
    }
  }

  // ========== 补充:完整打印掩膜(mask)相关信息 ==========
  console.log("  掩膜(Mask)信息:");
  // 打印mask的行列数
  console.log("    掩膜行数(maskRows): " + (yoloObject.maskRows || 0));
  console.log("    掩膜列数(maskCols): " + (yoloObject.maskCols || 0));

  // 打印mask数据
  if (yoloObject.maskData && yoloObject.maskData.length > 0) {
    console.log("    掩膜数据长度: " + yoloObject.maskData.length);
    // 可选:打印前10个数据示例(避免数据量过大)
    var sampleData = yoloObject.maskData.slice(0, 10);
    console.log("    掩膜数据前10个字节示例: " + sampleData.join(", "));
  } else {
    console.log("    掩膜数据: 无");
  }

  // ========== 补充:完整打印轮廓(contours)相关信息 ==========
  if (yoloObject.contours && yoloObject.contours.length > 0) {
    console.log("  轮廓(Contours)信息:");
    console.log("    轮廓总数: " + yoloObject.contours.length);

    for (var k = 0; k < yoloObject.contours.length; k++) {
      var contour = yoloObject.contours[k];
      console.log("    轮廓 " + (k + 1) + ":");
      console.log("      该轮廓的点数量: " + (contour ? contour.length : 0));

      if (contour && contour.length > 0) {
        // 打印前5个点(避免输出过多)
        var printCount = Math.min(contour.length, 5);
        for (var pointIndex = 0; pointIndex < printCount; pointIndex++) {
          var point = contour[pointIndex];
          // 兼容点数据的不同格式(int[] 或 float[])
          console.log("        点 " + (pointIndex + 1) + ": x=" + point[0] + ", y=" + point[1]);
        }
        // 如果点数量超过5,提示省略部分
        if (contour.length > 5) {
          console.log("        ... 省略 " + (contour.length - 5) + " 个点");
        }
      } else {
        console.log("      该轮廓无数据");
      }
    }
  } else {
    console.log("  轮廓(Contours)信息: 无");
  }

  console.log("--------------------");
}

YOLOObject.x

  • {float}

左上角的 x 坐标(除旋转外)。旋转时,代表中心点的 x 坐标。

YOLOObject.y

  • {float}

左上角的 y 坐标(除旋转外)。旋转时,代表中心点的 y 坐标。

YOLOObject.w

  • {float}

目标的宽度(除旋转外)。旋转时,代表目标的宽度。

YOLOObject.h

  • {float}

目标的高度(除旋转外)。旋转时,代表目标的高度。

YOLOObject.angle

  • {float}

目标的旋转角度(度,OpenCV 标准:0~360度,有些系统用 -180~180度)。

YOLOObject.cls

  • {number}

目标的类别ID。

YOLOObject.conf

  • {float}

目标的置信度(0~1)。

YOLOObject.maskRows

  • {number}

目标的掩膜行数。

YOLOObject.maskCols

  • {number}

目标的掩膜列数。

YOLOObject.maskData

  • maskData {byte[]}

目标的掩膜数据。

YOLOObject.keypoints

目标的关键点信息。

YOLOObject.contours

  • {List<List<number[]>>}

目标的轮廓信息。每个轮廓点使用 float[2] 表示坐标。

YOLOObject.bounds()

获取目标的边界框(Rect)。

  • angle = 0 时,返回模型输出的原始边界矩形(左上角 + 宽高)。
  • angle ≠ 0 时,返回 旋转后的最小包围矩形(Axis-Aligned Bounding Box, AABB),即包含旋转目标的最小矩形,等同于 OBB.xyxy() 得到的左上角和右下角坐标矩形

KeyPoint

单个关键点对象(通常用于姿态估计或人体关键点检测)

KeyPoint.x

  • {float}

关键点的横坐标(像素单位),通常相对于输入图像的左上角。

KeyPoint.y

  • {float}

关键点的纵坐标(像素单位),通常相对于输入图像的左上角。

KeyPoint.conf

  • {float}

关键点的置信度(可见性),取值范围 0~1,表示模型对该关键点预测的可信程度。

FloatImage

FloatImage 表示一个用于显示图像的悬浮窗对象,支持动态更新图像、设置标题、调整位置和大小,以及关闭窗口。

通常通过 YOLOResults.show() 获取实例。

FloatImage.setTitle(title)

  • title {string} 标题文本

设置悬浮窗标题。

FloatImage.setPosition(x, y)

  • x {number} X 坐标(像素)
  • y {number} Y 坐标(像素)

设置悬浮窗位置。坐标基于屏幕左上角。

FloatImage.setSize(width, height)

  • width {number} 宽度(像素)
  • height {number} 高度(像素)

设置悬浮窗显示尺寸。

FloatImage.close()

关闭悬浮窗并释放资源。

关闭后悬浮窗不可再使用。