5.5. Regiões e máscaras¶
Por omissão, todas as operações do módulo image afetam todos os pixels da imagem de origem. Este é o comportamento mais simples de descrever, e o correto quando o algoritmo atua genuinamente sobre o fotograma inteiro – uma correção de cor uniforme, um histograma global, uma passagem de codificação para transmissão. Mas a maioria dos algoritmos, na prática, precisa de analisar menos do que isso. Um rastreador de manchas que monitoriza um marcador colorido preocupa-se apenas com a parte da cena onde o marcador pode aparecer, não com a parede atrás dele. Uma passagem de limpeza morfológica só é segura sobre os pixels que uma etapa anterior identificou como candidatos. Um detetor de faces pode apenas ser executado dentro da caixa delimitadora que um detetor menos preciso já restringiu. O módulo image suporta esse trabalho através de dois mecanismos que limitam uma operação a um subconjunto de pixels: regiões de interesse retangulares e máscaras binárias. Estes mecanismos compõem-se livremente, e quase todos os métodos que tocam em pixels aceitam um ou outro – ou ambos – como argumento de palavra-chave.
5.5.1. Regiões de interesse¶
Uma região de interesse é um retângulo de pixels identificado pelo quádruplo (x, y, w, h) apresentado na página de coordenadas. Cerca de trinta métodos da superfície aceitam um argumento de palavra-chave roi; quando presente, a operação é executada apenas sobre os pixels dentro desse retângulo e deixa o resto da imagem intocado. Quando roi é None ou omitido, a operação é executada sobre toda a imagem – o mesmo que se tivesse sido passado roi=(0, 0, width, height).
No código, o argumento de palavra-chave aparece a par dos restantes argumentos que a operação aceita:
# Compute a histogram over a centred crop of the image.
h = img.get_histogram(roi=(64, 64, 128, 128))
O primeiro benefício das ROIs é o controlo de falsos positivos. Um rastreador de cores que só analisa a mesa nunca será acionado pelo casaco que passa à sua frente; um detetor de arestas que só é executado dentro da área de trabalho definida nunca reportará as arestas do próprio suporte da câmara. Reduzir a área de pesquisa à parte da cena que o algoritmo realmente considera é a melhoria mais económica que um pipeline pode fazer à sua própria fiabilidade.
O segundo benefício é o pipeline do grosseiro para o fino. Os objetos de resultado de deteção – um blob, um rect, um apriltag, entre outros – expõem as suas caixas delimitadoras como o mesmo quádruplo (x, y, w, h) que roi aceita. Assim, uma primeira etapa grosseira pode devolver uma caixa delimitadora, essa caixa é passada diretamente para o roi da etapa seguinte, e a segunda etapa é executada sobre a área mais restrita. Cada refinamento progressivo tanto acelera a etapa seguinte como torna os seus resultados mais fiáveis, porque o espaço de pesquisa já foi filtrado.
5.5.2. Máscaras binárias¶
Um retângulo é a forma adequada quando a área de interesse está alinhada com os eixos. Quando não está – uma região curva, uma região não convexa, os pixels que uma etapa anterior classificou como «correspondências» – a operação tem de ser instruída a limitar-se a um padrão arbitrário de pixels. O mecanismo para isso é uma máscara binária: uma Image separada, com as mesmas dimensões que a origem, usada como um interruptor ligado/desligado por pixel. Um pixel diferente de zero na máscara indica «incluir o pixel de origem correspondente»; um pixel a zero indica «deixar o pixel de origem intocado».
Uma máscara é normalmente uma imagem BINARY – o formato de um bit por pixel que existe precisamente para este propósito – mas qualquer imagem de canal único funciona, porque o consumidor trata qualquer valor diferente de zero como ligado.
Os métodos de filtragem, limiarização e aritmética aceitam um argumento de palavra-chave mask. A forma é a mesma em cada um: uma imagem binária alocada separadamente, com as mesmas dimensões que a origem, passada diretamente.
As ROIs e as máscaras compõem-se. Passando ambas, a operação é executada apenas sobre os pixels que estão dentro da ROI e ativos na máscara. Os dois mecanismos fornecem ao código da aplicação controlos independentes – um para a área retangular de interesse, outro para o padrão arbitrário dentro dela – sem que nenhuma das formas herde restrições da outra.
Uma ROI confina uma operação a um retângulo alinhado com os eixos. Uma máscara restringe-a ainda mais a um padrão arbitrário de pixels. Os dois compõem-se: apenas os pixels dentro da ROI e ativos na máscara são modificados.¶
5.5.3. Construção de máscaras¶
Três métodos de Image constroem geometrias de máscara comuns no próprio objeto, zerando os pixels fora da região escolhida:
mask_rectangle()mantém um retângulo.mask_circle()mantém um círculo.mask_ellipse()mantém uma elipse.
Cada um aceita (x, y, w, h) (para o retângulo e a elipse) ou (x, y, radius) (para o círculo). Chamar qualquer um deles sem argumentos centra a geometria e dimensiona-a para preencher a imagem, que é a forma usada por uma aplicação quando o objetivo é um óvalo ou círculo simples sobre toda a imagem que oculta apenas os cantos.
mask = image.Image(img.width(), img.height(), image.BINARY)
mask.clear() # start from all zeros
mask.mask_ellipse() # centred, full-size oval
As máscaras mais interessantes raramente resultam apenas dos métodos mask_*. Provêm de etapas anteriores do pipeline: uma passagem de limiarização produz uma imagem binária cujos pixels diferentes de zero marcam as correspondências, exatamente a forma certa para alimentar o argumento mask= da etapa seguinte. Uma passagem de limpeza morfológica refina essa máscara sem alterar a sua forma. Qualquer resultado que seja uma imagem de canal único é, em si mesmo, uma máscara válida.
5.5.4. Como as operações modificam a imagem¶
Um padrão visível em todos os fragmentos de código das últimas páginas – a operação devolver o mesmo img para encadeamento – merece ser explicitado para não ter de ser repetido cada vez que um novo método é apresentado. Na superfície de Image surgem três famílias de métodos, cada uma tratando a imagem de origem de forma diferente:
Métodos de operação modificam os pixels da origem no próprio objeto e devolvem a mesma imagem para encadeamento. As famílias de desenho, aritmética, limiar e filtro comportam-se desta forma.
img.gaussian(1)desfocaimge devolve o mesmoimg; reatribuir –img = img.gaussian(1)– é inócuo mas desnecessário.Métodos de conversão operam no próprio objeto por omissão, da mesma forma que os métodos de operação, mas aceitam
copy=Trueecopy_to_fb=Truepara alocar uma imagem de resultado separada quando a origem precisa de ser preservada. As conversões de formato e as cópias geométricas são os principais membros desta família.Métodos de inspeção leem os pixels e devolvem um objeto de resultado – uma lista de características detetadas, um histograma, um conjunto de estatísticas – sem modificar a imagem de origem.
Esta tricotomia é consistente em toda a superfície. Saber a que família pertence um método indica à aplicação o que esperar de uma chamada: se os pixels da origem vão sobreviver intactos, se uma imagem de resultado separada vai ser alocada, e se o valor de retorno é a própria origem ou outra coisa.