惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
A
About on SuperTechFans
IT之家
IT之家
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Blog — PlanetScale
Blog — PlanetScale
aimingoo的专栏
aimingoo的专栏
云风的 BLOG
云风的 BLOG
The GitHub Blog
The GitHub Blog
Vercel News
Vercel News
G
Google Developers Blog
J
Java Code Geeks
宝玉的分享
宝玉的分享
T
Tailwind CSS Blog
Cloudbric
Cloudbric
L
LINUX DO - 最新话题
MyScale Blog
MyScale Blog
H
Heimdal Security Blog
PCI Perspectives
PCI Perspectives
Attack and Defense Labs
Attack and Defense Labs
S
Security @ Cisco Blogs
Latest news
Latest news
I
Intezer
L
Lohrmann on Cybersecurity
C
CXSECURITY Database RSS Feed - CXSecurity.com
月光博客
月光博客
T
Threatpost
博客园 - 【当耐特】
S
Schneier on Security
P
Privacy International News Feed
G
GRAHAM CLULEY
T
Tenable Blog
AWS News Blog
AWS News Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
雷峰网
雷峰网
博客园 - Franky
Engineering at Meta
Engineering at Meta
美团技术团队
S
Secure Thoughts
T
Troy Hunt's Blog
Microsoft Security Blog
Microsoft Security Blog
SecWiki News
SecWiki News
V
Visual Studio Blog
人人都是产品经理
人人都是产品经理
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Cisco Talos Blog
Cisco Talos Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Martin Fowler
Martin Fowler
Webroot Blog
Webroot Blog
Google DeepMind News
Google DeepMind News
H
Hackread – Cybersecurity News, Data Breaches, AI and More

博客园 - 我才是银古

第16章:常见问题、排错与最佳实践 第15章:扩展生态、MCAD 与外部集成 第12章:实战案例:机械结构与 3D 打印零件 第14章:构建、测试、调试与贡献流程 第13章:OpenSCAD 源码架构与核心执行流程 第11章:预览、渲染、网格精度与性能优化 第09章:列表推导、递归与算法建模 第08章:参数化零件库与复用设计 第10章:导入导出、命令行与自动化 第06章:CSG 布尔建模方法 第07章:二维图形、拉伸、旋转与投影 第05章:基础几何、坐标系与变换 第04章:参数、变量、函数、模块与作用域 OpenSCAD 教程目录 第03章:OpenSCAD 语言基础 第02章:安装、环境配置与开发工作流 第01章:OpenSCAD 项目全景与学习路线 第02章:源码获取、编译与开发环境配置 第01章:OCCT项目全景与学习路线 第18章:二次开发实战与综合案例 第18章:综合实战案例 第17章:数据交换与协同 第16章:源码架构与二次开发 第15章:插件与自定义工作台开发 第14章:Python脚本宏与自动化 第13章:FEM仿真分析 第12章:CAM数控加工 第11章:SurfaceMesh与逆向工程 第10章:Draft二维绘图与BIM建筑 第09章:工程图TechDraw 第07章:参数化表达式与Spreadsheet 第08章:装配设计Assembly 第06章:Part工作台与几何内核 第05章:PartDesign实体特征建模 第04章:草图Sketcher约束建模 第02章:安装版本与工作环境配置 第03章:界面工作台与基础操作 第01章:项目全景与学习路线 第十二章:插件开发、研究功能与最佳实践 第十章:定时任务与自动化(Cron) 第七章:技能、记忆与自学习闭环 第八章:MCP 集成与上下文文件 第六章:工具系统与终端后端 第五章:模型供应商与配置体系 Hermes Agent 教程目录 第十一章:语音、视觉、浏览器与子代理协作 第四章:CLI/TUI 与会话管理 第十二章:学习路线、实战方案与最佳实践 第十一章:源码结构、开发调试与插件开发 第十章:自动化、远程访问、日志与排障 第九章:Control UI、节点、Canvas 与语音能力 第七章:工具、技能、插件与能力扩展 第八章:安全模型、访问控制与沙箱实践 第六章:Agent 工作区、会话与多智能体路由 第五章:多通道消息接入与聊天平台配置 第四章:配置体系、模型接入与认证管理 第三章:Gateway 架构、协议与运行机制 第二章:安装、环境准备与快速上手 第一章:OpenClaw 项目概览与核心定位 oh-my-openagent 教程目录 09-命令模型回退与配置参考 10-实战案例最佳实践与故障排除 05-工作模式-Ultrawork-Prometheus-Atlas 08-Hooks与MCP系统 06-Category与Skill系统 07-核心工具链 04-智能体全景详解 03-安装与环境配置 02-整体架构与多模型编排机制 01-项目简介与核心理念 01-项目概览与学习路线 02-安装部署与工具适配 03-Skill机制与using-superpowers 05-TDD系统化调试与完成前验证 04-需求澄清方案设计与计划编写 07-并行智能体子智能体与Git-Worktree 第六章:代码审查、反馈处理与分支收尾 08-中国特色Skills与本土团队落地 09-MCP构建工作流执行与自定义Skill 第23章:FreeCAD-Python-API Clipper2 C# 源码解读教程 第19章:PolyTree 多边形树结构 第20章:实际应用与最佳实践 第18章:Minkowski 和与差 第17章:RectClip 矩形裁剪优化 第16章:ClipperOffset 偏移类详解 第15章:填充规则详解 第14章:布尔运算执行流程 第13章:ClipperD 浮点裁剪类 第11章:OutRec 与 OutPt 输出结构 第9章:Active 活动边结构 第10章:Vertex 顶点与 LocalMinima 局部极小值 第12章:Clipper64 裁剪类详解 第7章:高精度运算与128位整数 第8章:ClipperBase 基类详解 第5章:枚举类型与常量定义 第6章:InternalClipper 内部工具类 第2章:核心数据结构 - Point64、PointD 第3章:路径与多边形表示 - Path64、PathD、Paths64、PathsD 第4章:矩形边界 - Rect64、RectD
第08章 - Bitmap 位图与图像查找
我才是银古 · 2026-06-24 · via 博客园 - 我才是银古

第08章 - Bitmap 位图与图像查找

“在屏幕上找到某张小图并定位它的坐标”,是桌面自动化中极其实用的能力:找到按钮、找到图标、找到游戏中的某个元素,然后移动鼠标点击它。RobotGo 通过配套的 bitmap 子库(vcaesar/bitmap)提供了基于位图的查找能力。本章讲解位图的打开、保存、查找与定位。

8.1 为什么需要位图查找

第 6 章我们用“像素颜色”来识别界面状态,但单个像素信息量太小、容易误判。位图查找则是用“一整张小图”作为特征,在更大的截图(或整个屏幕)中寻找它出现的位置。相比硬编码坐标,它的最大优势是位置无关:哪怕目标元素移动了位置,只要外观不变,就能被找到。

位图查找属于“精确匹配”——要求目标在屏幕上的外观与模板图基本一致(同样的缩放、同样的颜色)。如果需要更鲁棒的、容忍缩放和细微差异的匹配,则要用第 12 章的 OpenCV 方案。

8.2 引入 bitmap 子库

位图查找的核心函数在 bitmap 子库中,需要单独导入:

import (
    "github.com/go-vgo/robotgo"
    "github.com/vcaesar/bitmap"
)

并在 Linux 上确保已安装 libpng 开发库(见第 2 章),因为位图功能依赖它。

8.3 获取位图

位图可以来自截图,也可以从文件打开。

8.3.1 从截图获取

bit := robotgo.CaptureScreen(10, 20, 30, 40)
defer robotgo.FreeBitmap(bit) // C 位图需释放

8.3.2 从文件打开

bit := bitmap.Open("template.png")
defer robotgo.FreeBitmap(bit)

8.3.3 从 image.Image 转换

如果你手上是 image.Image,可以先转成位图:

img, _ := robotgo.CaptureImg()
bit := robotgo.ToCBitmap(robotgo.ImgToBitmap(img))

8.4 保存位图

bit := robotgo.CaptureScreen(10, 20, 30, 40)
defer robotgo.FreeBitmap(bit)

bitmap.Save(bit, "test.png")

也可以借助前一章的转换函数把位图转为 image.Image 再用 robotgo.Save 保存。

8.5 查找位图:Find 与 FindAll

bitmap 子库的核心是查找函数。

8.5.1 Find:查找第一个匹配位置

bitmap.Find 在屏幕(或指定的大图)中查找给定的小位图,返回它左上角的坐标:

bit := bitmap.Open("button.png")
defer robotgo.FreeBitmap(bit)

fx, fy := bitmap.Find(bit)
fmt.Println("找到位置:", fx, fy)

if fx >= 0 && fy >= 0 {
    robotgo.Move(fx, fy)
    robotgo.Click()
}

如果没找到,返回的坐标通常为 -1(请以实际返回值判断,对负值做“未找到”处理)。

8.5.2 FindAll:查找所有匹配位置

当目标图在屏幕上出现多次时,用 FindAll 获取所有匹配位置:

bit := bitmap.Open("icon.png")
defer robotgo.FreeBitmap(bit)

arr := bitmap.FindAll(bit)
fmt.Println("所有匹配位置:", arr)

8.6 完整示例

下面是官方位图示例的整理版,演示从截图获取位图、保存、转换与查找:

package main

import (
    "fmt"

    "github.com/go-vgo/robotgo"
    "github.com/vcaesar/bitmap"
)

func main() {
    // 截取屏幕的一小块作为位图
    bit := robotgo.CaptureScreen(10, 20, 30, 40)
    defer robotgo.FreeBitmap(bit) // 释放 C 位图

    fmt.Println("位图:", bit)

    // 转为 image.Image 并保存
    img := robotgo.ToImage(bit)
    robotgo.Save(img, "test_1.png")

    // image -> Bitmap -> CBitmap,然后查找
    bit2 := robotgo.ToCBitmap(robotgo.ImgToBitmap(img))
    fx, fy := bitmap.Find(bit2)
    fmt.Println("FindBitmap:", fx, fy)
    robotgo.Move(fx, fy)

    // 查找所有匹配
    arr := bitmap.FindAll(bit2)
    fmt.Println("FindAll:", arr)

    // 直接用截图位图查找
    fx, fy = bitmap.Find(bit)
    fmt.Println("FindBitmap:", fx, fy)

    bitmap.Save(bit, "test.png")
}

8.7 典型工作流:截取模板 → 查找 → 点击

位图查找在实践中通常遵循这样一个工作流:

  1. 准备模板图:先手动截取目标元素(按钮、图标)的小图,保存为 PNG,作为模板。
  2. 运行时查找:脚本运行时打开模板图,在当前屏幕中 Find 它的位置。
  3. 执行操作:找到后移动鼠标到该坐标并点击。
func clickByImage(template string) bool {
    bit := bitmap.Open(template)
    defer robotgo.FreeBitmap(bit)

    fx, fy := bitmap.Find(bit)
    if fx < 0 || fy < 0 {
        return false // 没找到
    }
    robotgo.Move(fx, fy)
    robotgo.MilliSleep(100)
    robotgo.Click()
    return true
}

配合轮询,可以实现“等待某个按钮出现再点击”的健壮逻辑:

func waitAndClick(template string, timeoutMs int) bool {
    elapsed := 0
    for elapsed < timeoutMs {
        if clickByImage(template) {
            return true
        }
        robotgo.MilliSleep(300)
        elapsed += 300
    }
    return false
}

8.8 位图查找 vs 像素颜色 vs OpenCV

RobotGo 生态里有三种“看屏幕找东西”的层次,适用场景各不相同:

方法 所在库 特点 适用场景
像素颜色 GetPixelColor robotgo 主库 最轻量,只看单点颜色 判断简单的开关/状态
位图查找 bitmap.Find bitmap 子库 精确匹配整张小图 外观固定的按钮/图标定位
OpenCV 匹配 gcv gcv 子库 模板匹配 + 特征匹配,容错强 有缩放/细微差异的复杂识别

选择原则:能用像素就用像素(最快),需要定位元素用位图查找,遇到位图查找不稳定(缩放、抗锯齿、半透明等)再升级到 OpenCV。

8.9 实战技巧与注意事项

  1. 模板要“干净”:截取模板图时尽量只包含目标元素本身,避免包含会变化的背景,否则匹配率会下降。
  2. 保持环境一致:位图查找是精确匹配,模板图必须与运行环境的分辨率、缩放、主题保持一致。换了缩放比例往往就匹配不到了。
  3. 判断未找到:始终检查返回坐标是否为负,不要拿着 -1 去 Move
  4. 释放内存:所有 CaptureScreen / bitmap.Open / ToCBitmap 得到的 C 位图都要 FreeBitmap
  5. 性能考量FindAllFind 慢;在大屏上全屏查找也较慢。尽量缩小查找范围(先截取目标可能出现的区域)。
  6. 优先 PNG 模板:用无损的 PNG 作为模板图,避免 JPEG 压缩引入的像素差异影响匹配。

8.10 小结

本章我们学习了基于 bitmap 子库的位图查找:如何从截图或文件获取位图、保存位图,以及用 Find / FindAll 在屏幕上定位目标小图的位置。我们梳理了“截模板→查找→点击”的典型工作流,并对比了像素颜色、位图查找、OpenCV 三种识别方式的取舍。下一章我们回到主库,讲解更基础但同样重要的剪贴板操作。