[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"solution-scenes-menu":3,"tech-detail-2555":4},true,{"id":5,"title":6,"content":7,"picUrl":8,"tagIds":9,"keyWords":10,"htmlDescribe":11,"htmlUrl":12,"gmtCreate":13,"gmtModified":13,"articleInfoId":14},"2555","畅联云平台丨01-YOLOv8人体检测与Letterbox","\u003Ch1>YOLOv8 人体检测与 Letterbox：从像素到可用框\u003C\u002Fh1>\u003Cp>本文讲透一件事：在本项目里，一张监控帧如何变成一组可跟踪的人体框。重点不是「YOLO 很火」，而是 Letterbox 几何、张量布局、解码逆变换、阈值与 NMS 各自在算什么、错了会怎样。\u003C\u002Fp>\u003Ch1>一、问题定义：检测要交付什么\u003C\u002Fh1>\u003Cp>人体检测的交付物不是「热力图好看」，而是结构化框：\u003C\u002Fp>\u003Cp>人体框：左上角坐标、宽高、置信度分数\u003C\u002Fp>\u003Cp>坐标必须在原图像素系。后面跟踪、人脸 ROI、镜头中心全部依赖这组数。\u003C\u002Fp>\u003Cp>所以链路的成功标准只有一句：框在原图上贴住人，且分数可排序、可阈值过滤。\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Ch1>二、 为什么不能直接 resize 成正方形\u003C\u002Fh1>\u003Cp>YOLOv8 导出模型通常接受固定边长输入（本项目默认 640×640）。监控源却是 1280×720、1920×1080、4K。若把宽高各自拉到 640：\u003C\u002Fp>\u003Cul>\u003Cli style=\"line-height:2\">人体长宽比被破坏（人变胖\u002F变瘦）；\u003C\u002Fli>\u003Cli style=\"line-height:2\">训练分布是「比例正确的人」，推理分布变成「压扁的人」；\u003C\u002Fli>\u003Cli style=\"line-height:2\">召回与定位同时变差。\u003C\u002Fli>\u003C\u002Ful>\u003Cp style=\"text-align:center\">\u003Cimg src=\"https:\u002F\u002Fqu-link.oss-cn-hangzhou.aliyuncs.com\u002F2026\u002F08\u002F14\u002F7647ef00-e0aa-48fa-93c1-f93f690bf57e.png\" alt=\"\" loading=\"lazy\" \u002F>\u003C\u002Fp>\u003Cp style=\"text-align:center\">\u003Cspan style=\"font-size:13px\">图：直接拉伸会压扁人体；Letterbox 先等比缩放再补边，比例不变。\u003C\u002Fspan>\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Cp>Letterbox 做三件事：\u003C\u002Fp>\u003Col>\u003Cli style=\"line-height:2\">用同一比例缩放，使缩放后的图能完整放进 input_size×input_size；\u003C\u002Fli>\u003Cli style=\"line-height:2\">不足的边用常数色填充（本项目为灰色 114）；\u003C\u002Fli>\u003Cli style=\"line-height:2\">记录 scale, pad_x, pad_y，供框坐标还原。\u003C\u002Fli>\u003C\u002Fol>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Ch1>三、本项目 Letterbox 的精确实现\u003C\u002Fh1>\u003Cp>要点拆解：\u003C\u002Fp>\u003Cp style=\"text-align:center\">\u003Cimg src=\"https:\u002F\u002Fqu-link.oss-cn-hangzhou.aliyuncs.com\u002F2026\u002F08\u002F14\u002F183ef67f-6252-4a58-beb3-6f6113da37c9.png\" alt=\"\" loading=\"lazy\" \u002F>\u003C\u002Fp>\u003Cp>\u003Cstrong>数值例子（1920×1080 → 640）\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>scale = min(640\u002F1920, 640\u002F1080) = min(0.3333, 0.5926) = 0.3333\u003C\u002Fp>\u003Cp>rw = 640, rh = 360\u003C\u002Fp>\u003Cp>pad_x = 0, pad_y = (640-360)\u002F2 = 140\u003C\u002Fp>\u003Cp>有效画面占中间 640×360，上下各 140 行灰边。\u003C\u002Fp>\u003Cp>Letterbox 实现：\u003C\u002Fp>\u003Cpre>\u003Ccode>cv::Mat person_focus_yolo_letterbox_bgr(const cv::Mat &amp;src, int input_size,\r\n float &amp;scale, int &amp;pad_x, int &amp;pad_y) {\r\n scale = std::min((float)input_size \u002F (float)std::max(1, src.cols),\r\n (float)input_size \u002F (float)std::max(1, src.rows));\r\n const int rw = std::max(1, (int)(src.cols * scale));\r\n const int rh = std::max(1, (int)(src.rows * scale));\r\n pad_x = (input_size - rw) \u002F 2;\r\n pad_y = (input_size - rh) \u002F 2;\r\n cv::Mat resized;\r\n cv::resize(src, resized, cv::Size(rw, rh), 0, 0, cv::INTER_LINEAR);\r\n cv::Mat out(input_size, input_size, CV_8UC3, cv::Scalar(114, 114, 114));\r\n resized.copyTo(out(cv::Rect(pad_x, pad_y, rw, rh)));\r\n return out;\r\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch1>\u003C\u002Fh1>\u003Ch1>四、数值预处理：BGR 到模型输入\u003C\u002Fh1>\u003Cp>几何之后还有数值层（GPU 或 CPU 都要做同类数值预处理）：\u003C\u002Fp>\u003Col>\u003Cli style=\"line-height:2\">BGR → RGB（多数 YOLO 权重按 RGB 训练；通道反了「有框但飘\u002F分低」）；\u003C\u002Fli>\u003Cli style=\"line-height:2\">排成通道优先的张量：批量1、三通道、高640、宽640；\u003C\u002Fli>\u003Cli style=\"line-height:2\">转 float，并按训练约定缩放（常见 \u002F255.0 到 0～1）。\u003C\u002Fli>\u003C\u002Fol>\u003Cp>这一段错了的特点是：不报错，只变差。接入新环境时，应用同一张图对比官方推理 脚本的框与分数。\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Ch1>五、模型输出：84×N 张量到底是什么\u003C\u002Fh1>\u003Cp>COCO 80 类的 YOLOv8 检测头，每个候选给出 84 个数：\u003C\u002Fp>\u003Cp>[cx, cy, bw, bh, score_cls0, score_cls1, …, score_cls79]\u003C\u002Fp>\u003Cp>人体只要 class 0 = person，即索引 4 + 0。\u003C\u002Fp>\u003Cp style=\"text-align:center\">\u003Cimg src=\"https:\u002F\u002Fqu-link.oss-cn-hangzhou.aliyuncs.com\u002F2026\u002F08\u002F14\u002Fad7a88d6-2b30-4765-82dd-88def9cf974a.png\" alt=\"\" loading=\"lazy\" \u002F>\u003C\u002Fp>\u003Cp style=\"text-align:center\">\u003Cspan style=\"font-size:12px\">图：每个候选 84 维；布局可能是「特征维在前」或「候选维在前」。\u003C\u002Fspan>\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Cp>本项目用布局探测兼容两种内存排列。\u003C\u002Fp>\u003Cp>读取时用统一的取值函数兼容两种排列：\u003C\u002Fp>\u003Cp>若导出工具改了维度顺序而业务只按一种硬解码，会出现「分数全是 0 \u002F 框飞到画外」——优先查输出布局，而不是先怪模型。\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Ch1>六、解码 + 逆 Letterbox：框如何回到原图\u003C\u002Fh1>\u003Cp>解码时按下面公式把框从 letterbox 坐标还原到原图。检测解析 \u002F 逆变换的核心：\u003C\u002Fp>\u003Cpre>\u003Ccode>\u002F\u002F 逆 Letterbox：网络框 → 原图\nconst int left = (int)std::lround((cx - 0.5f * bw - (float)pad_x) \u002F scale);\nconst int top = (int)std::lround((cy - 0.5f * bh - (float)pad_y) \u002F scale);\nconst int width = (int)std::lround(bw \u002F scale);\nconst int height = (int)std::lround(bh \u002F scale);\r\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>公式含义：\u003C\u002Fp>\u003Col>\u003Cli style=\"line-height:2\">(cx ± bw\u002F2, cy ± bh\u002F2) 是 letterbox 图上的角点；\u003C\u002Fli>\u003Cli style=\"line-height:2\">先减 pad，回到「无灰边的缩放图」坐标；\u003C\u002Fli>\u003Cli style=\"line-height:2\">再除以 scale，回到原图像素；\u003C\u002Fli>\u003Cli style=\"line-height:2\">与 原图矩形范围 求交，丢掉出界残片。\u003C\u002Fli>\u003C\u002Fol>\u003Cp style=\"text-align:center\">\u003Cimg src=\"https:\u002F\u002Fqu-link.oss-cn-hangzhou.aliyuncs.com\u002F2026\u002F08\u002F14\u002F88e12fa9-9374-4f41-9f2f-cdd83240c332.png\" alt=\"\" loading=\"lazy\" \u002F>\u003C\u002Fp>\u003Cp style=\"text-align:center\">\u003Cspan style=\"font-size:12px\">图：还原公式及数值例子。\u003C\u002Fspan>\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Cp>\u003Cstrong>用上一节的例子验算\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>letterbox 上：cx=320, cy=300, bw=40, bh=80，pad_x=0, pad_y=140, scale=1\u002F3：\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Cp>left = round((320 - 20 - 0) \u002F (1\u002F3)) = 900\u003C\u002Fp>\u003Cp>top = round((300 - 40 - 140) \u002F (1\u002F3)) = 360\u003C\u002Fp>\u003Cp>width = round(40 \u002F (1\u002F3)) = 120\u003C\u002Fp>\u003Cp>height= round(80 \u002F (1\u002F3)) = 240\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Cp>这就是原图上大约 120×240 的站立人。\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Cp>调试口诀：\u003C\u002Fp>\u003Col>\u003Cli style=\"line-height:2\">在 640 letterbox 图上画框 → 若已偏，问题在推理\u002F解码前；\u003C\u002Fli>\u003Cli style=\"line-height:2\">letterbox 对、原图偏 → 逆变换或 scale\u002Fpad 传错；\u003C\u002Fli>\u003Cli style=\"line-height:2\">两套都对但业务 ROI 错 → 后续模块坐标系统一问题。\u003C\u002Fli>\u003C\u002Fol>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Ch1>七、阈值过滤与 NMS\u003C\u002Fh1>\u003Cp>解码循环里先做 score 阈值（例如 0.25）：低于阈值的候选直接丢。\u003C\u002Fp>\u003Cp>同一人通常对应多个高分候选，再用 标准非极大值抑制：\u003C\u002Fp>\u003Cul>\u003Cli style=\"line-height:2\">NMS IoU 常见约 0.45～0.55；\u003C\u002Fli>\u003Cli style=\"line-height:2\">IoU = 交集面积 \u002F 并集面积；\u003C\u002Fli>\u003Cli style=\"line-height:2\">IoU 阈值调高：更不容易删，并肩两人更安全，但重复框可能多；\u003C\u002Fli>\u003Cli style=\"line-height:2\">IoU 阈值调低：删得更狠，重复少，贴靠两人易被合成一个。\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Tile 场景还会在全局再跑一轮 NMS，并可能使用 prefer-face 变体（有脸的框优先保留）——那是切块专题的内容，但单帧整图路径同样依赖这一步压冗余。\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Ch1>八、端到端链路\u003C\u002Fh1>\u003Cp style=\"text-align:center\">\u003Cimg src=\"https:\u002F\u002Fqu-link.oss-cn-hangzhou.aliyuncs.com\u002F2026\u002F08\u002F14\u002F2ff1edda-1d7d-4b95-b52a-b2113fa7bd02.png\" alt=\"\" loading=\"lazy\" \u002F>\u003C\u002Fp>\u003Cp style=\"text-align:center\">\u003Cspan style=\"font-size:12px\">图：原图 → Letterbox → 张量预处理 → 模型推理 → 解码与去重 → 原图框。\u003C\u002Fspan>\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Cp>部署上模型路径由默认人体模型路径探测得到（如 yolov8s_person.onnx 等），推理后端可走 TensorRT \u002F CUDA EP \u002F CPU，但对业务框格式保持不变——换 EP 不该改坐标语义。\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Ch1>九、小目标天花板：算清 “人在网络里有多高” \u003C\u002Fh1>\u003Cp style=\"text-align:center\">\u003Cimg src=\"https:\u002F\u002Fqu-link.oss-cn-hangzhou.aliyuncs.com\u002F2026\u002F08\u002F14\u002F0ecaeeb2-3996-486a-b747-a6f3279efb34.png\" alt=\"\" loading=\"lazy\" \u002F>\u003C\u002Fp>\u003Cp style=\"text-align:center\">\u003Cspan style=\"font-size:12px\">图：4K 上 80px 高的人，整帧进 640 后只剩约 13px。\u003C\u002Fspan>\u003C\u002Fp>\u003Cp>粗算：\u003C\u002Fp>\u003Cp>原图人身高 H_src\u003C\u002Fp>\u003Cp>网络内身高 ≈ H_src * (input_size \u002F max(W,H)) \u002F\u002F letterbox 近似\u003C\u002Fp>\u003Cp>例：H_src=80, 4K 长边 3840, input=640\u003C\u002Fp>\u003Cp>→ 80 * 640\u002F3840 ≈ 13.3 px\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Cp>13 像素高的「人」对卷积特征来说接近噪声。于是：\u003C\u002Fp>\u003Cul>\u003Cli style=\"line-height:2\">只换更大 YOLO 结构，救不了「已经被缩没」的目标；\u003C\u002Fli>\u003Cli style=\"line-height:2\">有效手段是：提高 input_size（960\u002F1280），或 Tile 切块让局部仍保有足够像素；\u003C\u002Fli>\u003Cli style=\"line-height:2\">本项目在宽≥1280 或高≥720 时由按帧规划 Tile 启用 tile plan，正是被这个数量级逼出来的。\u003C\u002Fli>\u003C\u002Ful>\u003Cp style=\"line-height:2\">\u003Cbr \u002F>\u003C\u002Fp>\u003Ch1>十、参数与失败模式（对着参数调）\u003C\u002Fh1>\u003Cp>\u003Cimg src=\"https:\u002F\u002Fqu-link.oss-cn-hangzhou.aliyuncs.com\u002F2026\u002F08\u002F14\u002F9b72481c-81c7-4c11-a35c-f6a14fb66cb3.png\" alt=\"\" loading=\"lazy\" \u002F>\u003C\u002Fp>\u003Cp>常见故障：\u003C\u002Fp>\u003Col>\u003Cli style=\"line-height:2\">整图平移：pad 符号反了，或居中\u002F右下 pad 与训练不一致；\u003C\u002Fli>\u003Cli style=\"line-height:2\">只有近处大人：input 太小或阈值过高；\u003C\u002Fli>\u003Cli style=\"line-height:2\">广告牌人形：语义误检，靠面积\u002F宽高比过滤或后续人脸验证；\u003C\u002Fli>\u003Cli style=\"line-height:2\">手机录像框旋转：元数据 rotation 未烧进像素，几何全错；\u003C\u002Fli>\u003Cli style=\"line-height:2\">TRT\u002FCUDA 换后端后框飞了：先查输出 layout 与 FP16，再查预处理是否仍走同一套 letterbox。\u003C\u002Fli>\u003C\u002Fol>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Ch1>十一、建议的最小验证集\u003C\u002Fh1>\u003Cp>固定 20～50 张图，覆盖：近景大人、走廊远人、侧身、遮挡、逆光、并排两人。每次改预处理或阈值：\u003C\u002Fp>\u003Col>\u003Cli style=\"line-height:2\">叠加画出 letterbox 框与原图框；\u003C\u002Fli>\u003Cli style=\"line-height:2\">对比改动前后同一张图的框列表；\u003C\u002Fli>\u003Cli style=\"line-height:2\">记录 scale\u002Fpad\u002Fscore_thresh\u002Fnms_iou 到日志（本项目定位阶段日志也依赖这些字段复盘）。\u003C\u002Fli>\u003C\u002Fol>\u003Cp>没有可视化回归，坐标类 bug 会在跟踪阶段以「ID 乱跳」的假象出现，极难从下游反查。\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Ch1>十二、 小结\u003C\u002Fh1>\u003Cp>本项目的人体检测，技术核心是：\u003C\u002Fp>\u003Col>\u003Cli style=\"line-height:2\">Letterbox 用 min 缩放比 + 居中 114 填充，保住人体比例并记下 scale\u002Fpad；\u003C\u002Fli>\u003Cli style=\"line-height:2\">84×N 张量里取出 person 分数与 cx,cy,bw,bh，并兼容两种内存布局；\u003C\u002Fli>\u003Cli style=\"line-height:2\">逆变换严格按 (cx - bw\u002F2 - pad) \u002F scale 回到原图，再 NMS；\u003C\u002Fli>\u003Cli style=\"line-height:2\">小目标首先卡在「网络内像素高度」，逼出更大输入或 Tile。\u003C\u002Fli>\u003C\u002Fol>\u003Cp>把这四段各自钉死，YOLO 才从「能跑的模型」变成「可跟拍的框」。切块、跟踪、认脸都建立在这个交付物之上。\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Ch1>十三、与 Tile 的分界（本篇只点到为止）\u003C\u002Fh1>\u003Cp>当 frame_w &gt;= 1280 或 frame_h &gt;= 720 时，按帧规划 Tile 会返回非零 grid，检测改为「多块 letterbox + 核心区过滤 + 全局 NMS」。\u003C\u002Fp>\u003Cp>单块内部仍然完整走本篇的 Letterbox→推理→逆变换；多出来的是 ROI 原点叠加 与 跨块去重。\u003C\u002Fp>\u003Cp>因此：Letterbox 公式错，Tile 必然全错；Letterbox 对了，Tile 才有调网格与 overlap 的意义。\u003C\u002Fp>\u003Cp>\u003Cbr \u002F>\u003C\u002Fp>\u003Ch1>十四、实现检查清单\u003C\u002Fh1>\u003Col>\u003Cli style=\"line-height:2\">scale\u002Fpad 是否从 letterbox 原样传到 检测解析（禁止中途被别的 resize 覆盖）。\u003C\u002Fli>\u003Cli style=\"line-height:2\">BGR\u002FRGB、\u002F255 是否与导出模型一致。\u003C\u002Fli>\u003Cli style=\"line-height:2\">输出 layout 是否同时覆盖 特征维在前的布局 与 候选维在前的布局。\u003C\u002Fli>\u003Cli style=\"line-height:2\">逆变换是否先减 pad 再除 scale（顺序反了框会漂）。\u003C\u002Fli>\u003Cli style=\"line-height:2\">NMS 前后是否做了与原图的 clip。\u003C\u002Fli>\u003Cli style=\"line-height:2\">日志是否打印 scale,pad,score_thresh,nms_iou,box_count。\u003C\u002Fli>\u003Cli style=\"line-height:2\">困难样张回归是否覆盖远人与并排两人。\u003C\u002Fli>\u003C\u002Fol>\u003Cp>满足以上，人体检测这一环才算「可维护地讲透」，而不是「碰巧能跑」。\u003C\u002Fp>","https:\u002F\u002Fqu-link.oss-cn-hangzhou.aliyuncs.com\u002F2026\u002F08\u002F14\u002Fc39dad9d-8f28-46e8-a8c8-c009d1c509fa.jpg","9,84,85","美畅，美畅物联，畅联，畅联云平台，视频监控云平台，云视频监控，视频云平台，视频开放平台，视频感知云，视频接入网关，AIoT综合接入网关，视频中台，物联网中台，视频上云网关，Ehome，I连锁行业，智慧交通，AI算法","原创技术分享丨美畅物联向工","https:\u002F\u002Fwww.24hlink.cn\u002Ftech\u002F2555","2026-08-14 10:54:17","857"]