5.20. Regressão e similaridade¶
Mais duas medições na classe Image resumem a imagem como algo diferente de uma distribuição de valores de pixels. A regressão linear de pixels limiarizados dá a uma aplicação uma linha sobre a qual ela pode agir – a entrada clássica para um robô seguidor de linha. A medição de similaridade dá a uma aplicação um único número que descreve o quão parecidas duas imagens são – a entrada natural para um teste de regressão de imagem de referência (golden image) ou um detector de mudanças grosseiras.
5.20.1. Regressão linear¶
Quando os pixels de primeiro plano de uma imagem por acaso formam uma linha através do quadro – a fita em uma pista que um robô está seguindo, a linha de um horizonte, a borda de uma estrada ou de um corredor – a aplicação geralmente não quer cada pixel individual de primeiro plano. Ela quer a linha de melhor ajuste através de todos eles, parametrizada para que possa decidir como a linha está orientada e onde ela cruza o quadro.
get_regression() faz esse ajuste. Ela recebe a mesma forma de tupla de limiar que binary() e find_blobs() usam, identifica cada pixel que corresponde ao limiar e retorna um único resultado line que descreve a linha de melhor ajuste através desses pixels:
line = img.get_regression([(0, 60)])
if line:
img.draw_line((line.x1(), line.y1(),
line.x2(), line.y2()),
color=(255, 0, 0))
O ajuste é a regressão linear de Theil-Sen – um método robusto que tolera outliers melhor do que o ajuste de mínimos quadrados, mais familiar. Um pequeno punhado de pixels distantes da linha verdadeira não distorce o resultado como o faria com mínimos quadrados, o que combina com a realidade de primeiro plano ruidoso de uma saída de limiar real.
O resultado line carrega os pontos finais recortados para o retângulo da imagem (x1, y1, x2, y2), o comprimento e a magnitude da linha (length, magnitude) e a descrição geométrica da linha em forma polar (theta, rho) – o ângulo da linha em relação à horizontal e sua distância perpendicular à origem. A forma polar é o que um laço de controle geralmente quer: theta diz ao robô para que lado a linha está inclinada, rho diz onde a linha cruza a imagem, e um laço de realimentação sobre os dois mantém o robô centrado na linha.
Um punhado de argumentos de palavra-chave ajusta a robustez e o custo. x_stride e y_stride pulam pixels durante o ajuste – passos maiores tornam a regressão mais barata ao custo de ajustar menos pixels. area_threshold e pixels_threshold rejeitam linhas que não têm pixels correspondentes suficientes por trás delas. target_size reescala a entrada para um tamanho menor antes do ajuste – a regressão roda mais rápido em um substituto de 80 por 60 da imagem sem muita perda na precisão da direção da linha.
Se nenhuma linha aceitável pôde ser ajustada – se o limiar não correspondeu a nenhum pixel, ou correspondeu a um padrão que não se parece com uma linha – o método retorna None. Um código real de seguimento de linha protege cada chamada a get_regression() com uma verificação de None antes de acessar os atributos da linha.
5.20.2. Similaridade de imagens¶
Um tipo diferente de medição: em vez de perguntar “o que a imagem contém?”, pergunta “o quão parecidas são estas duas imagens?”. A operação a ser usada é get_similarity(), que computa o Índice de Similaridade Estrutural (SSIM) entre a imagem fonte e uma imagem de referência.
s = img.get_similarity(reference)
print(s.mean, s.stdev)
O SSIM é a métrica padrão de similaridade de imagens usada em todo o processamento de imagens porque se comporta da forma como a intuição humana sobre similaridade se comporta – um pequeno deslocamento ou uma pequena mudança de brilho reduz a pontuação ligeiramente, enquanto uma grande mudança estrutural (objeto ausente, cena diferente) a reduz drasticamente. A pontuação varia de -1 a +1: +1 significa que as duas imagens são idênticas, 0 significa que não têm relação e -1 significa que são estruturalmente opostas. Um objeto similarity retornado expõe o SSIM médio em toda a imagem, além do desvio padrão, mínimo e máximo das pontuações por tile.
Para o tipo de comparação em que um número pequeno é melhor do que um grande – um teste de regressão que deve relatar zero em “nada mudou” e crescer à medida que as mudanças se acumulam – a flag dssim=True retorna a dissimilaridade estrutural: o SSIM médio subtraído de 1, de modo que o valor de retorno é 0.0 para imagens idênticas e cresce à medida que elas diferem.
5.20.3. Casos de uso para SSIM¶
As duas aplicações comuns:
Teste de regressão com imagem de referência (golden image). Um framework de teste captura um quadro de referência sob condições reconhecidamente boas e o armazena como a imagem de referência. Execuções de teste subsequentes capturam sob as mesmas condições e comparam com a imagem de referência usando SSIM. Uma pontuação acima de algum limiar (0.95 ou 0.98 dependendo da tolerância) é uma aprovação; abaixo é uma falha. O framework de teste não precisa saber o que mudou – a pontuação SSIM é o sinal.
Detecção de mudanças grosseiras. Uma aplicação que quer uma versão mais grosseira da diferenciação de quadros – uma que ignore pequenas mudanças de brilho mas reaja a grandes mudanças estruturais – pode usar SSIM contra um quadro de referência em vez da difference() por pixel seguida de um limiar. O SSIM é menos sensível à deriva de iluminação do que a diferenciação por pixel, o que o torna a melhor escolha quando o objetivo é detectar que “a cena parece materialmente diferente” em vez de que “algum pixel individual mudou.”
Ambas as aplicações usam a mesma chamada – img.get_similarity(reference) – e disparam com base em um limiar da pontuação retornada. A diferença é apenas se o limiar é alto (teste de regressão, procurando uma correspondência quase idêntica) ou baixo (detecção de mudanças, procurando qualquer grande mudança estrutural).
5.20.4. A forma de transformar e comparar¶
Uma sutileza útil: get_similarity() aceita os mesmos parâmetros x, y, x_scale, y_scale, roi, rgb_channel, alpha, color_palette, alpha_palette, hint e transform que draw_image(). A imagem de referência é posicionada, escalada e transformada por esses parâmetros antes de a comparação SSIM rodar.
Isso significa que uma aplicação pode perguntar “o quão similar é esta cena a um quadro de referência após um deslocamento / rotação / escala conhecidos” sem preparar uma imagem de referência pré-transformada. É a maneira barata de construir um rastreador que pesquisa um espaço de parâmetros e relata qual transformação da referência melhor corresponde ao quadro atual.