AI-深度学习

口鼻遮挡工程实录:04 图像预处理与坐标转换

展开合集目录
  1. 口鼻遮挡工程实录:01 需求与判断边界
  2. 口鼻遮挡工程实录:02 方案探索与演进
  3. 口鼻遮挡工程实录:03 总体架构与完整时序
  4. 口鼻遮挡工程实录:04 图像预处理与坐标转换
  5. 口鼻遮挡工程实录:05 头部检测与YuNet
  6. 口鼻遮挡工程实录:06 PIPNet98关键点与响应
  7. 口鼻遮挡工程实录:07 FaceOcc分割与口鼻覆盖率
  8. 口鼻遮挡工程实录:08 姿态与几何分析
  9. 口鼻遮挡工程实录:09 多证据融合规则
  10. 口鼻遮挡工程实录:10 跟踪与持续确认
  11. 口鼻遮挡工程实录:11 YOLO-World物体复核
  12. 口鼻遮挡工程实录:12 模型转换与海思部署
  13. 口鼻遮挡工程实录:13 板端运行与调试闭环
  14. 口鼻遮挡工程实录:14 测试评估与问题复盘
  15. 口鼻遮挡工程实录:A 附录A-参数字典
  16. 口鼻遮挡工程实录:B 附录B-状态与结果字段
  17. 口鼻遮挡工程实录:C 附录C-模型与代码索引
  18. 口鼻遮挡工程实录:D 附录D-完整教学样例
口鼻遮挡工程实录:04 图像预处理与坐标转换的封面

系列编排日期为 2026 年 8 月;正文依据 2026-10-12 核对的实现整理。历史实测保留真实日期,教学数字不代表实测;本次未重新执行板端推理。

返回系列目录 · 本篇为 14 章+4 份附录中的一篇。

预处理就是模型接口的一部分

模型文件相同,输入颜色、数值范围或裁剪几何不同,输出仍可能完全不同。调试时首先固定输入像素,再比较网络输出;不能直接通过调整阈值补偿预处理错误。

本地 OpenCV 图像是 BGR 交错布局:一个像素的 B、G、R 连续存放。板端 OM 接收 BGR planar UINT8:先放整幅 B 平面,再放 G、R 平面。planar() 的位置公式为:

dst[c × W × H + y × W + x] = bgr[y, x, c]
输入字节数 = 3 × W × H

NCHW 的概念不能与 BGR/RGB 混为一谈:前者描述维度排列,后者描述通道含义。传入 HWC 字节却声明成 planar,网络会看到错误图像。

五个模型的输入不能共用一套归一化

模型 几何输入 训练侧输入语义
YOLOv5s-P34 640×640,等比例补边 RGB,除以 255
YuNet 320 320×320,头部 ROI 等比例缩放,右下补黑 BGR;原网络为 0~255,本地 input255 图配合 AIPP 除以 255,详见第十二章
PIPNet98 256×256,直接缩放脸部裁剪 RGB,ImageNet 均值和标准差
FaceOcc 与 PIPNet 相同裁剪及尺寸 原始 FaceExtraction 权重对应 RGB/255
World64 640×640,等比例补边 RGB/255

PIPNet 的归一化为 z=(pixel/255−mean)/std,三个通道的 mean 为 [0.485,0.456,0.406],std 为 [0.229,0.224,0.225]。例如 R=128 时,标准化值约为 0.074,而 RGB/255 的值约为 0.502,两者不能互换。

在板端,AIPP 已经嵌入各自 OM,调用者提供 UINT8 原始值。若先在 CPU 上标准化一次,AIPP 再执行一次,就是重复预处理。FaceOcc 的同名衍生版本可能使用不同配置,本系列只针对本项目原始权重与已转换 OM,不把其他版本的预处理移植过来。

第一层:头部检测的 letterbox

给定原图 W×H 和目标 Tw×Th:

s = min(Tw/W, Th/H)
rw = round(W×s), rh = round(H×s)
模型坐标:u = x×s + pad_x,v = y×s + pad_y
原图坐标:x = (u−pad_x)/s,y = (v−pad_y)/s

例如 960×540 输入到 640×640,缩放后为 640×360,上下各补约 140 像素。模型点 (320,320) 对应原图 (480,270)。本地头模型代码用接近 YOLO 的 nearbyint(half_padding−0.1) 处理整数边界;应保存实际 padding,不要在后处理重新凭理论值猜测。

旧 YOLOv5m 输入是 640×384,不能只换 OM 而保留 640×640 解码。

第二层:扩大头框后找脸

head_padding=0.15 表示左右各扩头宽的 15%,上下各扩头高的 15%,未裁切时整体宽高约为原来的 1.3 倍。它与 World 的 review_expansion=1.6 不是同一种参数。

YuNet 对头部 ROI 缩放到最长边 320,图像放在输入左上角,剩余右边或下边补零。这里没有居中 padding。

人脸原图 x = YuNet_x × head_roi_width / resized_width + head_roi_x
人脸原图 y = YuNet_y × head_roi_height / resized_height + head_roi_y

宽高按各自实际整数缩放尺寸还原,避免取整造成一两个像素的累计偏差。

第三层:脸部裁剪并非四边对称扩展

当前 OcclusionCore.h::faceCrop() 使用带 +1 的框宽高。左右扩展约 10%;上边缘向下移动约脸高的 10%,下边缘也向下移动同量,然后裁到图像边界。它更接近水平扩展并下移裁剪,不能简写为“四周统一扩 10%”。

PIPNet 与 FaceOcc 都对这个裁剪直接 resize 到 256×256。原裁剪可以是矩形,所以几何计算必须恢复长宽比;分割与点位在共同的 256 坐标系内则能够直接对应。

归一化点 (u,v) → 原图:
x = crop_x + u × crop_width
y = crop_y + v × crop_height

归一化点 → 网络采样位置:
x256 = u × 256,y256 = v × 256

原图绘制与采样边界不是同一个判断。u=1 会映射到 256,已超出采样索引 0~255,因此局部 ROI 必须明确拒绝越界,不能简单裁到边缘伪造有效覆盖。

插值、取整与掩膜的区别

当前统计先在 256×256 概率图中阈值化,再对同坐标系的口鼻 mask 计数。显示则把概率图 resize 回原裁剪,再阈值叠绿。插值和阈值运算不交换,因此屏幕上看到的绿色边缘与统计 mask 可能略有不同。

复现覆盖率应复用统计过程,不能对标注截图的绿色像素重新计数。截图还可能经过颜色混合、JPEG 压缩和显示缩放。

定位问题的检查顺序

先比较原图 SHA-256,再比较裁剪四元组和裁剪像素;然后检查通道排列、输入字节数、AIPP、输出布局,最后比较点位和分割。如果第一处偏差已经发生在 crop,后面的网络误差统计就混入了输入差异。

本章依据:StreamNpuOcclusionProcessor.cpp、OcclusionCore.h、yunet_occlusion/model/pipnet_onnx.py、unet_occlusion/README.md、各模型转换脚本。


上一篇:总体架构与完整时序 · 系列目录 · 下一篇:头部检测与YuNet