From a0c5357efd87a63dbee6269d9335e6aa3ba78799 Mon Sep 17 00:00:00 2001 From: dayu <506228475@qq.com> Date: Thu, 22 Oct 2026 20:02:23 +0800 Subject: [PATCH] analysis: inspect the current sun-hat clip at 25fps and narrow flicker candidates --- .../current-clip-summary.json | 318 ++++++++++++++++++ .../tracking-flicker-20261022/manifest.json | 17 +- docs/analysis/跟踪闪烁对齐分析.md | 21 +- docs/项目交接.md | 2 +- docs/验证记录.md | 2 +- scripts/inspect-tracking-sequence.m | 109 ++++++ 6 files changed, 458 insertions(+), 11 deletions(-) create mode 100644 docs/analysis/tracking-flicker-20261022/current-clip-summary.json create mode 100644 scripts/inspect-tracking-sequence.m diff --git a/docs/analysis/tracking-flicker-20261022/current-clip-summary.json b/docs/analysis/tracking-flicker-20261022/current-clip-summary.json new file mode 100644 index 0000000..4ccbc7e --- /dev/null +++ b/docs/analysis/tracking-flicker-20261022/current-clip-summary.json @@ -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 + } +} diff --git a/docs/analysis/tracking-flicker-20261022/manifest.json b/docs/analysis/tracking-flicker-20261022/manifest.json index 34b7c9d..5de98ef 100644 --- a/docs/analysis/tracking-flicker-20261022/manifest.json +++ b/docs/analysis/tracking-flicker-20261022/manifest.json @@ -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" } diff --git a/docs/analysis/跟踪闪烁对齐分析.md b/docs/analysis/跟踪闪烁对齐分析.md index c4c34d8..6cfc29e 100644 --- a/docs/analysis/跟踪闪烁对齐分析.md +++ b/docs/analysis/跟踪闪烁对齐分析.md @@ -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,不更新安装包或文章。 ## 保留资料 diff --git a/docs/项目交接.md b/docs/项目交接.md index 19a927b..dc216ec 100644 --- a/docs/项目交接.md +++ b/docs/项目交接.md @@ -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`;这次不是新发行版,无需重发安装包或文章。 ## 先读和先查 diff --git a/docs/验证记录.md b/docs/验证记录.md index 47b0786..d28e68d 100644 --- a/docs/验证记录.md +++ b/docs/验证记录.md @@ -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项回归不代表连续跟踪稳定性已通过。 diff --git a/scripts/inspect-tracking-sequence.m b/scripts/inspect-tracking-sequence.m new file mode 100644 index 0000000..9fb007e --- /dev/null +++ b/scripts/inspect-tracking-sequence.m @@ -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 +#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 \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 *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=0&&(NSUInteger)index1)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