跳到主要内容

第 3 章 · 视觉定位:把"点登录"变成屏幕坐标

这是全框架工程含量最高的一章。模型看图后只会说"点那个登录按钮",可 pyautogui 需要的是精确的 (x, y)。这中间的翻译层——visual grounding(视觉定位)——决定了 SOC 到底点不点得准。


3.1 它要解决的小问题

模型的输出是语义的("登录按钮"、"搜索框"),而鼠标要的是几何的(第 312 像素、第 88 像素)。谁来把"登录"翻成 (312, 88)? 这就是定位要解决的核心矛盾。

为什么难: 模型直接报坐标往往很不准(它不擅长精确读像素);所以 SOC 大多数模式不信任模型报的坐标,而是让模型只说"点哪个东西",由框架用传统 CV 手段去找那个东西在哪。


3.2 三条定位路线

SOC 提供三种互补的定位法,对应三套系统 prompt(见 02-models-and-prompts.md):

路线模型输出什么框架怎么找坐标代表模式
OCR"text": "登录"EasyOCR 读全屏文字,找匹配的那块,取包围盒中心默认(gpt-4-with-ocr)
Set-of-Mark"label": "~7"YOLO 先检测所有按钮、画上红框+编号,模型点编号,框架查编号对应的框gpt-4-with-som
直接百分比"x": "0.10", "y": "0.13"信模型报的坐标,直接用gpt-4(标准)

三者殊途同归: 最后都得到一个 0~1 的 {x, y} 百分比,交给 click_at_percentage(见 01-control-loop.md)乘屏幕分辨率点下去。用百分比而非绝对像素,是为了跨分辨率无关


3.3 路线一:OCR 文字定位(默认)

这是项目默认模式(README 说 OCR 实测比 SoM 和裸 GPT-4 都好)。思路:模型说点"登录"两个字,那我就在屏幕上用 OCR 找到"登录"这块文字,点它的中心。

图示

模型: click text="登录"


EasyOCR.readtext(截图) ──► [(框1,"用户名"), (框2,"登录"), (框3,"注册") ...]
│ 每个元素 = (四点包围盒, 识别文字, 置信度)

get_text_element:遍历找 "登录" in text ──► 命中 index=1


get_text_coordinates:取框2四角 → 算中心 → 除以图宽高 ──► {x:0.42, y:0.31}

真实实现

call_gpt_4o_with_ocr 的 click 分支(apis.py:368-406):每遇到一个 click 动作,新建 easyocr.Reader(["en"]),readtext 整张截图,再调两个工具函数。

找哪一块文字 —— get_text_element(operate/utils/ocr.py:10):

# ocr.py:37-45(简化:线性扫 OCR 结果,子串匹配)
for index, element in enumerate(result):
text = element[1] # 识别出的文字
if search_text in text: # 子串包含即命中
found_index = index

注意是子串匹配(search_text in text),而且循环不 break——取最后一个命中。找不到就抛异常,由外层 except 触发回退(见 02 章)。

算坐标 —— get_text_coordinates(operate/utils/ocr.py:66):取包围盒四角的 min/max 算中心,再除以图片宽高转成百分比(ocr.py:84-98):

center_x = (min_x + max_x) / 2
center_y = (min_y + max_y) / 2
percent_x = round((center_x / width), 3)
percent_y = round((center_y / height), 3)
return {"x": percent_x, "y": percent_y}

Claude 的一个小 trick

call_claude_3_with_ocr 找文字时只用前 3 个字符去匹配(apis.py:991-993,text_to_click[:3]),注释说"限制提取文字能提高成功率"——因为 OCR 对长串识别容易出偏差,短前缀更容易命中。


3.4 路线二:Set-of-Mark(YOLO 框标注)

思路:让模型报坐标不靠谱,那就反过来——我先把屏幕上所有按钮框出来、编上号,模型只需要说"点 7 号框"。 这就是学术界的 Set-of-Mark Prompting(README 引了 arXiv 2310.11441)。

图示

截图 ──► YOLO(best.pt) 检测按钮 ──► 一堆包围盒


add_labels:给每个非重叠框画红框 + 写 "~0" "~1" ...

┌─────────────────────────┴──────────────┐
▼ ▼
带标号的图发给模型 label_coordinates = {"~0":框, "~7":框...}
│ │
▼ │
模型: click label="~7" ──────────────────────────► 查 ~7 → 取框中心 → 百分比

真实实现

加载随包发布的 YOLO 权重 best.pt(apis.py:653-654,pkg_resources 取包内文件),跑检测。核心在 add_labels(operate/utils/label.py:55):

  • 遍历 YOLO 检出的每个框,跳过与已画框重叠的(is_overlapping,label.py:40),避免标号糊成一团。
  • 给保留的框画红框、写 ~N 标签,同时把 label → (x1,y1,x2,y2) 存进 label_coordinates(label.py:99-114)。
  • 返回"带标注的图 base64" + 坐标字典。

模型回 label="~7" 后,get_label_coordinates(label.py:29)查字典拿到框,get_click_position_in_percent(label.py:141)算中心转百分比:

# label.py:153-158
x_center = (coordinates[0] + coordinates[2]) / 2
y_center = (coordinates[1] + coordinates[3]) / 2
x_percent = x_center / image_size[0]
y_percent = y_center / image_size[1]

可换权重: README 明说 best.pt 是个简单训练的 YOLOv8,鼓励用户换成自己更强的模型。


3.5 路线三:直接百分比

最朴素:系统 prompt(SYSTEM_PROMPT_STANDARD,prompts.py:11)直接要求模型输出 "x": "0.10", "y": "0.13",框架原样相信。用于 gpt-4(标准)、gemini-pro-visionllava

代价: 模型报坐标本就不准,这条路的点击命中率最差——正是它促成了 OCR / SoM 两条更可靠路线的出现。


3.6 巧妙之处小结

  • 不信模型的坐标,信模型的"意图"。 OCR 和 SoM 都把"精确定位"从模型手里夺走,交给确定性的 CV,这是 computer-use 定位的关键洞察。
  • 一切归一到百分比。 三条路殊途同归到 0~1 坐标,click_at_percentage 只需处理一种输入,分辨率无关。
  • 重叠框去重(is_overlapping)。 小细节,但决定了 SoM 标号图可不可读。
  • 短前缀匹配(Claude 的 [:3])。 一行代码换来更高的 OCR 命中率。

3.7 边界与局限

  • OCR 只配了英文: easyocr.Reader(["en"]) 硬编码(如 apis.py:377),非英文界面基本失效。
  • 子串 + 取最后命中: get_text_element 若屏幕上有多处相同文字,取的是最后一个,可能点错。
  • 每次 click 重建 Reader: EasyOCR 每次 click 都 easyocr.Reader(["en"]) 重新初始化(如 apis.py:377),很慢。
  • SoM 依赖一个弱 YOLO: best.pt 是简单模型,漏检/误检直接导致点空。
  • 找不到就整轮回退: OCR 抛异常会把整轮甩给 gpt-4o 回退,而非局部重试。

3.8 横向对比

定位(grounding)是所有 computer-use agent 的共同命门,兄弟项目的取舍:

项目定位手段
SOC(本项目)OCR / YOLO-SoM / 直接百分比,全是外挂的传统 CV
agent-s(docs/agent-s/02-grounding-aci.md)独立的视觉定位模型(UI-TARS),把"描述→坐标"交给专门训练的模型
ui-tars-desktop(docs/ui-tars-desktop/index.md)端到端 GUI 模型,定位内建进模型,无需外部 OCR
cua(docs/cua/03-composed-grounded.md)组合式定位,可插拔多种 grounder

趋势很清楚: SOC 用外挂 OCR/YOLO 是 2023 年的做法;后来者把定位内化进专用模型,更准更快。但 SOC 的三路对照,恰好是理解"为什么需要专用定位模型"最好的反面教材。


3.9 代码地图

主题文件符号
OCR 找文字operate/utils/ocr.pyget_text_element
OCR 算坐标operate/utils/ocr.pyget_text_coordinates
OCR click 分支operate/models/apis.pycall_gpt_4o_with_ocr(click 分支)
Claude 短前缀匹配operate/models/apis.pycall_claude_3_with_ocrtext_to_click[:3]
YOLO 画框标号operate/utils/label.pyadd_labelsis_overlapping
查标号坐标operate/utils/label.pyget_label_coordinatesget_click_position_in_percent
SoM click 分支operate/models/apis.pycall_gpt_4o_labeled
百分比→像素点击operate/utils/operating_system.pyclick_at_percentage