教程秉持"授人以鱼,也授人以渔"的核心理念 • 🐟 速食攻略: • 🎣 进阶学习:我会分享我的学习路径、踩坑复盘、思考过程和优质信源等。我们的目标不仅是解决问题,更是掌握学习的方法,共同进步。 • ❓ 遇到问题:善用AI和搜索引擎;文章末尾扫码加入技术交流群 • 项目链接:https://github.com/microsoft/OmniParser • 核心功能: 1. 可靠地识别用户界面中的可交互图标及坐标,它将生成带有边界框和数字 ID 叠加的解析截图图像,以及包含提取文本和图标描述的局部语义 2. 理解截图中各种元素的语义并准确地将预期动作与屏幕上的相应区域关联起来 • 技术栈:Python、FastAPI、内网穿透技术、机器视觉 • 效果预览: 本专题的目标是打造能够自主思考、学习与成长的AI系统,内容涵盖: 为了达成上述目标中的系统操控能力,我们需要使用OmniParser分析当前UI界面中的可交互元素,使得视觉大模型更加准确地理解当前界面中的交互行为,更好的规划下一步动作。 使用网上免费算力(此教程中以Google Colab为例)部署OmniParser,并通过内网穿透为本地电脑提供GUI解析服务。 • Google Colab: https://colab.research.google.com/drive/1_MwpieN-XMguMnpZrrqwiXpiyhFuwqrX?usp=sharing • Kaggle: https://www.kaggle.com/ • 其他:网上搜索免费算力 • 获取 ngrok api key: https://dashboard.ngrok.com/get-started/your-authtoken • pyngrok文档: https://pyngrok.readthedocs.io/en/latest/ • Google Colab 代码分享链接: • 步骤1:准备环境 将Colab代码中的YOUR_NGROK_API为你的ngrok api key • 步骤2:更改为使用GPU运行代码 • 步骤3:运行服务端代码 依次运行Colab中的代码,直到获取到Public URL • 步骤1:发送请求并获取结果 ⚠️需要根据实际情况修改为从服务端中获取到的Public URL • 核心架构: 1. Omniparser 类: 主要解析类,负责初始化模型和处理图像 2. 目标检测模型: 使用 YOLO 模型进行界面元素的检测 3. 文本识别 (OCR): 使用 EasyOCR 或 PaddleOCR 进行文本识别 4. 图像描述生成: 使用预训练的图像描述模型(如 BLIP2 或 Florence2)为图标生成描述 • 工作流程:OmniParser 的工作流程如下(在源码上添加了注释,方便理解): 1. 初始化: 2. 图像解析: • 接收 base64 编码的图像 • 将图像解码为 PIL 图像对象 • 调整绘制边界框的配置参数 3. 文本识别: • 使用 OCR 模型识别图像中的文本 • 获取文本内容及其边界框位置 4. 界面元素检测: • 使用 YOLO 模型检测图像中的界面元素 • 获取元素的边界框坐标 5. 重叠处理: • 处理文本框和图标框之间的重叠 • 根据 IoU (交并比) 阈值过滤重叠的边界框 • 优先保留文本框,或者将重叠的文本内容合并到图标描述中 6. 图标描述生成: • 对于检测到的图标,裁剪相应区域 • 使用图像描述模型为每个图标生成描述文本 7. 结果整合: • 将所有识别的元素(文本和图标)整合到一个列表中 • 为每个元素添加类型、位置、交互性和内容信息 • 生成带有标注的图像 • 如何学习项目源码: 1. 将项目克隆到本地:学会使用git和github 2. 下载一个AI IDE:推荐Trae、Cursor、windsurf等 3. 从整体到局部逐步理解代码: • 先阅读README文档,了解项目的整体架构和功能 • 查看依赖项(requirements.txt),了解项目使用的主要库 • 找到入口文件(如app.py或main.py),理解程序的启动流程 • 分析核心类(如Omniparser类)的结构和功能 4. 理解关键模块的实现: • 研究YOLO模型的集成方式和参数配置 • 学习OCR文本识别的实现细节 • 分析图像描述模型的使用方法 • 了解重叠处理算法的工作原理 5. 遇到难以理解的代码时利用AI辅助: • 使用AI IDE自带的AI功能对复杂代码段进行提问 • 请AI解释特定函数或算法的工作原理 • 让AI帮助分析代码中的数据流和逻辑关系 • 使用AI生成示例或简化版本以便更好理解 6. 实践与调试: • 搭建开发环境,安装必要的依赖 • 准备测试图像,运行示例代码 • 使用断点调试,观察数据流转过程 • 尝试修改参数,观察结果变化 7. 扩展与创新: • 尝试替换不同的模型(如更换YOLO版本或使用不同的图像描述模型) • 优化现有算法(如改进重叠处理算法) • 添加新功能(如支持更多类型的UI元素识别) • 提高性能(如优化批处理逻辑或添加缓存机制) 1. 计算机视觉基础: • Stanford CS231n: https://cs231n.stanford.edu/ 2. 目标检测技术: • YOLO官方文档和论文:https://pjreddie.com/darknet/yolo/ • Ultralytics 文档:https://docs.ultralytics.com/ 3. OCR技术: • EasyOCR文档:https://www.jaided.ai/easyocr/ • PaddleOCR文档:https://github.com/PaddlePaddle/PaddleOCR 4. 多模态模型: • BLIP2论文与代码:https://github.com/salesforce/LAVIS • Florence2模型介绍:https://arxiv.org/abs/2311.06242 5. Web服务开发: • FastAPI官方文档:https://fastapi.tiangolo.com/ • RESTful API设计最佳实践 • 1:下载一个AI IDE:推荐Trae、Cursor、windsurf等 • 2:在客户端代码中将图片坐标转换为相对于屏幕的坐标 • 3:修改源码以支持中文OCR,tips:PaddleOCR • 4:结合任意Agent框架实现简单的GUI Agent • 近期计划 (1-2月内) • 使用Qwen2.5-VL实现简单的GUI Agent • AI自动操作浏览器 • AI辅助数据建模、text2sql • RAG • 微信机器人 • 中期规划 (3-6月) • 如何利用AI快速学习 • ArlenTuring Agent开源项目 前言
时间有限?只需阅读[速食攻略],快速解决当前问题📋 OmniParser:基于纯视觉的 GUI 代理屏幕解析工具
项目介绍
🎯专题目标
核心领域 所需技术 🤖 AI Agent架构 自主决策、任务规划、目标分解 📚 RAG增强系统 知识库构建、语义检索、动态学习 👁️ 多模态交互 图文音视频理解、语音识别/合成 🔧 工具使用能力 工具发现、调用与创造 💻 AI RPA 系统操控、API对接、任务自动化 🧠 认知架构 元认知反思、自我改进、思维链路 🐟 速食攻略
前期准备
算力平台(任选一个)
内网穿透
服务端代码
https://colab.research.google.com/drive/1_MwpieN-XMguMnpZrrqwiXpiyhFuwqrX?usp=sharing
# ================= 配置区域 =================
class Config:
# Ngrok配置
NGROK_AUTH_TOKEN = "YOUR_NGROK_API" # 替换为你的Ngrok令牌
NGROK_REGION = "us" # 可选区域: us/eu/ap/au
# 服务器配置
PORT = 8000
# 模型配置
SOM_MODEL_PATH = "weights/icon_detect/model.pt"
CAPTION_MODEL_NAME = "florence2"
CAPTION_MODEL_PATH = "weights/icon_caption_florence"
# 处理参数
BOX_THRESHOLD = 0.05
IOU_THRESHOLD = 0.7
BATCH_SIZE = 128
# 文件限制
MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
# ================= 配置结束 =================本地客户端代码
import os
import requests
from PIL import Image
from typing import Optional
class APIClient:
def __init__(self, base_url: str = 'http://localhost:8000'):
self.base_url = base_url
self.session = requests.Session()
def validate_image(self, image_path: str) -> Optional[Image.Image]:
try:
img = Image.open(image_path)
if img.format not in ['JPEG', 'PNG']:
print(f"错误:不支持的图像格式 {img.format},仅支持JPEG/PNG")
return None
return img.convert('RGB')
except Exception as e:
print(f"图像验证失败:{str(e)}")
return None
def predict(self, image_path: str) -> dict:
"""
执行预测请求
:param image_path: 待分析图像的本地路径
:return: 解析结果字典
"""
try:
with open(image_path, 'rb') as f:
files = {'file': (os.path.basename(image_path), f, 'image/jpeg')}
response = self.session.post(
f"{self.base_url}/predict",
files=files,
timeout=300
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"请求失败:{str(e)}")
return {}
def format_result(self, result: dict) -> str:
"""格式化显示解析结果"""
if not result or result.get('status') != 200:
return "请求失败或未获取到有效结果"
output = []
if parsed := result.get('parsed_content'):
output.append("✅ 解析内容:")
output.append(parsed) # parsed_content已经是格式化的字符串
if labels := result.get('label_coordinates'):
output.append("\n📍 标签坐标:")
for label, coords in labels.items():
output.append(f" - {label}: {coords}")
# 保存标记后的图片
if labeled_image := result.get('labeled_image'):
import base64
try:
img_data = base64.b64decode(labeled_image)
with open('labeled_image.jpg', 'wb') as f:
f.write(img_data)
output.append("\n💾 标记后的图片已保存为 labeled_image.jpg")
except Exception as e:
output.append(f"\n❌ 保存标记图片失败:{str(e)}")
return '\n'.join(output) if output else "未获取到有效结果"
if __name__ == "__main__":
# 待分析图像的本地路径,可以自己改成 自动获取当前桌面截屏
image_path = r"你的图像路径"
# 将url设置为服务端中获取到的Public URL
url = "https://af00-34-19-24-97.ngrok-free.app" # 这里只是示例,需要根据实际情况修改为服务端中获取到的Public URL
client = APIClient(url)
if img := client.validate_image(image_path):
print(f"🖼️ 正在分析图像:{os.path.basename(image_path)} ({img.size[0]}x{img.size[1]})")
result = client.predict(image_path)
print("\n" + client.format_result(result))🎬 成果展示
🎣 进阶学习
💡 技术原理解析
OmniParser 的核心架构由以下几个主要组件构成: from util.utils import get_som_labeled_img, get_caption_model_processor, get_yolo_model, check_ocr_box
import torch
from PIL import Image
import io
import base64
from typing import Dict
class Omniparser(object):
def __init__(self, config: Dict):
"""
初始化Omniparser对象
参数:
config: 包含模型路径和参数的配置字典
"""
self.config = config
# 检测是否有GPU可用,选择合适的设备
device = 'cuda' if torch.cuda.is_available() else 'cpu'
# 加载YOLO模型用于界面元素检测
self.som_model = get_yolo_model(model_path=config['som_model_path'])
# 加载图像描述模型用于生成图标描述
# model_name可以是'blip2'或'florence2'等
# model_name_or_path是模型的本地路径或Hugging Face模型ID
self.caption_model_processor = get_caption_model_processor(
model_name=config['caption_model_name'],
model_name_or_path=config['caption_model_path'],
device=device
)
print('Omniparser initialized!!!')
def parse(self, image_base64: str):
"""
解析base64编码的图像,识别界面元素
参数:
image_base64: base64编码的图像字符串
返回:
dino_labled_img: 带标注的图像(base64编码)
parsed_content_list: 解析出的界面元素列表
"""
# 解码base64图像
image_bytes = base64.b64decode(image_base64)
image = Image.open(io.BytesIO(image_bytes))
print('image size:', image.size)
# 根据图像大小计算边界框绘制参数的比例
# 3200是基准大小,较大的图像会有更粗的线条和更大的文本
box_overlay_ratio = max(image.size) / 3200
draw_bbox_config = {
'text_scale': 0.8 * box_overlay_ratio, # 文本大小
'text_thickness': max(int(2 * box_overlay_ratio), 1), # 文本粗细
'text_padding': max(int(3 * box_overlay_ratio), 1), # 文本内边距
'thickness': max(int(3 * box_overlay_ratio), 1), # 边界框线条粗细
}
# 使用OCR识别图像中的文本
# display_img=False: 不显示识别结果
# output_bb_format='xyxy': 输出格式为[x1,y1,x2,y2]
# text_threshold=0.8: OCR置信度阈值
(text, ocr_bbox), _ = check_ocr_box(
image,
display_img=False,
output_bb_format='xyxy',
easyocr_args={'text_threshold': 0.8},
use_paddleocr=False # 使用EasyOCR而非PaddleOCR
)
# 使用YOLO模型检测界面元素并生成描述
# BOX_TRESHOLD: 目标检测置信度阈值
# output_coord_in_ratio=True: 输出坐标为相对比例而非像素值
# ocr_bbox: OCR识别的文本框位置
# caption_model_processor: 图像描述模型
# ocr_text: OCR识别的文本内容
# use_local_semantics=True: 使用局部语义分析
# iou_threshold=0.7: 重叠框过滤的IoU阈值
# batch_size=128: 批处理大小,影响图标描述生成的效率
dino_labled_img, label_coordinates, parsed_content_list = get_som_labeled_img(
image,
self.som_model,
BOX_TRESHOLD = self.config['BOX_TRESHOLD'],
output_coord_in_ratio=True,
ocr_bbox=ocr_bbox,
draw_bbox_config=draw_bbox_config,
caption_model_processor=self.caption_model_processor,
ocr_text=text,
use_local_semantics=True,
iou_threshold=0.7,
scale_img=False,
batch_size=128
)
# 返回带标注的图像和解析出的界面元素列表
return dino_labled_img, parsed_content_listdef parse(self, image_base64: str):
image_bytes = base64.b64decode(image_base64)
image = Image.open(io.BytesIO(image_bytes))
box_overlay_ratio = max(image.size) / 3200
draw_bbox_config = {
'text_scale': 0.8 * box_overlay_ratio,
'text_thickness': max(int(2 * box_overlay_ratio), 1),
# ...
}(text, ocr_bbox), _ = check_ocr_box(
image,
display_img=False,
output_bb_format='xyxy',
easyocr_args={'text_threshold': 0.8},
use_paddleocr=False)def predict_yolo(model, image, box_threshold, imgsz, scale_img, iou_threshold=0.7):
result = model.predict(
source=image,
conf=box_threshold,
iou=iou_threshold
)
boxes = result[0].boxes.xyxy # 返回xyxy格式的边界框def remove_overlap_new(boxes, iou_threshold, ocr_bbox=None):
# 处理重叠的文本框和图标框
for box1_elem in boxes:
# 检查与其他框的重叠
if ocr_bbox:
# 当OCR文本框在图标内部时
if is_inside(box3, box1):
ocr_labels += box3_elem['content'] + ' '
filtered_boxes.remove(box3_elem)
# 当图标在OCR文本框内部时
elif is_inside(box1, box3):
box_added = True
breakdef get_parsed_content_icon(filtered_boxes, starting_idx, image_source, caption_model_processor, prompt=None, batch_size=128):
# 裁剪图标区域
for coord in non_ocr_boxes:
xmin, xmax = int(coord[0]*image_source.shape[1]), int(coord[2]*image_source.shape[1])
ymin, ymax = int(coord[1]*image_source.shape[0]), int(coord[3]*image_source.shape[0])
cropped_image = image_source[ymin:ymax, xmin:xmax, :]
croped_pil_image.append(to_pil(cropped_image))
# 生成图标描述
inputs = processor(images=batch, text=[prompt]*len(batch), return_tensors="pt")
generated_ids = model.generate(**inputs, max_length=100)
generated_text = processor.batch_decode(generated_ids, skip_special_tokens=True)# 整合结果
filtered_boxes_elem = sorted(filtered_boxes, key=lambda x: x['content'] is None)
# 生成带标注的图像
annotated_frame, label_coordinates = annotate(
image_source=image_source,
boxes=filtered_boxes,
logits=logits,
phrases=phrases,
**draw_bbox_config)
# 编码结果图像
pil_img = Image.fromarray(annotated_frame)
buffered = io.BytesIO()
pil_img.save(buffered, format="PNG")
encoded_image = base64.b64encode(buffered.getvalue()).decode('ascii')📚 学习方法论
📚 推荐阅读
🔄 互动与反馈
📋 小作业
📅 更新计划
📱 联系方式
个人微信
技术交流群
👆 扫码加入,一起探讨AI Agent开发
自定义模型:
{文章来源和文章摘要}
文章来源: ArlenTuring 公众号
文章摘要: 文章介绍了如何零成本部署 OmniParser 实现 Computer Use,并附带了使用内网穿透白嫖算力的教程。文章分为速食攻略和进阶学习两部分,旨在帮助读者快速解决问题并掌握学习方法。内容涵盖了模型初始化、目标检测、文本识别、图像描述生成等技术细节,并提供了详细的工作流程和代码示例。
======
{文章总结}
文章详细讲解了如何利用 OmniParser 实现计算机界面解析,并通过内网穿透技术实现低成本算力利用。主要内容包括:
======
{对文章的看法}
这篇文章内容详实,既有快速的解决方案,也有深入的技术探讨,适合不同层次的读者。通过内网穿透技术实现算力白嫖的思路非常实用,能够显著降低开发成本。文章结构清晰,代码示例丰富,便于读者实践。不过,对于初学者来说,部分技术细节可能较为复杂,建议在进阶学习部分增加更多基础知识的补充,以帮助更多人理解。整体而言,这是一篇非常有价值的技术分享文章。
微信扫一扫
关注该公众号