Check out what’s new from Firebase at Google I/O 2022. Learn more

Reconheça texto em imagens com segurança com o Cloud Vision usando o Firebase Auth and Functions em plataformas Apple

Para chamar uma API do Google Cloud do seu aplicativo, você precisa criar uma API REST intermediária que processe a autorização e proteja valores secretos, como chaves de API. Em seguida, você precisa escrever código em seu aplicativo móvel para autenticar e se comunicar com esse serviço intermediário.

Uma maneira de criar essa API REST é usando o Firebase Authentication and Functions, que oferece um gateway gerenciado e sem servidor para as APIs do Google Cloud que lidam com a autenticação e podem ser chamados de seu aplicativo para dispositivos móveis com SDKs pré-criados.

Este guia demonstra como usar essa técnica para chamar a API Cloud Vision do seu aplicativo. Esse método permitirá que todos os usuários autenticados acessem os serviços faturados do Cloud Vision por meio de seu projeto do Cloud. Portanto, considere se esse mecanismo de autenticação é suficiente para seu caso de uso antes de continuar.

Antes de você começar

Configure seu projeto

Se você ainda não adicionou o Firebase ao seu aplicativo, faça isso seguindo as etapas do guia de primeiros passos .

Use o Swift Package Manager para instalar e gerenciar as dependências do Firebase.

  1. No Xcode, com seu projeto de aplicativo aberto, navegue até File > Add Packages .
  2. Quando solicitado, adicione o repositório do SDK das plataformas Firebase Apple:
  3.   https://github.com/firebase/firebase-ios-sdk
      
  4. Escolha a biblioteca do Firebase ML.
  5. Quando terminar, o Xcode começará automaticamente a resolver e baixar suas dependências em segundo plano.

Em seguida, execute algumas configurações no aplicativo:

  1. No seu aplicativo, importe o Firebase:

    Rápido

    import FirebaseMLModelDownloader

    Objetivo-C

    @import FirebaseMLModelDownloader;

Mais algumas etapas de configuração e estamos prontos:

  1. Se você ainda não ativou as APIs baseadas em nuvem para seu projeto, faça isso agora:

    1. Abra a página de APIs do Firebase ML do console do Firebase.
    2. Se você ainda não atualizou seu projeto para o plano de preços Blaze, clique em Atualizar para fazer isso. (Você será solicitado a atualizar somente se seu projeto não estiver no plano Blaze.)

      Somente projetos de nível Blaze podem usar APIs baseadas em nuvem.

    3. Se as APIs baseadas em nuvem ainda não estiverem habilitadas, clique em Habilitar APIs baseadas em nuvem .
  2. Configure suas chaves de API do Firebase existentes para impedir o acesso à API Cloud Vision:
    1. Abra a página Credenciais do console do Cloud.
    2. Para cada chave de API na lista, abra a visualização de edição e, na seção Restrições de chave, adicione à lista todas as APIs disponíveis, exceto a API Cloud Vision.

Implante a função que pode ser chamada

Em seguida, implante a Função do Cloud que você usará para fazer a ponte entre seu aplicativo e a API Cloud Vision. O repositório functions-samples contém um exemplo que você pode usar.

Por padrão, acessar a API do Cloud Vision por meio dessa função permitirá que apenas usuários autenticados do seu aplicativo acessem a API do Cloud Vision. Você pode modificar a função para diferentes requisitos.

Para implantar a função:

  1. Clone ou baixe o repositório functions-samples e mude para o diretório vision-annotate-image :
    git clone https://github.com/firebase/functions-samples
    cd vision-annotate-image
    
  2. Instalar dependências:
    cd functions
    npm install
    cd ..
    
  3. Se você não tiver a Firebase CLI, instale-a .
  4. Inicialize um projeto do Firebase no diretório vision-annotate-image . Quando solicitado, selecione seu projeto na lista.
    firebase init
  5. Implante a função:
    firebase deploy --only functions:annotateImage

Adicionar o Firebase Auth ao seu aplicativo

A função chamável implantada acima rejeitará qualquer solicitação de usuários não autenticados do seu aplicativo. Caso ainda não tenha feito isso, você precisará adicionar o Firebase Auth ao seu aplicativo.

Adicione as dependências necessárias ao seu aplicativo

Use o Swift Package Manager para instalar a biblioteca do Cloud Functions para Firebase.

Agora você está pronto para começar a reconhecer texto em imagens.

1. Prepare a imagem de entrada

Para chamar o Cloud Vision, a imagem deve ser formatada como uma string codificada em base64. Para processar uma UIImage :

Rápido

guard let imageData = uiImage.jpegData(compressionQuality: 1.0f) else { return }
let base64encodedImage = imageData.base64EncodedString()

Objetivo-C

NSData *imageData = UIImageJPEGRepresentation(uiImage, 1.0f);
NSString *base64encodedImage =
  [imageData base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];

2. Invoque a função que pode ser chamada para reconhecer texto

Para reconhecer pontos de referência em uma imagem, invoque a função que pode ser chamada passando uma solicitação JSON Cloud Vision .

  1. Primeiro, inicialize uma instância do Cloud Functions:

    Rápido

    lazy var functions = Functions.functions()
    

    Objetivo-C

    @property(strong, nonatomic) FIRFunctions *functions;
    
  2. Crie a solicitação. A API Cloud Vision é compatível com dois tipos de detecção de texto: TEXT_DETECTION e DOCUMENT_TEXT_DETECTION . Consulte os documentos de OCR do Cloud Vision para ver a diferença entre os dois casos de uso.

    Rápido

    let requestData = [
      "image": ["content": base64encodedImage],
      "features": ["type": "TEXT_DETECTION"],
      "imageContext": ["languageHints": ["en"]]
    ]
    

    Objetivo-C

    NSDictionary *requestData = @{
      @"image": @{@"content": base64encodedImage},
      @"features": @{@"type": @"TEXT_DETECTION"},
      @"imageContext": @{@"languageHints": @[@"en"]}
    };
    
  3. Por fim, invoque a função:

    Rápido

    functions.httpsCallable("annotateImage").call(requestData) { (result, error) in
      if let error = error as NSError? {
        if error.domain == FunctionsErrorDomain {
          let code = FunctionsErrorCode(rawValue: error.code)
          let message = error.localizedDescription
          let details = error.userInfo[FunctionsErrorDetailsKey]
        }
        // ...
      }
      // Function completed succesfully
    }
    

    Objetivo-C

    [[_functions HTTPSCallableWithName:@"annotateImage"]
                              callWithObject:requestData
                                  completion:^(FIRHTTPSCallableResult * _Nullable result, NSError * _Nullable error) {
            if (error) {
              if (error.domain == FIRFunctionsErrorDomain) {
                FIRFunctionsErrorCode code = error.code;
                NSString *message = error.localizedDescription;
                NSObject *details = error.userInfo[FIRFunctionsErrorDetailsKey];
              }
              // ...
            }
            // Function completed succesfully
            // Get information about labeled objects
    
          }];
    

3. Extraia texto de blocos de texto reconhecido

Se a operação de reconhecimento de texto for bem-sucedida, uma resposta JSON de BatchAnnotateImagesResponse será retornada no resultado da tarefa. As anotações de texto podem ser encontradas no objeto fullTextAnnotation .

Você pode obter o texto reconhecido como uma string no campo de text . Por exemplo:

Rápido

guard let annotation = (result?.data as? [String: Any])?["fullTextAnnotation"] as? [String: Any] else { return }
print("%nComplete annotation:")
let text = annotation["text"] as? String ?? ""
print("%n\(text)")

Objetivo-C

NSDictionary *annotation = result.data[@"fullTextAnnotation"];
if (!annotation) { return; }
NSLog(@"\nComplete annotation:");
NSLog(@"\n%@", annotation[@"text"]);

Você também pode obter informações específicas para regiões da imagem. Para cada block , paragraph , word e symbol , você pode obter o texto reconhecido na região e as coordenadas delimitadoras da região. Por exemplo:

Rápido

guard let pages = annotation["pages"] as? [[String: Any]] else { return }
for page in pages {
var pageText = ""
guard let blocks = page["blocks"] as? [[String: Any]] else { continue }
for block in blocks {
    var blockText = ""
    guard let paragraphs = block["paragraphs"] as? [[String: Any]] else { continue }
    for paragraph in paragraphs {
    var paragraphText = ""
    guard let words = paragraph["words"] as? [[String: Any]] else { continue }
    for word in words {
        var wordText = ""
        guard let symbols = word["symbols"] as? [[String: Any]] else { continue }
        for symbol in symbols {
        let text = symbol["text"] as? String ?? ""
        let confidence = symbol["confidence"] as? Float ?? 0.0
        wordText += text
        print("Symbol text: \(text) (confidence: \(confidence)%n")
        }
        let confidence = word["confidence"] as? Float ?? 0.0
        print("Word text: \(wordText) (confidence: \(confidence)%n%n")
        let boundingBox = word["boundingBox"] as? [Float] ?? [0.0, 0.0, 0.0, 0.0]
        print("Word bounding box: \(boundingBox.description)%n")
        paragraphText += wordText
    }
    print("%nParagraph: %n\(paragraphText)%n")
    let boundingBox = paragraph["boundingBox"] as? [Float] ?? [0.0, 0.0, 0.0, 0.0]
    print("Paragraph bounding box: \(boundingBox)%n")
    let confidence = paragraph["confidence"] as? Float ?? 0.0
    print("Paragraph Confidence: \(confidence)%n")
    blockText += paragraphText
    }
    pageText += blockText
}

Objetivo-C

for (NSDictionary *page in annotation[@"pages"]) {
  NSMutableString *pageText = [NSMutableString new];
  for (NSDictionary *block in page[@"blocks"]) {
    NSMutableString *blockText = [NSMutableString new];
    for (NSDictionary *paragraph in block[@"paragraphs"]) {
      NSMutableString *paragraphText = [NSMutableString new];
      for (NSDictionary *word in paragraph[@"words"]) {
        NSMutableString *wordText = [NSMutableString new];
        for (NSDictionary *symbol in word[@"symbols"]) {
          NSString *text = symbol[@"text"];
          [wordText appendString:text];
          NSLog(@"Symbol text: %@ (confidence: %@\n", text, symbol[@"confidence"]);
        }
        NSLog(@"Word text: %@ (confidence: %@\n\n", wordText, word[@"confidence"]);
        NSLog(@"Word bounding box: %@\n", word[@"boundingBox"]);
        [paragraphText appendString:wordText];
      }
      NSLog(@"\nParagraph: \n%@\n", paragraphText);
      NSLog(@"Paragraph bounding box: %@\n", paragraph[@"boundingBox"]);
      NSLog(@"Paragraph Confidence: %@\n", paragraph[@"confidence"]);
      [blockText appendString:paragraphText];
    }
    [pageText appendString:blockText];
  }
}