当前位置:首页 > 逆向工程 > 正文

Computer Use 点不中按钮:坐标映射的三个坑

约 3918 字 · 预计阅读 10 分钟
一句话总结:Computer Use 类 Agent 最常见的失败不是"看错了",是"点偏了"。从模型输出的页面坐标到真实的屏幕坐标,中间要过 DPI 缩放、窗口标题栏、窗口位置三层转换。我按 125% 缩放算了一遍,三层叠加后偏差 225×212 像素——按 32×32 的按钮算,偏出 7 个按钮宽度。

做 Computer Use 的人大概都遇到过这种情况:模型说"我点击登录按钮",日志显示它也点了,但界面上什么都没发生。

你去看截图,发现光标落在了一个空白区域。

这不是模型看错了,是坐标算错了。

一、模型给的坐标是什么坐标系

先说清楚一件事:Computer Use 模型输出的坐标,通常是相对于它看到的那张截图的。

比如截图是 1280×800,模型说"按钮在 (400, 300)",指的是那张图里第 400 列、第 300 行的位置。

而你要点的是屏幕上的那个像素。

这两者之间有转换,而且不止一层。

二、DPI 缩放:最常见的偏差源

第一层是显示缩放。

Windows 默认在 125% 或 150% 缩放下运行。这意味着逻辑像素和物理像素不是 1:1。

截图工具通常按逻辑像素截取——截出来是 1280×800。但屏幕实际的物理分辨率是 1600×1000。

模型在 1280×800 的图上说 (400, 300),落到物理屏幕上就是 (500, 375)。

偏差 (100, 75)。

这一层最容易被忽略,因为在 100% 缩放的机器上开发时,一切正常。换一台 125% 的机器,全部错位。

三、窗口偏移和标题栏

第二层是窗口位置,第三层是标题栏。

浏览器窗口不一定在屏幕左上角。假设它在 (100, 50),那么页面内容整体要加这个偏移。

标题栏和地址栏还占着高度。Chrome 大概是 80 到 90 像素,加上书签栏更多。假设 60(无书签栏、紧凑模式),页面内容的起点在窗口往下 60 像素处。

Computer Use 点不中按钮:坐标映射的三个坑

图 1:每加一层,偏差跳一次;三层加起来,偏出 7 个按钮

把三层叠起来算:

def to_screen(px, py, win_origin, chrome_h, dpr):
    """px,py: 页面内坐标;win_origin: 窗口左上角;chrome_h: 标题栏高度"""
    sx = (win_origin[0] + px) * dpr
    sy = (win_origin[1] + chrome_h + py) * dpr
    return sx, sy

print(to_screen(400, 300, (100, 50), 60, 1.25))
# (625.0, 512.5)

模型说 (400, 300),实际要点的位置是 (625, 512)。

偏差 225 × 212 像素。

一个标准的按钮是 32×32。225 像素相当于偏出 7 个按钮的宽度——点到隔壁去了,或者点到空白。

四、三条坐标偏差怎么一起算

逐层看更清楚:

叠加到哪一层 屏幕坐标 累计偏差
只算页面坐标(400, 300)(0, 0)
+ DPI 1.25(500, 375)(100, 75)
+ 标题栏 60(500, 450)(100, 150)
+ 窗口 (100, 50)(625, 512)(225, 212)

注意第二行:DPI 缩放对 x 和 y 都乘了 1.25,但 y 还要额外加标题栏,所以 y 的偏差比 x 大。

这就是为什么很多 Agent 的点击是"右下偏"——不是随机偏,是有规律的偏。

五、修复代码

反向转换,从屏幕坐标还原页面坐标:

def to_page(sx, sy, win_origin, chrome_h, dpr):
    """把屏幕坐标还原成页面坐标"""
    px = sx / dpr - win_origin[0]
    py = sy / dpr - win_origin[1] - chrome_h
    return px, py

print(to_page(625, 512, (100, 50), 60, 1.25))
# (400.0, 300.0)

关键在于参数的顺序:屏幕坐标是先除 DPI 再减偏移,不能反过来。

如果按"先减再除"算:(625 - 100) / 1.25 = 420,错了 20 像素。

这个顺序错误很隐蔽,因为在偏移为 0 的时候两种算法结果一样。只有窗口不在左上角时才暴露。

六、坑清单

1. DPR 不是 1,也不是固定值。 它跟着系统缩放设置走,用户的机器可能是 100%、125%、150%、175%。别写死 1.25,运行时读 window.devicePixelRatio 或者 Win32 的 DPI 接口。

2. 标题栏高度会变。 全屏、无边框窗口、标签页在顶部还是侧边,都会影响这个值。稳妥做法是从窗口内容区的实际位置取,不要用常量。

3. 多显示器要算相对坐标。 副屏的左上角不是 (0,0),可能是 (-1920, 0)。所有坐标要基于"所在显示器的原点"来算。

4. 截图和点击要用同一套坐标基准。 如果截图按物理像素存(1600×1000),模型给的坐标就要按物理像素理解,不能再乘 DPR。混用会导致双重缩放。

5. 页面滚动是第四层。 我只算了三层。如果页面滚动了 500 像素,元素在页面内的位置不变,但在视口内的位置变了。截图反映的是视口,所以要加上滚动偏移。

七、边界

这篇算的是"窗口在桌面上的坐标转换",适用于桌面自动化。

浏览器内的自动化通常有更简单的路径——用 CDP(Chrome DevTools Protocol)能直接拿到元素的 DOM 坐标,不用算这些。

另外我用的 60 像素标题栏是估算值,实际依浏览器和设置而定。真实的偏差要先测一次,不能照搬我的数字。

无障碍树那篇给了另一条路:不靠坐标,靠元素的 ID 和角色定位。这条路绕开了所有坐标转换的问题,但要求软件支持无障碍接口。

通过率那篇讲的是怎么判断"做对了没",这篇讲的是"为什么点不中"。两个问题经常同时出现——点偏了,任务自然不通过。

结语

坐标这件事,说起来是小学数学,做起来到处是坑。

我的建议是:别自己算。 能用系统的坐标转换接口就用,能用元素定位就用元素定位。手算 DPI 加偏移,早晚会在某台机器上翻车。

如果非要算,记住一句话:顺序比公式重要。 先除还是先减,差一个数量级。

参考资料

目录导航
  • 一、模型给的坐标是什么坐标系
  • 二、DPI 缩放:最常见的偏差源
  • 三、窗口偏移和标题栏
  • 四、三条坐标偏差怎么一起算
  • 五、修复代码
  • 六、坑清单
  • 七、边界
  • 结语
    • 参考资料
  • 相关文章:

  • 从 rc-ada-* 反推发布计划:模型 ID 泄露了什么
  • Computer Use 的通过率怎么算:三层条件,一个判定器
  • 腾讯混元 Hy4:770B 参数、能操作电脑,权重即将开源
  • GGUF 文件头怎么读:24 个字节看出量化方式
  • 从乱码里逆出 XOR 密钥:256 次爆破的实战,和一条会骗人的捷径
  • C++ 游戏辅助进阶系列(四):速度预判与边界,给自瞄系列收个尾
  • C++ 游戏辅助进阶系列(三):写视角与骨骼瞄准,把自瞄真正打通
  • C++ 游戏辅助进阶系列(一):自瞄的数学地基,从两个坐标算出该转多少度
  • 发表评论

    ◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。