在 iOS 上使用机器学习套件识别图片中的文本

您可以使用机器学习套件识别图片或视频中的文本,例如街道标志的文本。此功能的主要特性包括:

文本识别 API
说明识别图片或视频中的拉丁字母文本。
SDK 名称GoogleMLKit/TextRecognition (version 2.2.0)
实现素材资源在构建时静态关联到您的应用。
应用大小影响约 20 MB
性能在大多数设备上实时显示。
  • 请试用示例应用,以查看此 API 的用法示例。
  • 使用 Codelab 亲自试用代码。

准备工作

  1. 在 Podfile 中添加以下机器学习套件 pod:
    pod 'GoogleMLKit/TextRecognition','2.2.0'
    
  2. 安装或更新项目的 Pod 之后,使用 Xcode 项目的 .xcworkspace 打开该项目。Xcode 12.4 版或更高版本支持机器学习套件。

1. 创建 TextRecognizer 实例

通过调用 +textRecognizer 创建 TextRecognizer 的实例:

Swift

let textRecognizer = TextRecognizer.textRecognizer()
      

Objective-C

MLKTextRecognizer *textRecognizer = [MLKTextRecognizer textRecognizer];
      

2. 准备输入图片

将图片作为 UIImageCMSampleBufferRef 传递给 TextRecognizerprocess(_:completion:) 方法:

使用 UIImageCMSampleBuffer 创建 VisionImage 对象。

如果您使用的是 UIImage,请按以下步骤操作:

  • 使用 UIImage 创建一个 VisionImage 对象。请务必指定正确的 .orientation

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

如果您使用的是 CMSampleBuffer,请按以下步骤操作:

  • 指定 CMSampleBuffer 中包含的图片数据的方向。

    要获取图片方向,请执行以下操作:

    Swift

    func imageOrientation(
      deviceOrientation: UIDeviceOrientation,
      cameraPosition: AVCaptureDevice.Position
    ) -> UIImage.Orientation {
      switch deviceOrientation {
      case .portrait:
        return cameraPosition == .front ? .leftMirrored : .right
      case .landscapeLeft:
        return cameraPosition == .front ? .downMirrored : .up
      case .portraitUpsideDown:
        return cameraPosition == .front ? .rightMirrored : .left
      case .landscapeRight:
        return cameraPosition == .front ? .upMirrored : .down
      case .faceDown, .faceUp, .unknown:
        return .up
      }
    }
          

    Objective-C

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                                : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                                : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                                : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                                : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • 使用 CMSampleBuffer 对象和屏幕方向创建 VisionImage 对象:

    Swift

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    Objective-C

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

3. 处理图片

然后,将图片传递给 process(_:completion:) 方法:

Swift

textRecognizer.process(visionImage) { result, error in
  guard error == nil, let result = result else {
    // Error handling
    return
  }
  // Recognized text
}

Objective-C

[textRecognizer processImage:image
                  completion:^(MLKText *_Nullable result,
                               NSError *_Nullable error) {
  if (error != nil || result == nil) {
    // Error handling
    return;
  }
  // Recognized text
}];

4. 从识别出的文本块中提取文本

如果文本识别操作成功,它会返回 Text 对象。Text 对象包含图片中识别到的完整文本以及零个或多个 TextBlock 对象。

每个 TextBlock 表示一个矩形文本块,其中包含零个或多个 TextLine 对象。每个 TextLine 对象包含零个或多个 TextElement 对象,这些对象表示字词和类似字词的实体,例如日期和数字。

对于每个 TextBlockTextLineTextElement 对象,您可以获取区域中识别出的文本以及该区域的边界坐标。

例如:

Swift

let resultText = result.text
for block in result.blocks {
    let blockText = block.text
    let blockLanguages = block.recognizedLanguages
    let blockCornerPoints = block.cornerPoints
    let blockFrame = block.frame
    for line in block.lines {
        let lineText = line.text
        let lineLanguages = line.recognizedLanguages
        let lineCornerPoints = line.cornerPoints
        let lineFrame = line.frame
        for element in line.elements {
            let elementText = element.text
            let elementCornerPoints = element.cornerPoints
            let elementFrame = element.frame
        }
    }
}

Objective-C

NSString *resultText = result.text;
for (MLKTextBlock *block in result.blocks) {
  NSString *blockText = block.text;
  NSArray<MLKTextRecognizedLanguage *> *blockLanguages = block.recognizedLanguages;
  NSArray<NSValue *> *blockCornerPoints = block.cornerPoints;
  CGRect blockFrame = block.frame;
  for (MLKTextLine *line in block.lines) {
    NSString *lineText = line.text;
    NSArray<MLKTextRecognizedLanguage *> *lineLanguages = line.recognizedLanguages;
    NSArray<NSValue *> *lineCornerPoints = line.cornerPoints;
    CGRect lineFrame = line.frame;
    for (MLKTextElement *element in line.elements) {
      NSString *elementText = element.text;
      NSArray<NSValue *> *elementCornerPoints = element.cornerPoints;
      CGRect elementFrame = element.frame;
    }
  }
}

输入图片指南

  • 为了使机器学习套件准确识别文本,输入图片必须包含由足够像素数据表示的文本。理想情况下,每个字符至少应为 16x16 像素。通常,大于 24x24 像素的字符没有准确性优势。

    例如,640x480 的图片可能非常适合用于扫描占据图片全宽的名片。如需扫描打印在信纸大小纸张上的文档,可能需要 720x1280 像素的图片。

  • 图片聚焦不良会影响文本识别准确率。如果您未获得可接受的结果,请尝试让用户重新捕获图片。

  • 如果您在实时应用中识别文本,则应考虑输入图片的整体尺寸。较小图片的处理速度会更快。为缩短延迟时间,请确保文字占据尽可能多的图片,并以较低的分辨率捕获图片(但请牢记上述准确性要求)。如需了解详情,请参阅改善性能的技巧

效果提升技巧

  • 如需处理视频帧,请使用检测器的 results(in:) 同步 API。从 AVCaptureVideoDataOutputSampleBufferDelegatecaptureOutput(_, didOutput:from:) 函数中调用此方法,以同步获取给定视频帧的结果。将 AVCaptureVideoDataOutputalwaysDiscardsLateVideoFrames 保留为 true,以限制对检测器的调用。如果在检测器运行时有新的视频帧可用,将被丢弃。
  • 如果您使用检测器的输出在输入图片上叠加图形,请先从机器学习套件获取结果,然后在一个步骤中完成图片的渲染和叠加。采用这一方法,每个已处理的输入帧只需在显示表面呈现一次。如需查看示例,请参阅机器学习套件快速入门示例中的 updatePreviewOverlayViewWithLastFrame
  • 建议以较低分辨率捕获图片。但是,您也要牢记此 API 的图片尺寸要求。