detectando zonas legíveis por máquina em imagens de passaporte

mrz_output_04

o post de hoje não seria possível sem o membro do Pyimagesearch Gurus, Hans Boone. Hans está trabalhando em um projeto de visão computacional para detectar automaticamente zonas legíveis por máquina (MRZs) em imagens de passaporte-muito parecido com a região detectada na imagem acima.

a região MRZ em passaportes ou cartões de viagem se enquadra em duas classes: tipo 1 e Tipo 3. MRZs tipo 1 são três linhas, com cada linha contendo 30 caracteres. O MRZ Tipo 3 tem apenas duas linhas, mas cada linha contém 44 caracteres. Em ambos os casos, o MRZ codifica informações de identificação de um determinado cidadão, incluindo o tipo de passaporte, ID do passaporte, país emissor, nome, nacionalidade, data de validade, etc.

dentro do curso Pyimagesearch Gurus, Hans me mostrou seu progresso no projeto e eu imediatamente me interessei. Eu sempre quis aplicar algoritmos de visão computacional para passaporte imagens (principalmente apenas por diversão), mas não tinha o conjunto de dados para fazê-lo. Dadas as informações de identificação pessoal que um passaporte contém, obviamente não consegui escrever um post no blog sobre o assunto e compartilhar as imagens que usei para desenvolver o algoritmo.

felizmente, Hans concordou em compartilhar algumas das imagens de passaporte de amostra/espécime que ele tem acesso — e eu aproveitei a chance de brincar com essas imagens.Agora, antes de chegarmos longe, é importante notar que esses passaportes não são “reais” no sentido de que podem estar ligados a um ser humano real. Mas eles são passaportes genuínos que foram gerados usando nomes falsos, endereços, etc. para que os desenvolvedores trabalhem com.

você pode pensar que, para detectar a região MRZ de um passaporte, você precisa de um pouco de aprendizado de máquina, talvez usando a estrutura linear SVM + HOG para construir um “detector MRZ” — mas isso seria um exagero.

em vez disso, podemos realizar a detecção de MRZ usando apenas técnicas básicas de processamento de imagem, como thresholding, operações morfológicas e propriedades de contorno. No restante desta postagem do blog, detalharei minha própria opinião sobre como aplicar esses métodos para detectar a região MRZ de um passaporte.

procurando o código fonte para este post?

ir direto para a seção Downloads

detectando zonas legíveis por máquina em imagens de passaporte

vamos em frente e começar este projeto. Abra um novo arquivo, nomeie-o detect_mrz.py e insira o seguinte código:

# import the necessary packagesfrom imutils import pathsimport numpy as npimport argparseimport imutilsimport cv2# construct the argument parse and parse the argumentsap = argparse.ArgumentParser()ap.add_argument("-i", "--images", required=True, help="path to images directory")args = vars(ap.parse_args())# initialize a rectangular and square structuring kernelrectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (13, 5))sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 21))

as linhas 2-6 importam nossos pacotes necessários. Presumo que você já tenha o OpenCV instalado. Você também precisará do imutils, minha coleção de funções de conveniência para facilitar as operações básicas de processamento de imagem com o OpenCV. Você pode instalar imutils usando pip :

$ pip install --upgrade imutils

a partir daí, as linhas 9-11 lidam com a análise de nosso argumento de linha de comando. Precisamos apenas de um único switch aqui, --images , que é o caminho para o diretório que contém as imagens do passaporte que vamos processar.Finalmente, as linhas 14 e 15 inicializam dois kernels que usaremos mais tarde ao aplicar operações morfológicas, especificamente a operação de fechamento. Por enquanto, basta observar que o primeiro kernel é retangular com uma largura aproximadamente 3x maior que a altura. O segundo kernel é quadrado. Esses kernels nos permitirão Fechar lacunas entre os caracteres MRZ e as aberturas entre as linhas MRZ.

Agora que nossos argumentos de linha de comando são analisados, podemos começar a fazer loop para cada uma das imagens no nosso conjunto de dados e processá-los:

# loop over the input image pathsfor imagePath in paths.list_images(args):# load the image, resize it, and convert it to grayscaleimage = cv2.imread(imagePath)image = imutils.resize(image, height=600)gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# smooth the image using a 3x3 Gaussian, then apply the blackhat# morphological operator to find dark regions on a light backgroundgray = cv2.GaussianBlur(gray, (3, 3), 0)blackhat = cv2.morphologyEx(gray, cv2.MORPH_BLACKHAT, rectKernel)

Linhas 20 e 21 de cargas nossa imagem original a partir do disco e redimensiona-lo a ter uma altura máxima de 600 pixels. Você pode ver um exemplo de uma imagem original abaixo:

Figura 1: Nossa imagem original do passaporte em que estamos tentando detectar o MRZ.
Figura 1: Nossa imagem original do passaporte em que estamos tentando detectar o MRZ.

a desfocagem Gaussiana é aplicada na linha 26 para reduzir o ruído de alta frequência. Em seguida, aplicamos uma operação morfológica blackhat à imagem desfocada em tons de cinza na linha 27.

um operador blackhat é usado para revelar regiões escuras (ou seja, texto MRZ) contra fundos claros (ou seja, o fundo do próprio passaporte). Como o texto do passaporte é sempre preto em um fundo claro (pelo menos em termos deste conjunto de dados), uma operação blackhat é apropriada. Abaixo você pode ver a saída da aplicação do operador blackhat:

Figura 2: A aplicação do operador morfológico blackhat revela o texto MRZ preto contra o fundo do passaporte leve.
Figura 2: a aplicação do operador morfológico blackhat revela o texto MRZ preto contra o fundo do passaporte leve.

o próximo passo na detecção de MRZ é calcular a representação de magnitude de gradiente da imagem blackhat usando o operador Scharr:

# compute the Scharr gradient of the blackhat image and scale the# result into the range gradX = cv2.Sobel(blackhat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)gradX = np.absolute(gradX)(minVal, maxVal) = (np.min(gradX), np.max(gradX))gradX = (255 * ((gradX - minVal) / (maxVal - minVal))).astype("uint8")

aqui calculamos o gradiente Scharr ao longo do eixo x da imagem blackhat, revelando regiões da imagem que não são apenas escuras contra um fundo claro, mas também contêm mudanças verticais no gradiente, como a região de texto MRZ. Em seguida, pegamos essa imagem de gradiente e a escalamos de volta para o intervalo usando escala mínima / máxima:

Figura 3: Aplicar o operador Scharr à nossa imagem blackhat revela regiões que contêm fortes mudanças verticais no gradiente.
Figura 3: A aplicação do operador Scharr à nossa imagem blackhat revela regiões que contêm fortes mudanças verticais no gradiente.

embora não seja totalmente óbvio por que aplicamos esta etapa, direi que é extremamente útil na redução de detecções MRZ falso-positivas. Sem ele, podemos acidentalmente marcar regiões embelezadas ou projetadas do passaporte como o MRZ. Vou deixar isso como um exercício para você verificar se o cálculo do gradiente da imagem blackhat pode melhorar a precisão da detecção MRZ.

o próximo passo é tentar detectar as linhas reais do MRZ:

# apply a closing operation using the rectangular kernel to close# gaps in between letters -- then apply Otsu's thresholding methodgradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)thresh = cv2.threshold(gradX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

primeiro, aplicamos uma operação de fechamento usando nosso kernel retangular. Esta operação de fechamento destina-se a fechar lacunas entre os caracteres MRZ. Em seguida, aplicamos thresholding usando o método Otsu para limitar automaticamente a imagem:

Figura 4: aplicando uma operação de fechamento usando um kernel retangular (que é mais largo do que alto) para fechar lacunas entre os caracteres MRZ
Figura 4: Aplicando uma operação de fechamento usando um kernel retangular (que é mais largo do que alto) para fechar lacunas entre os caracteres MRZ

como podemos ver na figura acima, cada uma das linhas MRZ está presente em nosso mapa de limiar.

o próximo passo é fechar as lacunas entre as linhas reais, dando-nos uma grande região retangular que corresponde ao MRZ:

# perform another closing operation, this time using the square# kernel to close gaps between lines of the MRZ, then perform a# series of erosions to break apart connected componentsthresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)thresh = cv2.erode(thresh, None, iterations=4)

aqui realizamos outra operação de fechamento, desta vez usando nosso kernel quadrado. Este kernel é usado para fechar lacunas entre as linhas individuais do MRZ, dando – nos uma grande região que corresponde ao MRZ. Uma série de erosões são então realizadas para separar os componentes conectados que podem ter sido Unidos durante a operação de fechamento. Essas erosões também são úteis na remoção de pequenas bolhas que são irrelevantes para o MRZ.

 Figura 5: uma segunda operação de fechamento é realizada, desta vez usando um kernel quadrado para fechar as lacunas entre as linhas MRZ individuais.
Figura 5: Uma segunda operação de fechamento é realizada, desta vez usando um kernel quadrado para fechar as lacunas entre as linhas MRZ individuais.

para algumas varreduras de passaporte, a fronteira do passaporte pode ter sido anexada à região MRZ durante as operações de fechamento. Para remediar isso, definimos 5% das bordas esquerda e direita da imagem como zero (ou seja, preto):

# during thresholding, it's possible that border pixels were# included in the thresholding, so let's set 5% of the left and# right borders to zerop = int(image.shape * 0.05)thresh = 0thresh - p:] = 0

você pode ver a saída de nossa remoção de borda abaixo.

 Figura 6: definindo 5% dos pixels da borda esquerda e direita para zero, garantindo que a região MRZ não esteja anexada à margem digitalizada do passaporte.
Figura 6: definindo 5% dos pixels da borda esquerda e direita para zero, garantindo que a região MRZ não esteja anexada à margem digitalizada do passaporte.

em comparação com a Figura 5 acima, Agora você pode ver que a borda foi removida.

a última etapa é encontrar os contornos em nossa imagem limítrofe e usar propriedades de contorno para identificar o MRZ:

# find contours in the thresholded image and sort them by their# sizecnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)cnts = sorted(cnts, key=cv2.contourArea, reverse=True)# loop over the contoursfor c in cnts:# compute the bounding box of the contour and use the contour to# compute the aspect ratio and coverage ratio of the bounding box# width to the width of the image(x, y, w, h) = cv2.boundingRect(c)ar = w / float(h)crWidth = w / float(gray.shape)# check to see if the aspect ratio and coverage width are within# acceptable criteriaif ar > 5 and crWidth > 0.75:# pad the bounding box since we applied erosions and now need# to re-grow itpX = int((x + w) * 0.03)pY = int((y + h) * 0.03)(x, y) = (x - pX, y - pY)(w, h) = (w + (pX * 2), h + (pY * 2))# extract the ROI from the image and draw a bounding box# surrounding the MRZroi = image.copy()cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)break# show the output imagescv2.imshow("Image", image)cv2.imshow("ROI", roi)cv2.waitKey(0)

na linha 56-58, calculamos os contornos (ou seja, contornos) de nossa imagem limítrofe. Em seguida, pegamos esses contornos e os classificamos com base em seu tamanho em ordem decrescente na linha 59 (O que implica que os maiores contornos são os primeiros da lista).

na linha 62, começamos a fazer looping em nossa lista classificada de contornos. Para cada um desses contornos, calcularemos a caixa delimitadora (linha 66) e a usaremos para calcular duas propriedades: a proporção e a proporção de cobertura. A proporção é simplesmente a largura da caixa delimitadora dividida pela altura. A relação de cobertura é a largura da caixa delimitadora dividida pela largura da imagem real.

usando essas duas propriedades, podemos fazer uma verificação na linha 72 para ver se estamos examinando a região MRZ. O MRZ é retangular, com uma largura muito maior que a altura. O MRZ também deve abranger pelo menos 75% da imagem de entrada.

desde que esses dois casos sejam mantidos, as linhas 75-84 usam as coordenadas (x, y) da caixa delimitadora para extrair o MRZ e desenhar a caixa delimitadora em nossa imagem de entrada.

finalmente, as linhas 87-89 exibem nossos resultados.

resultados

para ver nosso detector MRZ em ação, basta executar o seguinte comando:

$ python detect_mrz.py --images examples

abaixo você pode ver um exemplo de uma detecção MRZ bem-sucedida, com o MRZ descrito em verde:

Figura 7: à esquerda, temos nossa imagem de entrada. E à direita, temos a região MRZ que foi detectada com sucesso.
Figura 7: à esquerda, temos nossa imagem de entrada. E à direita, temos a região MRZ que foi detectada com sucesso.

aqui está outro exemplo de detecção da zona legível por máquina em uma imagem de passaporte usando Python e OpenCV:

Figura 8: Aplicação da detecção MRZ a um passaporte digitalizado.
Figura 8: Aplicação da detecção de MRZ a um passaporte digitalizado.

não importa se a região MRZ está na parte superior ou inferior da imagem. Aplicando operações morfológicas, extraindo contornos e computando propriedades de contorno, somos capazes de extrair o MRZ sem problemas.

o mesmo é verdadeiro para a seguinte imagem:

Figura 9: detecção de zonas legíveis por máquina em imagens usando visão computacional.
Figura 9: detecção de zonas legíveis por máquina em imagens usando visão computacional.

vamos tentar outra imagem:

 Figura 10: novamente, somos capazes de detectar o MRZ na varredura de passaporte usando técnicas básicas de processamento de imagem.
Figura 10: novamente, somos capazes de detectar o MRZ na varredura de passaporte usando técnicas básicas de processamento de imagem.

até agora, vimos apenas MRZs tipo 1 que contêm três linhas. No entanto, nosso método funciona tão bem com MRZs Tipo 3 que contêm apenas duas linhas:

Figura 11: detectando o MRZ em uma imagem de passaporte Tipo 3 usando Python e OpenCV.
Figura 11: Detectando o MRZ em uma imagem de passaporte Tipo 3 usando Python e OpenCV.

aqui está outro exemplo de detecção de um MRZ Tipo 3:

Figura 12: aplicação de visão computacional e processamento de imagem para detectar zonas legíveis por máquina em imagens.
Figura 12: aplicação de visão computacional e processamento de imagem para detectar zonas legíveis por máquina em imagens.

o que vem a seguir? Eu recomendo a Universidade PyImageSearch.

informações do curso:
30+ aulas totais • 39h 44m vídeo * última atualização: 12/2021
★★★★★ 4.84 (128 avaliações) * mais de 3.000 alunos matriculados

acredito fortemente que, se você tivesse o professor certo, poderia dominar a visão computacional e o aprendizado profundo.Você acha que aprender visão computacional e aprendizagem profunda tem que ser demorado, esmagador e complicado? Ou tem que envolver matemática e equações complexas? Ou requer um diploma em Ciência da computação?

esse não é o caso.Tudo o que você precisa para dominar a visão computacional e o aprendizado profundo é que alguém explique as coisas para você em termos simples e intuitivos. E é exatamente isso que eu faço. Minha missão é mudar a educação e como tópicos complexos de Inteligência Artificial são ensinados.

se você leva a sério o aprendizado de visão computacional, sua próxima parada deve ser a PyImageSearch University, o curso de visão computacional mais abrangente, aprendizado profundo e OpenCV online hoje. Aqui você aprenderá como aplicar com sucesso e confiança a visão computacional em seu trabalho, pesquisa e projetos. Junte-se a mim no domínio da visão computacional.

dentro da Universidade PyImageSearch você encontrará:

  • &verificar; 30+ cursos no essencial de visão por computador, aprendizagem profunda, e OpenCV tópicos
  • &seleção; 30+ Certificados de Conclusão
  • &seleção; 39h 44m de vídeo on-demand
  • &seleção; Marca novos cursos lançados a cada mês, garantindo assim você pode se manter atualizado com o estado-da-arte das técnicas
  • &de seleção; Pré-configurado Jupyter Notebooks no Google Colab
  • &seleção; Executar todos os exemplos de código a seguir em seu navegador da web — funciona em Windows, macOS e Linux (não dev configuração de ambiente necessárias!)
  • &verificar; Acesso a repositórios de código centralizados para todos os mais de 500 tutoriais no PyImageSearch
  • &verifique; downloads fáceis com um clique para código, conjuntos de dados, modelos pré-treinados, etc.
  • & verificar; acesso no celular, laptop, desktop, etc.

Clique aqui para participar PyImageSearch Universidade

Resumo

neste post do blog aprendemos a detectar legível por Máquina Zonas (MRZs) no passaporte exames usando apenas o básico de técnicas de processamento de imagem, nomeadamente:

  • Limiar.
  • gradientes.
  • operações morfológicas (especificamente, fechamentos e erosões).
  • propriedades do contorno.

essas operações, embora simples, nos permitiram detectar as regiões MRZ em imagens sem ter que confiar em métodos mais avançados de extração de recursos e aprendizado de máquina, como SVM + HOG Linear para detecção de objetos.

lembre-se, quando confrontado com um problema de visão de computador desafiador — sempre considere o problema e suas suposições! Como esta postagem do blog demonstra, você pode se surpreender com as funções básicas de processamento de imagem usadas em conjunto.

mais uma vez, um grande agradecimento ao Membro do Pyimagesearch Gurus, Hans Boone, que nos forneceu essas imagens de passaporte de exemplo! Obrigado Hans!

Leave a Reply

O seu endereço de email não será publicado.