给 AI 精准的点击坐标。 视觉模型看界面会偏 30~40 像素,OCR 与模板匹配能落到那个像素上。 纯 CPU · 无 GPU · 不调云 API · 零 token 消耗 · 没有视觉模型也能用
Pixel-precise screen coordinates for AI agents. Let the vision model understand the interface; let OCR and template matching deliver the exact click point.
现在几乎所有"AI 操作电脑"的方案都走同一条路:截屏 → 丢给视觉大模型 → 模型给出坐标 → 点击。 这条路有一个被普遍低估的硬伤:视觉大模型给出的坐标是不准的。
本项目的实测(2560×1440 屏,目标是一个文本输入框):
| 方式 | 给出的坐标 | 结果 |
|---|---|---|
| 视觉模型目测 | (1125, 1154) | 落在输入框上方的消息区 —— 失败 |
| OCR 像素级 bbox | (802, 1196) | 精确命中 |
误差约 30~40 逻辑像素,大于输入框本身的行高。
这不是模型不够聪明,而是结构性的:主流多模态模型会把输入图压到很粗的 patch 网格 (例如 14px patch、3:1 下采样、单图上限数百 token)。一张 1280×900 的截图进入模型时, 有效分辨率已经低到无法给出像素级坐标。
所以本项目的核心主张是:
让大模型干它擅长的(这是什么界面、该点哪一个), 让本地算法干它擅长的(那个东西精确在哪个像素)。 两件事分开做,各自达到最好,再用一条链路串起来。
| 工具 / Tool | 作用(中文) | What it does (English) |
|---|---|---|
vlocate |
混合定位(招牌):模板/锚点为主力,VLM 只做最后兜底;返回像素级可点击坐标 + 置信度分级(high/medium/low) | Hybrid locator (flagship): template/anchor first, VLM only as a last resort. Returns a pixel-precise click point with a confidence grade. |
findtext |
OCR 找字定位:给一个词,返回它在屏幕上的像素级 bbox;自带内容缓存与守护进程(提速约 35 倍) | OCR text locator: give it a word, get its pixel bbox on screen. Ships with a content cache and an optional daemon (~35× faster). |
tmatch |
模板匹配:定位无文字元素(图标、图形、按钮图形),输出像素框 + 相似度分;零 GPU(有 CUDA 自动加速,无卡自动降级) | Template matching: locate non-text elements (icons, graphics) with a pixel box and a similarity score. Zero GPU (CUDA auto-accelerates when present). |
guibot |
声明式 GUI 流程:把"找元素 → 点击 → 键入 → 断言"写成 JSON,一次跑完可复用 | Declarative GUI flows: write locate → click → type → assert steps as JSON and replay them. |
winctl |
窗口控制:列表 / 置顶 / 移动窗口,以及免激活后台截图(不抢用户焦点) | Window control: list / raise / move windows and capture them in the background without stealing focus. |
headless_check |
无头验收:渲染页面 → 截图 → OCR 核对文字,并自证全程没有抢用户焦点 | Headless acceptance: render → screenshot → verify text via OCR, and prove the foreground window never changed. |
六个工具共用一套约定:JSON 输出、统一退出码(0=成功 / 1=无结果或警告 / 2=用法错误),
坐标一律为屏幕物理像素。
vlocate 把下面这些路径按"从便宜到昂贵"依次尝试,前面命中就不往下走:
| 路径 | 命令 | 置信度 | 实测耗时 | 消耗 token |
|---|---|---|---|---|
| 区域 + 模板 | --region x0,y0,x1,y1 --template 图标.png |
high | 4 ms | 0 |
| 锚点 + 模板 | --anchor "设置" --template 齿轮.png |
high | 模板 23ms + OCR 2.2s | 0 |
| 锚点 + 几何偏移 | --anchor "密码" --offset 1,0 |
medium | ~2.2 s | 0 |
| 候选清单 | --list-all |
— | ~2.2 s | 0 |
| VLM 兜底 | --target "那个红色的提交按钮" |
low | 5~7 s | 消耗 |
VLM 的输出永远不会被直接当作点击坐标——它只负责把搜索范围从全屏缩小到一小块。
| 模式 | 耗时 | 相对基线 |
|---|---|---|
冷进程 + 强制真 OCR(--no-cache) |
7082 ms | 1× |
| 冷进程 + 内容缓存命中 | ~600 ms | 12× |
| 守护进程(引擎常驻)+ 缓存命中 | 175~225 ms | ~35× |
| 引擎已加载,全屏推理 | 2280 ms | 3× |
| 区域 800×600 推理 | 1280 ms | 5.5× |
| tmatch 窗口匹配(绕开 OCR) | 4 ms | ~1770× |
| vlocate 区域+模板 端到端 | 4 ms | — |
三条硬结论:
- OCR 有约 1.2 秒的物理下限——即使只识别 800×600 区域、只有 5 个文字块,也要 1280ms。 这是模型前向的固定开销,靠调参无法到毫秒级。
- 单项最大收益是守护进程(
findtext.py --serve):把"进程启动 + 导入 + 引擎初始化 + 预热" 全部归零,7 秒 → 0.6 秒。 - 毫秒级只能靠绕开 OCR:常态定位 = 坐标记忆(1ms)+ tmatch 验证(4ms)。 所以正确做法是让 OCR 尽量只出现一次,其结果沉淀为模板与记忆。
上图由 python docs/make_demo.py 生成——图里的每个坐标都是工具真实输出的,不是画上去的。
下载有三种方式(压缩包由 GitHub 自动生成,不需要作者上传):
| 方式 | 操作 / 地址 | 适合 |
|---|---|---|
| 下载 ZIP | 仓库页绿色 Code 按钮 → Download ZIP |
不想装 git,最省事 |
| git clone | git clone https://github.com/lyjlcbhtq/pixel-locator.git |
想跟着更新 |
| 固定版本 | https://github.com/lyjlcbhtq/pixel-locator/archive/refs/tags/v1.0.0.zip |
要可复现的版本 |
装好之后,一键安装脚本会做完剩下的事:
install.bat :: Windows —— 双击运行即可bash install.sh # Linux / macOS脚本做四件事:检查 Python → 安装依赖 → 环境自检 → 冒烟测试。 (依赖里含 OCR 模型,首次安装需要能访问 pypi.org)
前提:Python 3.10 或更高。Windows 安装时务必勾选 "Add Python to PATH"。
git clone https://github.com/lyjlcbhtq/pixel-locator.git
cd pixel-locator
pip install -r requirements.txt
# 1. 环境自检(应全部 ok)
python toolkit.py doctor
# 2. 冒烟测试(应 10/10)
python smoke.py
# 3. OCR 找字:拿到像素级坐标
python toolkit.py findtext --image fixtures/sample.png --query "像素级定位"
# 4. 模板匹配:定位无文字元素
python toolkit.py tmatch find fixtures/template.png fixtures/sample.png
# 5. 混合定位(推荐):锚点 + 模板,双证命中
python toolkit.py vlocate --image fixtures/sample.png \
--anchor "工具包冒烟测试" --template fixtures/template.png --window 1200
# 6. 完全不知道叫什么?列出候选,让上层 AI 自己挑
python toolkit.py vlocate --image fixtures/sample.png --list-all想直接看能跑的东西:
python examples/01_locate_text.py # OCR 找字,拿到像素级坐标
python examples/02_hybrid_locate.py # 锚点 + 模板双证定位(推荐用法)
python examples/03_python_api.py # 内嵌调用,列出屏幕上的文字块与坐标
python tools/guibot.py examples/04_flow.json --check # 校验声明式流程
python benchmarks/bench_ocr.py # 复现 OCR 速度数据
python benchmarks/bench_tmatch.py # 复现「全屏 vs 锚点窗口」速度差paths.json 是可选配置:不创建也能跑(自动回退 paths.example.json)。
需要时 cp paths.example.json paths.json 再改。
A. 点一个带文字的按钮(零模型,最快)
python tools/vlocate.py --text "发送" --clickB. 点一个图标(无文字,用模板)
python tools/tmatch.py collect --from 截图.png --region 640,300,726,386 --name 齿轮
python tools/vlocate.py --anchor "设置" --template 模板/齿轮.png --clickC. 把一串操作写成流程
{
"steps": [
{"action": "find", "text": "用户名", "save_as": "u"},
{"action": "type", "text": "alice"},
{"action": "find", "text": "密码"},
{"action": "type", "text": "s3cret"},
{"action": "find", "text": "登录", "click": true},
{"action": "assert_text", "text": "欢迎"}
]
}python tools/guibot.py 流程.json --dry # 先演练,不真的点
python tools/guibot.py 流程.json # 真跑D. 无人值守验收一个页面(不抢焦点)
python tools/headless_check.py 页面.html --out shot.png --expect "提交成功"这一节全是踩过的坑,照抄能省下大量调试时间。
- 所有工具输出的都是屏幕物理像素(DPI 100% 时两者相同)
- DPI 150% 时:逻辑坐标 = 物理坐标 / 1.5
- 点击总是偏移固定比例?先查 DPI 缩放
- 实测事故:把物理坐标按截图缩放比例又换算一次,结果点到了别处
- VLM 坐标误差可达几十像素,足以错过输入框、按钮等小目标
- 实测事故:VLM 圈出的区域
[63,69,405,151]甚至没罩住真实目标(真值y=51~117,顶部少圈 18px) - 正确用法:VLM 只用来缩小范围,最终坐标必须来自 OCR 或 tmatch
- OCR 会认错字(形近字、连字),也会把同名多处全部返回
- 页面里有三个"设置"时,OCR 无法告诉你是哪一个
- 正确做法:OCR 出锚点/候选 → 用 tmatch 匹配确认 → 两者一致才算命中
- 本项目的
vlocate已把纯 OCR 路径标记为confidence: low并附warning
findtext默认开启 md5 内容缓存:同一画面(像素级一致)直接复用上次结果- 还有模糊指纹缓存:同一区域差异很小时也会命中——用于动态屏(时钟、光标、流式文本)
- 屏幕已变但结果没变?加
--no-cache - 缓存是速度主要来源之一(12 倍),不要随手永久关掉
findtext.py --serve在127.0.0.1:8377常驻,CLI 自动复用(35 倍提速就来自这里)- 不想用:加
--no-daemon,或改--port - 用完记得停,否则一直占端口
- 屏幕截屏路径:
use_cls=False(屏幕文字无需方向分类,更快) --image图片路径:use_cls=True(图片可能带旋转,更稳但更慢)- 追求速度且确定图不旋转时用
--cls��式控制
winctl --top/--restore会激活窗口并抢走用户焦点- 需要"不打扰用户"时用
--background(免激活后台截图)或--list headless_check全程无窗口,验收类任务首选
- 实测踩坑:一个纯红色块模板匹配到了画面左上角的空白处,相似度却是满分 1.0。 原因是纯色块在灰度图上无方差,归一化相关会退化
vlocate已内置预检(灰度 std < 8 时返回template_quality.warning)- 正确做法:模板必须带边缘/纹理,用
tmatch collect从真实截图裁剪 - 另外默认
--threshold 0.8,降到 0.5 以下会大量误匹配
- 它靠 OCR 读截图文字,受字体渲染、抗锯齿、缩放的轻微影响
- 需要严格断言时请用专门的 DOM 工具
- 它的独特价值是返回
foreground{before,during,after,unchanged},自证全程没抢用户焦点
平台支持是分层的,请按这张表判断(python check_platform.py 可静态自检,
CI 也会在 Ubuntu 上真实执行一次):
| 工具 | Windows | Linux / macOS | 说明 |
|---|---|---|---|
tmatch |
可用 | 可用 | 纯模板匹配,完全跨平台 |
vlocate |
可用 | 可用(只定位) | --click 需要 Windows |
findtext |
可用 | 可用(--image 路径) |
实时截屏需 mss + 图形界面;窗口/点击需 Windows |
guibot |
可用 | 可用(只读动作) | find / wait / assert / screenshot 跨平台;click / type / key 需 Windows |
winctl |
可用 | 不支持 | Win32 窗口 API,仅 Windows |
headless_check |
可用 | 不支持 | 依赖 Edge / Chrome 路径与前台窗口 API |
- 非 Windows 平台上,需要键鼠注入的动作会抛出明确的中文错误,而不是静默失败或崩溃
- 本项目曾因
findtext.py顶层写import ctypes.wintypes导致 CI 全红,check_platform.py就是为杜绝这类问题加入的 - 安全提醒:本工具集能模拟键鼠。请勿在无人看管的敏感界面上放任自动点击;
写流程时先用
--dry演练
- 零 GPU 硬需求:全部 CPU 即可。
tmatch检测到 CUDA 会自动加速,无卡自动降级 CPU,结果一致 (本机实测 OpenCV 为 CPU 构建版,相似度仍为 1.0,窗口匹配 4ms) - 零模型训练:OCR 用 RapidOCR 自带 ONNX 模型,首次运行本地加载,无需联网下载
- 零外部服务:不需要代理、不需要任何云 API
- 可选:任意 OpenAI 兼容视觉端点(供
vlocate第 3 层兜底),不配也能完整使用
python >= 3.10
pillow / numpy / opencv-python / rapidocr-onnxruntime / requests / mss
pixel-locator/
├── toolkit.py 统一入口(list / doctor / paths / <工具>)
├── smoke.py 冒烟测试(自带素材,克隆即可跑;--ci 供 CI 使用)
├── check_platform.py 跨平台导入自检(防止 Windows 专有导入混入)
├── install.bat / install.sh 一键安装(检查 Python → 装依赖 → 自检 → 冒烟)
├── make_fixtures.py 重新生成测试素材
├── paths.example.json 配置模板(全部字段可空,不创建也能跑)
├── requirements.txt
├── README.md / README.en.md
├── CHANGELOG.md
├── LICENSE MIT
├── .github/workflows/ GitHub Actions 冒烟 CI
├── tools/
│ ├── vlocate.py 混合定位(招牌)
│ ├── findtext.py OCR 定位(缓存 + 守护进程)
│ ├── tmatch.py 模板匹配
│ ├── guibot.py GUI 流程编排
│ ├── winctl.py 窗口控制
│ └── headless_check.py 无头验收
├── examples/ 四个可直接运行的示例
├── benchmarks/ 两个基准脚本(复现 README 里的全部数字)
├── docs/ 演示图 + 可复现的生成脚本
└── fixtures/ 冒烟测试素材
- OCR 的 1.2 秒下限:单次推理无法更低,这是模型前向的固定开销,不是实现问题
- VLM 只能兜底:视觉模型坐标精度不足以直接点击,本项目只把它当"侦察兵"
- 模板匹配需要模板:无文字元素第一次需人工给一次模板(或
tmatch collect采一次),之后才能自动 - 动态界面:画面剧烈变化时缓存失效,会退回真实 OCR 耗时
- Windows 偏向:窗口相关能力依赖 Win32,跨平台需要替换这一层(接口已隔离)
- 不做 UIA/Accessibility:本项目走纯像素路线,这是刻意选择——为了覆盖 UIA 抓不到的自绘界面、游戏、Canvas 应用
MIT License,见 LICENSE。
English documentation: see README.en.md