analysis: inspect the current sun-hat clip at 25fps and narrow flicker candidates

这个提交包含在:
dayu 于 2026-10-22 20:02:23 +08:00 提交
1 父节点 623dcb878b
当前提交 a0c5357efd
6 个文件已更改
+458 -11

没有与搜索条件相匹配的文件

@@ -0,0 +1,318 @@
{
"decodedSize": [
1920,
1080
],
"decodeOrVisionErrors": 0,
"duplicateSourceFramePairs": 0,
"durationSeconds": 18.752066666666668,
"emptyDetectionFrames": 0,
"frames": 469,
"heldFrames": 0,
"landmarkConfidenceBelow055Frames": 0,
"largestContourChanges": [
{
"actualSeconds": 5.7057,
"bboxCenterStep": 0.010612391844050412,
"bboxRelativeSizeStep": 0.07225176667426436,
"faceConfidence": 1,
"faceCount": 1,
"frame": 143,
"held": false,
"landmarkConfidence": 0.85870361328125,
"outputAllShapeStep": 0.05320087993361461,
"outputContourShapeStep": 0.0524041977802718,
"points76Count": 76,
"rawAllShapeStep": 0.06465122287331607,
"rawContourShapeStep": 0.06330400492305996,
"rawEyeShapeStep": 0.07106297705037405,
"requestedSeconds": 5.72
},
{
"actualSeconds": 5.538866666666666,
"bboxCenterStep": 0.011085862886644501,
"bboxRelativeSizeStep": 0.06308677201537605,
"faceConfidence": 1,
"faceCount": 1,
"frame": 139,
"held": false,
"landmarkConfidence": 0.86663818359375,
"outputAllShapeStep": 0.05242709853363116,
"outputContourShapeStep": 0.046564814499130476,
"points76Count": 76,
"rawAllShapeStep": 0.06161259278352428,
"rawContourShapeStep": 0.05478966859045086,
"rawEyeShapeStep": 0.06493439304604706,
"requestedSeconds": 5.56
},
{
"actualSeconds": 5.6723333333333334,
"bboxCenterStep": 0.009899754844891629,
"bboxRelativeSizeStep": 0.07041863176014063,
"faceConfidence": 1,
"faceCount": 1,
"frame": 142,
"held": false,
"landmarkConfidence": 0.86846923828125,
"outputAllShapeStep": 0.0504812129727618,
"outputContourShapeStep": 0.04661140849311553,
"points76Count": 76,
"rawAllShapeStep": 0.05657646866920014,
"rawContourShapeStep": 0.05209665662633769,
"rawEyeShapeStep": 0.0633232078503364,
"requestedSeconds": 5.68
},
{
"actualSeconds": 18.7187,
"bboxCenterStep": 0.012083635671277248,
"bboxRelativeSizeStep": 0.045801810508214524,
"faceConfidence": 1,
"faceCount": 1,
"frame": 468,
"held": false,
"landmarkConfidence": 0.813995361328125,
"outputAllShapeStep": 0.034052174045594144,
"outputContourShapeStep": 0.043147628575738506,
"points76Count": 76,
"rawAllShapeStep": 0.04111983043006513,
"rawContourShapeStep": 0.05091513919680358,
"rawEyeShapeStep": 0.029191044989766733,
"requestedSeconds": 18.72
},
{
"actualSeconds": 5.739066666666667,
"bboxCenterStep": 0.0096878552974905,
"bboxRelativeSizeStep": 0.050414751769179866,
"faceConfidence": 1,
"faceCount": 1,
"frame": 144,
"held": false,
"landmarkConfidence": 0.86083984375,
"outputAllShapeStep": 0.036875562148072825,
"outputContourShapeStep": 0.036457754092126635,
"points76Count": 76,
"rawAllShapeStep": 0.0466359793805061,
"rawContourShapeStep": 0.04577259881583104,
"rawEyeShapeStep": 0.05000862947922753,
"requestedSeconds": 5.76
},
{
"actualSeconds": 0.8675333333333334,
"bboxCenterStep": 0.003874961092189615,
"bboxRelativeSizeStep": 0.07178938570952054,
"faceConfidence": 1,
"faceCount": 1,
"frame": 22,
"held": false,
"landmarkConfidence": 0.8583984375,
"outputAllShapeStep": 0.031532331820470494,
"outputContourShapeStep": 0.0381074357036598,
"points76Count": 76,
"rawAllShapeStep": 0.03707185765347939,
"rawContourShapeStep": 0.04568537667821508,
"rawEyeShapeStep": 0.034575716035532285,
"requestedSeconds": 0.88
},
{
"actualSeconds": 18.651966666666667,
"bboxCenterStep": 0.007272824106484237,
"bboxRelativeSizeStep": 0.03719342311108376,
"faceConfidence": 1,
"faceCount": 1,
"frame": 467,
"held": false,
"landmarkConfidence": 0.8199462890625,
"outputAllShapeStep": 0.03952595504917539,
"outputContourShapeStep": 0.0403761896420276,
"points76Count": 76,
"rawAllShapeStep": 0.04399124673462057,
"rawContourShapeStep": 0.0450952404425199,
"rawEyeShapeStep": 0.04542945579876513,
"requestedSeconds": 18.68
},
{
"actualSeconds": 0.9009,
"bboxCenterStep": 0.0017162987254983866,
"bboxRelativeSizeStep": 0.014351427482534596,
"faceConfidence": 1,
"faceCount": 1,
"frame": 23,
"held": false,
"landmarkConfidence": 0.85809326171875,
"outputAllShapeStep": 0.026103724683818753,
"outputContourShapeStep": 0.04109990769809984,
"points76Count": 76,
"rawAllShapeStep": 0.028649663225073875,
"rawContourShapeStep": 0.04465304774876588,
"rawEyeShapeStep": 0.02979010461963986,
"requestedSeconds": 0.92
},
{
"actualSeconds": 0.7007,
"bboxCenterStep": 0.007675079557145801,
"bboxRelativeSizeStep": 0.059965605197173644,
"faceConfidence": 1,
"faceCount": 1,
"frame": 18,
"held": false,
"landmarkConfidence": 0.877166748046875,
"outputAllShapeStep": 0.038188462475739905,
"outputContourShapeStep": 0.040855905682333056,
"points76Count": 76,
"rawAllShapeStep": 0.04142583196750897,
"rawContourShapeStep": 0.04413941822893812,
"rawEyeShapeStep": 0.04424396634844577,
"requestedSeconds": 0.72
},
{
"actualSeconds": 0.8341666666666666,
"bboxCenterStep": 0.0019315279136915449,
"bboxRelativeSizeStep": 0.03041757827231506,
"faceConfidence": 1,
"faceCount": 1,
"frame": 21,
"held": false,
"landmarkConfidence": 0.861602783203125,
"outputAllShapeStep": 0.023950562918532762,
"outputContourShapeStep": 0.0391113963086702,
"points76Count": 76,
"rawAllShapeStep": 0.026769304364061126,
"rawContourShapeStep": 0.043656761461571575,
"rawEyeShapeStep": 0.021617825564847367,
"requestedSeconds": 0.84
},
{
"actualSeconds": 5.9726333333333335,
"bboxCenterStep": 0.0076538482284609945,
"bboxRelativeSizeStep": 0.009531954788836172,
"faceConfidence": 1,
"faceCount": 1,
"frame": 150,
"held": false,
"landmarkConfidence": 0.85198974609375,
"outputAllShapeStep": 0.03696981884576201,
"outputContourShapeStep": 0.038389239030267384,
"points76Count": 76,
"rawAllShapeStep": 0.04143716031529852,
"rawContourShapeStep": 0.042871635488955444,
"rawEyeShapeStep": 0.0428226737500748,
"requestedSeconds": 6
},
{
"actualSeconds": 16.649966666666668,
"bboxCenterStep": 0.006605729070676864,
"bboxRelativeSizeStep": 0.025478189396700213,
"faceConfidence": 1,
"faceCount": 1,
"frame": 417,
"held": false,
"landmarkConfidence": 0.8674774169921875,
"outputAllShapeStep": 0.03284710686769975,
"outputContourShapeStep": 0.036339332152690744,
"points76Count": 76,
"rawAllShapeStep": 0.037116421558418974,
"rawContourShapeStep": 0.04240155312389841,
"rawEyeShapeStep": 0.03197382659897345,
"requestedSeconds": 16.68
}
],
"multipleFaceFrames": 0,
"nominalSourceFPS": 29.970029830932617,
"outputWithout76Frames": 0,
"partial76Frames": 0,
"samplingFPS": 25,
"scope": "Independent offline decoding and the current production detector/tracker; not FCP render logs or target execution. Shape steps remove previous bbox translation/scale, but still include actual pose/expression changes.",
"sourceBasename": "girl-in-sun-hat-smiling-in-rural-field-2026-10-03-13-54-14-utc.mov",
"statistics": {
"bboxCenterStep": {
"max": 0.012083635671277248,
"median": 0.0025497870742485452,
"min": 0.00020005997144872253,
"n": 468,
"p95": 0.006821726779186577
},
"bboxRelativeSizeStep": {
"max": 0.07225176667426436,
"median": 0.009157247402053037,
"min": 6.255832853296894e-06,
"n": 468,
"p95": 0.03431959948374386
},
"landmarkConfidence": {
"max": 0.9240875244140625,
"median": 0.867706298828125,
"min": 0.813995361328125,
"n": 469,
"p95": 0.902191162109375
},
"outputAllShapeStep": {
"max": 0.05320087993361461,
"median": 0.009735492145012412,
"min": 0.0029755122029975372,
"n": 468,
"p95": 0.026782532902396017
},
"outputContourShapeStep": {
"max": 0.0524041977802718,
"median": 0.011810624254892923,
"min": 0.002450992809745613,
"n": 468,
"p95": 0.028720841841711312
},
"rawAllShapeStep": {
"max": 0.06465122287331607,
"median": 0.01108023509780489,
"min": 0.0031002818411607846,
"n": 468,
"p95": 0.030464142596339925
},
"rawContourShapeStep": {
"max": 0.06330400492305996,
"median": 0.013550650249078297,
"min": 0.002692092571665042,
"n": 468,
"p95": 0.03357642027607019
},
"rawEyeShapeStep": {
"max": 0.07106297705037405,
"median": 0.010302814344493833,
"min": 0.0013460890263982167,
"n": 468,
"p95": 0.02979010461963986
}
},
"timelineOffsetSeconds": 18.72,
"nativeContext": {
"app": "Final Cut Pro",
"project": "大鱼人像美化验收-20261021",
"format": "1080p25",
"selectedClipStartTimecode": "00:00:18:18",
"selectedClipEndTimecode": "00:00:37:11",
"timelinePlayheadAX": "00:00:24:11",
"viewerLCD": "00:00:35:22",
"faceThin": 1,
"faceBigEye": 0.9035486629353234,
"fastMultiFace": false,
"sourceResolvedBy": "Selected timeline clip > File > Reveal in Finder",
"timelineMediaMapping": "Offset18.72 is inferred from clip placement; source in-point/retiming not exported, so source5.72 -> timeline24:11 is approximate. Viewer LCD differs from AX playhead; displayed frame not asserted."
},
"interpretation": {
"partialTopologySwitchObserved": false,
"candidate": "Fully detected geometry changes retained by the current box-remapping and 90% current-frame point blend; eye effect also active",
"notProven": [
"Observed geometric change includes actual head motion, rotation and expression; not all measured change is detector noise",
"No target output frames or live target internal geometry captured",
"Native FCP arrival order and detection/color/scale can differ from the independent decode",
"Big-eye contribution not measured independently on the native timeline"
]
},
"referenceProcessIdentity": {
"observedAlreadyRunning": true,
"outerApp": "/Library/Plug-Ins/FxPlug/MSE18V2.app",
"version": "2.4.0",
"pluginSha256": "577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109",
"matchesRequestedDownloadsBinary": true,
"analysisLaunchedTarget": false,
"internalTargetGeometryCaptured": false
}
}
@@ -1,5 +1,5 @@
{
"scope": "Source and isolated authored synthetic diagnostics plus static REA of the requested 2.4.0 binary; no native host comparison",
"scope": "Current source review, isolated authored diagnostics, static REA of requested2.4.0, and independent25fps scan of the user-selected current clip; no native dual-plugin comparison",
"sourceBaseline": "b58fec1a86db7a2e474e1cc65a5911447b5906b9",
"installedVersion": "1.3.2 (17)",
"productSourceUnchanged": true,
@@ -18,14 +18,19 @@
"scripts/diagnose-tracking.m": "bc758bf5ec4825006930be8997889404f63c28da1fe06ad8872b0901b2795d2c",
"docs/analysis/tracking-flicker-20261022/synthetic-results.json": "5fdbad4887dd78658c06f5c6d8e70c9e53fd7b54e11a9cc31ee1958631cbc1a8",
"docs/analysis/tracking-flicker-20261022/rea-evidence.json": "4b367759388c8e061e138623184ae8a6875dbab22659eefd4e474b141b8868fa",
"scripts/diagnose-tracking.sh": "c1993ca91cee596a21db1e4f86ba224be85c37495c783f9c3b21872aff210765"
"scripts/diagnose-tracking.sh": "c1993ca91cee596a21db1e4f86ba224be85c37495c783f9c3b21872aff210765",
"scripts/inspect-tracking-sequence.m": "0b94fc92669acf4d36861ccb25077b767189b8a72647e0d304627dbda5d052eb",
"docs/analysis/tracking-flicker-20261022/current-clip-summary.json": "043ba688c606fb9e56449fd02108b34789fd41c4d9a2552cd07f4d3bf78a00f0"
},
"limits": [
"No user frames or complete user landmark arrays used or uploaded",
"No target process executed or host UI controlled",
"Static reachable/default-configuration branches do not prove runtime branch execution",
"Same-frame raw cache, hold and out-of-order behavior were isolated using our actual current implementation",
"No APP rebuild, install, package or article publication for this analysis",
"User clarified current FCP timeline: sun-hat subject, 1080p25, fast multi off, faceThin1, bigEye about0.90; exact source/frame analysis in progress"
]
"User source decoded only locally; no source frames or complete real landmark arrays uploaded",
"User current FCP clip confirmed, all469 offline samples have full76; earlier missing-point synthetic case is not established as this clip cause",
"Only scalar clip summary retained; full scalar per-frame diagnostics remain in ignored build",
"Approximate timeline offset is not a substitute for verified source in-point/retiming",
"Reference was already running; only process executable identity read. Native UI read/reveal/raise only, no effect/timeline edits; no target launch, debugger or geometry trace."
],
"currentClipSummary": "current-clip-summary.json"
}
+18 -3
查看文件
@@ -1,12 +1,12 @@
# 瘦脸跟踪闪烁:1.3.2 与目标 2.4.0 的对齐缺口
2026-10-22。用户实测同一段素材,本插件瘦脸跟踪闪烁,目标插件稳定。本次分析基线为 `b58fec1a86db7a2e474e1cc65a5911447b5906b9`,已安装版仍为 1.3.2(17)。只做源码审查、隔离合成复现和静态二进制对照,没有修改产品源码、重新编译 APP 或操作宿主。
2026-10-22。用户实测同一段素材,本插件瘦脸跟踪闪烁,目标插件稳定。本次分析基线为 `b58fec1a86db7a2e474e1cc65a5911447b5906b9`,已安装版仍为 1.3.2(17)。完成源码审查、隔离合成复现、静态二进制对照和当前素材的独立连续帧采样;通过宿主界面读取状态并定位源文件,没有修改参数/片段、产品源码或重新编译 APP。
主要缺口在跨帧几何的有效性判定、坏帧保持与缓存更新。此前恢复单帧瘦脸位移场,并没有完整对齐新版目标的连续跟踪链。以下区分已经复现的本品行为、目标的静态分支,以及尚未定位到用户素材具体帧的部分。
## 目标版本与旧分析的边界
本次目标是用户指定的 `/Users/dayu/Downloads/MSE18V2.app`,版本 **2.4.0 / 20260724150000**。插件通用二进制 SHA-256 为 `577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109`,arm64 切片为 `afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df`。切片逐字节核对过本次目标,REA 使用 Ghidra 12.1.4;未执行目标。
本次目标是用户指定的 `/Users/dayu/Downloads/MSE18V2.app`,版本 **2.4.0 / 20260724150000**。插件通用二进制 SHA-256 为 `577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109`,arm64 切片为 `afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df`。切片逐字节核对过本次目标,REA 使用 Ghidra 12.1.4。随后仅读取已运行的系统 FxPlug 目标进程,其2.4.0可执行文件摘要与Downloads目标一致;本次没有启动目标、附加调试器或采集其内部几何。
原有 [auto-follow-report.json](auto-follow-report.json) 分析的是 `/Applications/MSE18V2.app` 的旧版 `1.0.20260617-170517`,通用二进制 SHA 为 `6c5d74bc844a5c5f745718b48ea10ec6635d08aa08a5b6dc6e62653980849f8a`。其中 temporal 混合系数和历史优先级不能直接当成 2.4.0 的默认瘦脸实现。
@@ -14,6 +14,21 @@
对应 Evidence:render `ev_2330b66132cd6539b8c66313c8dc43ca6ff5eb3e0881abbbe26857f99de6a83b`;pin-style `ev_58dee36fddf4e4c98ce3d880a0bb98190351d1269c960b3ccc275aef81265e8f`;直接调用关系 `ev_568a93f2165e5dc5046e610f47c23e9cebc33f55b5d12d3ee005a1e99a7191f6`、`ev_a8cf6f3aec6fbcf2b698ab8ec52313e20a6a5e0d636bc922c4293e436861db7e`、`ev_7c53c39d245e0063cab89358ab8948cdd734488460464d5f455674bb80a1515a`。
## 当前时间线素材的连续帧核对
用户补充截图后,在 Final Cut Pro 当前时间线选中片段,通过“文件 → 在访达中显示”确认源视频为 `girl-in-sun-hat-smiling-in-rural-field-2026-10-03-13-54-14-utc.mov`。项目为 1080p25,选中片段从18:18到37:11,瘦脸1.00、大眼0.90355、多人模式关闭。没有修改参数或片段;检查结束返回 FCP。
直接调用当前产品检测器与跟踪器,在独立1920×1080解码上按25fps采样源文件全长18.752秒,共 **469帧**。源帧率为29.97003,因此这里模拟项目的采样节奏,并非逐一处理所有源帧,也不等同于FCP的实时请求/色彩/尺寸路径。
- 469帧全部为单脸且完整76点;空检测、部分点、held、Vision/解码错误均为0,关键点置信度最低0.814。**本段离线检查没有触发上文合成的“缺点使瘦脸归零”路径,也没有触发低于0.55的置信度条件。不能将它直接认定为当前素材的主因。**
- 最大轮廓形状步幅出现在请求源时间5.72秒(实际取到5.7057秒)附近。扣除前后检测框的平移/缩放后,raw轮廓RMS步幅为脸框尺度的6.33%,当前稳定输出仍为5.24%;眼部区域步幅7.11%。同一步检测框尺寸变化7.23%,框中心变化0.01061(全图归一化距离)。
- 变化较大的连续区间包括源5.56–5.76秒,另有0.7–0.92秒与片尾。按照所选片段位置、假设源入点为0且未变速,5.72秒约对应时间线24:11,与AX播放头24:11相近;未导出源入点/重定时,且检视器LCD同时为35:22,不能断言用户截图就是该源帧。
- 数值包含真实头部旋转和表情变化;平移/缩放抵消并未消除这些运动。因此它证明“检测仍成功时,几何变化大部分继续进入变形”,尚未量出其中多少属于错误检测。瘦脸和接近0.90的大眼都开启,大眼实现仍为近似,需要独立排查其视觉贡献。
这次素材的排查优先级应先放在**完整有效帧的框/点变化如何进入瘦脸,以及高强度大眼叠加**,再核对新版目标的连续框、几何质量判定与时间状态。一般性的部分失检、空缓存和蒙版缺口仍成立,但不能拿其他情境的合成失败代替这段素材的逐帧归因。
[当前素材标量摘要](tracking-flicker-20261022/current-clip-summary.json) 保存计数、分布和峰值时间;原视频、截图和完整真实关键点没有上传。通用诊断源码为 `scripts/inspect-tracking-sequence.m`;包含生产 .m 以复用真实静态几何转换和跟踪器,编译时只编译该诊断入口,不再重复链接 PGFaceProcessor.m。
## 已确定的差异
| 环节 | 当前 1.3.2 | 目标 2.4.0 的静态证据 | 对闪烁的意义 |
@@ -48,7 +63,7 @@ pin-style 的接纳分支复制本帧合格点,保持分支使用旧有效点
- **补齐缓存和外观同步。** 明确同帧结果与新增前帧历史的失效关系、源切换隔离及默认蒙版跟随;以顺序/倒序/重复/多线程请求对照输出。
- **用同一段素材做连续帧验收。** 锁定宿主、原始帧率、预览/导出条件和相同单项参数;记录检测有效性、保持原因、框/点扰动与效果开关变化,和目标逐帧对照。单张图正常、自动用例通过都不足以宣布闪烁修复。
用户随后指定当前时间线的草帽人物素材,已在 Final Cut Pro 确认项目为1080p25、多人模式关闭、瘦脸1.00,且大眼约0.90;正在对源素材做连续帧核对。现有结论已定位实现缺口与可复现机制,尚未将某一种机制认定为该素材闪烁的唯一原因。本次不构建新 APP,不更新安装包或文章。
当前素材、宿主和可见参数已确认,并完成469帧独立采样;有效点短暂缺失未在该采样中出现。实现缺口与几何变化已定位,目标与本品的原生同帧输出、源入点映射和大眼贡献仍未分离,尚未认定唯一原因。本次不构建新 APP,不更新安装包或文章。
## 保留资料
+1 -1
查看文件
@@ -10,7 +10,7 @@
## 最新待修问题:瘦脸跟踪闪烁(2026-10-22)
用户实测同一段素材,本插件有闪烁、目标稳定。本次完成源码/合成诊断和 Downloads 2.4.0 的静态复核,未修改产品源码或安装版。新版单主要人脸的渲染路径为 pin-style 质量筛选、条件连续框跟踪和坏帧保持;原 auto-follow-report 的旧 Applications 版本 temporal 系数不能直接沿用。已复现部分76点缺失导致瘦脸归零、框抖动无衰减、首次请求空帧缓存不随补入前帧修正,以及几何保持时默认外观蒙版清零。用户已确认当前FCP时间线的草帽人物素材(1080p25、瘦脸1、大眼约0.9、多人关闭),具体连续帧触发率和宿主实际请求序列尚未测量,不宣称已修复。见[跟踪闪烁对齐分析](analysis/跟踪闪烁对齐分析.md),复现入口 `zsh scripts/diagnose-tracking.sh`;这次不是新发行版,无需重发安装包或文章。
用户实测同一段素材,本插件有闪烁、目标稳定。本次完成源码/合成诊断和 Downloads 2.4.0 的静态复核,未修改产品源码或安装版。新版单主要人脸的渲染路径为 pin-style 质量筛选、条件连续框跟踪和坏帧保持;原 auto-follow-report 的旧 Applications 版本 temporal 系数不能直接沿用。已复现部分76点缺失导致瘦脸归零、框抖动无衰减、首次请求空帧缓存不随补入前帧修正,以及几何保持时默认外观蒙版清零。已确认当前FCP草帽素材(1080p25、瘦脸1、大眼约0.9、多人关闭):独立469帧均单脸/完整76点,没有触发缺点归零;源5.56–5.76秒几何变化较大,5.72秒raw/稳定后轮廓步幅6.33%/5.24%。这些还含真实运动,原生请求与大眼贡献未分离,不宣称已修复。见[跟踪闪烁对齐分析](analysis/跟踪闪烁对齐分析.md),复现入口 `zsh scripts/diagnose-tracking.sh`;这次不是新发行版,无需重发安装包或文章。
## 先读和先查
+1 -1
查看文件
@@ -165,4 +165,4 @@ origin/github 的 main、工作分支和 v1.3.2 标签已推送并回读。匿
用户报告目标稳定而本插件闪烁。新目标2.4.0的静态REA复核发现瘦脸单主要人脸改走 pin-style 筛选与保持,条件可达连续对象框跟踪。现有旧版自动跟随报告不能作为该新版主路径完全对齐的依据。直接链接当前产品源码的合成探针确认:76点完整/缺失/完整使变形通道85835/0/85835;纯框抖动输出/输入振幅比1;先请求40ms空帧、再补0ms有效脸后,缓存40ms仍空,与顺序请求不同;默认外观蒙版在几何保持时可清零。这些均为合成诊断,不是用户素材或目标运行统计。
见 analysis/跟踪闪烁对齐分析.md 和同目录 tracking-flicker-20261022;诊断入口 `zsh scripts/diagnose-tracking.sh`。产品源码与正式1.3.2保持相同,未构建APP、未安装、未重发PKG或文章。用户随后确认当前FCP草帽人物素材,已定位源文件,连续帧核对进行中;原1901项回归不代表连续跟踪稳定性已通过。
见 analysis/跟踪闪烁对齐分析.md 和同目录 tracking-flicker-20261022;诊断入口 `zsh scripts/diagnose-tracking.sh`。产品源码与正式1.3.2保持相同,未构建APP、未安装、未重发PKG或文章。已定位当前FCP草帽素材并以项目25fps独立扫描469帧,全部单脸/完整76点、无held/错误,未复现缺点归零;源5.72秒轮廓步幅raw6.33%、稳定后5.24%,仍含真实头动。原生请求与大眼叠加贡献未分离;原1901项回归不代表连续跟踪稳定性已通过。
+109
查看文件
@@ -0,0 +1,109 @@
// Offline diagnostics: actual detector/tracker, scalar statistics only.
// No image, full landmark array, host edit, or reference execution is produced.
#import <AVFoundation/AVFoundation.h>
#import "../FCP-BeautyGirl/FCP-BeautyGirl/Plugin/PGFaceProcessor.m"
static double ShapeRMS(NSDictionary *a, NSDictionary *b, NSUInteger first, NSUInteger last) {
NSArray *x=a[@"points76"], *y=b[@"points76"];
if(x.count!=76 || y.count!=76) return NAN;
CGRect old=PGArrayRect(a[@"box"]), current=PGArrayRect(b[@"box"]);
if(!PGValidRect(old)||!PGValidRect(current)) return NAN;
double sum=0;
for(NSUInteger i=first;i<=last;i++) {
CGPoint p=PGRemapPoint(x[i],old,current);
double dx=(p.x-[y[i][0] doubleValue])/current.size.width;
double dy=(p.y-[y[i][1] doubleValue])/current.size.height;
sum+=dx*dx+dy*dy;
}
return sqrt(sum/(last-first+1));
}
static id NumberOrNull(double x) {return isfinite(x)?@(x):NSNull.null;}
static double EyeRMS(NSDictionary *a, NSDictionary *b) {
CGRect old=PGArrayRect(a[@"box"]), current=PGArrayRect(b[@"box"]);
if(!PGValidRect(old)||!PGValidRect(current))return NAN;
double sum=0;NSUInteger n=0;
for(NSString *key in @[@"leftEye",@"rightEye"]) {
NSArray *x=a[key],*y=b[key];if(!x.count||x.count!=y.count)return NAN;
for(NSUInteger i=0;i<x.count;i++) {
CGPoint p=PGRemapPoint(x[i],old,current);
double dx=(p.x-[y[i][0] doubleValue])/current.size.width;
double dy=(p.y-[y[i][1] doubleValue])/current.size.height;
sum+=dx*dx+dy*dy;n++;
}
}
return n?sqrt(sum/n):NAN;
}
int main(int argc,const char *argv[]) {@autoreleasepool {
if(argc!=6) {fprintf(stderr,"usage: inspect-tracking-sequence <video> <output.json> <fps> <decode-longest> <timeline-offset-seconds>\n");return 2;}
NSString *path=@(argv[1]), *output=@(argv[2]);
int fps=atoi(argv[3]), longest=atoi(argv[4]);double offset=atof(argv[5]);
if(fps<1||fps>120||longest<128||longest>4096||!isfinite(offset))return 2;
AVURLAsset *asset=[AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:path] options:nil];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
double duration=CMTimeGetSeconds(asset.duration);
AVAssetTrack *video=[[asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
if(!video||!isfinite(duration)||duration<=0)return 2;
double nominal=video.nominalFrameRate;
AVAssetImageGenerator *generator=[[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform=YES;generator.maximumSize=CGSizeMake(longest,longest);
generator.requestedTimeToleranceBefore=kCMTimeZero;generator.requestedTimeToleranceAfter=kCMTimeZero;
PGFaceProcessor *detector=[PGFaceProcessor new];PGRealtimeFaceTracker *tracker=[PGRealtimeFaceTracker new];
PGBeautySettings settings=PGBeautyDefaults();settings.singleFace=0;settings.trackingEnabled=0;
settings.fastMultiFace=0;settings.faceThin=1;settings.faceBigEye=.9035486629353234;
NSMutableArray *rows=[NSMutableArray new];NSDictionary *priorRaw=nil,*priorOutput=nil;
NSUInteger empty=0,partial=0,held=0,low=0,errors=0,multiple=0,invalidOutput=0,duplicateSourceFrames=0;
CMTime previousActual=kCMTimeInvalid;NSUInteger width=0,height=0;
for(int frame=0;frame<(int)ceil(duration*fps);frame++) {@autoreleasepool {
double requested=(double)frame/fps;if(requested>=duration)break;
NSError *error=nil;CMTime actual=kCMTimeInvalid;
CGImageRef cg=[generator copyCGImageAtTime:CMTimeMakeWithSeconds(requested,60000) actualTime:&actual error:&error];
if(!cg){errors++;fprintf(stderr,"decode failed at %.3f: %s\n",requested,error.localizedDescription.UTF8String);continue;}
if(CMTIME_IS_VALID(previousActual)&&CMTimeCompare(previousActual,actual)==0)duplicateSourceFrames++;
previousActual=actual;width=CGImageGetWidth(cg);height=CGImageGetHeight(cg);
CIImage *image=[CIImage imageWithCGImage:cg];
NSArray<VNFaceObservation *> *observations=[detector observationsInImage:image settings:settings error:&error];
if(!observations)errors++;
NSMutableArray *raw=[NSMutableArray new],*faces=[NSMutableArray new];
for(VNFaceObservation *face in observations)if(PGValidRect(face.boundingBox)&&raw.count<16){[raw addObject:PGGeometry(face)];[faces addObject:face];}
CMTime time=CMTimeAdd(CMTimeMake(frame,fps),CMTimeMakeWithSeconds(offset,60000));
NSDictionary *r=[tracker resultForGeometry:raw settings:settings time:time extent:image.extent];
NSInteger index=[r[@"index"] integerValue];NSDictionary *current=(index>=0&&(NSUInteger)index<raw.count)?raw[index]:nil;
VNFaceObservation *face=(index>=0&&(NSUInteger)index<faces.count)?faces[index]:nil;
NSDictionary *stable=[r[@"output"] firstObject];
double confidence=face.landmarks?face.landmarks.confidence:NAN;
if(!raw.count)empty++;if(raw.count>1)multiple++;
if(current&&[current[@"points76"] count]!=76)partial++;
if(stable&&[stable[@"points76"] count]!=76)invalidOutput++;
if([r[@"held"] boolValue])held++;
if(isfinite(confidence)&&confidence<.55)low++;
CGRect old=PGArrayRect(priorRaw[@"box"]),box=PGArrayRect(current[@"box"]);
double centerStep=NAN,sizeStep=NAN;
if(PGValidRect(old)&&PGValidRect(box)){
centerStep=hypot(CGRectGetMidX(old)-CGRectGetMidX(box),CGRectGetMidY(old)-CGRectGetMidY(box));
sizeStep=MAX(fabs(box.size.width/old.size.width-1),fabs(box.size.height/old.size.height-1));
}
NSMutableDictionary *row=[@{@"frame":@(frame),@"requestedSeconds":@(requested),@"actualSeconds":@(CMTimeGetSeconds(actual)),
@"faceCount":@(raw.count),@"points76Count":@([current[@"points76"] count]),@"held":r[@"held"],
@"landmarkConfidence":NumberOrNull(confidence),@"faceConfidence":NumberOrNull(face?face.confidence:NAN),
@"rawContourShapeStep":NumberOrNull(ShapeRMS(priorRaw,current,59,75)),
@"outputContourShapeStep":NumberOrNull(ShapeRMS(priorOutput,stable,59,75)),
@"rawAllShapeStep":NumberOrNull(ShapeRMS(priorRaw,current,0,75)),
@"outputAllShapeStep":NumberOrNull(ShapeRMS(priorOutput,stable,0,75)),
@"rawEyeShapeStep":NumberOrNull(EyeRMS(priorRaw,current)),
@"bboxCenterStep":NumberOrNull(centerStep),@"bboxRelativeSizeStep":NumberOrNull(sizeStep)} mutableCopy];
[rows addObject:row];priorRaw=current;priorOutput=stable;CGImageRelease(cg);
if(frame%50==0)fprintf(stderr,"inspected %d/%d frames\n",frame,(int)ceil(duration*fps));
}}
#pragma clang diagnostic pop
NSArray *keys=@[@"rawContourShapeStep",@"outputContourShapeStep",@"rawAllShapeStep",@"outputAllShapeStep",@"rawEyeShapeStep",@"bboxCenterStep",@"bboxRelativeSizeStep",@"landmarkConfidence"];
NSMutableDictionary *stats=[NSMutableDictionary new];
for(NSString *key in keys){NSMutableArray *values=[NSMutableArray new];for(NSDictionary *row in rows)if([row[key] isKindOfClass:NSNumber.class])[values addObject:row[key]];[values sortUsingSelector:@selector(compare:)];if(values.count){stats[key]=@{@"n":@(values.count),@"min":values.firstObject,@"median":values[values.count/2],@"p95":values[(NSUInteger)floor((values.count-1)*.95)],@"max":values.lastObject};}}
NSArray *ranked=[rows sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *a,NSDictionary *b){double x=[a[@"rawContourShapeStep"] isKindOfClass:NSNumber.class]?[a[@"rawContourShapeStep"] doubleValue]:-1;double y=[b[@"rawContourShapeStep"] isKindOfClass:NSNumber.class]?[b[@"rawContourShapeStep"] doubleValue]:-1;return x>y?NSOrderedAscending:(x<y?NSOrderedDescending:NSOrderedSame);}];
NSDictionary *summary=@{@"sourceBasename":path.lastPathComponent,@"durationSeconds":@(duration),@"nominalSourceFPS":@(nominal),@"samplingFPS":@(fps),@"decodedSize":@[@(width),@(height)],@"timelineOffsetSeconds":@(offset),@"frames":@(rows.count),@"emptyDetectionFrames":@(empty),@"partial76Frames":@(partial),@"heldFrames":@(held),@"outputWithout76Frames":@(invalidOutput),@"landmarkConfidenceBelow055Frames":@(low),@"multipleFaceFrames":@(multiple),@"decodeOrVisionErrors":@(errors),@"duplicateSourceFramePairs":@(duplicateSourceFrames),@"statistics":stats,@"largestContourChanges":[ranked subarrayWithRange:NSMakeRange(0,MIN(12,ranked.count))],@"scope":@"Independent offline decoding and the current production detector/tracker; not FCP render logs or target execution. Shape steps remove previous bbox translation/scale, but still include actual pose/expression changes."};
NSDictionary *report=@{@"summary":summary,@"scalarFrames":rows};NSData *data=[NSJSONSerialization dataWithJSONObject:report options:NSJSONWritingPrettyPrinted|NSJSONWritingSortedKeys error:nil];
if(!data||![data writeToFile:output atomically:YES])return 1;
NSData *print=[NSJSONSerialization dataWithJSONObject:summary options:NSJSONWritingPrettyPrinted|NSJSONWritingSortedKeys error:nil];fwrite(print.bytes,1,print.length,stdout);fputc('\n',stdout);
return 0;
}}