Fix V-face deformation with lower-jaw landmark pins; pass regression
这个提交包含在:
1 父节点
58f09e5756
当前提交
7fa3298e02
19 个文件已更改
+566
-36
没有与搜索条件相匹配的文件
@@ -12,6 +12,8 @@
|
||||
|
||||
1.3.0 的磨皮卡片依次提供「磨皮程度、微细锐化、五官保护、非肤色区保护」。两种保护默认 100%;降低五官保护让五官区域参与更多磨皮,降低非肤色区保护则扩大磨皮范围,均不扩大肤色提亮范围。微细锐化在局部支持区域恢复纹理;旧全局磨皮和全局锐化仍保留在更多设置,旧工程的参数与归档继续兼容。迁移证据、实现边界与验证见[新版磨皮参数迁移](docs/analysis/新版磨皮参数迁移.md)。1.3.0(15)APP 已完成签名、公证及正式安装,1636 项自动检查通过;原生宿主效果由用户实测。1.2.0 下载链接仍对应原发行包,本次未更新文章或安装包。
|
||||
|
||||
1.3.1(16)修复 V 脸影响眼区的问题,改为四组下颌轮廓到外唇的局部采样,并对齐新目标的 0.065 强度映射。1901 项自动检查通过;正式交付状态见验证记录。原理与边界见 [V 脸下颌区域修复](docs/analysis/V脸下颌区域修复.md)。
|
||||
|
||||
## 开发和恢复
|
||||
|
||||
需要 Xcode 27.1、FxPlug SDK 4.3.4 与 PluginManager 1.7.4;最低运行系统 macOS 13。正式产物为 arm64/x86_64 通用版本。
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.3.0</string>
|
||||
<string>1.3.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>15</string>
|
||||
<string>16</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string></string>
|
||||
<key>PlugInKit</key>
|
||||
@@ -72,7 +72,7 @@
|
||||
<key>uuid</key>
|
||||
<string>FB14B0E6-59B2-4836-916F-CD0C559E9241</string>
|
||||
<key>version</key>
|
||||
<string>1.3.0</string>
|
||||
<string>1.3.1</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>className</key>
|
||||
@@ -84,7 +84,7 @@
|
||||
<key>uuid</key>
|
||||
<string>E0E432C8-3D71-4ABA-B006-E7F519E06C87</string>
|
||||
<key>version</key>
|
||||
<string>1.3.0</string>
|
||||
<string>1.3.1</string>
|
||||
<key>protocolNames</key>
|
||||
<array>
|
||||
<string>FxOnScreenControl</string>
|
||||
|
||||
@@ -14,6 +14,8 @@ static const uint8_t PGThinPins[17][2] = {
|
||||
{69,49},{65,49},{68,52},{66,52},{67,47}
|
||||
};
|
||||
static const uint8_t PGChinPins[3][2] = {{68,38},{67,37},{66,36}};
|
||||
// Lower contour to lip anchors, in the 2.4.0 V-face shader's update order.
|
||||
static const uint8_t PGVFacePins[4][2] = {{69,39},{65,35},{70,26},{64,34}};
|
||||
// Origin and radius neighbour; all six directions point toward landmark 29.
|
||||
static const uint8_t PGJawPins[6][2] = {{72,71},{62,63},{71,70},{63,64},{70,71},{64,63}};
|
||||
|
||||
@@ -347,11 +349,11 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
_lock = [[NSLock alloc] init];
|
||||
_realtime = [PGRealtimeFaceTracker new];
|
||||
_targets = [NSMutableArray arrayWithObjects:[NSMutableDictionary dictionary], [NSMutableDictionary dictionary], [NSMutableDictionary dictionary], nil];
|
||||
// Thin/chin/jaw/short reconstruct the recovered local coordinate math.
|
||||
// The other five controls retain this project's analytic approximation.
|
||||
// Recovered jaw -> chin -> short order follows the reference. The other
|
||||
// analytic body controls still precede jaw, so the full combined chain
|
||||
// (narrow/V/cheek/small-head/eyes) is not claimed reference-equivalent.
|
||||
// Thin/V/chin/jaw/short reconstruct recovered local coordinate math.
|
||||
// Four other controls retain this project's analytic approximation.
|
||||
// Recovered V -> jaw -> chin -> short order follows the reference. Other
|
||||
// analytic body controls still precede V, so the full combined chain
|
||||
// with narrow/cheek/small-head/eyes is not claimed reference-equivalent.
|
||||
// Each pin changes the sampling coordinate, with only one image resample.
|
||||
NSMutableString *source = [NSMutableString stringWithString:
|
||||
@"vec2 pgThinPin(vec2 q, vec4 control, float ratio) {"
|
||||
@@ -371,8 +373,9 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
" float dy=b.y-a.y; if(abs(dy)<=0.000001) dy=dy<0.0?-0.000001:0.000001;"
|
||||
" if(q.x<a.x+(b.x-a.x)*(q.y-a.y)/dy) crossing=1.0; }"
|
||||
" return vec2(distance,crossing); }"
|
||||
" kernel vec2 pgFaceWarp(vec2 c, vec2 size, vec2 le, vec2 re, vec2 er, float thinRatio, float bigEye, float shortRatio, float narrow, float chinRatio, float vFace, float jawRatio, float cheek, float smallHead, float headRange, vec2 imageOrigin, vec2 imageSize"];
|
||||
" kernel vec2 pgFaceWarp(vec2 c, vec2 size, vec2 le, vec2 re, vec2 er, float thinRatio, float bigEye, float shortRatio, float narrow, float chinRatio, float vRatio, float jawRatio, float cheek, float smallHead, float headRange, vec2 imageOrigin, vec2 imageSize"];
|
||||
for (NSUInteger i=0; i<17; i++) [source appendFormat:@", vec4 pin%lu",(unsigned long)i];
|
||||
for (NSUInteger i=0; i<4; i++) [source appendFormat:@", vec4 vPin%lu",(unsigned long)i];
|
||||
for (NSUInteger i=0; i<3; i++) [source appendFormat:@", vec4 chinPin%lu",(unsigned long)i];
|
||||
[source appendString:@", vec2 jawAnchor, vec2 shortAxis"];
|
||||
for (NSUInteger i=0; i<6; i++) [source appendFormat:@", vec4 jawPin%lu",(unsigned long)i];
|
||||
@@ -383,14 +386,14 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
[source appendString:@" q.y=1.0-q.y; p=imageOrigin+q*imageSize; }"
|
||||
" vec2 n = (p-c)/size;"
|
||||
" float body = 1.0-smoothstep(0.38,0.76,length(n*vec2(1.0,0.82)));"
|
||||
" float lower = (1.0-smoothstep(-0.12,0.27,n.y))*body;"
|
||||
" float sides = smoothstep(0.08,0.32,abs(n.x));"
|
||||
" float j=(n.y+0.23)/0.22; float jawBand = exp(-j*j)*body;"
|
||||
" float ch=(n.y-0.02)/0.19; float cheekBand = exp(-ch*ch)*body;"
|
||||
" float head = 1.0-smoothstep(0.38,0.75+0.32*headRange,length(n*vec2(0.9,0.65)));"
|
||||
" p += (p-c)*smallHead*0.18*head;"
|
||||
" p.x += size.x*n.x*(narrow*0.30*body + vFace*0.24*jawBand + cheek*0.18*cheekBand)*sides;"
|
||||
" p.y += size.y*(-vFace*0.025*lower);"
|
||||
" p.x += size.x*n.x*(narrow*0.30*body + cheek*0.18*cheekBand)*sides;"
|
||||
" if(vRatio>0.000001) { vec2 q=(p-imageOrigin)/imageSize; q.y=1.0-q.y;"];
|
||||
for (NSUInteger i=0; i<4; i++) [source appendFormat:@" q=pgThinPin(q,vPin%lu,vRatio);",(unsigned long)i];
|
||||
[source appendString:@" q.y=1.0-q.y; p=imageOrigin+q*imageSize; }"
|
||||
" if(abs(jawRatio)>0.000001) { vec2 q=(p-imageOrigin)/imageSize; q.y=1.0-q.y;"];
|
||||
for (NSUInteger i=0; i<6; i++) [source appendFormat:@" q=pgJawPin(q,jawPin%lu,jawAnchor,jawRatio);",(unsigned long)i];
|
||||
[source appendString:@" q.y=1.0-q.y; p=imageOrigin+q*imageSize; }"
|
||||
@@ -527,7 +530,7 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
for (NSDictionary *face in geometry) {
|
||||
CGRect box = PGArrayRect(face[@"box"]), pixels = PGToPixels(box, extent);
|
||||
NSArray *points76 = PGSanitizedPoints76(face[@"points76"]);
|
||||
float thinRatio = 0, chinRatio = 0, jawRatio = 0, shortRatio = 0;
|
||||
float thinRatio = 0, chinRatio = 0, jawRatio = 0, shortRatio = 0, vRatio = 0;
|
||||
if (points76) {
|
||||
double width = hypot(([points76[75][0] doubleValue]-[points76[59][0] doubleValue])*extent.size.width,
|
||||
([points76[75][1] doubleValue]-[points76[59][1] doubleValue])*extent.size.height);
|
||||
@@ -541,18 +544,21 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
chinRatio = chin*(chin>0 ? .04 : .02)*gain;
|
||||
jawRatio = PGClamp(s.faceJaw,0,1)*.05*gain;
|
||||
shortRatio = PGClamp(s.faceShort,-1,1)*.25*gain;
|
||||
// The specified 2.4.0 shader takes the CPU-scaled .065 V ratio
|
||||
// directly; it no longer applies the older shader's size gain.
|
||||
vRatio = PGClamp(s.faceV,0,1)*.065;
|
||||
}
|
||||
BOOL otherControls = s.faceBigEye || s.faceNarrow || s.faceV || s.faceCheekbone || s.faceSmallHead;
|
||||
// No full topology means no guessed bbox thin/chin/jaw/short deformation. Legacy
|
||||
BOOL otherControls = s.faceBigEye || s.faceNarrow || s.faceCheekbone || s.faceSmallHead;
|
||||
// No full topology means no guessed bbox thin/V/chin/jaw/short deformation. Legacy
|
||||
// archives using only those controls remain exact image/mask pass-through.
|
||||
if (thinRatio <= .000001 && fabsf(chinRatio) <= .000001 && fabsf(jawRatio) <= .000001 && fabsf(shortRatio) <= .000001 && !otherControls) continue;
|
||||
if (thinRatio <= .000001 && vRatio <= .000001 && fabsf(chinRatio) <= .000001 && fabsf(jawRatio) <= .000001 && fabsf(shortRatio) <= .000001 && !otherControls) continue;
|
||||
CGRect le = PGRegionBounds(face, @"leftEye", PGInFace(box, 0.16, 0.53, 0.25, 0.15));
|
||||
CGRect re = PGRegionBounds(face, @"rightEye", PGInFace(box, 0.59, 0.53, 0.25, 0.15));
|
||||
CGPoint left = PGCenter(PGToPixels(le, extent)), right = PGCenter(PGToPixels(re, extent));
|
||||
NSMutableArray *arguments = [@[PGVector(PGCenter(pixels)), [CIVector vectorWithX:pixels.size.width Y:pixels.size.height],
|
||||
PGVector(left), PGVector(right), [CIVector vectorWithX:MAX(2, pixels.size.width * 0.24) Y:MAX(2, pixels.size.height * 0.17)],
|
||||
@(thinRatio), @(PGClamp(s.faceBigEye, 0, 1)), @(shortRatio),
|
||||
@(PGClamp(s.faceNarrow, -1, 1)), @(chinRatio), @(PGClamp(s.faceV, 0, 1)),
|
||||
@(PGClamp(s.faceNarrow, -1, 1)), @(chinRatio), @(vRatio),
|
||||
@(jawRatio), @(PGClamp(s.faceCheekbone, 0, 1)), @(PGClamp(s.faceSmallHead, 0, 1)), @(PGClamp(s.faceSmallHeadRange, 0, 1)),
|
||||
[CIVector vectorWithX:extent.origin.x Y:extent.origin.y], [CIVector vectorWithX:extent.size.width Y:extent.size.height]] mutableCopy];
|
||||
for (NSUInteger i=0; i<17; i++) {
|
||||
@@ -564,6 +570,15 @@ static NSDictionary *PGStableGeometry(NSDictionary *current, NSDictionary *previ
|
||||
}
|
||||
[arguments addObject:[CIVector vectorWithX:ox Y:oy Z:ax W:ay]];
|
||||
}
|
||||
for (NSUInteger i=0; i<4; i++) {
|
||||
double ox=0,oy=0,ax=0,ay=0;
|
||||
if (points76) {
|
||||
NSArray *origin=points76[PGVFacePins[i][0]],*anchor=points76[PGVFacePins[i][1]];
|
||||
ox=[origin[0] doubleValue];oy=1-[origin[1] doubleValue];
|
||||
ax=[anchor[0] doubleValue];ay=1-[anchor[1] doubleValue];
|
||||
}
|
||||
[arguments addObject:[CIVector vectorWithX:ox Y:oy Z:ax W:ay]];
|
||||
}
|
||||
for (NSUInteger i=0; i<3; i++) {
|
||||
double ox=0,oy=0,ax=0,ay=0;
|
||||
if (points76) {
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.3.0</string>
|
||||
<string>1.3.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>15</string>
|
||||
<string>16</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# V 脸下颌区域修复
|
||||
|
||||
2026-10-22,针对用户报告「V 脸作用到眼睛,应作用于下颌」。目标为本机 MSE18V2 2.4.0(20260724150000),产品修复版本为 1.3.1(16)。
|
||||
|
||||
## 原因与修改
|
||||
|
||||
1.3.0 仍使用脸框上的宽范围高斯带及纵向位移近似 V 脸。它不依赖真实下颌轮廓,在真实人像上能测到眼区变化。不是面板标签或参数 ID 接错;本次只替换 V 脸几何场。
|
||||
|
||||
新版目标的 AIR 按 `69→39、65→35、70→26、64→34` 顺序执行四组局部逆向采样。起点都是下颌轮廓,锚点都是外唇。每步使用前一步更新后的 q:
|
||||
|
||||
```text
|
||||
r = length(anchor − origin)
|
||||
if r > 0.0001:
|
||||
weight = clamp(1 − length(q − origin) / r, 0, 1)
|
||||
q = clamp(q − (anchor − origin) × ratio × weight, 0, 1)
|
||||
```
|
||||
|
||||
CPU 函数 `0x10002fb74` 从参数 `+0x90` 读取 V 值,乘位于 `0x100085ea0` 的 double `0.065` 和公共强度,再转 float 写入 shape 结构的 `+8`。新版三个 shader helper 都没有旧版的 `280/尺寸` 增益;本项目 V 使用 `clamp(faceV,0,1)×0.065`,整体混合沿用现有产品链。公共强度各调用方的完整来源尚未追踪,不将整体混合宣称为原版该参数的等价重建。
|
||||
|
||||
生产实现复用局部 pin 核心,四步严格顺序更新,与图像/四张支持蒙版共享同一坐标场;完整 76 点缺失或不合法时安全直通。Core Image 坐标和关键点一起转换到 Y 向下的全图 UV,结束后一起转回,支持非零图像原点、横竖画幅和歪头。
|
||||
|
||||
## 静态证据与复现
|
||||
|
||||
原始 APP、metallib、完整 AIR 与用户帧仅留本机 build,不是构建依赖。源码没有嵌入目标二进制、私有模型或授权逻辑。
|
||||
|
||||
- 原 APP 嵌套 Mach-O(fat)SHA-256:`577303e0de72e07feb576c882e82382b3f056b023a7e987d990ffb37f6b16109`。
|
||||
- arm64 切片 SHA-256:`afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df`。
|
||||
- metallib SHA-256:`856849c45cea2c8f083eeba06a9e318c450f4a56694b438d1a5ba8ef752a0ee0`。
|
||||
- `xcrun metal-objdump --metallib --disassemble` 输出 SHA-256:`1d5bd8d5a3917afbb3b4fe1c40b44480760614102685ac826e84ad2e30a450f9`;V 分支 3364–3431 行,四组点索引在 3374、3376、3378、3380 行。
|
||||
- 精简 AIR 摘录:[vface-air.txt](vface-air.txt);CPU 字段/系数与分析条件:[vface-findings.json](vface-findings.json);REA CPU 汇编和常量证据:[rea-vface-evidence.json](rea-vface-evidence.json)。REA 操作为只读,未运行原 APP 或原 shader。
|
||||
|
||||
## 验证
|
||||
|
||||
修改前隔离 V 测试复现:NASA 人像瞳孔 6 的位移约 0.031493 像素;宿主物理行序测试四种原点组合的 V 输出与独立 upright 参考均不符。原宿主输出两眼区像素变化量分别为 12824、19304,下颌为 195206。
|
||||
|
||||
修改后瞳孔检查通过;宿主四种原点组合的 V 眼区像素变化量均为 0,下颌为 39246,独立 upright 对照最大差 1/255、均差 0.000124/255。数值场覆盖 4 种画幅、正侧脸和歪头、半强度、小脸不带旧增益、顺序组合、缺点/坏点以及四张蒙版同步。独立的真实解剖位置检查要求下颌有位移且两瞳孔位移小于 0.002 像素,避免只用复制实现的数值公式验收。
|
||||
|
||||
完整自动回归:1901 项通过(57 Beauty、116 Face、1033 几何、370 Host ASan、98 OSC ASan、227 Inspector ASan)。真实用户帧专项另记交付验证;与基础用例重叠,不相加。正式安装和原生宿主 V 脸视觉验收状态见 [验证记录](../验证记录.md)。
|
||||
|
||||
## 范围
|
||||
|
||||
V 脸现在加入已恢复的五项局部控制。瘦脸、下巴、短脸、下颌骨沿用此前版本的尺寸增益;未将新版目标的其他差异混入本次修复。大眼、窄脸、颧骨和小头仍为近似,整条混合控制链的数学、顺序和最终像素尚未全部对齐。静态重建、离屏/接口检查不等于原版 shader 的运行时逐像素比较,也不等于 Motion/FCP 原生视觉验收。
|
||||
@@ -0,0 +1 @@
|
||||
{"artifacts":[{"architecture":"arm64","digest":{"sha256":"afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df"},"format":"mach-o"}],"captures":[],"environments":[],"providers":[{"id":"ghidra","name":"Ghidra","version":"12.1.4"}],"records":[{"analysis_profile":{"digest":"20565088524a2d0359b9b96f46ac48e679d774c7b0092c56abc06de8fdbec11c","parameters":{"analyzer_preset":"ghidra-default","annotation_policy":"atomic-function-entry-metadata-v1","architecture":"arm64","available_architectures":["arm64"],"compiler_spec_id":"auto-default","decompiler_jump_loads":true,"function_body_evidence":"complete-inclusive-ranges-v1","function_boundary_observations":"ghidra-terminal-call-limitations-v1","function_references":"complete-body-and-entry-reference-manager-v2","import_mode":"ephemeral-source-immutable","instruction_flow_evidence":"decoded-return-pcode-v1","jump_table_evidence":"typed-case-default-blocks-v1","language_id":"auto-from-header","load_image_observations":"source-mappings-entry-context-v2","loader":"auto-from-header","location_resolution":"explicit-address-exact-entry-symbol-first-v3","no_return_repair":"returning-imports-decoded-return-v2","process_launch":"inspected-jvm-launch-support-v1","string_inventory_evidence":"defined-data-coverage-v1","target_format":"mach-o","target_kind":"executable"},"provider":{"id":"ghidra","name":"Ghidra","version":"12.1.4"}},"authority":"shipped-artifact","confidence":"observed","environment":null,"evidence_id":"ev_32b6ee46d4fb5eab563883ba73e35a458d5da21229b8977fddcb4df656517152","evidence_links":[],"limitations":["The session serves operations only after Ghidra reports default auto-analysis complete; incomplete analysis does not expose partial results.","The imported Program and temporary project are ephemeral and deleted on close. Annotation operations edit session database metadata; original executable bytes are never written.","Cancelling an active Ghidra request terminates its ephemeral database and discards session annotations. The selected target remains open; the next provider query imports the original artifact again.","Default-space addresses use lowercase 0x-prefixed hexadecimal; other address spaces use <percent-encoded-space>:0x<hex>.","Bytes reflect Ghidra's initialized memory, including loader fixups. Reads stop at an unmapped or uninitialized byte and report completeness explicitly.","macOS sessions require a matching executable Ghidra native decompiler; REA checks for it but does not build native components or change Gatekeeper quarantine state."],"locations":[],"normalized_result":{"address":"0x100085ea0","bytes_hex":"a4703d0ad7a3b03f9a9999999999a93f","complete":true,"requested_bytes":16,"returned_bytes":16},"operation":"read_bytes","parameters":{"address":"0x100085ea0","length":16},"predicate_type":"rea.analysis","provider":{"id":"ghidra","name":"Ghidra","version":"12.1.4"},"raw_result":{"address":"0x100085ea0","bytes_hex":"a4703d0ad7a3b03f9a9999999999a93f","complete":true,"requested_bytes":16,"returned_bytes":16},"subject":{"architecture":"arm64","digest":{"sha256":"afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df"},"format":"mach-o","local_path":"/Users/dayu/Documents/PaintFCP/build/body-analysis/MSE18V2-arm64","name":"MSE18V2-arm64"}},{"analysis_profile":{"digest":"20565088524a2d0359b9b96f46ac48e679d774c7b0092c56abc06de8fdbec11c","parameters":{"analyzer_preset":"ghidra-default","annotation_policy":"atomic-function-entry-metadata-v1","architecture":"arm64","available_architectures":["arm64"],"compiler_spec_id":"auto-default","decompiler_jump_loads":true,"function_body_evidence":"complete-inclusive-ranges-v1","function_boundary_observations":"ghidra-terminal-call-limitations-v1","function_references":"complete-body-and-entry-reference-manager-v2","import_mode":"ephemeral-source-immutable","instruction_flow_evidence":"decoded-return-pcode-v1","jump_table_evidence":"typed-case-default-blocks-v1","language_id":"auto-from-header","load_image_observations":"source-mappings-entry-context-v2","loader":"auto-from-header","location_resolution":"explicit-address-exact-entry-symbol-first-v3","no_return_repair":"returning-imports-decoded-return-v2","process_launch":"inspected-jvm-launch-support-v1","string_inventory_evidence":"defined-data-coverage-v1","target_format":"mach-o","target_kind":"executable"},"provider":{"id":"ghidra","name":"Ghidra","version":"12.1.4"}},"authority":"shipped-artifact","confidence":"observed","environment":null,"evidence_id":"ev_6a88310573f4dfd2f23feef7d12c3f58eba366db1717861770656d55375e07a1","evidence_links":[],"limitations":["The session serves operations only after Ghidra reports default auto-analysis complete; incomplete analysis does not expose partial results.","The imported Program and temporary project are ephemeral and deleted on close. Annotation operations edit session database metadata; original executable bytes are never written.","Cancelling an active Ghidra request terminates its ephemeral dataLine truncated
|
||||
@@ -0,0 +1,71 @@
|
||||
MSE18V2 2.4.0 AIR excerpt; original complete-text line numbers.
|
||||
SHA256: 1d5bd8d5a3917afbb3b4fe1c40b44480760614102685ac826e84ad2e30a450f9
|
||||
|
||||
3364: 158: ; preds = %109, %85
|
||||
3365: %159 = phi <2 x float> [ %155, %109 ], [ %86, %85 ]
|
||||
3366: %160 = tail call fast float @air.fast_fabs.f32(float %5) #2
|
||||
3367: %161 = fcmp fast ogt float %160, 0x3EB0C6F7A0000000
|
||||
3368: br i1 %161, label %162, label %209
|
||||
3369:
|
||||
3370: 162: ; preds = %158
|
||||
3371: %163 = bitcast [4 x <2 x i32>]* %17 to i8*
|
||||
3372: call void @llvm.lifetime.start.p0i8(i64 32, i8* nonnull %163) #10
|
||||
3373: %164 = getelementptr inbounds [4 x <2 x i32>], [4 x <2 x i32>]* %17, i64 0, i64 0
|
||||
3374: store <2 x i32> <i32 69, i32 39>, <2 x i32>* %164, align 8
|
||||
3375: %165 = getelementptr inbounds [4 x <2 x i32>], [4 x <2 x i32>]* %17, i64 0, i64 1
|
||||
3376: store <2 x i32> <i32 65, i32 35>, <2 x i32>* %165, align 8
|
||||
3377: %166 = getelementptr inbounds [4 x <2 x i32>], [4 x <2 x i32>]* %17, i64 0, i64 2
|
||||
3378: store <2 x i32> <i32 70, i32 26>, <2 x i32>* %166, align 8
|
||||
3379: %167 = getelementptr inbounds [4 x <2 x i32>], [4 x <2 x i32>]* %17, i64 0, i64 3
|
||||
3380: store <2 x i32> <i32 64, i32 34>, <2 x i32>* %167, align 8
|
||||
3381: %168 = insertelement <2 x float> undef, float %5, i64 0
|
||||
3382: %169 = shufflevector <2 x float> %168, <2 x float> undef, <2 x i32> zeroinitializer
|
||||
3383: br label %171
|
||||
3384:
|
||||
3385: 170: ; preds = %205
|
||||
3386: call void @llvm.lifetime.end.p0i8(i64 32, i8* nonnull %163) #10
|
||||
3387: br label %209
|
||||
3388:
|
||||
3389: 171: ; preds = %205, %162
|
||||
3390: %172 = phi <2 x float> [ %159, %162 ], [ %206, %205 ]
|
||||
3391: %173 = phi i32 [ 0, %162 ], [ %207, %205 ]
|
||||
3392: %174 = zext i32 %173 to i64
|
||||
3393: %175 = getelementptr inbounds [4 x <2 x i32>], [4 x <2 x i32>]* %17, i64 0, i64 %174
|
||||
3394: %176 = load <2 x i32>, <2 x i32>* %175, align 8
|
||||
3395: %177 = extractelement <2 x i32> %176, i64 0
|
||||
3396: %178 = add nsw i32 %177, %2
|
||||
3397: %179 = sext i32 %178 to i64
|
||||
3398: %180 = getelementptr inbounds %struct.MSSFaceThinPoint, %struct.MSSFaceThinPoint addrspace(2)* %1, i64 %179, i32 0
|
||||
3399: %181 = load <2 x float>, <2 x float> addrspace(2)* %180, align 8, !tbaa !74
|
||||
3400: %182 = extractelement <2 x i32> %176, i64 1
|
||||
3401: %183 = add nsw i32 %182, %2
|
||||
3402: %184 = sext i32 %183 to i64
|
||||
3403: %185 = getelementptr inbounds %struct.MSSFaceThinPoint, %struct.MSSFaceThinPoint addrspace(2)* %1, i64 %184, i32 0
|
||||
3404: %186 = load <2 x float>, <2 x float> addrspace(2)* %185, align 8, !tbaa !74
|
||||
3405: %187 = fsub fast <2 x float> %181, %186
|
||||
3406: %188 = tail call fast float @air.dot.v2f32(<2 x float> %187, <2 x float> %187) #2
|
||||
3407: %189 = tail call fast float @air.fast_sqrt.f32(float %188) #2
|
||||
3408: %190 = fcmp fast ugt float %189, 0x3F1A36E2E0000000
|
||||
3409: br i1 %190, label %191, label %205
|
||||
3410:
|
||||
3411: 191: ; preds = %171
|
||||
3412: %192 = fsub fast <2 x float> %186, %181
|
||||
3413: %193 = fsub fast <2 x float> %172, %181
|
||||
3414: %194 = tail call fast float @air.dot.v2f32(<2 x float> %193, <2 x float> %193) #2
|
||||
3415: %195 = tail call fast float @air.fast_sqrt.f32(float %194) #2
|
||||
3416: %196 = fdiv fast float %195, %189
|
||||
3417: %197 = fsub fast float 1.000000e+00, %196
|
||||
3418: %198 = tail call fast float @air.fast_clamp.f32(float %197, float 0.000000e+00, float 1.000000e+00) #2
|
||||
3419: %199 = insertelement <2 x float> undef, float %198, i64 0
|
||||
3420: %200 = shufflevector <2 x float> %199, <2 x float> undef, <2 x i32> zeroinitializer
|
||||
3421: %201 = fmul fast <2 x float> %192, %169
|
||||
3422: %202 = fmul fast <2 x float> %201, %200
|
||||
3423: %203 = fsub fast <2 x float> %172, %202
|
||||
3424: %204 = tail call fast <2 x float> @air.fast_clamp.v2f32(<2 x float> %203, <2 x float> zeroinitializer, <2 x float> <float 1.000000e+00, float 1.000000e+00>) #2
|
||||
3425: br label %205
|
||||
3426:
|
||||
3427: 205: ; preds = %191, %171
|
||||
3428: %206 = phi <2 x float> [ %204, %191 ], [ %172, %171 ]
|
||||
3429: %207 = add nuw nsw i32 %173, 1
|
||||
3430: %208 = icmp eq i32 %207, 4
|
||||
3431: br i1 %208, label %170, label %171, !llvm.loop !89
|
||||
@@ -0,0 +1,258 @@
|
||||
{
|
||||
"authority": "Static shipped Apple AIR and Mach-O byte/assembly inspection; target app and shaders not executed",
|
||||
"sources": {
|
||||
"metallib": "/Users/dayu/Downloads/MSE18V2.app/Contents/PlugIns/MSE18V2.pluginkit/Contents/Resources/default.metallib",
|
||||
"metallib_sha256": "856849c45cea2c8f083eeba06a9e318c450f4a56694b438d1a5ba8ef752a0ee0",
|
||||
"command": [
|
||||
"xcrun",
|
||||
"metal-objdump",
|
||||
"--metallib",
|
||||
"--disassemble",
|
||||
"/Users/dayu/Downloads/MSE18V2.app/Contents/PlugIns/MSE18V2.pluginkit/Contents/Resources/default.metallib"
|
||||
],
|
||||
"air_sha256": "1d5bd8d5a3917afbb3b4fe1c40b44480760614102685ac826e84ad2e30a450f9",
|
||||
"binary": "/Users/dayu/Downloads/MSE18V2.app/Contents/PlugIns/MSE18V2.pluginkit/Contents/MacOS/MSE18V2",
|
||||
"binary_arm64_sha256": "afc71d0d21fd3c1ca95ca745ddafcd729e36ad95f17d8638009f2e45d9b7e8df",
|
||||
"double065_file_offsets_in_arm64_slice": [
|
||||
548512
|
||||
]
|
||||
},
|
||||
"new_version_vface": {
|
||||
"struct_field": "MSSFaceShapeParams.vlian offset8; helper parameter5",
|
||||
"render_params_field": "faceV double offset0x90",
|
||||
"cpu_function": "0x10002fb74",
|
||||
"cpu_coefficient_address": "0x100085ea0",
|
||||
"cpu_coefficient": 0.065,
|
||||
"cpu_ratio": "float(clamp(faceV,0,1)*0.065*double(float(clamp(commonStrength,0,1))))",
|
||||
"pin_order": [
|
||||
[
|
||||
69,
|
||||
39
|
||||
],
|
||||
[
|
||||
65,
|
||||
35
|
||||
],
|
||||
[
|
||||
70,
|
||||
26
|
||||
],
|
||||
[
|
||||
64,
|
||||
34
|
||||
]
|
||||
],
|
||||
"pin_fields": [
|
||||
"origin",
|
||||
"direction/radius anchor"
|
||||
],
|
||||
"coordinate_system": "full-image normalized UV; q and points must share the same vertical axis",
|
||||
"radius": "length(Panchor-Porigin), unscaled UV metric; skip radius<=0.0001",
|
||||
"weight": "clamp(1-length(q-Porigin)/radius,0,1)",
|
||||
"step": "q=clamp(q-(Panchor-Porigin)*ratio*weight,0,1)",
|
||||
"sequential": true,
|
||||
"ratio_threshold": 1e-06,
|
||||
"shader_lines": {
|
||||
"helper": 3159,
|
||||
"vface_gate": 3364,
|
||||
"pins": [
|
||||
3374,
|
||||
3376,
|
||||
3378,
|
||||
3380
|
||||
],
|
||||
"loop": 3389,
|
||||
"radius": 3405,
|
||||
"offset": 3412,
|
||||
"clamp": 3424,
|
||||
"count": 3430,
|
||||
"metadata": 4132
|
||||
},
|
||||
"order": "thin17 -> narrow16 -> V4 -> jaw6 -> cheek6 -> chin3 -> short -> smallHead -> bigEye",
|
||||
"helper_copies": [
|
||||
{
|
||||
"start_line": 3159,
|
||||
"v_pins": [
|
||||
[
|
||||
69,
|
||||
39
|
||||
],
|
||||
[
|
||||
65,
|
||||
35
|
||||
],
|
||||
[
|
||||
70,
|
||||
26
|
||||
],
|
||||
[
|
||||
64,
|
||||
34
|
||||
]
|
||||
],
|
||||
"has_old_pixel_gain_constant": false
|
||||
},
|
||||
{
|
||||
"start_line": 6840,
|
||||
"v_pins": [
|
||||
[
|
||||
69,
|
||||
39
|
||||
],
|
||||
[
|
||||
65,
|
||||
35
|
||||
],
|
||||
[
|
||||
70,
|
||||
26
|
||||
],
|
||||
[
|
||||
64,
|
||||
34
|
||||
]
|
||||
],
|
||||
"has_old_pixel_gain_constant": false
|
||||
},
|
||||
{
|
||||
"start_line": 8682,
|
||||
"v_pins": [
|
||||
[
|
||||
69,
|
||||
39
|
||||
],
|
||||
[
|
||||
65,
|
||||
35
|
||||
],
|
||||
[
|
||||
70,
|
||||
26
|
||||
],
|
||||
[
|
||||
64,
|
||||
34
|
||||
]
|
||||
],
|
||||
"has_old_pixel_gain_constant": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"version_difference": {
|
||||
"old_air": "build/pose-analysis/face-thin.air.txt",
|
||||
"old_gain_lines": [
|
||||
592,
|
||||
633
|
||||
],
|
||||
"old_vface_lines": [
|
||||
830,
|
||||
897
|
||||
],
|
||||
"old_cpu_coefficient_address": "0x10005f9a0",
|
||||
"coefficient_unchanged": true,
|
||||
"old_extra_gain": "clamp(280/max(length((P75-P59)*pixelSize),2*length((P67-(P74+P60)/2)*pixelSize),1),1,2.25)",
|
||||
"new_extra_gain": "Absent from all3 new shader helper copies and the complete new AIR text; CPU helper is plain clamped-control*.065*commonStrength",
|
||||
"anatomy": "Origin indices64,65,69,70 are lower contour; anchor indices26,34,35,39 are outer lips; eyes0..13 are not controls."
|
||||
},
|
||||
"eye_support_probe": {
|
||||
"authority": "Derived from existing local public-API Vision probe; no new image coordinates or original plug-in execution",
|
||||
"settings": {
|
||||
"vface": 1,
|
||||
"common_strength": 1,
|
||||
"coefficient": 0.065,
|
||||
"pins": [
|
||||
[
|
||||
69,
|
||||
39
|
||||
],
|
||||
[
|
||||
65,
|
||||
35
|
||||
],
|
||||
[
|
||||
70,
|
||||
26
|
||||
],
|
||||
[
|
||||
64,
|
||||
34
|
||||
]
|
||||
]
|
||||
},
|
||||
"samples": [
|
||||
{
|
||||
"seconds": 0,
|
||||
"minimum_eye_distance_over_pin_radius": 2.86112178668839,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 2,
|
||||
"minimum_eye_distance_over_pin_radius": 2.7386373955689196,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 4,
|
||||
"minimum_eye_distance_over_pin_radius": 2.0723834235969316,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 6,
|
||||
"minimum_eye_distance_over_pin_radius": 2.7994186406360964,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 8,
|
||||
"minimum_eye_distance_over_pin_radius": 2.720538093620307,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 10,
|
||||
"minimum_eye_distance_over_pin_radius": 2.7459899006401245,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 12,
|
||||
"minimum_eye_distance_over_pin_radius": 2.8522571566241655,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 14,
|
||||
"minimum_eye_distance_over_pin_radius": 2.7849986024852744,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 16,
|
||||
"minimum_eye_distance_over_pin_radius": 2.86097776991491,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 18,
|
||||
"minimum_eye_distance_over_pin_radius": 2.4994391012873294,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
},
|
||||
{
|
||||
"seconds": 20,
|
||||
"minimum_eye_distance_over_pin_radius": 2.3076941598447127,
|
||||
"max_eye_weight": 0,
|
||||
"max_sequential_eye_displacement_pixels": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"limits": [
|
||||
"No reference shader runtime or pixel comparison performed.",
|
||||
"The commonStrength caller-source semantics are not fully traced; formula reports the helper input.",
|
||||
"CPU prechecks/license/module gates are observed but are outside the independently authored geometry reconstruction.",
|
||||
"Eye support results apply to the11 existing saved Vision samples, not every possible pose.",
|
||||
"No product sources, app build, host session or Git were changed."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
Beauty renderer: 57 checks, 0 failures (Metal).
|
||||
2026-10-22 16:24:20.836 face-tests[22582:8025448] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
|
||||
Face processing: 116 checks passed
|
||||
2026-10-22 16:24:34.977 slim-tests[22589:8025534] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
|
||||
PASS: 1033 slim alignment checks; maximum UV oracle error 1.09828022e-05
|
||||
@@ -0,0 +1,37 @@
|
||||
2026-10-22 16:21:55.726 host-tests[22385:8017721] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
|
||||
Default IOSurface maximum byte difference: 0
|
||||
Alternate destination tag maximum byte difference: 0
|
||||
Anatomy default 0/0 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
|
||||
Anatomy default 0/1 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
|
||||
Anatomy default 1/0 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
|
||||
Anatomy default 1/1 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0
|
||||
Anatomy big-eye 0/0 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
|
||||
Anatomy big-eye 0/1 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
|
||||
Anatomy big-eye 1/0 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
|
||||
Anatomy big-eye 1/1 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0
|
||||
Anatomy chin-positive 0/0 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
|
||||
Anatomy chin-positive 0/1 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
|
||||
Anatomy chin-positive 1/0 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
|
||||
Anatomy chin-positive 1/1 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0
|
||||
Anatomy chin-negative 0/0 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
|
||||
Anatomy chin-negative 0/1 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
|
||||
Anatomy chin-negative 1/0 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
|
||||
Anatomy chin-negative 1/1 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0
|
||||
Anatomy short-positive 0/0 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
|
||||
Anatomy short-positive 0/1 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
|
||||
Anatomy short-positive 1/0 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
|
||||
Anatomy short-positive 1/1 max=2 mean=0.0011072 eye=0/0 chin=285953 inverted=0
|
||||
Anatomy short-negative 0/0 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
|
||||
Anatomy short-negative 0/1 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
|
||||
Anatomy short-negative 1/0 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
|
||||
Anatomy short-negative 1/1 max=2 mean=0.0008583 eye=0/0 chin=225648 inverted=0
|
||||
Anatomy jaw 0/0 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
|
||||
Anatomy jaw 0/1 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
|
||||
Anatomy jaw 1/0 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
|
||||
Anatomy jaw 1/1 max=1 mean=0.0001974 eye=0/0 chin=12951 inverted=0
|
||||
Anatomy v-face 0/0 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
|
||||
Anatomy v-face 0/1 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
|
||||
Anatomy v-face 1/0 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
|
||||
Anatomy v-face 1/1 max=1 mean=0.0001240 eye=0/0 chin=39246 inverted=0
|
||||
Legacy fallback upright comparison: max=2 mean=0.0010357
|
||||
Host adapter: 370 checks, 0 failures
|
||||
@@ -0,0 +1 @@
|
||||
Inspector: 227 checks, 0 failures
|
||||
@@ -0,0 +1,21 @@
|
||||
2026-10-22 16:24:26.444 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.25,0.75) setter=(0.25,0.75) readback=(0.25,0.75) mode=normalized verified=1
|
||||
2026-10-22 16:24:26.452 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(80,180) surface=320x240 origin=0
|
||||
2026-10-22 16:24:26.887 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.8,0.3) setter=(1152,-432) readback=(0.8,0.3) mode=centered-pixels verified=1
|
||||
2026-10-22 16:24:26.887 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.7,0.4) objectBounds=(-1920,-1080,3840,2160) canvas=(152,78) surface=320x240 origin=0
|
||||
2026-10-22 16:24:26.944 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.8,0.3) setter=(0.8,0.3) readback=(0.12345,0.87654) mode=normalized verified=0
|
||||
2026-10-22 16:24:26.944 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.75,0.25) setter=(0.75,0.25) readback=(0.75,0.25) mode=normalized verified=1
|
||||
2026-10-22 16:24:26.944 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.75,0.25) objectBounds=(-100,-50,200,100) canvas=(160,60) surface=320x240 origin=0
|
||||
2026-10-22 16:24:26.994 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.625,0.375) setter=(0.625,0.375) readback=(0.625,0.375) mode=normalized verified=1
|
||||
2026-10-22 16:24:26.994 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.625,0.375) objectBounds=(-100,-50,200,100) canvas=(240,60) surface=320x240 origin=0
|
||||
2026-10-22 16:24:27.043 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.25,0.75) setter=(0.25,0.75) readback=(0.25,0.75) mode=normalized verified=1
|
||||
2026-10-22 16:24:27.043 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(144,180) surface=320x240 origin=0
|
||||
2026-10-22 16:24:27.094 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
2026-10-22 16:24:27.094 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0,1) objectBounds=(-100,-50,200,100) canvas=(100,140) surface=320x240 origin=0
|
||||
2026-10-22 16:24:27.144 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(nan,nan) surface=320x240 origin=0
|
||||
2026-10-22 16:24:27.194 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
2026-10-22 16:24:27.194 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(inf,nan) surface=320x240 origin=0
|
||||
2026-10-22 16:24:27.242 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
2026-10-22 16:24:27.242 osc-tests[22624:8025751] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(80,nan) surface=320x240 origin=0
|
||||
2026-10-22 16:24:27.304 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
2026-10-22 16:24:27.304 osc-tests[22624:8025751] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1
|
||||
OSC adapter: 98 checks, 0 failures
|
||||
@@ -0,0 +1,2 @@
|
||||
2026-10-22 16:25:35.195 slim-tests[22704:8027100] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2
|
||||
PASS: 1561 slim alignment checks; maximum UV oracle error 1.09828022e-05
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"version": "1.3.1",
|
||||
"build": "16",
|
||||
"checks": {
|
||||
"beauty": 57,
|
||||
"face": 116,
|
||||
"geometry": 1033,
|
||||
"hostASan": 370,
|
||||
"oscASan": 98,
|
||||
"inspectorASan": 227
|
||||
},
|
||||
"total": 1901,
|
||||
"extraRealPoseASan": {
|
||||
"checks": 1561,
|
||||
"inputs": "NASA astronaut plus 11 local user frames; frame images and full Vision points not uploaded",
|
||||
"overlapsBaseline": true
|
||||
},
|
||||
"maximumUVOracleError": 1.09828022e-05,
|
||||
"isolatedV": {
|
||||
"eyeChange": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"lowerFaceChange": 39246,
|
||||
"originsCompared": 4,
|
||||
"uprightMax255": 1,
|
||||
"uprightMean255": 0.000124
|
||||
},
|
||||
"nativeVisualQA": "pending user"
|
||||
}
|
||||
+6
-3
@@ -2,6 +2,8 @@
|
||||
|
||||
更新时间:2026-10-22,Asia/Shanghai。项目根目录:`/Users/dayu/Documents/PaintFCP`。
|
||||
|
||||
正在准备 **1.3.1(16)** 的 V 脸下颌修复;1901 项自动检查通过,正式安装尚未替换。
|
||||
|
||||
当前正式安装的 APP 为 **1.3.0(构建 15)**,已完成通用 Release 编译、正式签名、Apple 公证、票据验证及唯一正式路径安装。新增磨皮参数迁移与 1636 项自动检查已完成,原生效果视觉仍待用户实测。公开文章、PKG 与 GitHub Release 继续对应 **1.2.0**;本次未更新这些发行资料,也未覆盖模板或宣传图。
|
||||
|
||||
代码由 **OpenAI + Codex 全程编写,站长仅参与调试和测试**。文章和仓库须保留这个表述,不使用“站长原创代码”等说法。免费版本无需账号、激活码或付费授权;“自动注册”指系统插件注册。
|
||||
@@ -84,18 +86,19 @@ Xcode 工程:`beatygril/beatygril.xcodeproj`。外层 scheme 为 `Wrapper Appl
|
||||
|
||||
本项目几何历史只取当前请求之前的近时记录,原版还存在近未来历史分支;冷启动、热缓存、乱序渲染、同尺寸换源和多人交叉仍有差异边界。旧离线分析字段保留兼容,但当前新面板的渲染统一使用实时自动跟随。
|
||||
|
||||
### 已完成的四项局部算法
|
||||
### 已完成的五项局部算法
|
||||
|
||||
| 控制项 | 当前实现 | 防止回归的要点 |
|
||||
| --- | --- | --- |
|
||||
| 瘦脸 | 76 点、17 组轮廓到鼻部或瞳孔锚点的局部逆向采样 | 不恢复整脸框水平挤压;保留尺寸增益、组顺序和逐步 clamp |
|
||||
| V 脸 | `69→39`、`65→35`、`70→26`、`64→34` 四组下颌到外唇局部位移 | 新版 2.4.0 使用 0.065 系数、无旧尺寸增益;两瞳孔保持不动 |
|
||||
| 下巴 | `68→38`、`67→37`、`66→36` 三组局部位移 | 正值上收、负值延伸,保留正负不同系数 |
|
||||
| 下颌骨 | 六组相邻轮廓半径的顺序局部位移 | 半径来自相邻轮廓点,方向锚点为 P29;不能同时求和替代逐步更新 |
|
||||
| 短脸 | P62 至 P72 的下半脸闭合区域,沿 P46−P48 鼻梁轴位移 | 正值收短、负值延长;不是太阳穴区域或脸框纵向压缩 |
|
||||
|
||||
这四项共享由实际图像像素尺寸计算的增益。完整合法 76 点缺失时,四项安全直通,不退回猜测的脸框场。图像与磨皮、肤色、牙齿、眼睛蒙版共用几何变形路径,避免效果与蒙版错位。
|
||||
此前四项沿用由实际图像像素尺寸计算的增益;V 脸对齐新版目标,不带该额外增益。完整合法 76 点缺失时,五项安全直通,不退回猜测的脸框场。图像与磨皮、肤色、牙齿、眼睛蒙版共用几何变形路径,避免效果与蒙版错位。
|
||||
|
||||
**仍为近似实现的五项:大眼、窄脸、V 脸、颧骨、小头。** 原版完整链为 `thin → narrow → V → jaw → cheek → chin → short → small-head → eyes`,本项目尚未完全恢复整条组合链的数学及顺序。用户单项验收不代表所有参数组合逐像素等价。详细索引、系数和独立数值场验证见[下巴与坐标分析](analysis/下巴与坐标分析.md)、[短脸与下颌骨分析](analysis/短脸与下颌骨分析.md)。
|
||||
**仍为近似实现的四项:大眼、窄脸、颧骨、小头。** 原版完整链为 `thin → narrow → V → jaw → cheek → chin → short → small-head → eyes`,本项目尚未完全恢复整条组合链的数学及顺序。用户单项验收不代表所有参数组合逐像素等价。V 脸修复见 [下颌区域分析](analysis/V脸下颌区域修复.md)。详细索引、系数和独立数值场验证见[下巴与坐标分析](analysis/下巴与坐标分析.md)、[短脸与下颌骨分析](analysis/短脸与下颌骨分析.md)。
|
||||
|
||||
### 坐标约定
|
||||
|
||||
|
||||
+5
@@ -138,3 +138,8 @@ Motion:独立普通视频项目,源PTS0、1920×1080/25fps/10秒,媒体通
|
||||
按用户纠正后的截图需求,迁移连续五官保护、非肤色区保护和局部微细锐化;保留旧 bool、全局磨皮/锐化 ID 与旧工程行为。正式签名源码 `2f2c081980dc610ac810f8daf92da8966f310802`。1636 项通过:57 Beauty、116 Face、796 几何、341 宿主适配 ASan、98 OSC ASan、228 Inspector ASan(含 1 项可选 PNG 输出)。保护 0/50/100 像素响应、色彩覆盖隔离、透明度、v1 状态迁移、新控件归档/插值/输入/重置/旁路/松手前发布均有检查;离屏面板已查看。
|
||||
|
||||
通用 Release 正式签名、公证 Accepted(`ca96837f-bf33-44fa-8d58-799026ce5c7d`)、票据、双架构严格签名、安装身份、Gatekeeper、PluginKit 正式路径与临时副本清理通过。独立从 origin 克隆签名源码节点,205 个受跟踪文件逐字节匹配且 strict/full fsck 通过。本次没有原生新滑杆/效果视觉验收,也没有生成新 PKG 或更新文章;用户已保存并退出宿主后才执行安装。详见 `verification/v1.3.0/` 与 `analysis/新版磨皮参数迁移.md`。
|
||||
|
||||
|
||||
## 1.3.1(16)V 脸下颌区域修复(构建前)
|
||||
|
||||
移除 V 脸的脸框近似宽带,改为新版目标的四组下颌到外唇 pin,单项映射为 clamp(V,0,1)×0.065,不叠加旧尺寸增益。无合法76点时直通,图像与四张蒙版同场变形。1901项自动检查通过:57 Beauty、116 Face、1033几何、370 Host ASan、98 OSC ASan、227 Inspector ASan。原失败复现、点位/CPU/AIR证据和未对齐范围见 analysis/V脸下颌区域修复.md。另对 NASA 人像和本机用户视频11帧运行1561项几何ASan专项(含重复基础用例,不相加),通过;用户帧和完整点坐标未上传。安装及用户视觉待完成,当前正式APP仍为1.3.0。
|
||||
+2
-2
@@ -323,8 +323,8 @@ int main(int argc, const char *argv[]) {
|
||||
*controls[i] = 1;
|
||||
PGFaceFrame *warped = [processor processImage:image settings:changed time:kCMTimeZero error:&error];
|
||||
BOOL changedPixels=![Pixels(context, warped.image) isEqualToData:base];
|
||||
BOOL requiresPoints=(i==0 || i==2 || i==4 || i==6);
|
||||
Check(warped != nil && (requiresPoints ? !changedPixels : changedPixels), requiresPoints ? @"recovered thin/chin/short/jaw skip a face with no indexed landmarks" : [@"geometry control changes pixels: " stringByAppendingString:names[i]]);
|
||||
BOOL requiresPoints=(i==0 || i==2 || i==4 || i==5 || i==6);
|
||||
Check(warped != nil && (requiresPoints ? !changedPixels : changedPixels), requiresPoints ? @"recovered thin/V/chin/short/jaw skip a face with no indexed landmarks" : [@"geometry control changes pixels: " stringByAppendingString:names[i]]);
|
||||
Check(CGRectEqualToRect(warped.image.extent, image.extent), @"warp preserves image extent");
|
||||
}
|
||||
settings.faceShort = 0.8;
|
||||
|
||||
@@ -337,15 +337,16 @@ static void PortraitAnatomyTests(NSString *fixture, CIImage *portrait) {
|
||||
}
|
||||
lowerFace = CGRectInset(lowerFace, -fw*.15, -fh*.15);
|
||||
CGRect upsideDownFace = CGRectMake(box.origin.x*width, box.origin.y*height, fw, fh);
|
||||
const UInt32 controls[] = {0, PGBigEye, PGChin, PGChin, PGShort, PGShort, PGJaw};
|
||||
const double values[] = {0, 1, 1, -1, 1, -1, 1};
|
||||
NSArray<NSString *> *names = @[@"default", @"big-eye", @"chin-positive", @"chin-negative", @"short-positive", @"short-negative", @"jaw"];
|
||||
const UInt32 controls[] = {0, PGBigEye, PGChin, PGChin, PGShort, PGShort, PGJaw, PGVFace};
|
||||
const double values[] = {0, 1, 1, -1, 1, -1, 1, 1};
|
||||
NSArray<NSString *> *names = @[@"default", @"big-eye", @"chin-positive", @"chin-negative", @"short-positive", @"short-negative", @"jaw", @"v-face"];
|
||||
for (NSUInteger effect = 0; effect < names.count; effect++) {
|
||||
PGBeautySettings settings = PGBeautyDefaults();
|
||||
if (effect == 1) settings.faceBigEye = 1;
|
||||
else if (effect == 2 || effect == 3) settings.faceChin = values[effect];
|
||||
else if (effect == 4 || effect == 5) settings.faceShort = values[effect];
|
||||
else if (effect == 6) settings.faceJaw = values[effect];
|
||||
else if (effect == 7) settings.faceV = values[effect];
|
||||
NSData *expected = ImageBytes(context, ProcessedReference(portrait, settings, kCMTimeZero, nil));
|
||||
Check(expected.length == canonical.length, [names[effect] stringByAppendingString:@" independent upright face/beauty chain renders"]);
|
||||
if (expected.length != canonical.length) continue;
|
||||
|
||||
+42
-7
@@ -28,6 +28,7 @@ static NSDictionary *Geometry(double yaw,double roll) {
|
||||
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))];
|
||||
@@ -79,7 +80,7 @@ static CGPoint ChinOracle(CGPoint pixel,NSDictionary *g,CGRect e,double thin,dou
|
||||
return CGPointMake(q.x,1-q.y);
|
||||
}
|
||||
|
||||
// Independent double-precision reconstruction of AIR's jaw and short-face
|
||||
// Independent double-precision reconstruction of AIR's V, jaw and short-face
|
||||
// branches. This does not call or inspect the production kernel/parameter table.
|
||||
// Jaw's support uses the adjacent contour edge, not the much longer lip vector.
|
||||
// Short-face uses a filled lower-contour polygon and its distance envelope.
|
||||
@@ -108,6 +109,15 @@ static double ReferencePolygonWeight(CGPoint q,CGPoint p[76]) {
|
||||
static CGPoint JawShortOracle(CGPoint pixel,NSDictionary *g,CGRect e,PGBeautySettings s) {
|
||||
CGPoint p[76];for(NSUInteger i=0;i<76;i++)p[i]=ReadPoint(g[@"points76"][i]);
|
||||
double gain=ReferenceSizeGain(p,e);CGPoint q=Oracle(pixel,g,e,s.faceThin);q.y=1-q.y;
|
||||
// 2.4.0 consumes the CPU's .065 V ratio directly, without the old size gain.
|
||||
const unsigned int vOrigins[]={69,65,70,64},vAnchors[]={39,35,26,34};
|
||||
double vRatio=Clamp(s.faceV,0,1)*.065;
|
||||
if(vRatio>1e-6)for(NSUInteger i=0;i<4;i++){
|
||||
CGPoint a=ReferencePoint(p,vOrigins[i]),b=ReferencePoint(p,vAnchors[i]);
|
||||
double radius=hypot(b.x-a.x,b.y-a.y);if(radius<=.0001)continue;
|
||||
double influence=Clamp(1-hypot(q.x-a.x,q.y-a.y)/radius,0,1);
|
||||
q.x=Clamp(q.x-(b.x-a.x)*vRatio*influence,0,1);q.y=Clamp(q.y-(b.y-a.y)*vRatio*influence,0,1);
|
||||
}
|
||||
const unsigned int origin[]={72,62,71,63,70,64},neighbour[]={71,63,70,64,71,63};
|
||||
double jaw=Clamp(s.faceJaw,0,1)*.05*gain;
|
||||
if(fabs(jaw)>1e-6)for(NSUInteger i=0;i<6;i++){
|
||||
@@ -251,6 +261,21 @@ static void JawShortAnatomicalChecks(CIContext *context,PGFaceProcessor *process
|
||||
}
|
||||
}
|
||||
}
|
||||
static void VFaceAnatomicalChecks(CIContext *context,PGFaceProcessor *processor,NSDictionary *geometry,CGRect extent) {
|
||||
CIImage *ramp=CoordinateImage(extent);PGBeautySettings settings=PGBeautyDefaults();settings.faceV=1;
|
||||
CIImage *output=[processor warpImage:ramp geometry:@[geometry] settings:settings extent:extent];
|
||||
NSArray *points=geometry[@"points76"];double lowerMove=0;
|
||||
for(NSNumber *index in @[@69,@65,@70,@64]) {
|
||||
CGPoint motion=Displacement(context,ramp,output,ReadPoint(points[index.unsignedIntegerValue]));
|
||||
lowerMove=fmax(lowerMove,hypot(motion.x,motion.y));
|
||||
}
|
||||
Check(lowerMove>.1,@"V-face moves the actual lower-jaw contour");
|
||||
for(NSNumber *index in @[@6,@13]) {
|
||||
CGPoint motion=Displacement(context,ramp,output,ReadPoint(points[index.unsignedIntegerValue]));
|
||||
if(hypot(motion.x,motion.y)>=.002)fprintf(stderr,"V-face pupil %u moved %.6f pixels\n",index.unsignedIntValue,hypot(motion.x,motion.y));
|
||||
Check(hypot(motion.x,motion.y)<.002,@"isolated V-face leaves the physical pupils unchanged");
|
||||
}
|
||||
}
|
||||
static void JawShortSupportChecks(CIContext *context,PGFaceProcessor *processor) {
|
||||
NSDictionary *g=Geometry(0,0);CGPoint points[76];for(NSUInteger i=0;i<76;i++)points[i]=ReadPoint(g[@"points76"][i]);
|
||||
CGPoint probe=CGPointMake((points[72].x+points[29].x)/2,(points[72].y+points[29].y)/2);
|
||||
@@ -267,16 +292,18 @@ static void JawShortSupportChecks(CIContext *context,PGFaceProcessor *processor)
|
||||
Check(ReferenceSizeGain(points,e)==2.25,@"small-face numerical case reaches the recovered gain cap");
|
||||
NumericLocalCase(context,processor,e,small,settings,@"small face jaw max gain");settings.faceJaw=0;settings.faceShort=1;
|
||||
NumericLocalCase(context,processor,e,small,settings,@"small face short max gain");
|
||||
settings.faceShort=0;settings.faceV=1;
|
||||
NumericLocalCase(context,processor,e,small,settings,@"small face V excludes legacy size gain");
|
||||
for(NSUInteger i=0;i<76;i++)points[i]=ReadPoint(g[@"points76"][i]);Check(ReferenceSizeGain(points,CGRectMake(0,0,1600,1600))==1,@"large-face numerical case reaches gain floor");
|
||||
// Four full process masks must use exactly the same new warp as the image.
|
||||
[processor setTrackingData:Archive(g) forTarget:0];settings=PGBeautyDefaults();settings.trackingEnabled=1;
|
||||
PGFaceFrame *neutral=[processor processImage:ramp settings:settings time:kCMTimeZero error:nil];
|
||||
for(NSUInteger mode=0;mode<3;mode++){
|
||||
PGBeautySettings shape=settings;shape.faceJaw=mode!=1?1:0;shape.faceShort=mode!=0?-.65:0;
|
||||
for(NSUInteger mode=0;mode<4;mode++){
|
||||
PGBeautySettings shape=settings;shape.faceJaw=(mode==0||mode==2)?1:0;shape.faceShort=(mode==1||mode==2)?-.65:0;shape.faceV=mode==3?1:0;
|
||||
PGFaceFrame *frame=[processor processImage:ramp settings:shape time:kCMTimeZero error:nil];
|
||||
Check([Pixels(context,frame.image)isEqualToData:Pixels(context,[processor warpImage:ramp geometry:@[g] settings:shape extent:e])],@"process image uses the new common jaw/short field");
|
||||
Check([Pixels(context,frame.image)isEqualToData:Pixels(context,[processor warpImage:ramp geometry:@[g] settings:shape extent:e])],@"process image uses the common V/jaw/short field");
|
||||
NSArray *before=@[neutral.skinMask,neutral.colorMask,neutral.teethMask,neutral.eyeMask],*after=@[frame.skinMask,frame.colorMask,frame.teethMask,frame.eyeMask];
|
||||
for(NSUInteger i=0;i<4;i++)Check([Pixels(context,after[i])isEqualToData:Pixels(context,[processor warpImage:before[i] geometry:@[g] settings:shape extent:e])],@"every image support mask shares the jaw/short coordinate field");
|
||||
for(NSUInteger i=0;i<4;i++)Check([Pixels(context,after[i])isEqualToData:Pixels(context,[processor warpImage:before[i] geometry:@[g] settings:shape extent:e])],@"every image support mask shares the V/jaw/short coordinate field");
|
||||
}
|
||||
}
|
||||
static void IndependentImageLandmarkCheck(NSString *path,NSDictionary *geometry) {
|
||||
@@ -318,16 +345,21 @@ int main(int argc,const char *argv[]) {@autoreleasepool {
|
||||
NumericSettingsCase(c,p,extents[2],Geometry(-.6,-.2),1,-1,@"thin plus negative chin");
|
||||
NumericSettingsCase(c,p,extents[0],Geometry(0,0),0,.5,@"half positive chin");
|
||||
NumericSettingsCase(c,p,extents[0],Geometry(0,0),0,-.5,@"half negative chin");
|
||||
for(NSUInteger e=0;e<4;e++)for(NSUInteger y=0;y<3;y++)for(NSUInteger r=0;r<3;r++)for(NSUInteger mode=0;mode<3;mode++){
|
||||
PGBeautySettings local=PGBeautyDefaults();if(mode==0)local.faceJaw=1;else local.faceShort=mode==1?1:-1;
|
||||
for(NSUInteger e=0;e<4;e++)for(NSUInteger y=0;y<3;y++)for(NSUInteger r=0;r<3;r++)for(NSUInteger mode=0;mode<4;mode++){
|
||||
PGBeautySettings local=PGBeautyDefaults();if(mode==0)local.faceJaw=1;else if(mode==3)local.faceV=1;else local.faceShort=mode==1?1:-1;
|
||||
double angle=y==0?0:(y==1?1.4:-1.4);
|
||||
NumericLocalCase(c,p,extents[e],Geometry(angle,roll[r]),local,
|
||||
[NSString stringWithFormat:@"local size%lu yaw%lu roll%lu mode%lu",(unsigned long)e,(unsigned long)y,(unsigned long)r,(unsigned long)mode]);
|
||||
if(mode==3)VFaceAnatomicalChecks(c,p,Geometry(angle,roll[r]),extents[e]);
|
||||
}
|
||||
PGBeautySettings combined=PGBeautyDefaults();combined.faceThin=.7;combined.faceJaw=.8;combined.faceChin=-.6;combined.faceShort=.75;
|
||||
NumericLocalCase(c,p,extents[2],Geometry(.8,.45),combined,@"ordered thin jaw chin short positive");
|
||||
combined.faceShort=-.75;combined.faceChin=.7;
|
||||
NumericLocalCase(c,p,extents[1],Geometry(-.8,-.45),combined,@"ordered thin jaw chin short negative");
|
||||
combined.faceV=.85;
|
||||
NumericLocalCase(c,p,extents[3],Geometry(.6,.2),combined,@"thin V jaw chin short combined sequential order");
|
||||
PGBeautySettings vHalf=PGBeautyDefaults();vHalf.faceV=.5;
|
||||
NumericLocalCase(c,p,extents[2],Geometry(-.6,-.4),vHalf,@"half V strength tilted portrait");
|
||||
combined=PGBeautyDefaults();combined.faceJaw=.5;combined.faceShort=-.5;
|
||||
NumericLocalCase(c,p,extents[1],Geometry(0,0),combined,@"half signed short plus jaw");
|
||||
JawShortSupportChecks(c,p);
|
||||
@@ -361,6 +393,8 @@ int main(int argc,const char *argv[]) {@autoreleasepool {
|
||||
Check([Pixels(c,[p processImage:image settings:shortOnly time:kCMTimeZero error:&error].image) isEqualToData:source],@"legacy/malformed indexed points skip recovered short-face field exactly");
|
||||
PGBeautySettings jawOnly=s;jawOnly.faceThin=0;jawOnly.faceJaw=1;
|
||||
Check([Pixels(c,[p processImage:image settings:jawOnly time:kCMTimeZero error:&error].image) isEqualToData:source],@"legacy/malformed indexed points skip recovered jaw field exactly");
|
||||
PGBeautySettings vOnly=s;vOnly.faceThin=0;vOnly.faceV=1;
|
||||
Check([Pixels(c,[p processImage:image settings:vOnly time:kCMTimeZero error:&error].image) isEqualToData:source],@"legacy/malformed indexed points skip recovered V-face without a guessed face-box band");
|
||||
PGBeautySettings other=s;other.faceNarrow=.5;
|
||||
Check(![Pixels(c,[p processImage:image settings:other time:kCMTimeZero error:&error].image) isEqualToData:source],@"other controls remain available in legacy archives");
|
||||
}
|
||||
@@ -385,6 +419,7 @@ int main(int argc,const char *argv[]) {@autoreleasepool {
|
||||
Check([Pixels(c,[copy processImage:portrait settings:rs time:kCMTimeZero error:&error].image) isEqualToData:Pixels(c,f.image)],@"real pose replays from persisted 76 points with identical pixels");
|
||||
AnatomicalChecks(c,real,f.deformationGeometry.firstObject,portrait.extent);
|
||||
JawShortAnatomicalChecks(c,real,f.deformationGeometry.firstObject,portrait.extent);
|
||||
VFaceAnatomicalChecks(c,real,f.deformationGeometry.firstObject,portrait.extent);
|
||||
IndependentImageLandmarkCheck(@(argv[index]),f.deformationGeometry.firstObject);
|
||||
}}
|
||||
printf("PASS: %lu slim alignment checks; maximum UV oracle error %.9g\n",(unsigned long)checks,maxOracleError);return 0;
|
||||
|
||||
在新工单中引用
屏蔽一个用户