Desenvolvimento - Visual Studio

OCR em Aplicações Universais: extraindo texto de imagens

Neste artigo veremos como utilizar a API de OCR (Optical Character Recognition) do Windows 10 para extrair texto de imagens.

por Joel Rodrigues



A técnica de OCR (Optical Character Recognition) consiste no reconhecimento de textos a partir de imagens, ou seja, a extração de informação textual a partir de um elemento onde não há distinção bem definida entre imagens e caracteres alfanuméricos (letras, números e pontuação, dependendo do idioma).

O ORC possui aplicações práticas em diversas áreas e tipos, mas em geral, busca automatizar a identificação de textos sem que haja a necessidade de interação direta do usuário final nesta etapa. Na maior parte dos casos, a intenção é facilitar o trabalho do cliente ou mesmo realizar tarefas que se mostram "humanamente inviáveis".

Algumas aplicações conhecidas para esse procedimento são:

  • Reconhecimento de placas de veículos a partir de fotos capturadas por mecanismos automatizados de controle;
  • Extração de texto de documentos digitalizados e fotos.

Na plataforma Windows/Windows Phone já era possível utilizar esse recurso desde a versão 8.1 ao baixar o pacote Microsoft.Windows.Ocr via Nuget. No Windows 10 essa ferramenta foi evoluída e está disponível por padrão na forma de uma API da plataforma universal, com suporte a 25 idiomas e processamento totalmente local. Assim, não há necessidade de conexão com a internet para que o reconhecimento de texto funcione.

Windows.Media.Ocr

As funcionalidades que precisamos para aplicar a OCR em projetos UWP estão contidas, basicamente, no namespace Windows.Media.Ocr, que contém as seguintes classes:

  • OcrEngine: principal classe da biblioteca e contém as funções que definem o idioma e que realizam o reconhecimento propriamente dito;
  • OcrResult: essa classe representa o resultado de uma operação de reconhecimento. Ao ser invocado, o método RecognizeAsync da classe OcrEngine retorna um objeto desse tipo;
  • OcrLine: representa cada linha do texto obtido pelo método RecognizeAsync da classe OcrEngine. Um objeto OcrResult pode conter um ou mais objetos do tipo OcrLine;
  • OcrWord: representa cada palavra de cada linha do texto obtido. Um objeto OcrLine possui uma coleção de objetos do tipo OcrWord.

Exemplo prático

No exemplo que desenvolveremos agora faremos o reconhecimento do texto em duas imagens, com conteúdo em inglês e português. As imagens, que podem ser vistas nas Figuras 1 e 2, contém texto em e composições posições diferentes.

Imagem com texto em português

Figura 1. Imagem com texto em português

Imagem com texto em inglês

Figura 2. Imagem com texto em inglês

O primeiro passo será criar um novo projeto do tipo Universal Windows usando o template Blank App no Visual Studio. Em seguida, devemos adicionar as imagens que serão processadas clicando com o botão direito do mouse sobre o projeto e utilizando a opção Add &gr; Existing item. Em seguida, devemos alterar a propriedade Copy to Output Directory das duas imagens para Copy if Newer, assim copiará os arquivos para o pacote gerado.

Vale ressaltar que aqui utilizaremos as imagens embutidas no pacote da aplicação, no entanto, pode-se capturar imagens da câmera ou mesmo solicitar que o usuário selecione uma de sua biblioteca, por exemplo.

Feito isso, adicionaremos na MainPage.xaml apenas um botão para realizar o processamento e um TextBlock para receber o texto obtido. O código adicionado a essa página pode ser visto na Listagem 1.

Listagem 1. Código XAML da MainPage

  <StackPanel>
      <Button Content="Reconhecer texto" Name="btnReconhecer" Click="btnReconhecer_Click"/>
      <TextBlock Name="txtTexto" HorizontalAlignment="Stretch" TextWrapping="Wrap"/>
  </StackPanel>

Agora podemos realizar o processamento, bastando para isso acionar o evento Click do botão e no event handler gerado adicionar o código da Listagem 2.

Listagem 2. Reconhecendo o texto da imagem

  private async void btnReconhecer_Click(object sender, RoutedEventArgs e)
  {
      OcrEngine ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages();
      var file = await Package.Current.InstalledLocation.GetFileAsync("imgPortugues.jpg");
      using (var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
      {
          var decoder = await BitmapDecoder.CreateAsync(stream);
          var bitmap = await decoder.GetSoftwareBitmapAsync();
          OcrResult result = await ocrEngine.RecognizeAsync(bitmap);
          txtTexto.Text = result.Text;
      }
  }

Aqui nos interessam principalmente as linhas onde criamos a OcrEngine com base nos idiomas suportados no ambiente em que a aplicação está rodando, e aquela em que extraímos o texto da imagem, obtendo um OcrResult.

O resultado dessa operação para as duas imagens pode ser visto na Figura 3. É importante observar que apesar de em alguns casos o reconhecimento não ser perfeito, está muito perto disso.

Resultado do reconhecimento do texto

Figura 3. Resultado do reconhecimento do texto

No próximo exemplo adicionaremos um ListBox na MainPage, ao qual chamaremos aqui de listResultado e adicionaremos as linhas do texto separadamente.

Na Listagem 3 temos o texto que deve substituir a linha da Listagem 2 onde atribuímos o texto obtido ao TextBlock.

Listagem 3. Lendo as linhas do texto obtido

  foreach(var line in result.Lines)
  {
      listResultado.Items.Add(line.Text);
  } 

Na Figura 4 temos o resultado obtido ao processar as duas imagens novamente, agora com cada linha adicionada como um item do ListBox.

Linhas do texto obtido

Figura 4. Linhas do texto obtido

Por fim, podemos ver na Listagem 4 como recuperar as palavras de cada linha separadamente, adicionando-as como um novo item do ListBox. O resultado é visto na Figura 5.

Listagem 4. Obtendo as palavras de cada linha separadamente

  foreach(var line in result.Lines)
  {
      foreach(var word in line.Words)
      {
          listResultado.Items.Add(word.Text);
      }
  }

Figura 5. Palavras obtidas do texto separadamente

A classe OcrWord possui ainda a propriedade BoudingRect, que contém a posição e dimensões do retângulo onde a palavra se encontra na imagem. Também é possível definir um idioma específico ao processar o texto. Para isso, deve-se utilizar a função TryCreateFromLanguage ao criar a OcrEngine e indicar o idioma desejado.

Veja que são várias as aplicações possíveis para essa técnica e a API do Windows simplifica sua utilização em projetos UWP, bastando obter a imagem a partir de alguma fonte e processá-la para obter o texto desejado.

Joel Rodrigues

Joel Rodrigues - Técnico em Informática - IFRN Cursando Bacharelado em Ciências e Tecnologia - UFRN Programador .NET/C# e Delphi há quase 3 anos, já tendo trabalhado com Webservices, WPF, Windows Phone 7 e ASP.NET, possui ainda conhecimentos em HTML, CSS e Javascript (JQuery).