前言
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 即可