固定按钮、固定图标一类目标,我平时仍然更愿意用 FindText,部署轻、维护也直接。可一旦图片里的目标会缩放、换位置、同时出现多个,或者需要区分人、车辆、动物等类别,模板匹配就不太合适了,这时才轮到 YOLO 目标检测。

这套 Yolo_v1 资源是给 AutoHotkey v1 使用的本地目标检测封装,底层由 yolo.dll 调用 ONNX Runtime 和 OpenCV。当前下载目录配的是 yolov5s.onnx、COCO 类别和一张测试图片,默认走 CPU 推理,不需要联网,也不会把图片上传到在线识别服务。站内已经有 v2 的 Yolo4、5、X 示例,本篇整理的是 v1 可直接调用的版本。

 

它和找图有什么不同

FindText、ImageSearch 解决的是“在画面中找到这张已知图”,YOLO 解决的是“画面里有哪些属于某个类别的目标”。同一辆车换了大小、角度或背景,普通模板可能需要准备多张素材,训练好的目标检测模型则会直接返回类别、置信度和位置框。

它也不是 OCR。YOLO 可以找到车、人物、按钮区域或自己训练过的业务对象,但要读取框里的文字,仍然需要再接 RapidOcr 或其他 OCR 流程。

 

检测结果能拿来做什么

  • 一次找出图片中的多个目标,而不是只返回一个坐标;
  • 取得 x1、y1、x2、y2,计算中心点后继续点击或截取区域;
  • 通过 score 过滤置信度较低的结果;
  • 读取 label 和 label_text,按类别执行不同自动化动作;
  • 把检测框写入 CSV、叠加到图片,或交给后续 OCR 处理;
  • 除图片路径外,也能继续接二进制图片、BitmapBuffer 和 cv::Mat 指针。

 

主要调用流程

先调用 Yolo.init() 加载运行库,再用 new Yolo() 指定模型类型、ONNX 模型、标签文本、线程数和推理模式。当前 yolov5s.onnx 对应类型参数“5”。创建检测器后,detect() 会返回一个对象数组,每个对象包含坐标、类别、类别文字、置信度和标志字段。

detect() 中最常调的是 score_threshold、iou_threshold 和 topk。score_threshold 控制最低置信度;iou_threshold 用于非极大值抑制,减少同一目标的重叠框;topk 限制候选数量。阈值过低会留下大量误检,过高又可能漏掉小目标,新手先从示例的 0.25 和 0.45 开始。

 

64 位和依赖要求

当前打包目录只支持 64 位 AutoHotkey,必须使用 AutoHotkeyU64.exe。Lib 目录中的 yolo.dll 是 64 位,外层目录还要保留 onnxruntime.dll、opencv_world455.dll 和模型文件,不能只拿走 yolo_v1.ahk 单独运行。

封装会以自身所在位置为基准寻找 DLL,并在 yolo.dll 同级或上一级目录加载 ONNX Runtime 与 OpenCV,因此不依赖当前工作目录。默认 CPU 模式的 inferencemode 为 0;CUDA 和 TensorRT 虽然保留了模式入口,但需要额外准备匹配版本的显卡运行环境,本下载包没有把这些大型依赖一并打进去。

 

模型和类别必须对应

模型能识别什么,不是由 AHK 代码临时决定的,而是由 ONNX 模型训练时的类别决定。当前示例使用 COCO 80 类标签;更换自己的模型时,标签顺序也必须一起更换,否则框的位置可能正确,显示的类别名称却会错位。

这里还有一个实际边界:通用 yolov5s 适合验证流程,不代表它对所有业务画面都足够准确。检测特别小的目标、非常规界面元素或行业专用物体,通常需要更合适的模型、输入尺寸甚至重新训练。

 

下载包里的展示示例

素材中另附“Yolo_v1_展示示例+报告.ahk”,运行后会生成 HTML 检测报告和 CSV 明细,并在原图上叠加检测框。那份示例包含较长的 HTML 和 JavaScript,文章里不整段展开,避免前台安全过滤破坏代码;下载包中的原文件是完整版本。

下面放的是完整基础 demo,先验证 64 位运行环境、DLL、模型和图片是否能正常工作。它不会修改系统设置,只读取 car.jpg,并在消息框中列出类别、分数和坐标。

 

本文移植自 thqby 的 ahk2_lib,由本站适配为 AutoHotkey v1 版本,原作者及项目版权归其所有。
源项目地址:https://github.com/thqby/ahk2_lib

 

打包库和示例的下载地址:

 

demo代码片段展示:

#Requires AutoHotkey v1.1
#NoEnv
#SingleInstance Force
SetBatchLines, -1
SetWorkingDir, %A_ScriptDir%
#Include <yolo_v1>

if (A_PtrSize != 8)
{
    MsgBox, 16, Yolo_v1, 请使用 AutoHotkeyU64.exe 运行本示例。
    ExitApp
}

modelPath := A_ScriptDir "\yolov5s.onnx"
imagePath := A_ScriptDir "\car.jpg"
detector := ""
errorMsg := ""

try
{
    Yolo.init()
    labels := YoloDemo_CocoLabels()
    detector := new Yolo("5", modelPath, labels, 4, 0, 0, 0)
    boxes := detector.detect(imagePath, 0, 0.25, 0.45, 100, 2)

    result := "检测数量:" (boxes.MaxIndex() ? boxes.MaxIndex() : 0) "`n`n"
    for index, box in boxes
    {
        result .= index ". " box.label_text
        result .= " | score=" Round(box.score, 4)
        result .= " | (" Round(box.x1) ", " Round(box.y1) ")"
        result .= " - (" Round(box.x2) ", " Round(box.y2) ")`n"
    }
    MsgBox, 64, Yolo_v1 检测结果, %result%
}
catch e
{
    errorMsg := "检测失败:`n" e.Message
}

detector := ""
try
{
    Yolo.Free()
}
catch e2
{
}

if (errorMsg != "")
    MsgBox, 16, Yolo_v1, %errorMsg%
ExitApp

YoloDemo_CocoLabels()
{
    return "person`nbicycle`ncar`nmotorcycle`nairplane`nbus`ntrain`ntruck`nboat`ntraffic light`nfire hydrant`nstop sign`nparking meter`nbench`nbird`ncat`ndog`nhorse`nsheep`ncow`nelephant`nbear`nzebra`ngiraffe`nbackpack`numbrella`nhandbag`ntie`nsuitcase`nfrisbee`nskis`nsnowboard`nsports ball`nkite`nbaseball bat`nbaseball glove`nskateboard`nsurfboard`ntennis racket`nbottle`nwine glass`ncup`nfork`nknife`nspoon`nbowl`nbanana`napple`nsandwich`norange`nbroccoli`ncarrot`nhot dog`npizza`ndonut`ncake`nchair`ncouch`npotted plant`nbed`ndining table`ntoilet`ntv`nlaptop`nmouse`nremote`nkeyboard`ncell phone`nmicrowave`noven`ntoaster`nsink`nrefrigerator`nbook`nclock`nvase`nscissors`nteddy bear`nhair drier`ntoothbrush"
}
声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。