Reconnaître du texte dans des images avec ML Kit sur iOS

Vous pouvez utiliser ML Kit pour reconnaître du texte dans des images ou des vidéos, comme le texte d'un panneau de signalisation. Voici les principales caractéristiques de cette fonctionnalité :

API Text Recognition v2
DescriptionReconnaissez du texte dans des images ou des vidéos, avec prise en charge des alphabets latin, chinois, devanagari, japonais et coréen, ainsi que d'un large éventail de langues.
Noms des SDKGoogleMLKit/TextRecognition
GoogleMLKit/TextRecognitionChinese
GoogleMLKit/TextRecognitionDevanagari
GoogleMLKit/TextRecognitionJapanese
GoogleMLKit/TextRecognitionKorean
ImplémentationLes assets sont associés de manière statique à votre application au moment de la compilation.
Impact sur la taille de l'applicationEnviron 38 Mo par SDK de script
PerformancesEn temps réel sur la plupart des appareils pour le SDK de script latin, plus lent pour les autres.

Essayer

Avant de commencer

  1. Incluez les pods ML Kit suivants dans votre Podfile :
    # To recognize Latin script
    pod 'GoogleMLKit/TextRecognition', '8.0.0'
    # To recognize Chinese script
    pod 'GoogleMLKit/TextRecognitionChinese', '8.0.0'
    # To recognize Devanagari script
    pod 'GoogleMLKit/TextRecognitionDevanagari', '8.0.0'
    # To recognize Japanese script
    pod 'GoogleMLKit/TextRecognitionJapanese', '8.0.0'
    # To recognize Korean script
    pod 'GoogleMLKit/TextRecognitionKorean', '8.0.0'
    
  2. Après avoir installé ou mis à jour les pods de votre projet, ouvrez votre projet Xcode à l'aide de son fichier .xcworkspace. ML Kit est compatible avec Xcode 12.4 ou version ultérieure.

1. Créer une instance de TextRecognizer

Créez une instance de TextRecognizer en appelant +textRecognizer(options:), en transmettant les options liées au SDK que vous avez déclaré comme dépendance ci-dessus :

Swift

// When using Latin script recognition SDK
let latinOptions = TextRecognizerOptions()
let latinTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Chinese script recognition SDK
let chineseOptions = ChineseTextRecognizerOptions()
let chineseTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Devanagari script recognition SDK
let devanagariOptions = DevanagariTextRecognizerOptions()
let devanagariTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Japanese script recognition SDK
let japaneseOptions = JapaneseTextRecognizerOptions()
let japaneseTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Korean script recognition SDK
let koreanOptions = KoreanTextRecognizerOptions()
let koreanTextRecognizer = TextRecognizer.textRecognizer(options:options)

Objective-C

// When using Latin script recognition SDK
MLKTextRecognizerOptions *latinOptions = [[MLKTextRecognizerOptions alloc] init];
MLKTextRecognizer *latinTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Chinese script recognition SDK
MLKChineseTextRecognizerOptions *chineseOptions = [[MLKChineseTextRecognizerOptions alloc] init];
MLKTextRecognizer *chineseTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Devanagari script recognition SDK
MLKDevanagariTextRecognizerOptions *devanagariOptions = [[MLKDevanagariTextRecognizerOptions alloc] init];
MLKTextRecognizer *devanagariTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Japanese script recognition SDK
MLKJapaneseTextRecognizerOptions *japaneseOptions = [[MLKJapaneseTextRecognizerOptions alloc] init];
MLKTextRecognizer *japaneseTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Korean script recognition SDK
MLKKoreanTextRecognizerOptions *koreanOptions = [[MLKKoreanTextRecognizerOptions alloc] init];
MLKTextRecognizer *koreanTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

2. Préparer l'image d'entrée

Transmettez l'image en tant que UIImage ou CMSampleBufferRef à la méthode process(_:completion:) de TextRecognizer :

Créez un objet VisionImage à l'aide d'un UIImage ou d'un CMSampleBuffer.

Si vous utilisez un UIImage, procédez comme suit :

  • Créez un objet VisionImage avec UIImage. Veillez à spécifier le bon .orientation.

    Swift

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

    Objective-C

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

Si vous utilisez un CMSampleBuffer, procédez comme suit :

  • Spécifiez l'orientation des données d'image contenues dans CMSampleBuffer.

    Pour obtenir l'orientation de l'image :

    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;
      }
    }
          
  • Créez un objet VisionImage à l'aide de l'objet CMSampleBuffer et de l'orientation :

    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. Traiter l'image

Ensuite, transmettez l'image à la méthode 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. Extraire du texte à partir de blocs de texte reconnu

Si l'opération de reconnaissance de texte réussit, elle renvoie un objet Text. Un objet Text contient le texte intégral reconnu dans l'image et zéro ou plusieurs objets TextBlock.

Chaque TextBlock représente un bloc de texte rectangulaire, qui contient zéro ou plusieurs objets TextLine. Chaque objet TextLine contient zéro ou plusieurs objets TextElement, qui représentent des mots et des entités de type mot, telles que des dates et des nombres.

Pour chaque objet TextBlock, TextLine et TextElement, vous pouvez obtenir le texte reconnu dans la région et les coordonnées de délimitation de la région.

Exemple :

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;
    }
  }
}

Consignes concernant les images d'entrée

  • Pour que ML Kit reconnaisse précisément le texte, les images d'entrée doivent contenir du texte représenté par suffisamment de données de pixels. Idéalement, chaque caractère doit mesurer au moins 16 x 16 pixels. En général, une taille de caractères supérieure à 24 x 24 pixels n'améliore pas la précision.

    Par exemple, une image de 640 x 480 peut convenir pour scanner une carte de visite qui occupe toute la largeur de l'image. Pour scanner un document imprimé sur du papier au format Letter, une image de 720 x 1 280 pixels peut être nécessaire.

  • Une mauvaise mise au point de l'image peut affecter la précision de la reconnaissance de texte. Si vous n'obtenez pas de résultats acceptables, demandez à l'utilisateur de reprendre l'image.

  • Si vous reconnaissez du texte dans une application en temps réel, vous devez tenir compte des dimensions globales des images d'entrée. Les images plus petites peuvent être traitées plus rapidement. Pour réduire la latence, assurez-vous que le texte occupe la plus grande partie possible de l'image et capturez des images à des résolutions inférieures (en gardant à l'esprit les exigences de précision mentionnées ci-dessus). Pour en savoir plus, consultez Conseils pour améliorer les performances.

Conseils pour améliorer les performances

  • Pour traiter des images vidéo, utilisez l'API synchrone results(in:) du détecteur. Appelez cette méthode à partir de la fonction captureOutput(_, didOutput:from:) de AVCaptureVideoDataOutputSampleBufferDelegate pour obtenir de manière synchrone les résultats de l'image vidéo donnée. Conservez la valeur true pour l'élément alwaysDiscardsLateVideoFrames de AVCaptureVideoDataOutput afin de limiter les appels au détecteur. Si une nouvelle image vidéo devient disponible pendant l'exécution du détecteur, elle sera supprimée.
  • Si vous utilisez la sortie du détecteur pour superposer des graphiques sur l'image d'entrée, commencez par obtenir le résultat de ML Kit, puis affichez l'image et la superposition en une seule étape. De cette façon, vous n'effectuez le rendu sur la surface d'affichage qu'une seule fois pour chaque frame d'entrée traité. Pour obtenir un exemple, consultez updatePreviewOverlayViewWithLastFrame dans l'exemple de démarrage rapide de ML Kit.
  • Envisagez de capturer des images à une résolution inférieure. Toutefois, gardez également à l'esprit les exigences de cette API concernant les dimensions des images.
  • Pour éviter une dégradation potentielle des performances, n'exécutez pas simultanément plusieurs instances TextRecognizer avec des options de script différentes.