diff --git a/src/main/capabilities/vision.ts b/src/main/capabilities/vision.ts index a8e893b..c90d02e 100644 --- a/src/main/capabilities/vision.ts +++ b/src/main/capabilities/vision.ts @@ -307,12 +307,19 @@ function scanBest(screen: PNG, template: PNG, maximumDifference: number): MatchR let best: MatchResult | null = null; for (let y = 0; y <= screen.height - template.height; y += scanStep) { for (let x = 0; x <= screen.width - template.width; x += scanStep) { - const difference = pixelDifference(screen, template, x, y, sampleStep, best ? 1 - best.score : maximumDifference); + // 尚无 best 时不剪枝(完整评估): 若初始就按 maximumDifference 剪枝, + // 均匀背景位置在少数采样后返回"刚好压线"的部分均值抢占 best, + // 而真位置(常不在网格上)附近的网格点因部分重叠被剪, 精化永远够不到—— + // 相似度 0.95 时实测 score=1.0 的真位置被判"未达到阈值" + const cutoff = best ? 1 - best.score : 1; + const difference = pixelDifference(screen, template, x, y, sampleStep, cutoff); const score = 1 - difference; if (!best || score > best.score) best = { x, y, width: template.width, height: template.height, score }; } } - if (!best || 1 - best.score > maximumDifference) return null; + if (!best) return null; + // 注意: 阈值判定必须放在精化之后——粗扫网格(步长=模板短边/12)通常够不到精确位置, + // 粗扫 best 常差在阈值边缘, 精化后才能提到满分; 先判阈值会把真命中误杀 const refine = Math.max(1, scanStep); const minX = Math.max(0, best.x - refine); const maxX = Math.min(screen.width - template.width, best.x + refine); @@ -320,11 +327,14 @@ function scanBest(screen: PNG, template: PNG, maximumDifference: number): MatchR const maxY = Math.min(screen.height - template.height, best.y + refine); for (let y = minY; y <= maxY; y += 1) { for (let x = minX; x <= maxX; x += 1) { - const difference = pixelDifference(screen, template, x, y, sampleStep, 1 - best.score); + // 精化区域只有几百个位置, 完整评估避免同样的剪枝偏置 + const difference = pixelDifference(screen, template, x, y, sampleStep, 1); const score = 1 - difference; if (score > best.score) best = { x, y, width: template.width, height: template.height, score }; } } + // 阈值判定: 精化后的最终得分才与 maximumDifference 比较 + if (1 - best.score > maximumDifference) return null; return best; }