比较提交
4
次代码提交
| 作者 | SHA1 | 提交日期 | |
|---|---|---|---|
|
|
79710f17b3 | ||
|
|
a0c5357efd | ||
|
|
623dcb878b | ||
|
|
b58fec1a86 |
没有与搜索条件相匹配的文件
+8
@@ -140,3 +140,11 @@ GitHub用户名现为 `dayumeida`,账号ID117798680保持一致。当前公开
|
|||||||
发行入口为 `v1.3.2`;正式 APP 源码为 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`。新机器按 `product.json` 的工程、scheme 与路径恢复,运行 `python3 scripts/deliver.py --wait-for-hosts --user-tests`;旧产品先验证 Bundle ID、签名团队和滤镜 UUID,再迁移并支持失败回滚。最终包为 `releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg`,SHA-256 `20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1`,签名、公证 Accepted `4a831775-2317-4372-a4cc-102415657ea3`、票据和 Gatekeeper 均通过。正式 APP 已安装并清理旧身份。1901 项自动回归、8 项 APP 迁移、8 项最终 PKG 身份脚本迁移与模板隔离测试通过;未运行真实 installer,原生旧工程重开仍待用户检查。
|
发行入口为 `v1.3.2`;正式 APP 源码为 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`。新机器按 `product.json` 的工程、scheme 与路径恢复,运行 `python3 scripts/deliver.py --wait-for-hosts --user-tests`;旧产品先验证 Bundle ID、签名团队和滤镜 UUID,再迁移并支持失败回滚。最终包为 `releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg`,SHA-256 `20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1`,签名、公证 Accepted `4a831775-2317-4372-a4cc-102415657ea3`、票据和 Gatekeeper 均通过。正式 APP 已安装并清理旧身份。1901 项自动回归、8 项 APP 迁移、8 项最终 PKG 身份脚本迁移与模板隔离测试通过;未运行真实 installer,原生旧工程重开仍待用户检查。
|
||||||
|
|
||||||
源码包须从发行标签导出,排除 PKG 二进制并加入 SOURCE-SNAPSHOT.json。发布与独立克隆恢复回执位于 `docs/verification/v1.3.2/`,不包含用户人脸素材、签名私钥或公证凭据。历史标签和旧版本安装包保留,不覆盖。
|
源码包须从发行标签导出,排除 PKG 二进制并加入 SOURCE-SNAPSHOT.json。发布与独立克隆恢复回执位于 `docs/verification/v1.3.2/`,不包含用户人脸素材、签名私钥或公证凭据。历史标签和旧版本安装包保留,不覆盖。
|
||||||
|
|
||||||
|
|
||||||
|
1.3.2 发行标签完整 SHA 为 `8a70d38b7cd17e0ea530c5226f2be8c2df4308b3`。独立匿名 GitHub 克隆 271 个文件的字节/blob/执行位、strict/full fsck、Xcode 工程读取和恢复包签名/票据/Gatekeeper 均通过,无 LFS/子模块,临时克隆已清理。见 `docs/verification/v1.3.2/final-tag-recovery.json`。GitHub 与文章的安装包、源码快照已匿名下载核对哈希,源 ZIP 对应本标签;后续 main 补充回执,不移动发行标签或改变已签名产品源码。
|
||||||
|
|
||||||
|
|
||||||
|
## 1.3.2 后续跟踪闪烁分析
|
||||||
|
|
||||||
|
分析节点 `a0c5357efd87a63dbee6269d9335e6aa3ba78799` 保留新目标2.4.0静态证据、实际当前FCP草帽素材的469帧独立采样摘要与两个通用诊断入口;产品源码和安装版仍为v1.3.2,未宣布闪烁修复。独立匿名克隆284文件/fsck/合成诊断重建复现通过,无LFS或子模块。具体运行与边界见 `docs/analysis/跟踪闪烁对齐分析.md`,用户素材和完整真实关键点不在仓库中。
|
||||||
@@ -45,3 +45,6 @@ GitHub仓库从 `FAMEDaYu/FCP-BeatyGril` 更名为 `FAMEDaYu/FCP-BeautyGirl`,
|
|||||||
## 1.3.2 产品身份统一
|
## 1.3.2 产品身份统一
|
||||||
|
|
||||||
发行标签 `v1.3.2`,正式 APP 签名源码 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`。新工程和 APP 名为 FCP-BeautyGirl,应用标识及安装路径见 product.json;旧身份仅保留经过验证的迁移入口。GitHub、大鱼 Release 和文章 15593 使用新名称安装包及源码快照,历史发行资料不改写。当前交付与发布核验保存在 verification/v1.3.2。
|
发行标签 `v1.3.2`,正式 APP 签名源码 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`。新工程和 APP 名为 FCP-BeautyGirl,应用标识及安装路径见 product.json;旧身份仅保留经过验证的迁移入口。GitHub、大鱼 Release 和文章 15593 使用新名称安装包及源码快照,历史发行资料不改写。当前交付与发布核验保存在 verification/v1.3.2。
|
||||||
|
|
||||||
|
|
||||||
|
1.3.2 标签完整 SHA `8a70d38b7cd17e0ea530c5226f2be8c2df4308b3`,双远端引用回读一致。已匿名独立克隆核对 271 个文件、strict/full fsck、Xcode 工程和恢复包签名/票据/Gatekeeper。正式包 SHA256 `20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1`,源码 ZIP SHA256 `c75a516192375c45e446b3f0170615773ec2bd63b0430c3441a87282ba8b6834`;GitHub 与文章四项匿名下载均与本地字节一致。文章作者、封面和免费规则保留,正常及新请求前台版本/路径/SEO通过。大鱼 Release 只回读附件名称/大小,未绕过站点登录网关。
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"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,
|
||||||
|
"selectedTarget": {
|
||||||
|
"path": "/Users/dayu/Downloads/MSE18V2.app",
|
||||||
|
"version": "2.4.0",
|
||||||
|
"build": "20260724150000",
|
||||||
|
"universalPluginSha256": "577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109",
|
||||||
|
"arm64Sha256": "afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df"
|
||||||
|
},
|
||||||
|
"comparisonCaution": "Existing auto-follow-report.json describes the older /Applications target; its temporal weights/history must not be asserted as 2.4.0 default behavior",
|
||||||
|
"evidenceRecordsRetained": 17,
|
||||||
|
"checks": {
|
||||||
|
"FCP-BeautyGirl/FCP-BeautyGirl/Plugin/PGFaceProcessor.m": "cca826d5602b45b2c79ea3c3c78be7c78ad1defe7b062ed8ec54c311d53ac395",
|
||||||
|
"FCP-BeautyGirl/FCP-BeautyGirl/Plugin/FCPBeautyGirlPlugIn.m": "9d3d30d1f7f6467c634e8d6e832d2330618b9ff240de37f57de9bc48e2792de8",
|
||||||
|
"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/inspect-tracking-sequence.m": "0b94fc92669acf4d36861ccb25077b767189b8a72647e0d304627dbda5d052eb",
|
||||||
|
"docs/analysis/tracking-flicker-20261022/current-clip-summary.json": "043ba688c606fb9e56449fd02108b34789fd41c4d9a2552cd07f4d3bf78a00f0"
|
||||||
|
},
|
||||||
|
"limits": [
|
||||||
|
"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 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"
|
||||||
|
}
|
||||||
文件差异过大,未显示。
加载差异
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"status": "verified",
|
||||||
|
"repository": "https://github.com/dayumeida/FCP-BeautyGirl.git",
|
||||||
|
"anonymousClone": true,
|
||||||
|
"commit": "a0c5357efd87a63dbee6269d9335e6aa3ba78799",
|
||||||
|
"trackedFilesByteBlobAndModeCompared": 284,
|
||||||
|
"strictFullFsck": true,
|
||||||
|
"syntheticDiagnosticRebuiltAndReproduced": true,
|
||||||
|
"productSourceUnchangedFromRelease": "v1.3.2",
|
||||||
|
"lfs": false,
|
||||||
|
"submodules": false,
|
||||||
|
"temporaryCloneRemoved": true,
|
||||||
|
"mediaBoundary": "User source clip not included; clip scalar summary and static/synthetic evidence retained"
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
{
|
||||||
|
"authoredTwoFaceCrossing" : {
|
||||||
|
"rawIndex0" : "same authored identity A moved by .10",
|
||||||
|
"rawIndex1" : "different authored identity B moved within .01 of old center",
|
||||||
|
"selectedRawIndex" : 1
|
||||||
|
},
|
||||||
|
"defaultAppearanceOnDetectionLoss" : {
|
||||||
|
"geometryFacesAfter" : 1,
|
||||||
|
"geometryFacesBefore" : 1,
|
||||||
|
"meanColorMaskAfter" : 0,
|
||||||
|
"meanColorMaskBefore" : 0.39522577568114048,
|
||||||
|
"meanSkinMaskAfter" : 0,
|
||||||
|
"meanSkinMaskBefore" : 0.29670316041502076
|
||||||
|
},
|
||||||
|
"landmarkWeightsByFrameRate" : [
|
||||||
|
{
|
||||||
|
"currentLandmarkWeight" : 0.89999999999999925,
|
||||||
|
"fps" : 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currentLandmarkWeight" : 0.89999999999999925,
|
||||||
|
"fps" : 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currentLandmarkWeight" : 0.5,
|
||||||
|
"fps" : 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currentLandmarkWeight" : 0.25,
|
||||||
|
"fps" : 120
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outOfOrderCachedMissingFrame" : {
|
||||||
|
"initial40OutputFaces" : 0,
|
||||||
|
"ordered0Then40OutputFaces" : 1,
|
||||||
|
"replay40AfterAdding0OutputFaces" : 0
|
||||||
|
},
|
||||||
|
"pureBBoxTranslationJitter" : {
|
||||||
|
"fps" : 25,
|
||||||
|
"frames" : 20,
|
||||||
|
"maximumOutputVsRawPointError" : 0,
|
||||||
|
"outputOverRawAmplitude" : 1,
|
||||||
|
"outputStepNormalized" : 0.0080000000000000071,
|
||||||
|
"rawStepNormalized" : 0.0080000000000000071
|
||||||
|
},
|
||||||
|
"reacquisition" : {
|
||||||
|
"continuousPoint69x" : 0.60288473677011323,
|
||||||
|
"rawPoint69x" : 0.60568473677011325,
|
||||||
|
"reacquiredPoint69x" : 0.60568473677011325
|
||||||
|
},
|
||||||
|
"scope" : "Authored synthetic geometry and image only; actual current PGFaceProcessor implementation linked; no target binary or user media.",
|
||||||
|
"topologyValidMissingValid" : {
|
||||||
|
"held" : [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
"pixelDifferencesFromUnwarpedInput" : [
|
||||||
|
{
|
||||||
|
"changedChannelsAbove1e_6" : 85835,
|
||||||
|
"maxChannelDifference" : 0.89999997615814209,
|
||||||
|
"meanChannelDifference" : 0.055795646515334418
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"changedChannelsAbove1e_6" : 0,
|
||||||
|
"maxChannelDifference" : 0,
|
||||||
|
"meanChannelDifference" : 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"changedChannelsAbove1e_6" : 85835,
|
||||||
|
"maxChannelDifference" : 0.89999997615814209,
|
||||||
|
"meanChannelDifference" : 0.055795646515334418
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"points76Counts" : [
|
||||||
|
76,
|
||||||
|
0,
|
||||||
|
76
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# 瘦脸跟踪闪烁:1.3.2 与目标 2.4.0 的对齐缺口
|
||||||
|
|
||||||
|
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。随后仅读取已运行的系统 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 的默认瘦脸实现。
|
||||||
|
|
||||||
|
新版 `renderDestinationImage`(`0x10002179c`)的单主要人脸几何分支直接调用 **`mss_pinStyleFacePoints…`(`0x10003d69c`)**。后者在筛选当前几何后,选择接纳新点或回用上一组有效点,并可向 `trackedFaceBox…`(`0x10003cc78`)请求连续跟踪框。旧 `temporalFacePoints…` 方法仍存在,但当前提供者没有解析到它的直接调用者;这不能排除任意 Objective-C 间接调用,却足以纠正“只按旧 temporal 方法调平滑系数即可对齐新版”的假设。
|
||||||
|
|
||||||
|
对应 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 的静态证据 | 对闪烁的意义 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 部分关键点失效 | 有合法脸框就接纳;当前缺 76 点时删去完整拓扑,且不标为 held | 接纳前要求足量点、轮廓、有限坐标、有效五官布局和置信度;不合格时可回用上一组有效点 | 当前会在部分失效帧直接关闭瘦脸,目标有完整形状保持路径 |
|
||||||
|
| 框与几何稳定 | 每次重新检测,旧点先映射到当前原始框;没有连续对象框跟踪器 | pin-style 可调用 VNSequenceRequestHandler / VNTrackObjectRequest,坏帧可把旧点映射到可用跟踪框 | 当前框噪声完全进入几何;目标另外维护连续框和上次有效形状 |
|
||||||
|
| 异常姿态与跳点 | 主要判断眼轴翻转;合法有限 76 点一般直接进入混合 | 额外检查眼/鼻/口/下轮廓结构、前后几何兼容及归一化点位跳变的中位数/P90 | 当前会接受点数足够但位置不可靠的帧 |
|
||||||
|
| 同帧检测复用 | 每个请求新建 Vision handler;几何缓存要求 raw 也完全相同才命中 | 人脸检测有按帧时间、输入范围和 tile 范围复用的缓存,并有重试分支 | 当前重复请求可能产生不同 raw 后重新计算;未测得其在用户素材中的发生频率 |
|
||||||
|
| 丢检时的外观支持 | 默认几何可以保持,但皮肤/牙齿/眼睛蒙版仍取 raw 检测 | 本次只完整核对目标的瘦脸主路径,未恢复其全部外观蒙版稳定策略 | 本品已复现几何保持时外观蒙版清零,可能叠加视觉闪烁;不把目标外观路径宣称为已完全对齐 |
|
||||||
|
|
||||||
|
pin-style 的接纳分支复制本帧合格点,保持分支使用旧有效点并尝试框重映射。因此**不能据旧报告把“目标平滑更强”或某个固定混合权重当作这次原因**。应优先恢复它筛掉坏几何、保留有效几何的机制。
|
||||||
|
|
||||||
|
目标跟踪器还有开关与时间管理:静态初始化检查 `MSE18_DISABLE_FACE_THIN_VISION_TRACKER`,通常未设置时启用;已核对初始化汇编的 OR/EOR 写入。跟踪方法包含同帧复用、时间倒退/间隔后的重置、跟踪结果置信度检查和短期保框分支。这里证明默认配置下的可达控制流,没有记录用户宿主内实际环境变量或运行命中次数,不能称为运行验证,也不能仅添加一个 VNTrackObjectRequest 就声称完整复刻。
|
||||||
|
|
||||||
|
## 隔离复现结果
|
||||||
|
|
||||||
|
探针直接链接当前 `PGFaceProcessor.m`,用自造 256×256 图与合成关键点调用实际选择器、变形和蒙版实现。没有使用用户画面、真实人脸点阵或目标运行结果。运行 `zsh scripts/diagnose-tracking.sh` 输出 JSON;它是诊断统计,退出码 0 只表示执行完成。
|
||||||
|
|
||||||
|
1. **76 → 缺 76 → 76,瘦脸中间一帧完全归零。** 三帧一直有输出脸框,点数为 `76/0/76`,held 全为 false。只开瘦脸时,相对原图的变化通道数为 `85835/0/85835`,中间帧像素完全直通。源码入口:`PGFaceProcessor.m` 208–227、308、532–554、645–646。这证明了一个足以造成闪烁的路径;没有测量它在用户视频中的出现率。
|
||||||
|
2. **纯脸框抖动衰减为 0%。** 25fps、20 帧,框的 X 方向交替 ±0.004,框内点保持一致;输入和稳定后的点位步幅均为 0.008,输出/输入振幅比 `1.0`。源码 177–186、196、214–217 的重映射原样继承了框平移。目标对各种轻微框噪声的最终响应尚未做数值对照,不能把此数值直接说成两插件的实测差值。
|
||||||
|
3. **当前点混合在 25/30fps 时采用 90% 新点。** 60fps 为 50%,120fps 为 25%;现有 10ms 用例只检查 30% 新点。掉检后重获还跳过 76 点混合而直接采用 raw。源码 186、211–225、308;现有 `slim_tests.m` 408–410 明确要求重获采用 raw。这解释当前实现为何对扰动敏感,不是目标 2.4.0 权重的证据。
|
||||||
|
4. **空缓存会保留第一次请求顺序的结果。** 先请求 40ms 空帧,再补入 0ms 有效脸,重播 40ms 仍输出 0 脸;按 0→40ms 请求则输出 1 脸。源码 279 的命中直接返回,插入早期帧不会更新后续结果。宿主锁只串行化到达顺序;并发测试只验证安全和重复一致,没有要求不同到达顺序获得相同几何。尚未记录用户宿主实际请求顺序。
|
||||||
|
5. **几何保持不等于美容蒙版保持。** 默认路径掉检时几何脸数仍为 1,colorMask 均值从 `0.3952` 变为 `0`,skinMask 从 `0.2967` 变为 `0`。生产入口强制 singleFace=0,走源码 664–666 的 raw 外观支持;单人 held 外观分支并未在该默认路径使用。
|
||||||
|
6. **多人仍有额外边界。** 默认关联只按防跳区域内距上一框中心最近者选脸;自造交叉可选到陌生人。fastMulti 直接返回 raw,不做当前单主要人脸的保持。此项没有证明用户单人素材发生了换脸,修复时应单列验收。
|
||||||
|
|
||||||
|
原 1901 项回归主要证明单帧图像、几何和接口行为。已有跟随测试检查完全空检测、10ms 扰动与缓存重复安全,没有覆盖“76 点短暂不完整”的连续帧,也没有以常用帧率约束抖动幅度。此前每两秒取一帧、共 11 帧的真实视频检查同样不能替代连续序列稳定性验收。
|
||||||
|
|
||||||
|
## 建议修复顺序与验证要求
|
||||||
|
|
||||||
|
- **先处理部分失效和异常几何。** 在接纳新主脸前检查完整拓扑与五官布局;不合格时进入上一组有效形状的保持/重映射路径。明确区分有效检测时间、输出时间和保持状态,避免仅靠刷新输出时间无限保持。
|
||||||
|
- **再对齐连续框、重获和时间管理。** 结合新版默认可达跟踪链处理同帧、倒退、跳时、正常运动及重获;从转头、遮挡恢复检查形状是否突然跳回 raw。先逐条核对机制,再决定系数,避免用增加滞后来掩盖坏点。
|
||||||
|
- **补齐缓存和外观同步。** 明确同帧结果与新增前帧历史的失效关系、源切换隔离及默认蒙版跟随;以顺序/倒序/重复/多线程请求对照输出。
|
||||||
|
- **用同一段素材做连续帧验收。** 锁定宿主、原始帧率、预览/导出条件和相同单项参数;记录检测有效性、保持原因、框/点扰动与效果开关变化,和目标逐帧对照。单张图正常、自动用例通过都不足以宣布闪烁修复。
|
||||||
|
|
||||||
|
当前素材、宿主和可见参数已确认,并完成469帧独立采样;有效点短暂缺失未在该采样中出现。实现缺口与几何变化已定位,目标与本品的原生同帧输出、源入点映射和大眼贡献仍未分离,尚未认定唯一原因。本次不构建新 APP,不更新安装包或文章。
|
||||||
|
|
||||||
|
## 保留资料
|
||||||
|
|
||||||
|
- [诊断结果](tracking-flicker-20261022/synthetic-results.json)
|
||||||
|
- [目标版本、源码指纹和范围](tracking-flicker-20261022/manifest.json)
|
||||||
|
- [选取的完整 REA Evidence 记录](tracking-flicker-20261022/rea-evidence.json),含原始/规范化结果与提供者限制;为互操作研究资料,不包括目标 APP 或 metallib。
|
||||||
|
- 探针源码 `scripts/diagnose-tracking.m` 与入口 `scripts/diagnose-tracking.sh`。构建依赖与项目一致,需 macOS 的 Core Image/Vision;生成文件位于忽略的 build 下。
|
||||||
|
|
||||||
|
Ghidra 对部分 CGRect、CMTime 和返回寄存器的恢复不完整。报告依据渲染调用关系、完整点门槛、接纳/保持内存分支及初始化汇编作结构判断;未声称所有阈值布尔表达式与目标逐条等价。REA 会话已保存并关闭,证据可离线复查。
|
||||||
|
|
||||||
|
|
||||||
|
## 连续帧诊断恢复与复用
|
||||||
|
|
||||||
|
在项目根执行(先创建 build 目录):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir -p build/tracking-diagnostics
|
||||||
|
xcrun clang -fobjc-arc -fmodules -mmacosx-version-min=13.0 \
|
||||||
|
-framework Foundation -framework AVFoundation -framework CoreImage \
|
||||||
|
-framework CoreGraphics -framework CoreMedia -framework Metal \
|
||||||
|
-framework Vision -framework ImageIO scripts/inspect-tracking-sequence.m \
|
||||||
|
-o build/tracking-diagnostics/inspect-sequence
|
||||||
|
build/tracking-diagnostics/inspect-sequence '/绝对路径/源素材.mov' \
|
||||||
|
build/tracking-diagnostics/sequence.json 25 1920 18.72
|
||||||
|
```
|
||||||
|
|
||||||
|
最后三个参数是采样帧率、解码最长边与诊断时间偏移;18.72只来自本次所选片段位置,分析其他素材按实际设置。程序不导出图片或完整真实点阵,输出含逐帧标量;本次只提交汇总,详细本地数据保持在 build。用户视频和目标二进制均未随仓库分发,重跑具体素材需要自行提供原文件;二者不是产品构建依赖。源码、合成诊断及本次标量/静态证据均随 Git 保存。
|
||||||
|
|
||||||
|
|
||||||
|
分析与连续帧诊断的可恢复节点为 `a0c5357efd87a63dbee6269d9335e6aa3ba78799`,已推送并读回双远端。从 GitHub 匿名独立克隆核对284个文件的字节/blob/执行位、strict/full fsck,并重新构建合成诊断、逐项复现保存的JSON;产品源码与v1.3.2相同,无LFS/子模块。见[恢复回执](tracking-flicker-20261022/recovery.json)。后续main仅补充恢复说明,不改变已安装版或历史标签。
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"status": "verified",
|
||||||
|
"repository": "https://github.com/dayumeida/FCP-BeautyGirl.git",
|
||||||
|
"anonymousClone": true,
|
||||||
|
"tag": "v1.3.2",
|
||||||
|
"commit": "8a70d38b7cd17e0ea530c5226f2be8c2df4308b3",
|
||||||
|
"trackedFilesByteBlobAndExecutableModeCompared": 271,
|
||||||
|
"resourceEntries": 13,
|
||||||
|
"strictFullFsck": true,
|
||||||
|
"lfs": false,
|
||||||
|
"submodules": false,
|
||||||
|
"xcodeProjectRead": true,
|
||||||
|
"signedProductSourceUnchangedFrom": "767bba8ac11e9bf9268a1e02d1a06d3c120c46aa",
|
||||||
|
"packageSha256": "20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1",
|
||||||
|
"recoveredPackageSignatureTicketAndGatekeeper": true,
|
||||||
|
"temporaryCloneRemoved": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"remote": "https://dayu.media/git/dayu/codex-global-rules.git",
|
||||||
|
"before": "dde7e2ee26eae18627eefda9b956a6aca52354ad",
|
||||||
|
"commit": "4c3085861e26d34d82973483d0aae636b5fc7487",
|
||||||
|
"remoteRefVerified": true,
|
||||||
|
"independentCloneVerified": true,
|
||||||
|
"filesByteAndModeCompared": 11,
|
||||||
|
"strictFullFsck": true,
|
||||||
|
"temporaryCloneRemoved": true
|
||||||
|
}
|
||||||
@@ -31,5 +31,17 @@
|
|||||||
"legacyPluginOriginalPathAbsent": true,
|
"legacyPluginOriginalPathAbsent": true,
|
||||||
"filterUUIDPreserved": "FB14B0E6-59B2-4836-916F-CD0C559E9241",
|
"filterUUIDPreserved": "FB14B0E6-59B2-4836-916F-CD0C559E9241",
|
||||||
"templateBytesUnchanged": true,
|
"templateBytesUnchanged": true,
|
||||||
"nativeOldProjectReopen": "pending_user"
|
"nativeOldProjectReopen": "pending_user",
|
||||||
|
"afterPackagingCleanup": {
|
||||||
|
"buildPackageWorkAbsent": true,
|
||||||
|
"spotlightIndexedProductPaths": [
|
||||||
|
{
|
||||||
|
"path": "/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app",
|
||||||
|
"bundleId": "com.dayu.fcpbeautygirl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"newFormalPluginRegistered": true,
|
||||||
|
"legacyFormalPluginNotRegistered": true,
|
||||||
|
"appSignatureAndTicketRechecked": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"status": "verified",
|
||||||
|
"version": "1.3.2",
|
||||||
|
"releaseTag": "v1.3.2",
|
||||||
|
"releaseCommit": "8a70d38b7cd17e0ea530c5226f2be8c2df4308b3",
|
||||||
|
"githubRelease": "https://github.com/dayumeida/FCP-BeautyGirl/releases/tag/v1.3.2",
|
||||||
|
"dayuRelease": "https://dayu.media/git/dayu/paintfcp-fxplug/releases/tag/v1.3.2",
|
||||||
|
"dayuReleaseAssetNameAndSizeReadback": true,
|
||||||
|
"dayuReleaseDownloadByteReadback": false,
|
||||||
|
"dayuReleaseGateway": "Site login/member gateway retained; not bypassed",
|
||||||
|
"article": "https://dayu.media/15593/",
|
||||||
|
"articleId": 15593,
|
||||||
|
"authorCoverCategoriesTagsAndAccessRulesPreserved": true,
|
||||||
|
"articleCodeBlocks": 1,
|
||||||
|
"downloadChecks": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/dayumeida/FCP-BeautyGirl/releases/download/v1.3.2/FCP-BeautyGirl-1.3.2-source.zip",
|
||||||
|
"name": "FCP-BeautyGirl-1.3.2-source.zip",
|
||||||
|
"bytes": 9728489,
|
||||||
|
"sha256": "c75a516192375c45e446b3f0170615773ec2bd63b0430c3441a87282ba8b6834",
|
||||||
|
"anonymousByteReadback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/dayumeida/FCP-BeautyGirl/releases/download/v1.3.2/FCP-BeautyGirl-1.3.2.pkg",
|
||||||
|
"name": "FCP-BeautyGirl-1.3.2.pkg",
|
||||||
|
"bytes": 4889706,
|
||||||
|
"sha256": "20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1",
|
||||||
|
"anonymousByteReadback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "package",
|
||||||
|
"url": "https://dayu.media/wp-content/uploads/2026/10/1792666128-1202b0d4fd350d5.pkg",
|
||||||
|
"bytes": 4889706,
|
||||||
|
"sha256": "20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1",
|
||||||
|
"anonymousByteReadback": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "source",
|
||||||
|
"url": "https://dayu.media/wp-content/uploads/2026/10/1792666125-4e4f241a6fe317d.zip",
|
||||||
|
"bytes": 9728489,
|
||||||
|
"sha256": "c75a516192375c45e446b3f0170615773ec2bd63b0430c3441a87282ba8b6834",
|
||||||
|
"anonymousByteReadback": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"frontends": [
|
||||||
|
{
|
||||||
|
"url": "https://dayu.media/15593/",
|
||||||
|
"versionAndInstallCommand": true,
|
||||||
|
"singleCustomDescriptionAndKeywords": true,
|
||||||
|
"seoTitle": "大鱼人像美化 1.3.2|FCP / Motion 免费开源自动美颜插件",
|
||||||
|
"anonymousFreeAndLoginPromptVisible": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://dayu.media/15593/?release_check=1792666175",
|
||||||
|
"versionAndInstallCommand": true,
|
||||||
|
"singleCustomDescriptionAndKeywords": true,
|
||||||
|
"seoTitle": "大鱼人像美化 1.3.2|FCP / Motion 免费开源自动美颜插件",
|
||||||
|
"anonymousFreeAndLoginPromptVisible": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"testOrderPlaced": false,
|
||||||
|
"nativeOldProjectReopen": "pending_user"
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"sha": "8a70d38b7cd17e0ea530c5226f2be8c2df4308b3",
|
||||||
|
"mainAndBranchAndTagVerifiedBothRemotes": true,
|
||||||
|
"tag": "v1.3.2"
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"tag": "v1.3.2",
|
||||||
|
"commit": "8a70d38b7cd17e0ea530c5226f2be8c2df4308b3",
|
||||||
|
"file": "build/FCP-BeautyGirl-1.3.2-source.zip",
|
||||||
|
"bytes": 9728489,
|
||||||
|
"sha256": "c75a516192375c45e446b3f0170615773ec2bd63b0430c3441a87282ba8b6834",
|
||||||
|
"sourceFileCount": 268,
|
||||||
|
"excluded": [
|
||||||
|
"releases/1.2.0/\u5927\u9c7c\u4eba\u50cf\u7f8e\u5316-1.2.0.pkg",
|
||||||
|
"releases/1.3.1/\u5927\u9c7c\u4eba\u50cf\u7f8e\u5316-1.3.1.pkg",
|
||||||
|
"releases/1.3.2/FCP-BeautyGirl-1.3.2.pkg"
|
||||||
|
]
|
||||||
|
}
|
||||||
+5
-1
@@ -2,12 +2,16 @@
|
|||||||
|
|
||||||
更新时间:2026-10-22,Asia/Shanghai。项目根目录:`/Users/dayu/Documents/PaintFCP`。
|
更新时间:2026-10-22,Asia/Shanghai。项目根目录:`/Users/dayu/Documents/PaintFCP`。
|
||||||
|
|
||||||
当前正式 APP 为 **1.3.2(17)**,工程、APP、插件服务及应用标识统一为 FCP-BeautyGirl。通用 Release、正式签名、Apple 公证、票据、Gatekeeper 和正式路径注册均已核验,旧 APP 与临时副本已清理。签名源码 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`,发行标签 `v1.3.2`。1901 项自动回归、8 项 APP 身份迁移、8 项最终安装脚本身份迁移及模板隔离测试通过。滤镜 UUID、参数编号和归档保持原格式;新身份下的旧工程重开与最终原生视觉仍由用户实测。安装包基础由本机 PKG 工坊 CLI 生成,加入身份迁移后重新签名公证,包含指定已安装的「大鱼磨皮瘦脸」分类四项资源。文章 15593、GitHub 与大鱼 Release 沿用原入口,发布同步结果见本版回执。
|
当前正式 APP 为 **1.3.2(17)**,工程、APP、插件服务及应用标识统一为 FCP-BeautyGirl。通用 Release、正式签名、Apple 公证、票据、Gatekeeper 和正式路径注册均已核验,旧 APP 与临时副本已清理。签名源码 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`,发行标签 `v1.3.2`。1901 项自动回归、8 项 APP 身份迁移、8 项最终安装脚本身份迁移及模板隔离测试通过。滤镜 UUID、参数编号和归档保持原格式;新身份下的旧工程重开与最终原生视觉仍由用户实测。安装包基础由本机 PKG 工坊 CLI 生成,加入身份迁移后重新签名公证,包含指定已安装的「大鱼磨皮瘦脸」分类四项资源。文章 15593、GitHub 与大鱼 Release 已同步 1.3.2,四项包/源码匿名下载及前台 SEO 检查通过。标签完整 SHA `8a70d38b7cd17e0ea530c5226f2be8c2df4308b3`,独立匿名克隆 271 文件和恢复包核验通过;详细边界见本版回执。
|
||||||
|
|
||||||
代码由 **OpenAI + Codex 全程编写,站长仅参与调试和测试**。文章和仓库须保留这个表述,不使用“站长原创代码”等说法。免费版本无需账号、激活码或付费授权;“自动注册”指系统插件注册。
|
代码由 **OpenAI + Codex 全程编写,站长仅参与调试和测试**。文章和仓库须保留这个表述,不使用“站长原创代码”等说法。免费版本无需账号、激活码或付费授权;“自动注册”指系统插件注册。
|
||||||
|
|
||||||
1.2.0 交接整理前,工作区干净,`main`、`origin/main` 与 `github/main` 均为 `189a5d7634aa69db54330c90f8711b05d8e44b10`。这是文档新增前的基线;最新文档节点以 `git log -1` 和远端引用为准。
|
1.2.0 交接整理前,工作区干净,`main`、`origin/main` 与 `github/main` 均为 `189a5d7634aa69db54330c90f8711b05d8e44b10`。这是文档新增前的基线;最新文档节点以 `git log -1` 和远端引用为准。
|
||||||
|
|
||||||
|
## 最新待修问题:瘦脸跟踪闪烁(2026-10-22)
|
||||||
|
|
||||||
|
用户实测同一段素材,本插件有闪烁、目标稳定。本次完成源码/合成诊断和 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`;这次不是新发行版,无需重发安装包或文章。
|
||||||
|
|
||||||
## 先读和先查
|
## 先读和先查
|
||||||
|
|
||||||
接手时先查看 `git status --short --branch`、`git remote -v` 和最新提交,确认没有其他聊天的未提交改动。只读核对正式 APP 版本与模板目录,再决定是否需要编译或操作宿主。单纯修改文档不需要重建、重新公证或打开 Motion/FCP。
|
接手时先查看 `git status --short --branch`、`git remote -v` 和最新提交,确认没有其他聊天的未提交改动。只读核对正式 APP 版本与模板目录,再决定是否需要编译或操作宿主。单纯修改文档不需要重建、重新公证或打开 Motion/FCP。
|
||||||
|
|||||||
+18
@@ -148,3 +148,21 @@ PKG由本机PKG工坊CLI从正式APP与用户指定已安装的「大鱼磨皮
|
|||||||
|
|
||||||
|
|
||||||
1.3.1已发布至GitHub和大鱼Release,origin/github的main、修复分支与v1.3.1标签已同步回读。GitHub两个附件匿名下载哈希、安装包签名及票据通过;匿名独立标签克隆232文件、fsck和恢复包验证通过。文章15593就地更新为1.3.1,主下载PKG与源码ZIP的线上字节哈希一致,作者/封面/分类/免费及会员规则保留,前台正常和新请求的版本/说明/SEO通过。未登录前台仍显示免费及登录获取入口,未进行真实测试订单。大鱼Release只完成附件上传元数据回读,API令牌访问浏览器下载入口被重定向登录,未宣称该附件字节回读通过;必要PKG本体已随Git提交并在独立克隆中恢复。
|
1.3.1已发布至GitHub和大鱼Release,origin/github的main、修复分支与v1.3.1标签已同步回读。GitHub两个附件匿名下载哈希、安装包签名及票据通过;匿名独立标签克隆232文件、fsck和恢复包验证通过。文章15593就地更新为1.3.1,主下载PKG与源码ZIP的线上字节哈希一致,作者/封面/分类/免费及会员规则保留,前台正常和新请求的版本/说明/SEO通过。未登录前台仍显示免费及登录获取入口,未进行真实测试订单。大鱼Release只完成附件上传元数据回读,API令牌访问浏览器下载入口被重定向登录,未宣称该附件字节回读通过;必要PKG本体已随Git提交并在独立克隆中恢复。
|
||||||
|
|
||||||
|
|
||||||
|
## 1.3.2(17)统一产品名称、标识与旧安装迁移
|
||||||
|
|
||||||
|
工程、scheme、APP、嵌套插件服务及插件类名统一为 FCP-BeautyGirl / FCPBeautyGirlPlugIn;主 ID `com.dayu.fcpbeautygirl`,插件 ID `com.dayu.fcpbeautygirl.fxplug`。正式签名源码 `767bba8ac11e9bf9268a1e02d1a06d3c120c46aa`,发行标签 v1.3.2 为 `8a70d38b7cd17e0ea530c5226f2be8c2df4308b3`。滤镜 UUID、参数编号和 PGInspectorState 归档未改,渲染源码除名称/日志字符串外与 1.3.1 一致。1901 项自动回归重跑通过;新增 8 项 APP 迁移和 8 项最终 PKG 身份脚本测试,覆盖新装、旧版升级、失败回滚及无关身份保护。原生旧工程重开仍待用户实测,不将静态格式保留等同于原生验收。
|
||||||
|
|
||||||
|
通用 Release 使用固定 Developer ID 团队签名,APP 公证 Accepted `559eedf0-048f-4d0e-b013-6a187695f2da`,票据、严格双架构签名、Gatekeeper 和新 ID 的 PluginKit 正式路径通过。旧 ID 经团队和滤镜 UUID 核对后移出注册位置,成功安装后清理旧 APP 备份。唯一正式路径为 `/Library/Plug-Ins/FxPlug/FCP-BeautyGirl.app`;有界目录与现存 Spotlight 产品索引只发现此正式 APP,不声称已扫描全部挂载卷。
|
||||||
|
|
||||||
|
PKG 工坊 CLI 基础包包含指定已安装的「大鱼磨皮瘦脸」分类四项文件;加入本产品身份迁移/回滚段后重新签名、公证 Accepted `4a831775-2317-4372-a4cc-102415657ea3` 并粘附票据。最终包 4,889,706 bytes,SHA256 `20a88dacf68cc8812f5af86cfe94c1c0614414a68a019eaeac7ca9d078165ae1`。有效载荷与正式 APP、四项模板一致,模板锁定、更新和失败回滚隔离检查通过;未实际执行本 PKG 安装器。
|
||||||
|
|
||||||
|
origin/github 的 main、工作分支和 v1.3.2 标签已推送并回读。匿名独立 GitHub 克隆核对 271 个文件字节/blob/执行位,strict/full fsck、Xcode 工程读取和恢复出的 PKG 签名/票据/Gatekeeper 通过,无 LFS/子模块。GitHub、大鱼 Release 和文章 15593 已更新;GitHub 与文章的包/源码共四项匿名下载哈希一致,正常及新请求前台的版本、安装命令和三项 SEO 核验通过。作者、封面、分类及免费规则保留,未下订单。大鱼 Release 仅回读附件名称和大小,保留登录网关边界。完整回执在 verification/v1.3.2。
|
||||||
|
|
||||||
|
|
||||||
|
## 1.3.2 跟踪闪烁分析(2026-10-22,尚未修复)
|
||||||
|
|
||||||
|
用户报告目标稳定而本插件闪烁。新目标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草帽素材并以项目25fps独立扫描469帧,全部单脸/完整76点、无held/错误,未复现缺点归零;源5.72秒轮廓步幅raw6.33%、稳定后5.24%,仍含真实头动。原生请求与大眼叠加贡献未分离;原1901项回归不代表连续跟踪稳定性已通过。
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <CoreImage/CoreImage.h>
|
||||||
|
#import "PGFaceProcessor.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
@interface PGRealtimeFaceTracker : NSObject
|
||||||
|
- (NSDictionary *)resultForGeometry:(NSArray *)raw settings:(PGBeautySettings)s time:(CMTime)time extent:(CGRect)extent;
|
||||||
|
@end
|
||||||
|
@interface PGFaceProcessor (ProbeWarp)
|
||||||
|
- (CIImage *)warpImage:(CIImage *)image geometry:(NSArray *)geometry settings:(PGBeautySettings)s extent:(CGRect)extent;
|
||||||
|
- (NSArray<VNFaceObservation *> *)observationsInImage:(CIImage *)image settings:(PGBeautySettings)s error:(NSError **)error;
|
||||||
|
@end
|
||||||
|
@interface ProbeFaceProcessor : PGFaceProcessor
|
||||||
|
@property (nonatomic,copy) NSArray<VNFaceObservation *> *authoredDetections;
|
||||||
|
@end
|
||||||
|
@implementation ProbeFaceProcessor
|
||||||
|
- (NSArray<VNFaceObservation *> *)observationsInImage:(CIImage *)image settings:(PGBeautySettings)s error:(NSError **)error {return self.authoredDetections?:@[];}
|
||||||
|
@end
|
||||||
|
|
||||||
|
static NSDictionary *Geometry(CGRect box, double localJitter, BOOL has76) {
|
||||||
|
NSMutableDictionary *g=[@{@"box":@[@(box.origin.x),@(box.origin.y),@(box.size.width),@(box.size.height)]} mutableCopy];
|
||||||
|
for(NSString *name in @[@"leftEye",@"rightEye",@"leftBrow",@"rightBrow",@"nose",@"lips",@"mouth",@"contour"]){
|
||||||
|
double x=[name isEqual:@"rightEye"]?.7:.3;
|
||||||
|
g[name]=@[@[@(box.origin.x+(x+localJitter)*box.size.width),@(box.origin.y+.65*box.size.height)]];
|
||||||
|
}
|
||||||
|
if(has76){
|
||||||
|
NSMutableArray *p=[NSMutableArray new];
|
||||||
|
for(NSUInteger i=0;i<76;i++)[p addObject:@[@.5,@.5]];
|
||||||
|
p[6]=@[@.34,@.65];p[13]=@[@.66,@.65];
|
||||||
|
p[46]=@[@.5,@.68];p[47]=@[@.5,@.60];p[48]=@[@.5,@.52];p[49]=@[@.5,@.45];p[52]=@[@.5,@.42];
|
||||||
|
p[29]=@[@.5,@.39];p[36]=@[@.54,@.36];p[37]=@[@.5,@.35];p[38]=@[@.46,@.36];
|
||||||
|
p[26]=@[@.42,@.40];p[34]=@[@.58,@.40];p[35]=@[@.57,@.36];p[39]=@[@.43,@.36];
|
||||||
|
for(NSUInteger i=0;i<17;i++){double t=M_PI+M_PI*i/16;p[59+i]=@[@(.5+.29*cos(t)),@(.65+.43*sin(t))];}
|
||||||
|
for(NSUInteger i=0;i<76;i++)p[i]=@[@(box.origin.x+([p[i][0] doubleValue]+localJitter)*box.size.width),@(box.origin.y+[p[i][1] doubleValue]*box.size.height)];
|
||||||
|
g[@"points76"]=p;
|
||||||
|
}
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
static NSDictionary *Live(PGRealtimeFaceTracker *t,NSArray *g,PGBeautySettings s,int64_t tick){return[t resultForGeometry:g settings:s time:CMTimeMake(tick,1000) extent:CGRectMake(0,0,256,256)];}
|
||||||
|
static double PointX(NSDictionary *r){return[r[@"output"][0][@"points76"][69][0] doubleValue];}
|
||||||
|
static NSData *Pixels(CIContext *context,CIImage *image){
|
||||||
|
CGRect e=image.extent;NSUInteger w=e.size.width,h=e.size.height;NSMutableData *d=[NSMutableData dataWithLength:w*h*4*sizeof(float)];
|
||||||
|
[context render:image toBitmap:d.mutableBytes rowBytes:w*4*sizeof(float) bounds:e format:kCIFormatRGBAf colorSpace:NULL];return d;
|
||||||
|
}
|
||||||
|
static NSDictionary *Difference(NSData *a,NSData *b){
|
||||||
|
const float *x=a.bytes,*y=b.bytes;NSUInteger n=a.length/sizeof(float),changed=0;double maximum=0,sum=0;
|
||||||
|
for(NSUInteger i=0;i<n;i++){double v=fabs(x[i]-y[i]);sum+=v;maximum=fmax(maximum,v);if(v>1e-6)changed++;}
|
||||||
|
return@{@"maxChannelDifference":@(maximum),@"meanChannelDifference":@(sum/n),@"changedChannelsAbove1e_6":@(changed)};
|
||||||
|
}
|
||||||
|
static double MeanRed(CIContext *context,CIImage *image){NSData *d=Pixels(context,image);const float *p=d.bytes;NSUInteger n=d.length/(4*sizeof(float));double sum=0;for(NSUInteger i=0;i<n;i++)sum+=p[4*i];return sum/n;}
|
||||||
|
static CIImage *SyntheticPattern(void){
|
||||||
|
NSMutableData *d=[NSMutableData dataWithLength:256*256*4*sizeof(float)];float *p=d.mutableBytes;
|
||||||
|
for(NSUInteger y=0;y<256;y++)for(NSUInteger x=0;x<256;x++){NSUInteger i=4*(y*256+x);p[i]=x/255.;p[i+1]=y/255.;p[i+2]=((x/5+y/5)%2)*.9+.05;p[i+3]=1;}
|
||||||
|
return[CIImage imageWithBitmapData:d bytesPerRow:256*4*sizeof(float) size:CGSizeMake(256,256) format:kCIFormatRGBAf colorSpace:NULL];
|
||||||
|
}
|
||||||
|
int main(void){@autoreleasepool{
|
||||||
|
PGBeautySettings s=PGBeautyDefaults();s.faceThin=1;
|
||||||
|
CGRect b=CGRectMake(.15,.15,.7,.65);NSDictionary *good=Geometry(b,0,YES),*missing=Geometry(b,0,NO);
|
||||||
|
PGRealtimeFaceTracker *topology=[PGRealtimeFaceTracker new];NSMutableArray *counts=[NSMutableArray new],*held=[NSMutableArray new],*diffs=[NSMutableArray new];
|
||||||
|
PGFaceProcessor *processor=[PGFaceProcessor new];CIContext *context=[CIContext contextWithOptions:nil];CIImage *image=SyntheticPattern();NSData *original=Pixels(context,image);
|
||||||
|
NSArray *inputs=@[@[good],@[missing],@[good]];
|
||||||
|
for(NSUInteger i=0;i<inputs.count;i++){
|
||||||
|
NSDictionary *r=Live(topology,inputs[i],s,i*40);NSArray *output=r[@"output"];
|
||||||
|
[counts addObject:@([output[0][@"points76"] count])];[held addObject:r[@"held"]];
|
||||||
|
CIImage *warped=[processor warpImage:image geometry:output settings:s extent:image.extent];
|
||||||
|
[diffs addObject:Difference(original,Pixels(context,warped))];
|
||||||
|
}
|
||||||
|
NSMutableArray *rawX=[NSMutableArray new],*outX=[NSMutableArray new];PGRealtimeFaceTracker *jitter=[PGRealtimeFaceTracker new];
|
||||||
|
for(NSUInteger i=0;i<20;i++){
|
||||||
|
double dx=(i%2?.004:-.004);CGRect moved=b;moved.origin.x+=dx;NSDictionary *g=Geometry(moved,0,YES),*r=Live(jitter,@[g],s,i*40);
|
||||||
|
[rawX addObject:g[@"points76"][69][0]];[outX addObject:@(PointX(r))];
|
||||||
|
}
|
||||||
|
double rawAmplitude=0,outAmplitude=0,maxError=0;for(NSUInteger i=1;i<rawX.count;i++){rawAmplitude=fmax(rawAmplitude,fabs([rawX[i] doubleValue]-[rawX[i-1] doubleValue]));outAmplitude=fmax(outAmplitude,fabs([outX[i] doubleValue]-[outX[i-1] doubleValue]));maxError=fmax(maxError,fabs([rawX[i] doubleValue]-[outX[i] doubleValue]));}
|
||||||
|
PGRealtimeFaceTracker *late=[PGRealtimeFaceTracker new];NSDictionary *lateFirst=Live(late,@[],s,40);Live(late,@[good],s,0);NSDictionary *lateReplay=Live(late,@[],s,40);
|
||||||
|
PGRealtimeFaceTracker *ordered=[PGRealtimeFaceTracker new];Live(ordered,@[good],s,0);NSDictionary *ordered40=Live(ordered,@[],s,40);
|
||||||
|
PGRealtimeFaceTracker *reacquired=[PGRealtimeFaceTracker new];Live(reacquired,@[good],s,0);Live(reacquired,@[],s,40);NSDictionary *shift=Geometry(b,.04,YES),*r80=Live(reacquired,@[shift],s,80);
|
||||||
|
PGRealtimeFaceTracker *continuous=[PGRealtimeFaceTracker new];Live(continuous,@[good],s,0);NSDictionary *continuous80=Live(continuous,@[shift],s,80);
|
||||||
|
NSMutableArray *weights=[NSMutableArray new];for(NSNumber *fps in @[@25,@30,@60,@120]){
|
||||||
|
PGRealtimeFaceTracker *t=[PGRealtimeFaceTracker new];Live(t,@[good],s,0);
|
||||||
|
NSDictionary *r=[t resultForGeometry:@[shift] settings:s time:CMTimeMake(1,fps.intValue) extent:CGRectMake(0,0,256,256)];
|
||||||
|
double before=[good[@"points76"][69][0] doubleValue],after=[shift[@"points76"][69][0] doubleValue];
|
||||||
|
[weights addObject:@{@"fps":fps,@"currentLandmarkWeight":@((PointX(r)-before)/(after-before))}];
|
||||||
|
}
|
||||||
|
ProbeFaceProcessor *drop=[ProbeFaceProcessor new];PGBeautySettings defaultSettings=PGBeautyDefaults();
|
||||||
|
drop.authoredDetections=@[[VNFaceObservation faceObservationWithRequestRevision:VNDetectFaceLandmarksRequestRevision3 boundingBox:b roll:nil yaw:nil pitch:nil]];
|
||||||
|
PGFaceFrame *detected=[drop processImage:image settings:defaultSettings time:kCMTimeZero error:nil];
|
||||||
|
drop.authoredDetections=@[];PGFaceFrame *lost=[drop processImage:image settings:defaultSettings time:CMTimeMake(1,25) error:nil];
|
||||||
|
PGRealtimeFaceTracker *crossing=[PGRealtimeFaceTracker new];NSDictionary *initialA=Geometry(CGRectMake(.2,.25,.25,.5),0,YES);
|
||||||
|
Live(crossing,@[initialA],s,0);NSDictionary *movingA=Geometry(CGRectMake(.30,.25,.25,.5),.04,YES),*strangerB=Geometry(CGRectMake(.21,.25,.25,.5),-.04,YES);
|
||||||
|
NSDictionary *crossed=Live(crossing,@[movingA,strangerB],s,40);
|
||||||
|
NSDictionary *report=@{@"scope":@"Authored synthetic geometry and image only; actual current PGFaceProcessor implementation linked; no target binary or user media.",
|
||||||
|
@"topologyValidMissingValid":@{@"points76Counts":counts,@"held":held,@"pixelDifferencesFromUnwarpedInput":diffs},
|
||||||
|
@"pureBBoxTranslationJitter":@{@"frames":@20,@"fps":@25,@"rawStepNormalized":@(rawAmplitude),@"outputStepNormalized":@(outAmplitude),@"outputOverRawAmplitude":@(outAmplitude/rawAmplitude),@"maximumOutputVsRawPointError":@(maxError)},
|
||||||
|
@"outOfOrderCachedMissingFrame":@{@"initial40OutputFaces":@([lateFirst[@"output"] count]),@"replay40AfterAdding0OutputFaces":@([lateReplay[@"output"] count]),@"ordered0Then40OutputFaces":@([ordered40[@"output"] count])},
|
||||||
|
@"reacquisition":@{@"reacquiredPoint69x":@(PointX(r80)),@"rawPoint69x":shift[@"points76"][69][0],@"continuousPoint69x":@(PointX(continuous80))},
|
||||||
|
@"defaultAppearanceOnDetectionLoss":@{@"geometryFacesBefore":@(detected.deformationGeometry.count),@"geometryFacesAfter":@(lost.deformationGeometry.count),@"meanColorMaskBefore":@(MeanRed(context,detected.colorMask)),@"meanColorMaskAfter":@(MeanRed(context,lost.colorMask)),@"meanSkinMaskBefore":@(MeanRed(context,detected.skinMask)),@"meanSkinMaskAfter":@(MeanRed(context,lost.skinMask))},
|
||||||
|
@"authoredTwoFaceCrossing":@{@"rawIndex0":@"same authored identity A moved by .10",@"rawIndex1":@"different authored identity B moved within .01 of old center",@"selectedRawIndex":crossed[@"index"]},
|
||||||
|
@"landmarkWeightsByFrameRate":weights};
|
||||||
|
NSData *json=[NSJSONSerialization dataWithJSONObject:report options:NSJSONWritingPrettyPrinted|NSJSONWritingSortedKeys error:nil];fwrite(json.bytes,1,json.length,stdout);fputc('\n',stdout);
|
||||||
|
}return 0;}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/zsh
|
||||||
|
# Diagnostic statistics for authored inputs; a zero exit is not a stability pass.
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
WORK="$ROOT/build/tracking-diagnostics"
|
||||||
|
mkdir -p "$WORK"
|
||||||
|
xcrun clang -fobjc-arc -fmodules -Wall -Wextra -Wno-unused-parameter \
|
||||||
|
-DCI_SILENCE_GL_DEPRECATION -mmacosx-version-min=13.0 \
|
||||||
|
-I "$ROOT/FCP-BeautyGirl/FCP-BeautyGirl/Plugin" \
|
||||||
|
-framework Foundation -framework CoreImage -framework CoreGraphics \
|
||||||
|
-framework CoreMedia -framework Metal -framework Vision -framework ImageIO \
|
||||||
|
"$ROOT/FCP-BeautyGirl/FCP-BeautyGirl/Plugin/PGFaceProcessor.m" \
|
||||||
|
"$ROOT/scripts/diagnose-tracking.m" -o "$WORK/tracking-probe"
|
||||||
|
"$WORK/tracking-probe"
|
||||||
@@ -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;
|
||||||
|
}}
|
||||||
在新工单中引用
屏蔽一个用户