Swift如何使用Vision来识别获取图片中的文字(OCR),通过SwiftUI视图和终端命令行,以及一系列注意事项

news2025/1/9 2:27:12

在过去的一年里,我发现苹果系统中的“文字搜图片”功能非常好用,这个功能不光 iPhone/iPad,Mac 也有,找一些图片真的很好用。但是遇到了一个问题:这个功能需要一段时间才能找到新的图片,而且没法手动刷新,这对于外接硬盘里的图片来说不方便。所以就想自己能不能写一个类似的程序来查找一些图片。

这个程序的功能还挺好实现的:就是通过图片中的文字或者物体进行查找,而这两个功能苹果都替我们做好了,我们可以做到苹果演示的文本识别和相册识别所能达到的效果。不过本文只讲述如何使用 Vision 识别图片中的文字,因为识别图像和本文类似,存放这些数据到数据库中我也写过如何使用 Core Data 的博客:SwiftUI——Core Data数据库的使用(在纯SwiftUI生命周期中)。

本文较长,建议通过侧边栏跳转阅读。

简单介绍 Vision

首先简单介绍一下 Vision:

Vision 是一个计算机视觉算法的架构,可以对图像和视频执行多种任务。支持 iOS 11/iPad OS 11/macOS 10.13/tvOS 11 或更新系统。支持 ISO 语言代码中的所有语言。
需要注意由于汉字的复杂性,自定义单词(customWords)功能和语言矫正功能对于中文不可用。

需要注意 Vision 是包含在这些系统中的,而不是程序里,所以编译出来的程序本身并不会很大,并且结果精度和系统版本挂钩,后续会有演示。但很可惜的是对于中文手写的识别不太好,精度不是很好,但是对于英文的识别还是不错的。

比如这样的一张手写英文+汉字的图像:
请添加图片描述

在最新的 iPad OS 16 中识别出来为:

请添加图片描述

中文识别精度可见非常不行。

测试图片

测试图片是一张系统截图,不使用手写图的原因上面你也看到了,中文识别很难说达到了可用的程度。

请添加图片描述

将其命名为info,放在一个你喜欢的位置和放在 Assets 中,方便后续使用,如下:

请添加图片描述

不同平台的代码实现

接下来将会介绍如何在 iOS/iPad OS 和 macOS 上识别获取图像中的文本,将会分为两部分来说。(按需求来说不应该有 iOS/iPad OS,但是想都试试看,万一用的到呢)

分为两部分是因为在 iOS/iPad OS 系统上,使用的图像格式为UIImage,而 macOS 中使用的是NSImage,不过二者只有一小部分不一样。

这里的NS前缀表示“NeXTSTEP”,这是当年乔布斯回到苹果带回来的成果。

iOS/iPad OS

这里使用 SwiftUI 来进行布局。

首先导入框架和库:

import SwiftUI
import Vision

然后新建一个视图,内容如下(为了阅读和复制代码的体验,在注释中解释代码的含义):

struct ContentView: View {
    //这个字符串数组是为了存放获取的文本
    @State var textStrings = [String]()
    //这个name用来指定使用哪个图像,如果想用其他图像修改这个变量就行
    @State var name = "info"
    
    var body: some View {
        VStack {
            Image(uiImage: UIImage(named: name)!)
            //这个循环是显示获取的文本
            ForEach(textStrings, id: \.self) { testString in
                Text(testString)
            }
        }
        .padding()
        //这样一打开App就自动识别了
        .onAppear(perform: {
            //生成执行需求的CGImage,也就是对这个图片进行OCR文本识别
            guard let cgImage = UIImage(named: name)?.cgImage else { return }

            //创建一个新的图像请求处理器
            let requestHandler = VNImageRequestHandler(cgImage: cgImage)

            //创建一个新的识别文本请求
            let request = VNRecognizeTextRequest(completionHandler: handleDetectedText)
            //使用accurate模式识别,不推荐使用fast模式,因为这是采用传统OCR的,精度太差了
            request.recognitionLevel = .accurate
            //设置偏向语言,不加的话会全按照英文和数字识别
    		//中文一起能识别的其他文字只有英文
   		 	//繁体中文为zh-Hant,其他语言码请见https://www.loc.gov/standards/iso639-2/php/English_list.php
            request.recognitionLanguages = ["zh-Hans"]

            do {
                //执行文本识别的请求
                try requestHandler.perform([request])
            } catch {
                print("Unable to perform the requests: \(error).")
            }
        })
    }
    //这个函数用来处理获取的文本
    func handleDetectedText(request: VNRequest?, error: Error?) {
        if let error = error {
            print("ERROR: \(error)")
            return
        }
        //results就是获取的结果
        guard let results = request?.results, results.count > 0 else {
            print("No text found")
            return
        }
        
		//通过循环将results的结果放到textStrings数组中
		//你可以在这里进行一些处理,比如说创建一个数据结构来获取获取文本区域的位置和大小,或者一些其他的功能。!!!通过observation的属性就可以获取这些信息!!!
        for result in results {
            if let observation = result as? VNRecognizedTextObservation {
            	//topCandidates(1)表示在候选结果里选择第一个,最多有十个,你也可以在这里进行一些处理
                for text in observation.topCandidates(1) {
                	//将results的结果放到textStrings数组中
                    let string = text.string
                    textStrings.append(string)
                }
            }
        }
    }
}

这时候运行就能看到结果了:

请添加图片描述

可以看到除了最开始的“展开”符号被识别成v之外,几乎没有识别错误。

macOS

接下来先介绍一下如何在 macOS 上实现这个功能。

首先新建一个空白文本文件ocr.swift,然后输入以下内容:

import SwiftUI
import Vision
import Foundation

func handleDetectedText(request: VNRequest?, error: Error?) {
    if let error = error {
        print("ERROR: \(error)")
        return
    }
    guard let results = request?.results, results.count > 0 else {
        print("No text found")
        return
    }

    //通过循环将results的结果全部打印
    //你可以在这里进行一些处理,比如说创建一个数据结构来获取获取文本区域的位置和大小,或者一些其他的功能。!!!通过observation的属性就可以获取这些信息!!!
    for result in results {
        if let observation = result as? VNRecognizedTextObservation {
            //topCandidates(1)表示在候选结果里选择第一个,最多有十个,你也可以在这里进行一些处理
            for text in observation.topCandidates(1) {
                //打印识别的文本字符串
                let string = text.string
                print(string)
            }
        }
    }
}

func ocrImage(path: String) {
    let cgImage = NSImage(byReferencingFile: path)?.ciImage()?.cgImage

    //创建一个新的图像请求处理器
    let requestHandler = VNImageRequestHandler(cgImage: cgImage!)
    //创建一个新的识别文本请求
    let request = VNRecognizeTextRequest(completionHandler: handleDetectedText)
    //使用accurate模式识别,不推荐使用fast模式,因为这是采用传统OCR的,精度太差了
    request.recognitionLevel = .accurate
    //设置偏向语言,不加的话会全按照英文和数字识别
    //中文一起能识别的其他文字只有英文
    //繁体中文为zh-Hant,其他语言码请见https://www.loc.gov/standards/iso639-2/php/English_list.php
    request.recognitionLanguages = ["zh-Hans"]

    do {
        //执行文本识别的请求
        try requestHandler.perform([request])
    } catch {
        print("Unable to perform the requests: \(error).")
    }
}

extension NSImage {
    //NSImage转CIImage
    func ciImage() -> CIImage? {
        guard let data = self.tiffRepresentation,
              let bitmap = NSBitmapImageRep(data: data) else {
            return nil
        }
        let ci = CIImage(bitmapImageRep: bitmap)
        return ci
    }
}

//执行函数,从命令行参数中获取图片的地址
ocrImage(path: CommandLine.arguments[1])

然后编译:

$ swiftc -o ocr ocr.swift

运行就可以看到这样的结果:

$ ./ocr ../info.png 
通用:
种类:宗卷
创建时间:1970年1月1日星期四 08:00
修改时间:1980年1月1日星期二 00:00
格式:EXFAT
容量:511.88 GB
可用:300.78GB
已使用:211,106,529,280字节 (磁盘上的
211.11 GB)

你可能会发现开头的v不见了,这是因为我使用的 macOS 是 12,而不是最新的,所以和 iOS 16 的结果不一样。

这个代码你还可以将其放到 Playground 中,可以看到每一步的状况。

建议你尝试用这个命令识别一些其他的图像,精度还是可以的。

识别对比和测试

上面是最理想的情况下测试,接下来进行一些不同设置或情形的识别结果对比,算是一种实验记录了。

新旧系统对比

macOS 12 对应的是 iOS 15。上文提到了macOS 12 和 iPadOS 16 的对比,这里记录一下手写文本的识别情况。

请添加图片描述

对于上面这张图来说,最新的 iPad OS 16 的结果为:

请添加图片描述

很完美。

而 macOS 12 的结果为:

$ ./ocr ../hand.jpeg 
这王-个不焙的决注
请坚持做下去,别放奔!

可以看到新系统虽然在文章开始的例子表现不是很好,但有时还是很精准的。

多语言测试

介绍 Vision 的时候提到中文只能搭配着英文使用,不能和其他语言套用,那么套用了会如何呢?

请添加图片描述

上图中是中文、英语、日语的“你好”,如果是在 macOS 12,无论是将识别语言设置成中文、日语或者不设置,都无法将日语识别成日语假名,而是将其识别成数字和英文字母或汉字。比如设置为jajpn

$ ./ocr ../5.png 
11$7
Hello
Zh-sla

但是在 iPadOS 16 上,如果设置为jajpn,那么三种语言都可以识别到(因为日语中也有汉字,所以这样其实不太对,但是应付可以):
请添加图片描述

但是如果设置为zh_Hans,那么日语部分根本不显示:
请添加图片描述

你可以用俄语ru也做一做测试,可以感觉到中文是被单独拎出来做的,不光不能搭配其他语言,其他语言也不能搭配中文。

倾斜测试

我很好奇文本倾斜还能识别出来吗?因为很多 CV 都是要找一个固定对象的,比如识别猫先定位猫胡子(水平的线)。那么 Vision 面对旋转过的文本还能识别出来吗?如果识别不出来,临界值大概是什么角度呢?

用下面这个图进行测试:

请添加图片描述

测试结果发现在旋转 25 到 30 度的时候,开始出现识别错误。当到达 45 度的时候基本上就不可用了。

这整个项目和后续更新我都放在 https://github.com/ZhongUncle/Swift-Vision-OCR.git,希望能帮到有需要的人~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1002943.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通信原理板块——信道的数学模型

微信公众号上线,搜索公众号小灰灰的FPGA,关注可获取相关源码,定期更新有关FPGA的项目以及开源项目源码,包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等 1、调制信道和编码信道 调制信道适…

学习笔记|回顾(1-12节课)|应用模块化的编程|分时复用|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(下)

文章目录 搜索功能寻址变量bdataTips:missing declaration specifiers错误的解决分时复用的简单应用 二、按键处理思路分析原有程序实现的功能:需求分析:定义功能码,功能定义为: key的取值示例 三、按键处理四、定时器利用time0实…

【数据库】Navicate运行数据区sql文件 1046 no database selected

文章目录 前言一、现象二、解决 前言 要通过Navicat导入数据库文件,但是不成功报错1046 no database selected 一、现象 选中已经建立的连接,右键运行sql文件,报错 二、解决 1、先在建立的localhost中右键建立和要导入数据库同名的数据…

ipad手写笔什么牌子好?apple pencil二代平替笔推荐

近年来,电容笔越来越受到大家的青睐,已然成为人们提高生产效率的数码产品之一。然而,市面上的电容笔大多质量都参差不齐,很多人也不知道哪个品牌的电容笔比较好。针对这个问题,我来给大家分享几款电容笔,都…

斐波那契堆——怎么发明一种非常聪明的数据结构——学习笔记

我是目录 0. 前言1. Fibonacci Heap介绍1.1 简单回顾堆和优先队列1.2 二项树1.3 二项堆 2. 那怎么推导出Fibonacci Heap?2.1 实现GetMin2.2 实现Insert2.3 实现ExtractMin2.4 实现DecreaseKey2.5 关键部分 3. 那么,和斐波那契数列有什么关系?…

【nvm版本】控制node版本

使用nvm切换node版本 nvm安装开始安装选择安装路径选择node安装位置点击完成即可测试是否安装成功查询可下载的node版本如果没有node版本,就安装一下镜像地址 nvm安装 nvm安装路径 开始安装 选择安装路径 选择node安装位置 点击完成即可 测试是否安装成功 cmd中…

UI库DHTMLX Suite v8.2发布全新表单组件,让Web表单实现高度可定制!

DHTMLX Suite v8.2日前已正式发布,此版本的核心是DHTMLX Form,这个小部件接收了4个备受期待的新控件,如Fieldset、Avatar、Toggle和ToggleGroup。官方技术团队还为Grid和TreeGrid小部件中的页眉/页脚工具提示提供了一系列新的配置选项等。 在…

Scrum敏捷开发流程及关键环节

​Scrum是一种敏捷开发流程,它旨在使软件开发更加高效和灵活。Scrum将软件开发过程分为多个短期、可重复的阶段,称为“Sprint”。每个Sprint通常为两周,旨在完成一部分开发任务。 在Scrum中,有一个明确的角色分工: 产…

一个好玩的浏览器插件

背景 最近抽空开发了一个有意思的浏览器插件。背景是我们在开发过程中有时需要做一些测试验证,需要修改请求头字段和响应头字段的内容,有时需要在页面做测试,反复请求同一个接口,并修改一些字段。 如果此时使用nginx做代理转发再…

HashMap、HashTable、CurrentHashMap对比

😜作 者:是江迪呀✒️本文关键词:Java、集合、Map、CurrentHashMap☀️每日 一言:坚持自己的风格,面对未知的一切! 一、HashMap、HashTable、CurrentHashMap对比 1.1 CurrentHashMap和HashMap…

9.多级缓存、JVM进程缓存、Lua语法

多级缓存 文章目录 多级缓存一、多级缓存介绍1.1 传统缓存的问题1.2 多级缓存方案 二、JVM进程缓存2.1 案例准备2.1.1 导入SQL2.1.2 导入item-service项目2.1.3 导入商品查询页面 2.2 初始 Caffeine2.2.1 基本用法 2.3 实现进程缓存 三、Lua语法3.1 初识Lua3.2 变量和循环3.2.1…

这篇文章是用AI大模型自动生成的

昨天用豆包AI大模型尝试生成了一段关于:企业转型、企业转型的要点、企业转型成功的标志,这样的文字。我又加了点自己的思考。 (1)企业转型的原因 企业转型的原因有很多,以下是一些常见的原因: 1. 市场变化&…

针对电子企业的WMS仓储管理系统解决方案

随着全球电子行业的快速发展,电子企业对于仓储管理的需求和挑战也日益增长。WMS仓储管理系统作为电子企业的核心管理工具,需要满足高效率、低成本、高灵活性以及精确控制库存等需求。本文将为电子企业提供一种针对WMS仓储管理系统的解决方案。 一、WMS仓…

Eclipse使用SFTP方式远程连接

安装插件 首先需要安装远程系统连接插件,安装方式可参考: Eclipse安装FTP连接工具_哭哭啼的博客-CSDN博客在过滤器字段中,键入"remote".选择Mobile and Device Development,并选择。找到Remote System Explorer->Connection。…

Outlook邮箱如何设置自动回复

很多小伙伴在刚开始使用Outlook邮箱的时候,不是很清楚Outlook邮箱如何设置自动回复,这里小编就给大家详细介绍一下Outlook邮箱设置自动回复的方法,有需要的小伙伴可以来看一看。 Outlook邮箱设置自动回复的方法: 1、打开软件&am…

ARM-M0内核MCU,内置24bit ADC,采样率4KSPS,传感器、电子秤、体脂秤专用,国产

ARM-M0内核MCU 内置24bit ADC ,采样率4KSPS flash 64KB,SRAM 32KB 适用于传感器,电子秤,体脂秤等等

QML android 采集手机传感器数据 并通过udp 发送

利用 qt 开发 安卓 app &#xff0c;采集手机传感器数据 并通过udp 发送 #ifndef UDPLINK_H #define UDPLINK_H#include <QObject> #include <QUdpSocket> #include <QHostAddress>class UdpLink : public QObject {Q_OBJECT public:explicit UdpLink(QObjec…

Win10无法访问你可能没有权限使用网络资源怎么解决

当我们使用Win10电脑打开文件时&#xff0c;弹出提示无法访问你可能没有权限使用网络资源&#xff0c;这是怎么回事&#xff0c;遇到这种问题应该怎么解决呢&#xff0c;下面小编就给大家详细介绍一下Win10无法访问你可能没有权限使用网络资源的解决方法&#xff0c;有需要的小…

使用亚马逊云科技人工智能内容审核服务,打造安全的图像生成和扩散模型

生成式人工智能技术发展日新月异&#xff0c;现在已经能够根据文本输入生成文本和图像。Stable Diffusion 是一种文本转图像模型&#xff0c;可让您创建栩栩如生的图像应用。您可以通过 Amazon SageMaker JumpStart&#xff0c;使用 Stable Diffusion 模型轻松地从文本生成图像…

继续聊聊API接口

什么是API接口 API接口(Application Programming Interface Interface)是应用程序与开发人员或其他程序互相通信的方式。它允许开发者访问应用程序的数据和功能。 API接口,软件的“握手”与“交流”之道,软件世界的“好基友”。想让软件聊得来?想开发App却无从下手?API来相救…