5.30. Correspondência de modelos

Os detetores abordados até agora respondem a questões sobre o conteúdo de um único fotograma: onde estão as manchas, por onde passam as linhas, o que diz um código impresso. Uma classe diferente de questões compara uma imagem com outra. Esta região do fotograma capturado parece-se com o recorte de referência que guardei na calibração? Os métodos de correspondência respondem a essa questão.

A análise tonal e estatística introduziu get_similarity() para a questão relacionada – quão semelhantes são no geral estas duas imagens do mesmo tamanho? – usando SSIM como métrica subjacente. A questão de correspondência restante é a da localização: não «quão semelhantes são estas duas imagens» mas «onde dentro desta imagem maior aparece esse recorte mais pequeno?» A ferramenta certa para a questão de localização é a correspondência de modelos.

5.30.1. A chamada básica

find_template() procura o primeiro local onde uma imagem de modelo pequena aparece no fotograma capturado. A implementação usa correlação cruzada normalizada (NCC): o modelo desliza pelo fotograma, a pontuação de correspondência por posição é calculada a partir da correlação entre os pixels do modelo e os pixels subjacentes do fotograma (normalizada em relação às médias e variâncias locais para que variações de ganho não iludam a correspondência), e a primeira posição cuja pontuação ultrapassa threshold é devolvida como caixa delimitadora:

template = image.Image("/sdcard/template.bmp", copy_to_fb=False)
template.to_grayscale()

match = img.find_template(template, threshold=0.7,
                           search=image.SEARCH_DS)

if match is not None:
    img.draw_rectangle(match, color=(255, 0, 0))

O método só funciona em imagens em escala de cinzentos. Capture em escala de cinzentos (a escolha natural para qualquer câmara sem sensor de cor), ou converta no local com to_grayscale() antes da chamada. O mesmo se aplica ao modelo carregado do disco: um modelo a cores é convertido com o mesmo método, e o resultado é o que o correspondente espera.

threshold é um número de vírgula flutuante entre 0.0 e 1.0. Um valor de 1.0 exige uma correspondência perfeita pixel a pixel (o que nunca acontece com imagens reais capturadas), 0.0 aceita qualquer coisa, e valores entre 0.6 e 0.8 cobrem o caso comum em que o modelo foi capturado sob iluminação semelhante e a cena não mudou dramaticamente. Aumente o limiar para suprimir falsos positivos; diminua-o para aceitar correspondências com mais ruído ao custo de mais resultados espúrios.

5.30.2. Estratégia de pesquisa

search escolhe entre duas estratégias. image.SEARCH_EX é a pesquisa exaustiva: o modelo desliza por cada posição de step pixels no fotograma e devolve o primeiro resultado acima do limiar. image.SEARCH_DS é a pesquisa em losango: o correspondente faz amostragem grosseira primeiro e depois refina em torno da melhor pontuação, o que é significativamente mais rápido mas pode falhar uma correspondência real se o passo grosseiro tiver ficado perto de um máximo local que supera o global. Para um pipeline em tempo real onde o modelo está bem definido e dificilmente será confundido, SEARCH_DS é o padrão adequado; para uma calibração pontual onde o custo de uma falha é maior do que o custo de uma pesquisa mais lenta, SEARCH_EX é mais seguro.

step controla o salto em pixels durante o passo exaustivo (a pesquisa em losango gere o seu próprio passo). Valores maiores de step aceleram a pesquisa ao custo de precisão subpixel. roi restringe a pesquisa a uma região do fotograma, limitando o que o correspondente considera e reduzindo o trabalho.

O valor devolvido é um tuplo de caixa delimitadora (x, y, w, h) que identifica a melhor correspondência, ou None se nenhuma posição ultrapassou o limiar. A caixa delimitadora pode ser passada diretamente para draw_rectangle() ou crop() para a fase seguinte do processamento.

5.30.3. A armadilha da escala e rotação

O problema clássico da correspondência de modelos é a sensibilidade à escala e rotação. O correspondente compara o modelo com o fotograma pixel a pixel; um modelo capturado a uma determinada distância não corresponde ao mesmo objeto capturado a uma distância diferente, e um modelo capturado de frente não corresponde ao mesmo objeto visto de lado. O limiar desce silenciosamente abaixo do nível de correspondência mesmo quando o objeto é claramente visível ao olho humano, e o método devolve None.

Existem alguns contornos para os casos simples. A aplicação pode capturar múltiplos modelos a diferentes escalas e executar find_template() para cada um em sequência, aceitando o primeiro que ultrapassa o limiar; o custo escala com o número de modelos. A aplicação pode pré-processar o fotograma com rotation_corr() ou a transformação polar (Transformações geométricas) para remover a rotação problemática antes de executar a correspondência; o modelo correspondido ainda tem de corresponder à geometria corrigida.

Um idioma útil para pipelines de inspeção de controlo de qualidade combina o correspondente de modelos com o pontuador de semelhança introduzido na análise tonal e estatística: find_template() localiza a peça no fotograma capturado e a caixa delimitadora devolvida é recortada e passada para get_similarity() em relação ao recorte de referência. O passo de correspondência de modelos decide onde está a peça; o passo de pontuação de semelhança decide se a peça é aceitável. Os dois passos são executados em cada fotograma, o limiar em mean é a condição de aprovação/reprovação, e a caixa delimitadora correspondida desenhada de volta no fotograma é a pré-visualização no IDE que o operador observa.