news 2026/8/30 2:14:10

macOS原生OCR:用Vision框架快速实现屏幕文字识别提取

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
macOS原生OCR:用Vision框架快速实现屏幕文字识别提取

在 macOS 上做 OCR,最容易想到的方案有两种:把图片上传到云端识别接口,或者在本地安装 Tesseract。而这个发布在 Hacker News Show HN 板块的项目给出了第三种做法:完全依赖 macOS 自带的原生 OCR 能力,把屏幕上看到的一段文字原样复现成可编辑文本,也就是项目名 Monkey see, monkey do 表达的意思——看到什么,就把什么复刻出来。这个思路的吸引力在于:不依赖网络,不把截图送出设备,不需要额外安装识别引擎,而且可以直接通过系统能力抓取任意窗口内容。

实际开发中,这种“看到但不能复制”的场景非常多,比如只读文档、视频字幕、老旧软件面板、禁止复制网页。与其手打,不如用一个几十行的 Swift 脚本完成从屏幕抓图到文字输出的完整链路。下面从 Vision 框架的核心概念讲起,逐步实现一个可运行的 macOS 屏幕 OCR 工具,并覆盖权限、精度、性能和扩展方向。跑通后,你会得到两个命令行工具:一个输入图片路径输出文本,另一个输入窗口编号输出该窗口内的文本。

1. 为什么说 macOS 原生 OCR 是常被忽略的现成能力

1.1 这个项目要解决的场景:可见但不可选

Monkey see, monkey do 这类工具的核心使用场景很明确:屏幕上明明显示着一行文字,但系统不让你选中、复制,或者根本没有对应的文本层。最常见的场景有几类:

  • 只读 PDF 和扫描文档,文字以图片形式存在,无法直接拷贝。
  • 视频里的字幕、会议录屏上的提示信息,想记录却只能暂停截图。
  • 老旧企业软件界面,文案写死在资源里,既不能复制也没有文本导出。
  • 网页开发者故意禁用文本选择,或者内容本身是图片验证码、图表。

这些场景如果手动重打一遍,效率低还容易出错。OCR 工具的作用就是让“眼睛看到的”直接变成“剪贴板里的”。项目名里的 monkey see,指截获屏幕内容;monkey do,指把识别出的文本交还给用户使用。所以这不是一个复杂的识别算法项目,而是一个典型的系统能力集成项目。

1.2 原生 OCR 的技术基础:Vision 框架

macOS 从 10.15 开始,在系统自带的 Vision 框架中加入了基于深度学习的文本识别能力,核心 API 是VNRecognizeTextRequest。OCR 的全称是 Optical Character Recognition,即光学字符识别,目标是从图像中提取可编辑的字符序列。Vision 的实现运行在设备本地,识别过程不需要联网,识别结果按文字行返回,每一行包含对应的文本框坐标和候选字符串。

到 macOS 13 之后,Vision 的文本识别准确率进一步提升,新的识别 revision 对中文、英文混排、表格数字都有更好的处理。从开发者角度看,macOS 的“实况文本”功能本质上也是基于这一套识别能力构建的。也就是说,系统已经内置了高质量 OCR 引擎,开发者的工作不是重新发明识别算法,而是把系统能力接入自己的业务场景。

这里有一个容易误解的地方:原生 OCR 不等于“随便拿一张模糊图片就能完美识别”。它擅长的是常见界面文本、截图、文档扫描件;对于复杂背景、艺术字体、低分辨率图片,仍然需要配合裁剪、放大和参数调整。

1.3 它和 Tesseract、云 OCR 的差异

选择 OCR 方案时,不能只看准确率一个维度。下面这张表可以帮助判断什么时候该用原生 Vision:

维度Vision 原生 OCRTesseract云 OCR
网络依赖需要联网
图片是否离开设备不会不会会上传
中文/多语言支持系统内置,按系统版本支持需要手动下载语言包一般支持较全
安装成本系统自带,无需安装需要 brew 或源码编译需要 SDK 和密钥
调用成本无按量费用通常按次计费
集成方式Swift/ObjC APIC/C++/Python/RESTHTTP API
适合场景macOS 工具、快捷脚本、隐私敏感场景跨平台离线批处理高精度多语种、复杂图像

选择原生 OCR 的最大理由不是“准确率一定最高”,而是集成成本最低、隐私边界最清晰。云 OCR 在复杂图像上准确率通常更高,但每次调用都要把截图传出去;对于这种抓取本地屏幕文字的小工具,隐私问题往往比精度更致命。Tesseract 的优点是跨平台,但中文识别需要额外语言包,且对 UI 字号较小的截图效果通常不如系统方案。

2. 理解 Vision 的识别链路,才知道参数该调哪里

2.1 一次识别请求的处理流程

Vision 的文本识别链路可以拆成四步:

  1. 准备图像。把图片文件转成CGImage,或者直接使用屏幕抓取的CGImage
  2. 创建请求。创建VNRecognizeTextRequest实例,设置识别精度、语言等参数。
  3. 交给处理器。用VNImageRequestHandler(cgImage:options:)承载图片,调用perform([request])
  4. 取回结果。从request.results拿到VNRecognizedTextObservation数组,每个观察对象对应一行文字。

用代码表达就是下面几行:

let request = VNRecognizeTextRequest() let handler = VNImageRequestHandler(cgImage: image, options: [:]) try handler.perform([request]) for case let observation as VNRecognizedTextObservation in request.results ?? [] { if let candidate = observation.topCandidates(1).first { print(candidate.string) } }

这个链路和 Core ML 的用法很像:handler 负责读图,request 负责描述任务,perform 负责执行。理解这一点后,后续所有参数调整都围绕 request 进行,抓图逻辑和识别逻辑可以完全分离。这也是为什么先写图片版脚本、再接入屏幕抓图是更合理的开发顺序。

2.2 请求参数与结果对象速查

VNRecognizeTextRequest的常用参数如下:

参数默认值作用
recognitionLevel.accurate识别精度,可选.fast.accurate
usesLanguageCorrectiontrue是否用语言模型修正拼写
recognitionLanguages空数组识别语言列表,空则按系统语言推断
minimumTextHeight0.0低于该高度比例的文字会被忽略
regionOfInterest全图只识别图像中的指定区域

结果对象VNRecognizedTextObservation包含两个重要成员:

  • boundingBox:识别文字行在图像中的位置,使用归一化坐标。
  • topCandidates(_:):按置信度排序的候选字符串数组。

实际项目中几乎只用topCandidates(1).first?.string取出最可能的字符串。少数场景会用前三个候选做纠错或人工确认,但普通抓字工具不需要。

2.3 坐标系统是最大的认知坑

boundingBox使用 Vision 归一化坐标系:原点 (0,0) 在图像左下角,(1,1) 在右上角。而 macOS 在 Core Graphics 里的常用显示坐标是原点在左上角。如果不做转换,直接把boundingBox画到图片上,会发现识别框整体上下颠倒。

转换公式很简单:

let normalized = observation.boundingBox let topLeftX = normalized.origin.x let topLeftY = 1.0 - normalized.origin.y - normalized.height

如果只是输出纯文本、不画框,这个坐标问题可以暂时忽略。但只要你想在截图上用红框标出识别到的文字,这一步就绕不开。另外,输出顺序也需要靠坐标排序,这一点在后文单独展开。

3. 从屏幕到文本:搭建最小抓字工具

3.1 环境准备:版本和工程形态

先确认本机环境,否则会在识别阶段无谓踩兼容性问题:

依赖最低要求建议
macOS10.15 以上13 以上,中文识别效果更好
Xcode Command Line Tools已安装保持最新
屏幕录制权限抓取其他 App 窗口时需要在系统设置中授权

可以用下面的代码查询当前系统支持的识别语言列表和可用 revision:

import Vision let supported = try VNRecognizeTextRequest.supportedRecognitionLanguages( for: .accurate, revision: VNRecognizeTextRequestRevision3 ) print(supported)

VNRecognizeTextRequestRevision3需要 macOS 13 及以上。低版本系统要把revision参数换成系统默认版本,或者直接调用不带 revision 参数的版本。如果原始项目没有给出明确版本要求,落地前要先确认自己系统的实际支持情况。

注意:swift直接运行脚本时,第一次会先编译,耗时比执行编译好的二进制慢不少,这是正常现象。

3.2 先写一个图片 OCR 脚本

为了让问题边界清晰,先实现输入图片、输出文本的最小脚本ocr.swift

#!/usr/bin/env swift import Foundation import AppKit import Vision guard CommandLine.arguments.count > 1 else { print("用法: swift ocr.swift <图片路径>") exit(1) } let path = CommandLine.arguments[1] guard let image = NSImage(contentsOfFile: path) else { print("无法读取图片: \(path)") exit(1) } var rect = NSRect(origin: .zero, size: image.size) guard let cgImage = image.cgImage(forProposedRect: &rect, context: nil, hints: nil) else { print("无法转换为 CGImage") exit(1) } let request = VNRecognizeTextRequest() request.recognitionLevel = .accurate request.recognitionLanguages = ["zh-Hans", "en-US"] request.usesLanguageCorrection = true let handler = VNImageRequestHandler(cgImage: cgImage, options: [:]) try handler.perform([request]) var lines: [String] = [] for case let observation as VNRecognizedTextObservation in request.results ?? [] { if let candidate = observation.topCandidates(1).first { lines.append(candidate.string) } } print(lines.joined(separator: "\n"))

这个脚本有几个关键点:

  • NSImage加载图片后再转CGImage,兼容常见图片格式;也可以直接用CGImageSource读取,更贴近底层但代码更长。
  • recognitionLanguages显式设置了["zh-Hans", "en-US"],避免系统语言环境不同导致的识别差异。
  • 输出顺序直接使用request.results的返回顺序,严格场景需要按坐标排序。

3.3 接入屏幕抓图:真正实现“看到什么复刻什么”

上面的脚本只解决了“图片到文字”,真正的 monkey see 还需要拿到屏幕内容。最简单的方式是用系统自带的screencapture命令:

screencapture -x -o /tmp/screen.png swift ocr.swift /tmp/screen.png

-x表示不播放抓图声音,-o表示不包含鼠标指针。这样可以得到全屏截图,再交给 OCR 脚本。如果想只抓一个区域,可以用-R x,y,w,h

screencapture -x -o -R 200,200,1000,600 /tmp/region.png

这种方式优点是零代码接入,缺点是每次都要落盘一次图片,而且无法精确指定某个窗口。如果要做成 Mac App,或者想对一个窗口

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/30 2:11:38

不会写代码也能全栈上线?用 Codex 做出 AI 剧本杀的完整拆解

最近看到有人在讨论&#xff1a;“不会写代码&#xff0c;我靠 Codex 做出一款 AI 剧本杀&#xff0c;前后端全程 AI 并自动发布上线。”说实话&#xff0c;第一次看到这类标题时&#xff0c;我的第一反应不是怀疑&#xff0c;而是想知道中间到底经历了什么。因为“不会写代码”…

作者头像 李华
网站建设 2026/8/30 2:11:27

用Python实现影视预告评论情感分析与可视化实战

最近《米尔扎布尔》&#xff08;Mirzapur&#xff09;电影版正式预告发布的消息&#xff0c;让很多追剧人瞬间来了精神。作为印度 Amazon Prime Video 上最具辨识度的犯罪剧集之一&#xff0c;这部剧凭借硬核的暴力美学、家族权力斗争和密集的剧情反转&#xff0c;积累了大量忠…

作者头像 李华
网站建设 2026/8/30 2:11:10

零基础AI编程入门:Claude Code与Codex实战指南

如果你最近刷技术社区&#xff0c;一定绕不开这几个词&#xff1a;AI 编程、Vibe Coding、Claude Code、Codex、Superpowers。很多人一开始是懵的——这些工具到底有什么区别&#xff1f;我完全没写过代码&#xff0c;能靠 AI 写项目吗&#xff1f;所谓 Vibe Coding 是不是就是…

作者头像 李华
网站建设 2026/8/30 2:10:40

Python爬虫入门实战:18个案例掌握HTTP请求、数据解析与存储

大家好&#xff0c;我是你们的技术博主。今天这篇文章想和大家聊一聊 Python 爬虫入门实战。网上关于 Python 爬虫的教程非常多&#xff0c;但大多只讲爬虫库的用法&#xff0c;或者直接丢出几个大网站的抓取案例就不管了&#xff0c;新手照着写&#xff0c;没过几天就被反爬机…

作者头像 李华
网站建设 2026/8/30 2:07:15

技术博客选题边界:为什么社会新闻不能写成CSDN教程

很抱歉&#xff0c;我无法基于这个标题生成 CSDN 技术博客正文。这个标题是一则社会新闻报道&#xff0c;内容涉及执法事件&#xff0c;既不是技术项目、开源工具&#xff0c;也不是框架集成、开发实战或编程经验分享&#xff0c;不属于 CSDN 技术博客的选题范围。按照内容边界…

作者头像 李华
网站建设 2026/8/30 2:06:52

AI芯片竞争背后:GPU、CUDA与大模型算力生态解析

最近大模型行业又有一则消息引发了不少讨论&#xff1a;OpenAI 被曝正在推进首款自研 AI 芯片&#xff0c;据称整个项目从启动到流片仅用了约 9 个月&#xff0c;并采用 3nm 制程。而英伟达创始人黄仁勋随后公开回应&#xff0c;核心观点是英伟达提供的是“截然不同”的服务。很…

作者头像 李华