前言
Vision 是 Apple 在 WWDC2017 推出的一个视觉处理框架,它可以进行人脸检测、文本识别、条形码检测、图像匹配和一般特征跟踪。它也支持使用自定义 Core ML 模型来完成分类或对象检测等任务。
在这篇文章里,我将使用 Vision 的文本识别功能来进行身份证信息的提取。废话不多说,让我们开始吧!
示例代码
swift
import Vision
fun recognizeTextRequest {
// 初始化 VNImageRequestHandler
let image = UIImage(named: "xxx")
var cgOrientation = CGImagePropertyOrientation.right
guard let image = image else { return }
switch image.imageOrientation {
case .up: cgOrientation = .up
case .upMirrored: cgOrientation = .upMirrored
case .down: cgOrientation = .down
case .downMirrored: cgOrientation = .downMirrored
case .left: cgOrientation = .left
case .leftMirrored: cgOrientation = .leftMirrored
case .right: cgOrientation = .right
case .rightMirrored: cgOrientation = .rightMirrored
@unknown default:
fatalError()
}
guard let cgImage = image.cgImage else { return }
let requestHandler = VNImageRequestHandler(cgImage: cgImage, orientation: cgOrientation)
// 初始化 VNRecognizeTextRequest
let request = VNRecognizeTextRequest(completionHandler: recognizeTextHandler)
// 默认情况下不会识别中文,需要手动指定 recognitionLanguages
request.recognitionLanguages = ["zh-Hans", "zh-Hant"]
request.usesLanguageCorrection = true
// 执行 request
DispatchQueue.global(qos: .userInitiated).async {
do {
try requestHandler.perform([request])
} catch {
print("Unable to perform the requests: \(error).")
}
}
}
func recognizeTextHandler(request: VNRequest, error: Error?) {
guard let observations = request.results as? [VNRecognizedTextObservation] else {
return
}
DispatchQueue.main.async {
let recognizedStrings = observations.compactMap { observation in
return observation.topCandidates(1).first?.string
}
print(recognizedStrings)
}
}
完整版代码如上,下面我们来进行代码说明。
代码解释
要想使用 Vision 框架,首先要做的第一步肯定是导入该框架。
接着,我们需要初始化 VNImageRequestHandler
来进行照片的文字提取。VNImageRequestHandler
共支持五种初始化方式,在本篇的示例代码中,我们使用了 CGImage
来进行初始化。
请注意:因为 CGImage
、CIImage
和 CVPixelBuffer
的示例对象没有资源的方向信息,所以使用这三种类型初始化时,需要把资源的方向信息也带进去。以下是其他四种初始化方式:
- CIImageL:可以通过
UIImage
的ciImage
属性获得,需要通过枚举CGImagePropertyOrientation
来指定,调用 init(ciImage:orientation:options:) 来初始化。 - CVPixelBuffer:它是 Core Video 的图像资源格式,主要用于实时画面或者电影。 通过 init(cvPixelBuffer:orientation:options:) 进行初始化。
- NSData:图像数据可能会被压缩或保存在内存中,也可能在服务器获取。如果在服务器获取资源,请检查从网络下载的图像是否有垂直方向;如果没有,需要调用 init(data:orientation:options:) 将资源的方向信息传递进去。
- NSURL:图片在磁盘的路径。
为什么 Vision 必需要获得图片的方向呢?因为如果 Vision 假设了错误的方向,它可能无法正确地检测到侧面或上下颠倒的特征。如果是相册中选择的照片包含方向信息。我们可以通过 UIImage
的 imageOrientation
属性来获得这些数据。如果你是通过其他方式获取照片,比如从网络或其他应用程序获取照片,如果这些图片没有包含方向信息,则你需要就单独提供。
在 Vision 中,每项功能都是一个 request,不同项的功能使用不同的 request。这里我们用到的是文字识别,所以接下来我们就需要初始化 VNRecognizeTextRequest
了。
VNRecognizeTextRequest
的初始化参数需要我们传递一个 completionHandler 来执行识别完成之后的逻辑。在 completionHandler 里我们只是简单的打印了一下识别结果。
然后就是设置一下 recognitionLanguages
和 usesLanguageCorrection
两个属性的值,因为 Vision 默认情况下不会识别中文,所以我们需要给 recognitionLanguages
赋值让 Vision 可以识别中文。
usesLanguageCorrection
则可以提高文字识别的准确率,但会多消耗性能。
最后一步就是调用 perform
执行 request 了。因为 Vision 的操作都是比较消耗性能的,所以最好将其放在后台队列里执行,以免阻塞主队列。
Tips:虽然 recognizeTextHandler 的打印代码不回到主队列也没问题,但为了表明如果进行 UI 操作是需要回到主队列的,所以我还是写了 DispatchQueue.main.async
。
总结
使用 Vision 进行文字识别需要以下几个步骤:
- 导入 Vision 框架
- 声明 completionHandler 处理识别后的逻辑
- 初始化 VNImageRequestHandler
- 初始化 VNRecognizeTextRequest
- handle 执行 request 即可