5.21. Escalonar, espelhar e recortar¶
As subseções anteriores trabalhavam todas com pixels nas mesmas posições em que começaram. A família transform muda isso. O escalonamento envia cada pixel de entrada para uma posição de saída diferente, possivelmente para várias posições de saída ao mesmo tempo (ao ampliar) ou para uma posição compartilhada com vários outros pixels de entrada (ao reduzir). Espelhar e rotacionar fazem a mesma coisa por meio de um mapeamento diferente. Recortar mantém um subconjunto retangular dos pixels de entrada e descarta o resto.
O módulo image expõe essa família por meio de três métodos que compartilham a maior parte de seus argumentos e a maior parte de seu comportamento:
copy()– produz uma cópia da imagem, possivelmente escalonada, recortada ou reorientada.crop()– a mesma operação quecopy, mas com a expectativa de que a aplicação vá selecionar um subretângulo da fonte.scale()– novamente o mesmo, com a expectativa de que a aplicação vá redimensionar o resultado.
Os três compartilham os mesmos argumentos e a mesma maquinaria de transformação; a diferença está em onde o resultado é colocado por padrão. copy() produz uma nova imagem, enquanto crop() e scale() modificam a fonte no lugar.
5.21.2. Interpolação: AREA, BILINEAR, BICUBIC¶
Quando o escalonamento envia cada pixel de saída para uma posição que não se alinha com nenhum pixel de entrada único, o método precisa escolher qual valor escrever. Três sinalizadores controlam como:
image.BILINEAR interpola entre os quatro pixels de entrada mais próximos ponderados por sua distância em relação à posição de saída. O resultado é mais suave do que o vizinho mais próximo, sem serrilhados visíveis em linhas diagonais, mas a aritmética extra custa cerca de quatro vezes a passagem de vizinho mais próximo. A escolha certa para a maioria dos trabalhos de ampliação e para qualquer fator de escala não inteiro.
image.BICUBIC interpola entre os dezesseis pixels de entrada mais próximos usando uma curva cúbica, o que produz resultados ainda mais suaves ao custo de mais aritmética novamente. Melhor qualidade para as aplicações sensíveis ao custo que precisam dela; raramente vale a computação extra para quadros ao vivo que o IDE apenas exibirá.
image.AREA faz a média de cada pixel de entrada que cai dentro da área de cobertura do pixel de saída – o algoritmo certo para redução. Bilinear e bicúbico são interpoladores: eles estimam um valor entre pixels da fonte, que é o que a ampliação precisa, mas na redução cada pixel de saída cobre muitos pixels da fonte e um interpolador lê apenas os poucos mais próximos – o detalhe que ele pula retorna como aliasing. image.AREA incorpora cada pixel coberto na média em vez disso.
O algoritmo de escalonamento padrão sem nenhum hint é o vizinho mais próximo, que é o mais barato e a resposta certa quando a fonte já está na resolução de pixel do destino.
5.21.3. Orientação: espelhamentos e rotações¶
Os sinalizadores de orientação são um pequeno conjunto de transformações booleanas que se compõem livremente entre si e com os sinalizadores de interpolação:
image.VFLIPespelha a imagem verticalmente (o topo se torna a base).image.HMIRRORespelha a imagem horizontalmente (a esquerda se torna a direita).image.TRANSPOSEtroca os eixos x e y (linhas se tornam colunas).
A maioria das rotações vem da composição desses três. O módulo também expõe atalhos nomeados:
image.ROTATE_90(=VFLIP | TRANSPOSE)image.ROTATE_180(=HMIRROR | VFLIP)image.ROTATE_270(=HMIRROR | TRANSPOSE)
Em código:
img.copy(hint=image.ROTATE_90, copy_to_fb=True)
5.21.4. Tratamento de proporção¶
Quando a proporção de aspecto da fonte não corresponde ao retângulo em que está sendo desenhada, três sinalizadores decidem o que fazer com a incompatibilidade:
image.SCALE_ASPECT_KEEP preserva a proporção de aspecto da fonte e aplica letterbox ao resultado – a fonte é escalonada até caber dentro do destino, com pixels vazios (zero) preenchendo o restante do destino. A escolha certa quando manter a fonte sem distorção importa mais do que preencher toda a saída.
image.SCALE_ASPECT_EXPAND preserva a proporção de aspecto da fonte e a recorta – a fonte é escalonada até preencher o destino, com as partes que se estendem além do destino cortadas. A escolha certa quando preencher toda a saída importa mais do que ver cada parte da fonte.
image.SCALE_ASPECT_IGNORE ignora a proporção de aspecto e estica a fonte para preencher o destino, aceitando qualquer distorção que isso introduza. A escolha certa quando a aplicação já levou em conta a distorção – quando as dimensões do destino não são, na verdade, um retângulo da mesma cena, por exemplo.
O padrão (nenhum sinalizador de aspecto definido) é o mesmo que SCALE_ASPECT_IGNORE: esticar para preencher. As aplicações que se importam com a proporção de aspecto especificam um dos três explicitamente.
5.21.5. Quando usar cada um¶
A maioria dos redimensionamentos usa scale() com um par x_scale / y_scale e um hint de interpolação:
img.scale(x_scale=0.5, y_scale=0.5, hint=image.AREA)
A maioria das rotações usa a mesma chamada com hint=image.ROTATE_90 ou similar.
O recorte usa crop() com um roi não padrão:
img.crop(roi=(40, 30, 200, 150))
Quando a fonte precisa sobreviver à operação – capturar um quadro de referência, tirar uma miniatura de um quadro que está prestes a ser processado de forma destrutiva – copy() produz o resultado como uma nova imagem e deixa a fonte intocada:
thumbnail = img.copy(x_scale=0.25, y_scale=0.25, hint=image.AREA)
Esse padrão é a real diferença por trás dos três nomes: scale e crop transformam no lugar, copy aloca. As palavras-chave de colocação do resultado fazem a ponte: copy=True em scale ou crop aloca o resultado como um buffer de heap separado em vez de sobrescrever a fonte, e copy_to_fb=True em qualquer um dos três o coloca no frame buffer para a pré-visualização do IDE.