畅联云平台丨08-路人头部椭圆虚化

2026年9月3日
畅联云平台丨08-路人头部椭圆虚化

路人头部椭圆虚化:观测、排主角、椭圆 mask 与一次 FFmpeg 合成

本文讲清:非主角脸如何变成有限条 椭圆虚化轨迹,再经 crop → boxblur → geq(alpha) → overlay 叠回成片,且与 Lens/Crop 合并进同一滤镜图,与跟拍同一遍转码完成,避免二次解码。

图:轴对齐椭圆半轴由脸框与 pad 决定;外为清晰,内为模糊。


一、观测从哪来:other_face_obs

扫描阶段,在人体检测与 ByteTrack  之外,收集 非主角脸观测:

写入路径包括:

  • 检测帧上,对非主角人体 ROI 跑 SCRFD(for_stranger_blur=true,ROI 阈值放宽);
  • 离线从 ByteTrack 历史回填;
  • 再剥一次主角;
  • 丢掉闪现。

最小脸尺寸与占比:短边至少约 16 px,且不超过画幅短边约 26%。

连续帧间隙容忍与检测步长挂钩:

stride=3 时,隔帧观测仍可串成一条路人轨。


二、排除主角:三道闸

图:任一闸命中则该观测不得进入虚化轨迹。

2.1 track_id

byte_track_id == hero_byte_track_id,直接排除。这是最干净的信号。

2.2 thumb 相似度

锁定阈值常见为 0.32。

轨迹级:若多点 拇指图相似度 达到「像主角」比例,整轨丢弃。

2.3 几何 IoU / 重叠

输出空间椭圆与主角保护区 IoU 过高 → 丢弃该关键点。

源空间也有类 似保护。

策略:宁可漏糊路人,不可误伤主角。

三、椭圆参数:半轴与 pad≈1.08

脸框 (x,y,w,h) → 输出椭圆,默认 face_pad ≈ 1.08

椭圆半轴:a ≈ 脸宽/2×1.08,b ≈ 脸高/2×1.08。

相对轴对齐脸框,面积放大 1.08²≈1.17(约 +17%),盖住发际与下巴外缘。

椭圆方程(patch 局部坐标,圆心在 (a,b)):

v = ((X-a)/a)² + ((Y-b)/b)²

  • v ≤ 1:完全在椭圆内;
  • 1 < v ≤ 1+f:羽化带;
  • 其它:透明。

数值例子

脸 80×100,pad=1.08:

外接矩形约 86×108。高分检测(det_score ≥ 0.50)还会再外扩(cover expand),再乘 margin=1.05,确保糊区盖住源脸。

由人体估头时,宽向也用 1.08:

与虚化 pad 同数量级,语义一致:「头比脸略宽」。


四、聚类、排序与「约 4 条」

按时空邻近串轨;再排序取显著轨。

硬上限 32。成片滤镜每个椭圆要 split + crop + boxblur + geq + overlay,节点线性膨胀。实务经验与科普约定:同时服务约 4 条显著路人轨 已够店内/合影场景;更短的路过会被排序挤掉。

最短连续:min_consec=2,避免单帧闪糊。

尾部 hold:离开后继续糊约 tail_hold=6 源帧(≈0.24 s @25),防止人刚出框椭圆瞬间消失。


五、中心平滑与半轴稳定

路人轨迹高斯 σ:Crop 约 0.18 s,Lens 约 0.12 s(稠密观测更短)。

半轴若帧间跳变超过半轴跳变切断比例(稀疏 0.15 / 稠密 0.28),切断为新 segment,避免一个巨大椭圆跨剧变。

实务技巧:segment 内对 semi 取较大稳定值,中心仍跟随——消除「呼吸感」。


六、 Alpha 合成公式

图:椭圆内用模糊图,外保留清晰图,边缘羽化过渡。

逐像素 alpha∈[0,1] 由椭圆 geq 给出(存成 0~255 再归一化)。

羽化宽度 feather_px(默认常为 1)。本项目实现:

std::string ellipse_alpha_geq_expr(int semi_a, int semi_b, int feather_px) {
 const std::string v = "((X-a)*(X-a)/a2+(Y-b)*(Y-b)/b2)"; // conceptual
 if (feather_px <= 0) return "if(lte(" + v + ",1),255,0)";
 return "if(lte(v,1),255, if(lte(v,1+f), floor(255*(1+f-v)/f), 0))";
}

七、FFmpeg 滤镜串:boxblur + geq + overlay

追加路人虚化滤镜(与滤镜构建同构)逐步:

  • split:一路做补丁,一路保持清晰底;
  • crop:按椭圆外接矩形从当前位置裁出;
  • boxblur:用 boxblur 滤镜表达式(半径受限时链式多次近似更强糊);
  • geq:写椭圆 alpha;
  • overlay:贴回,enable 限制活跃帧区间。

中心用分段线性:

任意输出帧的中心,由关键点序列做分段线性插值得到。

点列常关键点抽稀到约 24 点。

数值例子:算力粗估

1080p25,4 条椭圆,各平均半轴 50→补丁约 100×100:

  • 每帧 4 次小图 boxblur + overlay,远小于全图糊;
  • 滤镜图节点约 4×(split+crop+blur+geq+overlay)≈20+ 个标签。

若强行上 20 条长轨,字符串 与图编译时间会明显变差——这是「约 4 条」的工程动机。


八、与 Lens/Crop 合并为一遍

在 lens/crop 滤镜末尾:若有路人轨则先 format=yuv420p[vfocus],再串 stranger blur,最终 [vout]

即:跟拍几何与路人虚化同一滤镜图、一次解码一次编码。

合并出片若分步,也可能先 focus 再 blur 独立转码;优先路径是 merged one-pass。

映射注意:路人椭圆必须变到 输出坐标系。Lens 下要乘 zoom 并减 overlay 偏移;Crop 下要减窗原点再乘缩放。专门做这件事——在源坐标糊一发再拉伸,椭圆会错位。


九、覆盖率与丢弃

椭圆落到输出后,与有效画布(或 crop 内框)交集比例过低则丢点,避免糊在黑边/画外。

高分检测强制扩椭圆:det_score >= 0.50 时 cover expand(margin 1.05)。


十、GPU 路径对照

用同一套按帧取椭圆轨迹取圆心半轴,在 CUDA  上做 ROI blur + feather mask。参数语义与 FFmpeg 一致:radius / power / feather。调试可用叠加视频画椭圆轨迹验证。


十一、参数表


十二、 端到端心算例

场景:1280×720@25,crop 跟拍,路人脸源框 60×70,窗缩放后输出脸约 72×84,pad=1.08:

例如脸宽 72、脸高 84:半轴 a≈39、b≈45。

椭圆内像素约 πab≈5510。boxblur luma_radius=5、power=1,局部足够毁容级模糊;主角若 IoU 重叠被 guard 掉,则该关键点不入轨。

时间:观测在 frame 100、103、106(stride=3),max_gap 与 stride 挂钩,可聚成一条;平滑 σ=0.18 s 后写入圆心点列;成片 n 从对应 25fps 索引启用到尾 hold。


十三、公式卡

椭圆:

((X−cx)/a)² + ((Y−cy)/b)² ≤ 1

pad:

半轴公式:a=脸宽/2×pad,b=脸高/2×pad,pad≈1.08。

合成:椭圆内取 blur,外取 sharp,羽化带线性过渡。

排除主角(逻辑或):

排除主角:跟踪号相同,或相似度够高,或与主角框重叠过大——任一成立就不虚化。

合并:

把观测清洗、椭圆几何、滤镜串三件事分开调试,路人虚化问题通常一次就能定位到层。


十四、输出坐标映射:为何不能在源图糊完再拉伸

Lens 下源脸 (f_x,f_y,f_w,f_h) 到输出椭圆,核心步骤:

  1. 计算当前帧英雄圆心 (hero_cx, hero_cy) 与 zoom;
  2. 用与成片相同的圆镜叠加原点计算得到放大图层偏移;
  3. 把脸中心变到放大图层坐标,再变到圆镜 canvas,最后到输出 overlay 位置;
  4. 半轴乘 zoom * pad

Crop 下:

若同时做了裁切/缩放,椭圆中心与半轴都要变换到最终输出坐标系。

若错误地「源图椭圆 → 整帧 scale」,窗在移动时路人会相对主角滑动,出现「糊斑追错人」。因此构建时就按输出 n 采样映射,写入的圆心点列已是输出像素。

美畅美畅物联畅联畅联云平台视频监控云平台云视频监控视频云平台视频开放平台视频感知云视频接入网关AIoT综合接入网关视频中台物联网中台视频上云网关EhomeI连锁行业智慧交通AI算法