Exemplos do ImageMagick -- Camadas de Múltiplas Imagens
- Prefácio e Índice dos Exemplos do ImageMagick
- Introdução às Camadas
- Concatenação de Imagens (Append) (-append)
- Concatenar um Arranjo de Imagens
- Concatenar com Sobreposição
-
Concatenação por Smush (Smushing) (-smush)
-
Usando o Comando Composite (composite, -geometry)
- Operador Composite do Convert (-composite, -geometry)
-
Desenhar Múltiplas Imagens (-draw 'image ..')
- Mosaicos - Expansão da Tela
- Merge - para Criar uma Nova Imagem de Camada
- Composição Coalesce - uma Formação Progressiva de Camadas
- Métodos de Composição e Camadas
- Posicionamento Calculado de Imagens
- Posicionamento de Imagens em Dois Estágios
- Alfinetes em um Mapa
- Camadas de Sombras
-
Posicionamento de Imagens Distorcidas usando Camadas
Merge de Múltiplas Imagens com Evaluate Sequence
Média (Mean), Valor Mín/Máx, Pixel Mediano, Adição (Add), Multiplicação (Multiply) Poly - Mesclar Múltiplas Imagens com um Polinômio Sobrepor várias imagens umas sobre as outras para gerar um 'composto' maior é geralmente conhecido como o uso de 'camadas' (layering) de imagens. Estes exemplos envolvem a combinação de múltiplas 'camadas' de imagens para produzir a imagem final, maior e mais complexa.
Introdução às Camadas de Imagens
Como já observamos, o ImageMagick não lida com apenas uma imagem, mas com uma sequência ou lista de imagens. Isso permite usar o IM em duas técnicas de processamento de imagem muito especiais. Pode-se, por exemplo, pensar em cada imagem da lista como um único quadro no tempo, de modo que a lista inteira possa ser considerada uma Animação. Isso será explorado em outras Páginas de Exemplos do IM. Consulte Fundamentos de Animação. Como alternativa, pode-se pensar em cada imagem da sequência como Camadas de um conjunto de transparências sobrepostas. Ou seja, cada imagem representa uma pequena parte da imagem final. Por exemplo: a primeira camada (a mais baixa) pode representar uma imagem de fundo. Acima dela pode haver uma sombra difusa e translúcida. A camada seguinte contém o objeto que projeta essa sombra. Sobre ela, uma camada com algum texto escrito sobre esse objeto. Ou seja, é possível ter uma sequência de imagens ou 'camadas', cada uma acrescentando mais uma parte a uma imagem muito mais complexa. Cada camada de imagem pode ser movida, editada ou modificada de forma completamente independente de qualquer outra camada, e até salva em um arquivo de múltiplas imagens (como TIFF:, MIFF: ou XCF:) ou como imagens separadas, para processamento futuro. E esse é o objetivo das camadas de imagem. Somente depois que todas as camadas de imagem tiverem sido criadas é que se aplica Flatten, Mosaic ou Merge a todas as Imagens em Camadas para formar uma única imagem final.
Concatenação de Imagens (Append)
A concatenação (append) é provavelmente a mais simples das operações de múltiplas imagens fornecidas para lidar com várias imagens. Basicamente, ela une a sequência atual de imagens na memória em uma coluna ou uma linha, sem espaços. A opção "[-append](https://imagemagick.org/command-line-options/#append)" concatena verticalmente, enquanto a forma com sinal de mais "[+append](https://imagemagick.org/command-line-options/#append)" concatena horizontalmente. Por exemplo, aqui concatenamos um conjunto de imagens de letras lado a lado, para formar uma palavra vistosa, de maneira semelhante à forma como 'glifos' ou letras individuais de uma 'fonte' são unidos.
magick font_A.gif font_P.gif font_P.gif font_E.gif font_N.gif \
font_D.gif font_E.gif font_D.gif +append append_row.gif
O exemplo acima é semelhante (de modo bem básico) à forma como as fontes são tratadas. Ao contrário das fontes reais, não há limitação a apenas duas cores; é possível gerar alfabetos coloridos e bastante elaborados a partir de imagens de caracteres individuais. Muitas dessas 'fontes de imagem' estão disponíveis na WWW para download. Um pequeno conjunto pode ser encontrado na Biblioteca de Ícones do Anthony, em Fonts for Text and Counters, que é também onde foi encontrada a Fonte Blue Bubble usada acima. Note também como o operador "[+append](https://imagemagick.org/command-line-options/#append)" foi executado como última operação, depois que todas as imagens que se deseja concatenar já haviam sido adicionadas à sequência de imagens atual. Isso é excelente para acrescentar um rótulo a uma imagem, por exemplo... |
magick rose: -background LawnGreen label:Rose \
-background white -append append_label.jpg
![[IM Output]](../static/img/layers/append_label.jpg)
Note que a cor de "[-background](https://imagemagick.org/command-line-options/#background)" foi usada para preencher qualquer espaço que não tivesse sido ocupado. É claro que, se todas as imagens tiverem a mesma largura, nenhum espaço restará para esse preenchimento. A partir do IM v6.4.7-1, a configuração "[-gravity](https://imagemagick.org/command-line-options/#gravity)" pode ser usada para especificar como as imagens devem ser reunidas. Assim, em uma concatenação vertical, o valor 'Center' centraliza a imagem em relação à imagem final resultante (o mesmo ocorre com 'North' ou 'South'). |
magick rose: -background LawnGreen label:Rose \
-background white -gravity center -append \
append_center.jpg
![[IM Output]](../static/img/layers/append_center.jpg)
Naturalmente, qualquer valor de gravity 'East' alinha as imagens pelo lado direito. |
magick rose: -background LawnGreen label:Rose \
-background white -gravity east -append \
append_east.jpg
![[IM Output]](../static/img/layers/append_east.jpg)
Um alinhamento vertical semelhante pode ser obtido ao usar "[+append](https://imagemagick.org/command-line-options/#append)" | _Antes do IM v6.4.7 era bem mais difícil alinhar imagens concatenadas, o que geralmente envolvia usar um "[-flop](https://imagemagick.org/command-line-options/#flop)" para alinhamento à direita. Ou usar "[-extent](https://imagemagick.org/command-line-options/#extent)" ou "[-border](https://imagemagick.org/command-line-options/#border)" para ajustar a largura da imagem em concatenações com alinhamento centralizado.
Por exemplo, isto funciona com uma versão mais antiga 6.3.2 do IM..._ | |
magick rose: -background SkyBlue label:Rose \
-background White -gravity center -extent 200x \
-append -trim +repage append_center_old.jpg
![[IM Output]](../static/img/layers/append_center_old.jpg)
Também é possível usar múltiplas operações de concatenação, no mesmo comando, sem conflito ou confusão quanto ao resultado das operações (o que não era o caso antes do IM v6). |
magick font_{0,0,6,1,2}.gif +append dragon_long.gif \
-background none -append append_multi.gif
![[IM Output]](../static/img/layers/append_multi.gif)
Concatenamos cada linha de imagens e, em seguida, concatenamos uma imagem maior abaixo dela. Isso é bem simples e direto. Usando parênteses, é possível concatenar apenas os números depois da imagem maior. Por exemplo, aqui concatenamos todos os números antes de concatená-los verticalmente à imagem do dragão que foi lida antes dos números. |
magick dragon_long.gif '(' font_{0,0,6,2,9}.gif +append ')' \
-background none -append append_parenthesis.gif
![[IM Output]](../static/img/layers/append_parenthesis.gif)
| Os parênteses no exemplo acima devem ser colocados entre aspas ou escapados com uma barra invertida ('\') quando usados em um shell UNIX; caso contrário, serão interpretados pelo shell como algo completamente diferente.
---|---
| Como apenas duas imagens estavam envolvidas, poderíamos ter usado "[+swap](https://imagemagick.org/command-line-options/#swap)" ou "[-reverse](https://imagemagick.org/command-line-options/#reverse)" em vez de parênteses.
---|---
Concatenar um Arranjo de Imagens
É possível ir além e montar um arranjo inteiro de imagens, construindo-o por linhas ou por colunas. |
magick \( font_1.gif font_2.gif font_3.gif +append \) \
\( font_4.gif font_5.gif font_6.gif +append \) \
\( font_7.gif font_8.gif font_9.gif +append \) \
\( -size 32x32 xc:none font_0.gif +append \) \
-background none -append append_array.gif
![[IM Output]](../static/img/layers/append_array.gif)
Tecnicamente, o primeiro conjunto de parênteses não é necessário, pois nenhuma imagem foi lida ainda, mas ele deixa tudo uniforme e evidencia a intenção do comando de montar um arranjo de imagens. Veja também Modo de Concatenação do Montage para uma forma alternativa de criar arranjos de imagens de tamanho igual. | _O operador "[-append](https://imagemagick.org/command-line-options/#append)" concatena apenas as imagens em si e não usa o tamanho da tela virtual (a página da imagem) nem o deslocamento da imagem. No entanto, a informação de tela virtual parece ficar em um estado estranho, com os tamanhos de tela sendo somados e o deslocamento definido para algum valor indefinido.
Isso pode ser considerado um bug, e significa que as imagens de entrada ou o resultado devem ter a tela virtual redefinida com "[+repage](https://imagemagick.org/command-line-options/#repage)" antes de salvar, ou antes de usar a imagem em operações onde essa informação possa se tornar importante.
Essa situação provavelmente será corrigida em alguma expansão futura da operação. Recomenda-se, portanto, cautela, especialmente ao reconcatenar imagens Recortadas em Ladrilhos._
---|---
Concatenar com Sobreposição
No Fórum do IM, um usuário pediu uma forma simples de concatenar imagens com alguma sobreposição. Muitas soluções foram oferecidas. Esta foi uma das mais simples, com a quantidade de sobreposição indicada em um único lugar. |
magick granite: rose: -gravity east -background none \
\( -clone 1 -chop 30x0 \) \( -clone 0,2 +append \) \
-delete 0,2 +swap -composite append_overlap.gif
![[IM Output]](../static/img/layers/append_overlap.gif)
O exemplo acima não precisou de nenhum cálculo de posicionamento de imagem, que normalmente envolveria os tamanhos das imagens e representaria uma solução mais geral. Veja Manipulando Camadas de Imagens abaixo. O que ele fez foi cortar a parte que se sobrepunha, antes de concatenar o resultado à primeira imagem, produzindo o tamanho final da imagem. A imagem original é então composta (com gravity) por cima, para gerar a sobreposição de fato. Ele pode ser facilmente adaptado para sobreposição vertical, ou mesmo para sobreposição da direita para a esquerda, com relativa facilidade.
Concatenação por Smush (Smushing)
Outra forma de concatenar imagens é por smush. O operador "[-smush](https://imagemagick.org/command-line-options/#smush)" funciona de modo muito parecido com o Operador de Concatenação (veja acima), mas recebe um argumento indicando quanto espaço (ou anti-espaço) se quer entre as imagens. Por exemplo, vamos usá-lo para refazer o exemplo anterior de forma mais simples. |
magick granite: rose: -background none -gravity Center \
+smush -20 smush_overlap.png
![[IM Output]](../static/img/layers/smush_overlap.png)
Isso funciona muito bem, embora não seja para isso que o operador foi de fato projetado, e provavelmente seja bem mais lento. O que o smush realmente deve fazer é aproximar 'imagens com forma' o máximo possível. Por exemplo, aqui geramos as letras 'A' e 'V' e as unimos por smush com o menor espaço possível entre elas. |
magick -background none -pointsize 72 \
-fill red label:A -fill blue label:V \
+smush 0 smush_append.png
![[IM Output]](../static/img/layers/smush_append.png)
Note como as duas letras foram concatenadas bem mais próximas do que a concatenação comum faria, aproveitando o espaço vazio da 'forma' das imagens. A folga acima é causada pelos pixels de borda com anti-aliasing das duas letras. É isso que o "[-smush](https://imagemagick.org/command-line-options/#smush)" foi projetado para fazer, embora exija muitos cálculos e, por isso, seja bem mais lento que a Concatenação (veja acima). O argumento é um deslocamento para essa posição final e, em geral, é um valor positivo para gerar uma folga, mas pode ser negativo para criar uma sobreposição. |
magick -background none -pointsize 72 \
-fill red label:A -fill blue label:V \
+smush -15 smush_offset.png
![[IM Output]](../static/img/layers/smush_offset.png)
As imagens podem ser recortadas de formas não documentadas se um valor negativo muito grande for usado.
Composição de Múltiplos Pares de Imagens
A composição é a operação de baixo nível usada para mesclar duas imagens individuais. Quase todas as técnicas de camadas acabam se reduzindo à mesclagem de imagens duas de cada vez, até restar apenas uma imagem. Então, vamos começar examinando formas de fazer a composição de baixo nível de pares de imagens.
Usando o Comando Composite
O método tradicional de combinar duas imagens usando o ImageMagick é através do comando "magick composite". Esse comando só pode combinar duas imagens de cada vez, salvando o resultado de cada operação em um arquivo. É claro que isso não impede usá-lo para empilhar múltiplas imagens em camadas, uma imagem por vez... |
magick -size 100x100 xc:skyblue composite.gif
magick composite -geometry +5+10 balloon.gif composite.gif composite.gif
magick composite -geometry +35+30 medical.gif composite.gif composite.gif
magick composite -geometry +62+50 present.gif composite.gif composite.gif
magick composite -geometry +10+55 shading.gif composite.gif composite.gif
![[IM Output]](../static/img/layers/composite.gif)
| _Como todas as imagens de entrada são lidas pelo ImageMagick ANTES de a imagem de saída ser aberta, é possível gravar a saída em uma das imagens de entrada. Isso permite trabalhar sobre a mesma imagem repetidamente, como mostrado acima, sem problemas.
Não faça isso com um formato de imagem com perdas como o "JPEG", pois os erros de formato são cumulativos e a imagem base se degradará rapidamente._
---|---
Também é possível redimensionar a imagem sobreposta, além de posicioná-la, usando a configuração "[-geometry](https://imagemagick.org/command-line-options/#geometry)". |
magick -size 100x100 xc:skyblue comp_resize.gif
magick composite -geometry 40x40+5+10 balloon.gif comp_resize.gif comp_resize.gif
magick composite -geometry +35+30 medical.gif comp_resize.gif comp_resize.gif
magick composite -geometry 24x24+62+50 present.gif comp_resize.gif comp_resize.gif
magick composite -geometry 16x16+10+55 shading.gif comp_resize.gif comp_resize.gif
![[IM Output]](../static/img/layers/comp_resize.gif)
O comando "magick composite" também tem algumas outras vantagens: é possível controlar a forma como a imagem é desenhada sobre o fundo com a opção "[-compose](https://imagemagick.org/command-line-options/#compose)", e sua posição relativa é afetada pela configuração "[-gravity](https://imagemagick.org/command-line-options/#gravity)". Também é possível aplicar "[-tile](https://imagemagick.org/command-line-options/#tile)" à sobreposição, de modo que ela cubra a imagem de fundo, sem que seja preciso especificar limites de ladrilho. Isso só está disponível ao usar "magick composite". A grande desvantagem desse método é que se usam múltiplos comandos, e o IM precisa gravar a imagem de trabalho, seja em um pipeline, seja em disco, para que o próximo comando a leia novamente. Para mais exemplos de uso do comando "magick composite" para sobrepor imagens sobre outras imagens, veja "Anotando por Sobreposição de Imagens" e "Posicionamento de Imagens usando Gravity".
Operador Composite do Convert
O operador "[-composite](https://imagemagick.org/command-line-options/#composite)" está disponível dentro do comando "magick". Para mais detalhes, veja Composição de Imagens no IM. Ele permite fazer o mesmo que acima, mas tudo em um único comando. |
magick -size 100x100 xc:skyblue \
balloon.gif -geometry +5+10 -composite \
medical.gif -geometry +35+30 -composite \
present.gif -geometry +62+50 -composite \
shading.gif -geometry +10+55 -composite \
compose.gif
![[IM Output]](../static/img/layers/compose.gif)
Isto primeiro cria uma Imagem de Tela na cor "skyblue" e, em seguida, sobrepõe cada uma das imagens seguintes sobre essa tela nas posições indicadas. Agora, o "[-geometry](https://imagemagick.org/command-line-options/#geometry)" é um operador muito especial que não só define a posição de sobreposição para a próxima operação "[-composite](https://imagemagick.org/command-line-options/#composite)", como também aplica "[-resize](https://imagemagick.org/command-line-options/#resize)" à última imagem (e somente à última) da sequência de imagens atual. |
magick -size 100x100 xc:skyblue \
balloon.gif -geometry 40x40+5+10 -composite \
medical.gif -geometry +35+30 -composite \
present.gif -geometry 24x24+62+50 -composite \
shading.gif -geometry 16x16+10+55 -composite \
compose_geometry.gif
![[IM Output]](../static/img/layers/compose_geometry.gif)
Note que é recomendável evitar esse efeito colateral de 'redimensionamento' do "[-geometry](https://imagemagick.org/command-line-options/#geometry)", ainda que seja conveniente. Basicamente, trata-se mais de um efeito de compatibilidade retroativa e pode, em algumas situações, gerar outros efeitos. Segue a recomendação mais explícita... |
magick -size 100x100 xc:skyblue \
\( balloon.gif -resize 40x40 \) -geometry +5+10 -composite \
\( medical.gif \) -geometry +35+30 -composite \
\( present.gif -resize 24x24 \) -geometry +62+50 -composite \
\( shading.gif -resize 16x16 \) -geometry +10+55 -composite \
compose_resize.gif
Desenhar Múltiplas Imagens
Também com "magick" é possível usar Primitivas de Desenho para sobrepor imagens sobre a tela de trabalho. |
magick -size 100x100 xc:skyblue \
-draw "image over 5,10 0,0 'balloon.gif'" \
-draw "image over 35,30 0,0 'medical.gif'" \
-draw "image over 62,50 0,0 'present.gif'" \
-draw "image over 10,55 0,0 'shading.gif'" \
drawn.gif
![[IM Output]](../static/img/layers/drawn.gif)
É claro que também é possível especificar um redimensionamento para a imagem sobreposta... |
magick -size 100x100 xc:skyblue \
-draw "image over 5,10 40,40 'balloon.gif'" \
-draw "image over 35,30 0,0 'medical.gif'" \
-draw "image over 62,50 24,24 'present.gif'" \
-draw "image over 10,55 16,16 'shading.gif'" \
drawn_resize.gif
![[IM Output]](../static/img/layers/drawn_resize.gif)
As imagens 'desenhadas' também podem ser Rotacionadas, Escaladas e Distorcidas por Afinidade durante o processo de sobreposição. Embora possa ser complicado fazê-las funcionar do jeito desejado. As imagens desenhadas são afetadas por "[-gravity](https://imagemagick.org/command-line-options/#gravity)", assim como o texto.
Empilhando Múltiplas Imagens em Camadas
O verdadeiro empilhamento de imagens em camadas exige métodos para combinar múltiplas imagens de uma só vez, sem que seja preciso compor cada par de imagens separadamente. É aqui que os vários métodos do operador [-layers](https://imagemagick.org/command-line-options/#layers) se destacam. A ordem das imagens em camadas pode ser importante, então é uma boa ideia entender os Operadores de Sequência ou Lista de Imagens especiais. Note que 'imagens em camadas' é praticamente idêntico ao tratamento de 'quadros animados'. Assim, recomenda-se também consultar Fundamentos de Animação e Modificações de Animação para técnicas que envolvem o processamento de 'camadas' ou 'quadros' individuais. Na verdade, as animações costumam usar o mesmo operador [-layers](https://imagemagick.org/command-line-options/#layers) para processar imagens.
Flatten - sobre uma Imagem de Fundo
O operador de lista de imagens "[-layers](https://imagemagick.org/command-line-options/#layers) **flatten**" (ou seu atalho "[-flatten](https://imagemagick.org/command-line-options/#flatten)") basicamente faz a "Composição" de cada uma das imagens dadas sobre um fundo, para formar uma única imagem. Contudo, as posições das imagens são especificadas usando seu deslocamento atual de Tela Virtual, ou Página. Por exemplo, aqui crio uma bela tela e especifico cada uma das imagens que quero sobrepor sobre ela. |
magick -size 100x100 xc:skyblue \
-fill dodgerblue -draw 'circle 50,50 15,25' \
\( -page +5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( -page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-layers flatten flatten_canvas.gif
![[IM Output]](../static/img/layers/flatten_canvas.gif)
| _A partir do IM v6.3.6-2, o operador "[-flatten](https://imagemagick.org/command-line-options/#flatten)" é apenas um alias para um método "[-layers](https://imagemagick.org/command-line-options/#layers) 'flatten'".
Assim, a opção "[-flatten](https://imagemagick.org/command-line-options/#flatten)" pode ser considerada um atalho para o método de mesmo nome do "[-layers](https://imagemagick.org/command-line-options/#layers)"._
---|---
Não é necessário criar uma tela inicial como fizemos acima; em vez disso, pode-se deixar o "[-flatten](https://imagemagick.org/command-line-options/#flatten)" criar uma. A cor da tela será a cor "[-background](https://imagemagick.org/command-line-options/#background)" atual, enquanto seu tamanho é definido pelo tamanho da Tela Virtual da primeira imagem. |
magick \( -page 100x100+5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( --page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background dodgerblue -layers flatten flatten_page.gif
![[IM Output]](../static/img/layers/flatten_page.gif)
| _Embora a configuração "[-gravity](https://imagemagick.org/command-line-options/#gravity)" afete o posicionamento de imagens definido por meio das configurações "[-geometry](https://imagemagick.org/command-line-options/#geometry)", ela não afeta o posicionamento de imagens que usa deslocamentos de tela virtual definidos pela configuração "[-page](https://imagemagick.org/command-line-options/#page)". Isso faz parte da definição desses deslocamentos. Veja Deslocamentos de Geometry vs Página para mais detalhes.
Se for necessário posicionar com "[-gravity](https://imagemagick.org/command-line-options/#gravity)", consulte os métodos de composição de múltiplas imagens acima, ou o método especial de Composição por Camadas, que pode lidar com ambos os métodos de posicionamento simultaneamente._
---|---
Se alguma imagem não aparecer na área da tela virtual definida, ela será recortada ou ignorada, conforme apropriado. Por exemplo, aqui usamos um tamanho de tela menor, fazendo com que as imagens posteriores não apareçam por completo nessa tela. |
magick \( -page 75x75+5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( -page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background dodgerblue -flatten flatten_bounds.gif
![[IM Output]](../static/img/layers/flatten_bounds.gif)
O uso normal do Flatten é mesclar múltiplas 'camadas' de imagens. Ou seja, é possível gerar várias partes de uma imagem maior, normalmente usando Parênteses para limitar os operadores de imagem à única 'camada' que está sendo gerada, e depois fazer o flatten do resultado final. Por exemplo, um uso típico é criar uma camada de Imagem de Sombra, sobre a qual a imagem original é achatada. Por exemplo... |
magick balloon.gif \( +clone -background navy -shadow 80x3+5+5 \) +swap \
-background none -flatten flatten_shadow.png
![[IM Output]](../static/img/layers/flatten_shadow.png)
Note que, como quero a sombra sob a imagem original, precisei trocar as duas imagens para colocá-las na ordem correta. | _Usar o Flatten para adicionar Imagens de Sombra geradas não é recomendável, pois imagens de sombra geradas podem ter deslocamentos de imagem negativos.
A solução recomendada, conforme indicado na seção sobre Imagens de Sombra, é usar a técnica mais avançada de Mesclagem de Camadas, que veremos adiante._
---|---
Como a Tela Virtual consiste apenas de um tamanho, a imagem resultante terá esse tamanho, mas não terá deslocamento de tela virtual; assim, não é preciso se preocupar com nenhum deslocamento presente na imagem final. Esse uso da tela virtual para definir a tela sobre a qual sobrepor a imagem significa que é possível usá-la para adicionar uma borda ao redor de uma imagem. Por exemplo, aqui defino o tamanho e o deslocamento virtual de uma imagem para 'preencher' uma imagem até um tamanho específico. |
magick medical.gif -set page 64x64+20+20 \
-background SkyBlue -flatten flatten_padding.gif
![[IM Output]](../static/img/layers/flatten_padding.gif)
É claro que há maneiras melhores de Preencher uma Imagem de modo que o IM centralize automaticamente a imagem na área maior. Curiosamente, o mesmo tratamento pode ser usado para 'aparar' ou Recortar uma imagem em uma tela virtual menor que a imagem original. Nesse caso, porém, deve-se usar um deslocamento negativo para posicionar o 'recorte', pois você está deslocando a imagem, e não posicionando a 'janela' de recorte. |
magick logo: -repage 100x100-190-60 -flatten flatten_crop.gif
![[IM Output]](../static/img/layers/flatten_crop.gif)
É claro que um Recorte por Viewport também faria isso melhor, sem o processamento extra de geração de tela e sobreposição que o "[-flatten](https://imagemagick.org/command-line-options/#flatten)" também realiza. Ele também não 'expande' a própria imagem para cobrir todo o viewport se a imagem estava apenas parcialmente contida nessa janela de visualização. Um uso indevido comum do operador "[-flatten](https://imagemagick.org/command-line-options/#flatten)" é Remover a Transparência de uma imagem. Ou seja, eliminar qualquer transparência que uma imagem possa ter, sobrepondo-a à cor de fundo. Contudo, isso não funciona quando múltiplas imagens estão envolvidas e, por isso, não é mais recomendado.
Mosaic - Expansão da Tela
O operador "[-layers](https://imagemagick.org/command-line-options/#layers) **mosaic**" (ou seu atalho "[-mosaic](https://imagemagick.org/command-line-options/#mosaic)") é mais como uma versão de tela expansível do Operador Flatten. Em vez de criar uma tela inicial baseada apenas no tamanho de tela da imagem inicial, o Operador Mosaic cria uma tela grande o suficiente para conter todas as imagens (apenas na direção positiva). Por exemplo, aqui nem sequer defino uma Tela Virtual apropriada; ainda assim, o operador "[-mosaic](https://imagemagick.org/command-line-options/#mosaic)" calcula o tamanho necessário dessa tela para conter todas as camadas de imagem. |
magick \( -page +5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( -page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background dodgerblue -layers mosaic mosaic.gif
![[IM Output]](../static/img/layers/mosaic.gif)
| _A partir do IM v6.3.6-2, o operador "[-mosaic](https://imagemagick.org/command-line-options/#mosaic)" é apenas um alias para um "[-layers](https://imagemagick.org/command-line-options/#layers) 'mosaic'".
Assim, a opção "[-mosaic](https://imagemagick.org/command-line-options/#mosaic)" pode ser considerada um atalho para o método de mesmo nome do "[-layers](https://imagemagick.org/command-line-options/#layers)"._
---|---
Note que tanto o "[-mosaic](https://imagemagick.org/command-line-options/#mosaic)" quanto o "[-flatten](https://imagemagick.org/command-line-options/#flatten)" ainda criam uma tela que começa na 'origem', ou seja, no pixel 0,0. Isso faz parte da definição da 'tela virtual' ou 'página' de uma imagem e, por isso, pode-se ter certeza de que a imagem final de ambos os operadores não terá deslocamento virtual, e toda a tela estará totalmente definida em termos de dados de pixel reais. Note também que o "[-mosaic](https://imagemagick.org/command-line-options/#mosaic)" só expande a tela nas direções positivas (as bordas inferior ou direita), pois as bordas superior e esquerda estão fixas na origem virtual. Isso, é claro, significa que o "[-mosaic](https://imagemagick.org/command-line-options/#mosaic)" ainda recortará imagens com deslocamentos negativos... |
magick \( -page -5-10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( -page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background dodgerblue -mosaic mosaic_clip.gif
Merge - para Criar uma Nova Imagem de Camada
O operador "[-layers](https://imagemagick.org/command-line-options/#layers) **merge**" é quase idêntico aos operadores anteriores e foi adicionado no IM v6.3.6-2. Ele cria uma imagem de tela apenas grande o suficiente para conter todas as imagens dadas em seus respectivos deslocamentos. Como o Mosaic, também expande a tela, mas não apenas na direção positiva, e sim também na direção negativa. Basicamente, isso significa que não é preciso se preocupar com recorte, deslocamento ou outros aspectos ao mesclar camadas de imagem. Todas as imagens serão mescladas em relação à posição umas das outras. A saída não inclui nem garante que a origem faça parte da tela expandida. Assim, a saída de um Merge de Camadas pode conter um 'deslocamento de camadas' que pode ser positivo ou negativo. Em outras palavras... o Merge de Camadas mescla camadas de imagem para produzir uma nova imagem de camada. Portanto, se você não quiser esse deslocamento ao terminar, provavelmente vai querer incluir um operador "[+repage](https://imagemagick.org/command-line-options/#repage)" antes de salvar. Por exemplo, aqui está o mesmo conjunto de camadas de imagem que usamos anteriormente... |
magick \( -page +5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( -page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background dodgerblue -layers merge +repage layers_merge.gif
![[IM Output]](../static/img/layers/layers_merge.gif)
Como se pode ver, a imagem tem apenas o tamanho necessário para conter todas as imagens, que foram posicionadas umas em relação às outras, enquanto descartei o deslocamento da imagem resultante em relação à origem da tela virtual. Essa preservação da posição relativa, sem recorte nem espaço extra desnecessário, é o que torna essa variante tão poderosa. Vamos tentar de novo, atribuindo a uma imagem um deslocamento negativo... |
magick \( -page -5-10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( -page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background dodgerblue -layers merge +repage layers_merge_2.gif
![[IM Output]](../static/img/layers/layers_merge_2.gif)
Como se pode ver, o "balloon" não foi recortado, apenas afastado dos demais, de modo a preservar sua distância relativa a eles. É claro que o operador "[+repage](https://imagemagick.org/command-line-options/#repage)" nos exemplos acima remove o deslocamento absoluto de tela virtual na imagem final, preservando apenas os posicionamentos relativos entre as imagens. O deslocamento foi removido porque os navegadores web costumam ter problemas com deslocamentos de imagem, e em especial com deslocamentos negativos, a menos que façam parte de uma animação GIF. Mas, se eu não removesse esse deslocamento, todas as imagens permaneceriam em sua posição correta na tela virtual dentro da imagem de camada única gerada, permitindo continuar a processar e adicionar mais imagens à imagem mesclada. Normalmente, usa-se uma cor de "[-background](https://imagemagick.org/command-line-options/#background)" igual a 'None' para tornar transparentes as áreas não usadas da imagem mesclada. Quando aplicado a uma única imagem, o Merge de Camadas substitui qualquer transparência da imagem pela cor de fundo sólida, mas preserva o tamanho original da imagem, bem como quaisquer deslocamentos nela. O tamanho da tela virtual da imagem, porém, pode ser ajustado para se adequar 'da melhor forma' ao tamanho e ao deslocamento dessa imagem. O propósito original do operador era permitir aos usuários mesclar mais facilmente múltiplas imagens distorcidas em um todo unificado, independentemente do deslocamento de cada imagem. Por exemplo, ao alinhar fotos para formar um 'panorama' maior. Bastaria começar com uma imagem base central não distorcida (sem deslocamento) e usar esse operador para sobrepor as outras imagens ao redor desse ponto de partida (usando deslocamentos negativos ou positivos), que tenham sido alinhadas e distorcidas para casar com essa imagem central. Para outros exemplos de uso desse operador distorcendo imagens para alinhar pontos de controle comuns, veja Cubo de Foto Isométrico 3D e Caixa em Perspectiva 3D. Outros exemplos de uso desse operador incluem gerar uma simples série de Fotos Sobrepostas.
A operação "-layers trim-bounds" pode ser usada para garantir que todas
as imagens tenham um deslocamento positivo em uma tela de tamanho mínimo,
mantendo suas posições relativas e sem de fato mesclar as imagens em uma
única imagem final.
Isso permite então realizar mais processamento das imagens antes de elas
serem de fato mescladas, como posicionar mais imagens em relação a esse
grupo de imagens, consultando os limites da tela virtual resultante.
Contudo, se as imagens tiverem transparência, provavelmente é uma boa ideia
aparar essa transparência das imagens primeiro, tornando o uso ideal...
-alpha set -bordercolor none -border 1x1 -trim -layers trim-bounds
Isso minimiza as camadas de imagem, incluindo toda e qualquer área
transparente dos dados de imagem reais, garantindo que tudo esteja contido
em uma tela virtual (positiva) válida de tamanho mínimo.
Composição Coalesce - uma Formação Progressiva de Camadas
O operador de imagem "[-layers](https://imagemagick.org/command-line-options/#layers) **coalesce**" (ou seu atalho "[-coalesce](https://imagemagick.org/command-line-options/#coalesce)") foi de fato projetado para converter animações GIF em uma sequência de imagens. Para exemplos, veja Coalescendo Animações para mais detalhes. No entanto, ele está muito ligado ao "[-flatten](https://imagemagick.org/command-line-options/#flatten)" e tem efeitos muito úteis para imagens de múltiplas camadas nesse sentido. Por exemplo, usar o Coalesce em uma única imagem faz exatamente o mesmo trabalho que usar o Flatten com uma cor de "[-background](https://imagemagick.org/command-line-options/#background)" igual a 'None' ou 'Transparency'. Ou seja, ele 'preenche' a tela da imagem com pixels transparentes. |
magick \( -page 100x100+5+10 balloon.gif \) -layers coalesce coalesce_canvas.gif
![[IM Output]](../static/img/layers/coalesce_canvas.gif)
Ao lidar com uma imagem composta de múltiplas camadas, o Coalesce pode ser usado para gerar uma 'Formação Progressiva de Camadas' da imagem. Mas, para isso, precisamos tomar algumas precauções, a fim de desativar qualquer tratamento de 'animação GIF' pelo operador.
magick \( -page 100x100+5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( --page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-set dispose None -coalesce miff:- |\
montage - -frame 4 -tile x1 -geometry +2+2 \
-background none -bordercolor none coalesce_none.gif
No exemplo acima, definimos ("[-set](https://imagemagick.org/command-line-options/#set)") todas as configurações de "[-dispose](https://imagemagick.org/command-line-options/#dispose)" como '[None](anim_basics.html#none)'. Isso efetivamente diz ao "[-coalesce](https://imagemagick.org/command-line-options/#coalesce)" para apenas sobrepor cada quadro sobre os resultados das sobreposições anteriores. O resultado é que a primeira imagem é apenas um 'preenchimento' da tela da imagem, com um fundo transparente. A imagem seguinte é a imagem anterior com essa camada sobreposta. E assim por diante. Um flatten 'progressivo' da sequência de imagens. A última imagem da sequência será, portanto, igual ao que se obteria com um "[-flatten](https://imagemagick.org/command-line-options/#flatten)" normal com fundo transparente. Pode-se obter um tipo de efeito completamente diferente se for usada uma configuração de "[-dispose](https://imagemagick.org/command-line-options/#dispose)" igual a '[Background](anim_basics.html#background)'. Nesse caso, o "[-coalesce](https://imagemagick.org/command-line-options/#coalesce)" apenas 'preenche' a tela de cada imagem, como se fossem imagens completamente separadas!
magick \( -page 100x100+5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( --page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-set dispose Background -coalesce miff:- |\
montage - -frame 4 -tile x1 -geometry +2+2 \
-background none -bordercolor none coalesce_bgnd.gif
Note, porém, que, ao contrário do Flatten, do Mosaic ou do Merge, o operador "[-coalesce](https://imagemagick.org/command-line-options/#coalesce)" não usa a configuração atual de composição alfa "[-compose](https://imagemagick.org/command-line-options/#compose)". Ele usa apenas um método de composição '[Over](compose.html#over)', pois é isso que o tratamento de animação GIF exige. O uso de diferentes métodos "[-compose](https://imagemagick.org/command-line-options/#compose)" com os operadores mais padrão de camadas de imagem é o tema do próximo conjunto de exemplos.
Métodos de Composição e Camadas
Os três métodos de Camadas: Flatten, Mosaic e Merge usam a configuração "[-compose](https://imagemagick.org/command-line-options/#compose)" para determinar o método de composição usado ao sobrepor cada imagem em sequência. Assim, pode-se pensar nessas funções como um operador "[-composite](https://imagemagick.org/command-line-options/#composite)" de múltiplas imagens, com a capacidade de definir uma tela "[-background](https://imagemagick.org/command-line-options/#background)" inicial de cor especificada. No entanto, usar qualquer coisa além da Composição Alfa padrão 'Over' exige alguma reflexão antes de aplicar, ou você obterá resultados inesperados. Também pode ser preciso pensar no efeito da cor "[-background](https://imagemagick.org/command-line-options/#background)" usada por esses operadores para gerar uma tela inicial, sobre a qual cada imagem (inclusive a primeira) é composta. Por exemplo, vamos colocar cada imagem sucessiva sob as imagens anteriores usando um '[DstOver](compose.html#dstover)'... |
magick \( -page 100x100+5+10 balloon.gif \) \( -page +35+30 medical.gif \) \
\( --page +62+50 present.gif \) \( -page +10+55 shading.gif \) \
-background none -compose DstOver -flatten flatten_dstover.gif
![[IM Output]](../static/img/layers/flatten_dstover.gif)
Aqui, o fundo foi definido como transparente; caso contrário, você veria apenas a tela de fundo no resultado, pois todas as outras imagens teriam sido colocadas 'sob' essa tela inicial! Isso oferece uma forma de 'zerar' uma imagem com uma cor específica, como mostrado em Telas Dimensionadas para uma Imagem Existente. Aqui está um exemplo mais prático. Em vez de empilhar as imagens em camadas com a tela de fundo primeiro, o que é desajeitado e pouco natural em algumas situações de processamento de imagem, pode-se simplesmente gerar as imagens de cima para baixo, ou da frente para o fundo. |
magick rose: -repage +10+10 \
\( +clone -background black -shadow 60x3+5+5 \) \
\( granite: -crop 100x80+0+0 +repage \) \
-background none -compose DstOver -layers merge layer_dstover.gif
![[IM Output]](../static/img/layers/layer_dstover.gif)
Cada uma das três primeiras linhas gera uma camada de imagem, e a linha final mescla todas as camadas sob as camadas anteriores, invertendo efetivamente a ordem.
Como se pode ver, o processamento de imagem acima foi mais simples e limpo do que normalmente se veria na geração de sombras, apenas colocando cada imagem sob a anterior em sequência (com uma tela inicial transparente).
É claro que eu poderia ter, com a mesma facilidade, feito o Reverse da lista de imagens. |
magick rose: -repage +10+10 \
\( +clone -background black -shadow 60x3+5+5 \) \
\( granite: -crop 100x80+0+0 +repage \) \
-reverse -layers merge layer_reverse.gif
![[IM Output]](../static/img/layers/layer_reverse.gif)
No entanto, lembre-se de que isso apenas reordena as imagens existentes e não afeta a 'tela de fundo inicial' que os métodos de camadas criam. Os métodos de composição também podem ser usados para produzir efeitos interessantes. Por exemplo, se você desenhar três círculos e depois sobrepô-los usando o método de composição 'Xor', obtém um símbolo incomum e de aparência complexa, com esforço mínimo. |
magick -size 60x60 \
\( xc:none -fill blue -draw 'circle 21,39 24,57' \) \
\( xc:none -fill red -draw 'circle 39,39 36,57' \) \
\( xc:none -fill green -draw 'circle 30,21 30,3' \) \
-background none -compose Xor -flatten flatten_xor.png
Layers Composite - Mesclar Duas Listas de Camadas
No IM v6.3.3-7 foi adicionado o método '**Composite**' do "[-layers](https://imagemagick.org/command-line-options/#layers)", permitindo compor dois conjuntos de imagens completamente separados. Para fazer isso na linha de comando, é necessária uma imagem marcadora especial '[null:](files.html#null)' que define onde termina a primeira lista de destino de imagens e começa a lista de origem das imagens sobrepostas. Mas essa é a única complicação real desse método. Basicamente, cada imagem da primeira lista é composta contra a imagem correspondente da segunda lista, mesclando efetivamente as duas listas. A segunda lista pode ser posicionada globalmente em relação à primeira, usando um Deslocamento de Geometry, assim como se faz com um Operador Composite normal (veja acima). O gravity também é aplicado usando o tamanho de tela da primeira imagem para fazer os cálculos. Além desse 'deslocamento global', o deslocamento virtual individual de cada imagem também é preservado, à medida que cada par de imagens é composto. Um caso especial também é tratado. Se uma das listas de imagens contiver apenas uma imagem, essa imagem será composta contra todas as imagens da outra lista. E, nesse caso, os metadados de imagem (como os tempos de animação) da lista maior são os que serão mantidos, mesmo que não seja o lado de destino da composição.
Esse operador de camadas é mais tipicamente usado ao compor duas animações, que podem ser consideradas uma espécie de lista de imagens em camadas ao longo do tempo. Por causa disso, ele é melhor exemplificado na seção Modificações de Animação dos exemplos. Então, veja Composição Alfa de Múltiplas Imagens para mais detalhes.
Manipulando Camadas de Imagens
Empilhar múltiplas imagens em camadas usando os vários operadores de camada acima é uma técnica muito versátil. Ela permite trabalhar em um grande número de imagens individualmente e, ao terminar, combiná-las todas em um único todo unificado. Até aqui, mostramos várias formas de mesclar (compondo ou empilhando em camadas) múltiplas imagens de muitas maneiras diferentes. Aqui apresento alguns exemplos mais práticos de como usar essas técnicas.
Camadas de Imagens em Miniatura
Também é possível usar essa técnica para mesclar múltiplas miniaturas de várias formas complexas. Aqui adiciono uma Borda Suave às imagens à medida que você as lê e posiciona; assim, é possível gerar uma composição bastante agradável de imagens sobre uma Tela em Ladrilhos.
magick -page +5+5 holocaust_tn.gif \
-page +80+50 spiral_stairs_tn.gif \
-page +40+105 chinese_chess_tn.gif \
+page \
-alpha Set -virtual-pixel transparent \
-channel A -blur 0x10 -level 50,100% +channel \
\( -size 200x200 tile:tile_fabric.gif -alpha Set \) -insert 0 \
-background None -flatten overlap_canvas.jpg
Posicionamento Calculado de Imagens.
O Deslocamento de Tela Virtual (página) pode ser definido de muitas formas. Mais especificamente, pode-se "[-set](https://imagemagick.org/command-line-options/#set)" esse Atributo por imagem e até calcular uma posição diferente para cada uma. Por exemplo, aqui leio um grande conjunto de imagens (pequenos ícones, todos do mesmo tamanho) e as disponho em círculo.
magick {balloon,castle,eye,eyeguy,ghost,hand_point,medical}.gif \
{news,noseguy,paint_brush,pencil,present,recycle}.gif \
{shading,skull,snowman,storm,terminal,tree}.gif \
\
-set page '+%[fx:80*cos((t/n)*2*pi)]+%[fx:80*sin((t/n)*2*pi)]' \
\
-background none -layers merge +repage image_circle.png
A chave do exemplo acima é a operação "[-set](https://imagemagick.org/command-line-options/#set) page", que usa o índice de imagem normalizado (a Expressão FX 't/n') para criar um valor de 0.0 até quase 1.0 para cada imagem individual. Esse valor é então mapeado para posicionar a imagem (por ângulo) em um círculo de 80 pixels de raio, usando Expressões FX como Escape de Porcentagem. A posição calculada é a do canto superior esquerdo da imagem (não seu centro, embora esse seja um ajuste simples), que é então Mesclada para gerar uma nova imagem. O posicionamento é feito sem considerar se o deslocamento é positivo ou negativo, o que é a força do Operador de Camadas Merge. Ou seja, geramos uma nova imagem com todas as imagens conforme sua posição relativa entre si. O "[+repage](https://imagemagick.org/command-line-options/#repage)" final remove o deslocamento negativo resultante da imagem de camada mesclada, pois ele não é mais necessário e pode causar problemas ao visualizar a imagem resultante. Note que a primeira imagem (a mais à direita no resultado) fica em camada abaixo de todas as outras. Se você quiser que a formação de camadas seja verdadeiramente cíclica, de modo que a última imagem fique abaixo desta primeira, talvez seja preciso dividir essa primeira imagem ao meio e colocar a metade superior no fim da sequência, para que a metade superior da primeira imagem fique sobre a última imagem, enquanto a metade inferior permanece abaixo da segunda imagem. Essa técnica é poderosa, mas só consegue posicionar imagens em um deslocamento inteiro. Se você precisar de um posicionamento subpixel mais exato das imagens, então as imagens precisarão ser distorcidas (transladadas) para a localização subpixel exata, em vez de apenas ajustar seu deslocamento virtual.
Posições Calculadas Incrementalmente
É possível acessar alguns atributos de imagem de outras imagens usando expressões FX, ao mesmo tempo em que se define o atributo das imagens à medida que são processadas. Isso significa que você pode definir a localização de cada imagem em relação à posição calculada da imagem anterior. Por exemplo, isto define a posição de cada imagem para ficar à direita da imagem anterior. Ou seja, a posição da imagem anterior mais a sua largura.
magick rose: netscape: granite: \
\
+repage -set page '+%[fx:u[t-1]page.x+u[t-1].w]+0' \
\
-background none -layers merge +repage append_diy.png
Cada imagem é anexada à localização da imagem anterior, consultando essa localização e somando a largura dessa imagem. Essa localização anterior, na verdade, acabara de ser calculada, à medida que o IM percorria cada imagem definindo o atributo 'page' (deslocamento virtual). O resultado é um equivalente ao Operador Append feito por conta própria, a partir do qual você pode desenvolver suas próprias variações. Note que toda a sequência é, na verdade, deslocada por 'u[-1].w', definido durante o cálculo de posição da primeira imagem. Isso deve corresponder à largura da última imagem na sequência de imagens atual. Esse deslocamento geral, porém, é descartado pelo "[+repage](https://imagemagick.org/command-line-options/#repage)" final. É possível usar algum cálculo extra para fazê-lo ignorar esse deslocamento, mas isso não é necessário acima. | _Ao usar um índice de imagem como 'u[t]', todos os seletores de imagem 'u', 'v' e 's' referenciam a mesma imagem, de acordo com o '[index]' dado. Assim, é melhor usar 'u' (a primeira imagem, ou de índice zero) como mnemônico desse comportamento de indexação (e caso isso mude).
Para mais informações, veja FX, o Operador de Imagem Faça-Você-Mesmo._
---|---
Aqui está outro exemplo. Cada imagem é deslocada em relação à imagem anterior, usando tanto a posição quanto a largura dessa imagem, de modo a calcular uma Concatenação com Sobreposição.
magick font_[0-9].gif \
-set page '+%[fx:u[t-1]page.x+u[t-1].w-8]+%[fx:u[t-1]page.y+4]' \
-background none -layers merge +repage append_offset.gif
Essa capacidade de acessar atributos de outras imagens também inclui os dados de pixel de outras imagens. Isso significa que você poderia criar uma imagem especial em que os valores de cor representam as 'posições mapeadas' das outras imagens. É claro que essa imagem de 'mapeamento' também estaria posicionada e precisaria ser removida antes de a sobreposição ser realizada. Quão útil é criar imagens especiais de 'posição mapeada' é outra questão. É apenas mais uma possibilidade.
Posicionamento de Imagens em Dois Estágios
É possível simplificar seu processamento de imagem separando-o em dois passos. Um passo pode ser usado para gerar, distorcer, posicionar e adicionar enfeites às imagens, com um passo final para mesclar todas elas. Por exemplo, vamos criar Miniaturas Polaroid a partir das imagens originais maiores em Photo Store, processando cada uma individualmente (mantendo esse aspecto separado e simples).
center=0 # Start position of the center of the first image.
# This can be ANYTHING, as only relative changes are important.
for image in ../img_photos/[a-m]*_orig.jpg
do
# Add 70 to the previous images relative offset to add to each image
#
center=`magick xc: -format "%[fx: $center +70 ]" info:`
# read image, add fluff, and using centered padding/trim locate the
# center of the image at the next location (relative to the last).
#
magick -size 500x500 "$image" -thumbnail 240x240 \
-set caption '%t' -bordercolor Lavender -background black \
-pointsize 12 -density 96x96 +polaroid -resize 30% \
-gravity center -background None -extent 100x100 -trim \
-repage +${center}+0\! MIFF:-
done |
# read pipeline of positioned images, and merge together
magick -background skyblue MIFF:- -layers merge +repage \
-bordercolor skyblue -border 3x3 overlapped_polaroids.jpg
O script acima parece complicado, mas na verdade não é. Ele simplesmente gera cada imagem em miniatura em um laço, ao mesmo tempo em que centraliza o preenchimento (usando Extent) e Apara cada imagem, de modo que o 'centro' das imagens fique em uma localização conhecida na tela virtual. Ele poderia, na verdade, calcular essa posição, embora isso pudesse exigir arquivos temporários; por isso, é melhor garantir que ela esteja em uma localização bem conhecida para todas as imagens. A imagem é então transladada (usando um operador "[-repage](https://imagemagick.org/command-line-options/#repage)" relativo, veja Deslocamentos de Tela), de modo que cada imagem gerada fique exatamente 60 pixels à direita da anterior. Ou seja, o centro de cada imagem fica a uma distância fixa, independentemente do tamanho real da imagem, que poderia ter mudado devido a proporções e rotações. O outro grande truque desse script é que, em vez de salvar cada 'camada de imagem' em um arquivo temporário, você pode simplesmente escrever a imagem em um pipeline usando o formato de arquivo MIFF:. Um método conhecido como Streaming de Imagens MIFF. Isso funciona porque o formato de arquivo "MIFF:" permite simplesmente concatenar múltiplas imagens em um único fluxo de dados, preservando todos os metadados das imagens, como seu deslocamento de tela virtual. Essa técnica é um bom ponto de partida para muitos outros scripts. As imagens podem ser geradas ou modificadas, e o tamanho e a posição finais podem ser calculados da forma que você quiser. Outro exemplo é o script "[hsl_named_colors](../static/img/scripts/hsl_named_colors)", que pega a lista de cores nomeadas presentes no ImageMagick e as ordena em um gráfico dessas cores no espaço de cor HSL. Você pode ver sua saída em Especificação de Cor. Outras possibilidades incluem...
- Usar qualquer tipo de miniatura (ou outro Enfeite), ou simplesmente usar uma pequena miniatura bruta diretamente.
- Gerar imagens de modo que a primeira fique centralizada e as demais sejam dispostas à esquerda e à direita, abaixo dessa primeira imagem, como uma pirâmide.
- Posicionar imagens em Arcos, Círculos e espirais, colocando-as em coordenadas X e Y específicas umas em relação às outras. Por exemplo: PhD Circle, Sunset Flower, Fibonacci Spiral.
- Posicionar imagens de acordo com sua cor. Por exemplo: Book Covers.
- Posicionar imagens pela hora do dia ou pela hora de envio. Por exemplo: Year of Sunsets
Basicamente, você tem total liberdade no posicionamento das imagens na tela virtual e pode simplesmente deixar o IM determinar o tamanho final da tela necessário para conter todas as imagens.
Alfinetes em um Mapa
Aqui está um exemplo típico de camadas, colocando alfinetes coloridos em um mapa, em localizações específicas.
À esquerda está uma imagem de 'alfinete'. A ponta do alfinete está na posição +18+41. Também tenho uma imagem de um Mapa de Veneza e quero colocar um alfinete em vários pontos do mapa. Por exemplo, a 'Accademia' fica na posição de pixel +160+283. Para alinhar o alfinete a essa posição, é preciso subtrair a localização da ponta do alfinete da posição no mapa. Isso produz um deslocamento de +142+242 para nossa imagem de 'alfinete'. Aqui está o resultado, usando imagens em camadas
magick map_venice.jpg -page +142+242 push_pin.png \
-flatten map_push_pin.jpg
Este exemplo veio de uma discussão no Fórum do IM, Layering Images with Convert. Vamos automatizar isso ainda mais. Temos um arquivo que lista as localizações e cores de cada um dos alfinetes que queremos colocar no mapa. O nome da localização no arquivo não é usado e serve apenas como um comentário de referência sobre a posição de pixel listada.
Vamos ler esse arquivo de texto para criar 'alfinetes' em um laço.
pin_x=18 pin_y=41
cat map_venice_pins.txt |\
while read x y color location; do
[ "X$x" = "X#" ] && continue # skip comments in data
x=$(( x - pin_x )) # magick x,y to pin image offsets
y=$(( y - pin_y ))
# magick 'color' to settings for color modulate (hue only)
# assumes a pure 'red' color for the original push pin
mod_args=$(
magick xc:$color -colorspace HSL txt: |
tr -sc '0-9\012' ' ' |\
awk 'NR==1 { depth=$3 }
NR==2 { hue=$3;
print "100,100," 100+200*hue/depth
}'; )
# re-color and position the push pin
magick push_pin.png -repage +${x}+${y} -modulate $mod_args miff:-
done |\
# read pipeline of positioned images, and merge together
magick map_venice.jpg MIFF:- -flatten map_venice_pins.jpg
Note que ele assume que a cor original do alfinete é vermelha (que tem um matiz de 0) e usa o Operador Modulate para recolori-lo em outras cores, com os cálculos de escala apropriados. Note que o argumento de modulate para uma mudança de matiz nula é 100, com um ciclo sobre um valor de 200 (uma espécie de valor pseudo-percentual). FUTURO: distorcer o mapa em perspectiva, ajustar o tamanho do alfinete conforme a 'profundidade' no mapa, calcular a mudança na posição do alfinete devido à distorção e 'fixá-lo' ao mapa distorcido. O exemplo acima usou um método conhecido como Streaming de Imagens MIFF, com cada imagem gerada individualmente em um laço e depois 'canalizada' para o comando de 'camadas', a fim de gerar a imagem final. O método alternativo (comumente usado em scripts PHP) é usar a técnica de 'comando gerado', que utiliza um script de shell para gerar um longo comando "magick" a ser executado. Os scripts em Animações de Distorção de Imagem usam essa técnica. Ambos os métodos evitam a necessidade de gerar imagens temporárias.
Camadas de Sombras
Tratar corretamente efeitos de sombra semitransparentes em um conjunto de imagens sobrepostas é, na verdade, bem mais difícil do que parece. Simplesmente sobrepor fotos com sombras fará com que as sombras sejam aplicadas duas vezes. Ou seja, duas sombras sobrepostas ficam muito escuras, quando, na realidade, elas não se sobrepõem exatamente da mesma forma que as imagens sobrepostas. As várias partes da imagem deveriam estar simplesmente com ou sem sombra. Ou seja, a sombra deveria ser aplicada apenas uma vez a qualquer parte da imagem. Você não deveria obter áreas mais escuras, a menos que tenha duas fontes de luz separadas, e isso pode tornar as coisas ainda mais difíceis. Tomas Zathurecky < tom @ ksp.sk > aceitou o desafio de tratar efeitos de sombra em imagens em camadas e desenvolveu uma técnica de acumulador de imagens para resolver o problema. Basicamente, precisamos adicionar cada imagem ao fundo da pilha, uma de cada vez. À medida que adicionamos uma nova imagem, a sombra de todas as imagens anteriores precisa escurecer a nova imagem antes que ela seja adicionada à pilha. No entanto, apenas a sombra que cai sobre a nova imagem precisa ser adicionada. As sombras que não caem sobre a nova imagem precisam ser ignoradas até mais tarde, quando caírem sobre alguma outra imagem, ou sobre o fundo (se houver). Aqui está um exemplo... |
magick \
\( holocaust_tn.gif -frame 10x10+3+3 \
-background none -rotate 5 -repage +0+0 \) \
\
\( spiral_stairs_tn.gif -frame 10x10+3+3 \
-background none -rotate -15 -repage -90+60 \) \
\( -clone 0 -background black -shadow 70x3+4+7 \
-clone 1 -background black -compose DstATop -layers merge \
-trim \) \
\( -clone 2,0 -background none -compose Over -layers merge \) \
-delete 0--2 \
\
\( chinese_chess_tn.gif -frame 10x10+3+3 \
-background none -rotate 20 -repage +60+90 \) \
\( -clone 0 -background black -shadow 70x3+4+7 \
-clone 1 -background black -compose DstATop -layers merge \
-trim \) \
\( -clone 2,0 -background none -compose Over -layers merge \) \
-delete 0--2 \
\
\( +clone -background black -shadow 70x3+4+7 \) +swap \
-background none -compose Over -layers merge +repage \
layers_of_shadows.png
![[IM Output]](../static/img/layers/layers_of_shadows.png)
O programa acima parece complexo, mas na verdade é bastante direto. A primeira imagem é usada para iniciar uma pilha acumuladora de imagens (índice de imagem #0). Note que poderíamos ter começado com um único pixel transparente ("-size 1x1 xc:none"), caso você não queira usar essa primeira imagem para inicializar a pilha. Agora, para adicionar uma nova imagem ao fundo da pilha, aplicamos o mesmo conjunto de operações, a cada vez...
- Primeiro, a imagem em miniatura é lida para a memória, e quaisquer rotações e posicionamentos relativos (que podem ser negativos) são aplicados. Você também poderia aplicar outras operações de miniaturização à imagem neste ponto, se quisesse, embora, para este exemplo, elas já tenham sido realizadas. A nova imagem forma o índice de imagem #1.
- Agora pegamos a pilha anterior de imagens (#0) e geramos uma sombra com cor, desfoque, deslocamento e porcentagem de luz ambiente apropriados.
- Essa sombra é sobreposta à nova imagem (#1), de modo que apenas a sombra que cai '
[ATop](compose.html#atop)' da nova imagem é mantida. Também (opcionalmente) aplicamos uma Operação de Trim ao resultado para remover qualquer espaço extra adicionado pela operação de sombra, formando a imagem #2. - Agora simplesmente adicionamos a nova imagem (#2) à pilha acumuladora de imagens (#0).
- e apagamos todas as imagens de trabalho anteriores, exceto a última.
Para adicionar mais imagens, basicamente apenas repetimos o bloco de operações acima. Depois que todas as imagens tiverem sido adicionadas à pilha, é apenas uma questão de aplicar uma operação normal de sombra à pilha acumulada de imagens, removendo quaisquer deslocamentos de imagem remanescentes (que muitos navegadores web detestam). Usando o Merge, posso tratar automaticamente os deslocamentos virtuais, especialmente os negativos, o que permite simplesmente colocar imagens onde você quiser em relação aos posicionamentos das imagens anteriores. Ele também facilita a aplicação de sombras, que podem gerar imagens maiores com deslocamentos negativos, de forma adequada.
Ora, o exemplo acima trata corretamente as sombras de imagens em múltiplas camadas, mas, embora a sombra seja deslocada, ela é deslocada igualmente para todas as imagens! O que realmente deveria acontecer é que a sombra ficasse mais deslocada e também mais desfocada à medida que cai sobre imagens cada vez mais profundas na pilha. Ou seja, uma imagem no topo deveria projetar uma sombra bem mais desfocada sobre o fundo, em comparação com a imagem mais inferior. Isso é, na verdade, mais difícil de fazer, pois você não só precisa acompanhar a pilha de imagens, como também precisa acompanhar quão 'difusa' a sombra se tornou à medida que a pilha de imagens aumenta. Assim, você realmente precisa de dois acumuladores. A pilha de imagens (como acima) e a acumulação de sombra, à medida que adicionamos mais imagens. Por exemplo, aqui está o mesmo conjunto de imagens, mas com sombras que ficam mais desfocadas com a profundidade. |
magick xc:none xc:none \
\
\( holocaust_tn.gif -frame 10x10+3+3 \
-background none -rotate 5 -repage +0+0 \) \
\( -clone 1 -background black -shadow 70x0+0+0 \
-clone 2 -background black -compose DstATop -layers merge \
-clone 0 -background none -compose Over -layers merge \) \
\( -clone 2,1 -background none -compose Over -layers merge \
-background black -shadow 100x2+4+7 \) \
-delete 0-2 \
\
\( spiral_stairs_tn.gif -frame 10x10+3+3 \
-background none -rotate -15 -repage -90+60 \) \
\( -clone 1 -background black -shadow 70x0+0+0 \
-clone 2 -background black -compose DstATop -layers merge \
-clone 0 -background none -compose Over -layers merge \) \
\( -clone 2,1 -background none -compose Over -layers merge \
-background black -shadow 100x2+4+7 \) \
-delete 0-2 \
\
\( chinese_chess_tn.gif -frame 10x10+3+3 \
-background none -rotate 20 -repage +60+90 \) \
\( -clone 1 -background black -shadow 70x0+0+0 \
-clone 2 -background black -compose DstATop -layers merge \
-clone 0 -background none -compose Over -layers merge \) \
\( -clone 2,1 -background none -compose Over -layers merge \
-background black -shadow 100x2+4+7 \) \
-delete 0-2 \
\
\( -clone 1 -background black -shadow 70x0+0+0 \
-clone 0 -background none -compose Over -layers merge \) \
-delete 0-1 -trim +repage \
layers_of_deep_shadows.png
![[IM Output]](../static/img/layers/layers_of_deep_shadows.png)
Observe atentamente o resultado. O deslocamento e o desfoque da sombra são diferentes em partes diferentes da imagem. É bem fino entre imagens em camadas adjacentes, mas bem espesso quando cai sobre uma imagem, ou mesmo sobre o fundo, muito mais abaixo. É claro que, neste exemplo, o deslocamento da sombra é provavelmente grande demais, mas o resultado parece bem realista, dando uma melhor sensação de profundidade às camadas. Note como dividimos a operação de sombra em dois passos. Ao aplicar a sombra acumulada (índice de imagem #1) à nova imagem (#2), adicionamos apenas a porcentagem de luz ambiente, sem qualquer desfoque ou deslocamento ('70x0+0+0' neste caso). A nova imagem é então adicionada à pilha acumuladora de imagens (#0). Mas, depois de adicionar a sombra da nova imagem (#2) diretamente à sombra acumulada (#1), novamente sem desfoque ou deslocamento, só então desfocamos e deslocamos TODAS as sombras, para formar a nova imagem de sombra acumulada. Em outras palavras, a imagem de sombra acumulada fica cada vez mais desfocada e deslocada à medida que a pilha fica cada vez mais espessa. Apenas a sombra das imagens mais profundas não acumulou o efeito na mesma medida. Esse programa essencialmente separa a aplicação da sombra do acumulador incremental de sombra. Isso permite controlar coisas como...
- Sombra realista (como acima): 70x0+0+0 e 100x2+4+7
- Sombra constante (como no exemplo básico): 70x2+4+7 e 100x0+0+0
- desfoque constante, mas deslocamento cumulativo: 70x2+0+0 e 100x0+4+7
- deslocamento constante e progressivo: 60x0+4+7 e 100x0+1+1
- efeito cumulativo de luz ambiente: 80x0+0+0 e 95x2+4+7
A maioria deles é provavelmente irrealista, mas pode ficar bom em outras situações. Além disso, definir a cor de "-background" antes da composição "-compose ATOP" permite definir a cor da sombra (na verdade, uma luz ambiente colorida). Você pode até usar uma cor diferente para a sombra que acaba caindo sobre a camada de fundo final (a última configuração "-background black"), ou omiti-la por completo para fazer parecer que as imagens não estão acima de nenhum fundo (ou seja, flutuando no ar). É altamente versátil.
Tomas Zathurecky passou a desenvolver outro método de tratar as sombras de imagens em camadas, lidando com uma lista de imagens em camadas como um todo. Algo que eu mesmo não teria considerado possível. A vantagem desse método é que você pode lidar com uma lista inteira de imagens de uma só vez, em vez de ter de acumular uma imagem por vez, repetindo o mesmo bloco de operações continuamente. Primeiro, vamos novamente examinar o problema mais simples da 'sombra constante'. |
magick \
\( holocaust_tn.gif -frame 10x10+3+3 \
-background none -rotate 5 -repage +0+0 \) \
\( spiral_stairs_tn.gif -frame 10x10+3+3 \
-background none -rotate -15 -repage -90+60 \) \
\( chinese_chess_tn.gif -frame 10x10+3+3 \
-background none -rotate 20 -repage +60+90 \) \
\
-layers trim-bounds \
\
\( -clone 0--1 -dispose None -coalesce \
-background black -shadow 70x2+4+7 \
xc:none +insert null: +insert +insert xc:none \) \
-layers trim-bounds -compose Atop -layers composite \
\
-fuzz 10% -trim \
-reverse -background none -compose Over -layers merge +repage \
coalesced_shadows.png
![[IM Output]](../static/img/layers/coalesced_shadows.png)
O primeiro bloco de operadores apenas gera a lista de imagens em camadas. Poderia ser um laço programado à parte, como mostrado anteriormente. A operação começa com um "-layers trim-bounds", uma operação de Aparo por Limites que expande a tela virtual de todas as imagens de modo a conter todas elas e também garante que todos os deslocamentos sejam positivos. Isso é então clonado, Coalescido e sombreado para criar uma lista separada e progressiva de sombras. Agora podemos usar a Composição por Camadas para mesclar as sombras e a lista original de imagens. A complicação aqui é que, antes de mesclar, precisamos não só adicionar uma imagem marcadora especial 'null:' para dividir as duas listas, como também adicionar uma imagem em branco especial 'xc:none' para deslocar a lista de sombras. Dessa forma, cada imagem de sombra será sobreposta '[ATop](compose.html#atop)' da imagem seguinte da lista original. Só resta mesclar as imagens agora corretamente sombreadas, de baixo para cima (ordem Reverse).
Para tratar 'sombras profundas', são necessários Cálculos de Camadas. |
magick \
\( holocaust_tn.gif -frame 10x10+3+3 \
-background none -rotate 5 -repage +0+0 \) \
\( spiral_stairs_tn.gif -frame 10x10+3+3 \
-background none -rotate -15 -repage -90+60 \) \
\( chinese_chess_tn.gif -frame 10x10+3+3 \
-background none -rotate 20 -repage +60+90 \) \
\
\( -clone 0--1 \
-set page '+%[fx:page.x-4*t]+%[fx:page.y-7*t]' -layers merge \) \
-layers trim-bounds +delete \
\
\( -clone 0--1 \
-set page '+%[fx:page.x-4*t]+%[fx:page.y-7*t]' \
-dispose None -coalesce \
-set page '+%[fx:page.x+4*t]+%[fx:page.y+7*t]' \
-background black -shadow 70x2+4+7 \
xc:none +insert null: +insert +insert xc:none \) \
-layers trim-bounds -compose Atop -layers composite \
\
-fuzz 10% -trim \
-reverse -background none -compose Over -layers merge +repage \
coalesced_deep_shadows.png
![[IM Output]](../static/img/layers/coalesced_deep_shadows.png)
Você pode ver o mesmo conjunto de blocos usado anteriormente, mas com cálculos muito mais complicados para definir o Aparo por Limites inicial e, depois, calcular os deslocamentos necessários para a 'lista de sombras progressiva'. No entanto, a sombra atualmente não fica mais desfocada com a profundidade. | O procedimento acima ficará bem mais simples com o comando "magick" do IMv7, que permitiria usar 'cálculos fx' diretamente no argumento de "-shadow", o que deixaria não só calcular um deslocamento maior para a sombra com a profundidade, como também tornar a sombra mais desfocada com a profundidade.
---|---
Posicionando Imagens em Perspectiva Distorcida
Alinhar imagens distorcidas pode ser complicado, e aqui vou examinar o alinhamento dessas imagens para casar em uma localização bem específica. Aqui tenho duas imagens que destacam um ponto específico em cada uma.
A segunda imagem é 65% semitransparente, o que permite ver através dela quando é composta sobre a imagem azul, de modo que você possa verificar se os pontos marcados estão alinhados. Os próprios pontos de controle marcados estão nas coordenadas 59,26 (azul) e 35,14 (vermelho), respectivamente. Se você estiver apenas sobrepondo as duas imagens, pode simplesmente subtrair os deslocamentos e 'compor' as duas imagens uma sobre a outra, produzindo um deslocamento de +24+12. |
magick align_blue.png align_red.png -geometry +24+12 \
-composite align_composite.png
![[IM Output]](../static/img/layers/align_composite.png)
Note que esse deslocamento poderia ser negativo! E isso é algo que trataremos em breve. Isso só funciona porque as coordenadas são coordenadas inteiras de pixel. Se as coordenadas correspondentes forem localizações subpixel (como costuma ser o caso em uma montagem de fotos), a composição simples não funcionará. Também não funcionará bem se houver qualquer tipo de distorção envolvida (o que também é comum em imagens da vida real). E esse é o problema que vamos explorar.
Ao distorcer a imagem, você vai querer garantir que os dois pixels permaneçam alinhados. A melhor forma de fazer isso seria usar os pontos que você quer alinhar como Pontos de Controle de Distorção. Isso garantirá que eles sejam posicionados corretamente. |
magick align_blue.png \
\( align_red.png -alpha set -virtual-pixel transparent \
+distort SRT '35.5,14.5 1 75 59.5,26.5' \
\) -flatten align_rotate.png
![[IM Output]](../static/img/layers/align_rotate.png)
Como a distorção gera uma 'imagem de camada' com um 'deslocamento de tela', você não pode simplesmente usar o Composite para sobrepor as imagens (nível baixo demais); em vez disso, precisamos usar um operador Flatten, para que ele as posicione usando o deslocamento gerado pela distorção. Note como também adicionei um valor de 0.5 às coordenadas de 'pixel'. Isso ocorre porque os pixels têm área, enquanto os pontos matemáticos não têm; assim, se você quiser alinhar o centro de um pixel, precisa adicionar 0.5 à localização do 'ponto' central dentro do pixel. Veja Coordenadas de Imagem vs Coordenadas de Pixel para mais informações. O outro problema com o exemplo acima era que a imagem sobreposta foi 'recortada' pela imagem de tela de fundo azul, assim como o Operador Composite faz. Ou seja, a imagem 'azul' forneceu o 'viewport de recorte' para o resultado durante a composição. Para evitar isso, usamos o Merge de Camadas, que calcula automaticamente uma tela de 'viewport' grande o suficiente para conter todas as imagens sendo compostas. |
magick align_blue.png \
\( align_red.png -alpha set -virtual-pixel transparent \
+distort SRT '35.5,14.5 1 75 59.5,26.5' \
\) -background none -layers merge +repage align_rotate_merge.png
![[IM Output]](../static/img/layers/align_rotate_merge.png)
Como resultado do 'merge', a imagem terá um deslocamento 'negativo' (para preservar as posições de camada das imagens). Para exibir os resultados, precisei descartar esse deslocamento, pois muitos navegadores não tratam deslocamentos negativos em imagens. Faço isso usando "+repage" antes de salvar a imagem final. Se eu fosse realizar mais processamento (sem exibir o resultado na web), manteria esse deslocamento (removendo o "+repage"), para que as posições das imagens permanecessem em sua localização correta e conhecida para processamento posterior.
Agora, as mesmas técnicas mostradas acima também se aplicariam se você estivesse fazendo uma distorção mais complexa, como a Perspectiva. |
magick align_blue.png \
\( align_red.png -alpha set -virtual-pixel transparent \
+distort Perspective '35.5,14.5 59.5,26.5
0,0 32,4 0,%h 14,36 %w,%h 72,53 ' \
\) -background none -layers merge +repage align_perspective.png
![[IM Output]](../static/img/layers/align_perspective.png)
O problema com essa técnica é que você posiciona a distorção de perspectiva usando um ponto de controle interno. Ou seja, um ponto no interior da imagem e 3 pontos ao redor da borda. Isso pode dificultar o controle da forma real da perspectiva, pois um pequeno movimento de qualquer ponto de controle pode fazer o 'canto livre' se mover descontroladamente. Essa situação pode ser ainda pior se você estiver usando uma longa lista de 'pontos registrados' para obter um 'ajuste por mínimos quadrados' mais exato ao posicionar as imagens. Nesse caso, o ponto que lhe interessa pode não estar perto de nenhum dos 'pontos registrados' de controle usados para distorcer a imagem. A alternativa é simplesmente distorcer a imagem da forma necessária e depois descobrir como precisamos transladar a imagem resultante para alinhar os pontos que nos interessam. Para que isso funcione, precisaremos saber como o 'ponto de interesse' se moveu como resultado da distorção. Esse é um problema real ao distorcer e posicionar imagens, especialmente imagens da vida real. Por exemplo, aqui distorço a imagem usando os quatro cantos para produzir uma forma de distorção específica (supostamente desejada), mas não vou tentar alinhar os pontos de controle neste momento, apenas aplicar a distorção... |
magick align_blue.png \
\( align_red.png -alpha set -virtual-pixel transparent \
+distort Perspective '0,0 10,12 0,%h 14,40
%w,0 68,6 %w,%h 63,48 ' \
\) -background none -layers merge +repage align_persp_shape.png
![[IM Output]](../static/img/layers/align_persp_shape.png)
Como se pode ver, embora a imagem vermelha tenha sido distorcida, a posição do ponto de controle vermelho não está nem perto do ponto de controle azul que queremos alinhar. Você não pode simplesmente medir esses dois pontos, pois é improvável que o ponto vermelho esteja em uma posição de pixel exata; ele terá um deslocamento subpixel envolvido. Precisaremos primeiro calcular exatamente onde está o ponto vermelho. Para isso, podemos reexecutar a distorção acima com o modo verbose ativado, a fim de obter os coeficientes de mapeamento direto da perspectiva. Esses coeficientes podem então ser usados para calcular conforme descrito em Distorção por Projeção em Perspectiva.
magick align_red.png -define distort:viewport=1x1 -verbose \
+distort Perspective '0,0 10,12 0,%h 14,40
%w,0 68,6 %w,%h 63,48 ' null:
Tudo o que queremos são apenas os coeficientes calculados usados pela distorção. Assim, não precisamos da imagem de destino, então geramos a saída usando um formato de arquivo de imagem "null:". Também informamos à distorção que a nova imagem que ela está gerando tem apenas um pixel de tamanho, usando um Viewport de Distorção. Dessa forma, ela faz a preparação da distorção e o relatório verbose, mas depois distorce apenas um único pixel de 'destino', que é então descartado. Isso pode economizar bastante tempo de processamento. Na verdade, se a distorção não usasse metadados da imagem de origem (necessários para os escapes de porcentagem '%w' e '%h') como parte de seus cálculos, nem sequer precisaríamos da imagem de origem "align_red.png". Nesse caso, poderíamos ter usado uma imagem "null:" de um único pixel também como imagem de entrada. Também não estamos realmente interessados nos pixels virtuais, fundos ou qualquer outra coisa para esta etapa de coleta de informações, então não precisamos nos preocupar em configurar esses recursos.
Agora que conseguimos obter as informações da distorção, precisamos extrair os 8 coeficientes de perspectiva da 3ª e da 4ª linha da saída. Esses coeficientes podem então ser usados para mapear o ponto de controle vermelho para sua nova posição distorcida e, a partir daí, subtraí-lo do ponto de controle azul, de modo a obter a quantidade real de translação necessária para alinhar a coordenada vermelha marcada com a coordenada azul.
bluex=59; bluey=26
redx=35; redy=14
magick align_red.png -verbose \
+distort Perspective '0,0 10,12 0,%h 14,40
%w,0 68,6 %w,%h 63,48 ' null: 2>&1 |\
tr -d "'," |\
awk 'BEGIN { redx='"$redx"'+0.5; redy='"$redy"+0.5';
bluex='"$bluex"'+0.5; bluey='"$bluey"'+0.5; }
NR == 3 { sx=$1; ry=$2; tx=$3; rx=$4; }
NR == 4 { sy=$1; ty=$2; px=$3; py=$4; }
END { div = redx*px + redy*py + 1.0;
dx = ( redx*sx + redy*ry + tx ) / div;
dy = ( redx*rx + redy*sy + ty ) / div;
printf "red point now at %f,%f\n", dx, dy;
printf "translate shape by %+f %+f\n", bluex-dx, bluey-dy; }'
O exemplo acima usou o filtro de texto "tr" para remover aspas e vírgulas extras da saída. Em seguida, ele usa o programa "awk" para extrair os coeficientes e realizar a matemática de ponto flutuante necessária para 'mapear diretamente' o marcador vermelho de modo a casar com o marcador azul. Note que novamente adicionei 0.5 às 'coordenadas de pixel' dos pontos de controle, para garantir que o centro do pixel seja o que é usado nos cálculos. Veja Coordenadas de Imagem vs Coordenadas de Pixel. Agora que sabemos a quantidade de translação necessária para a imagem distorcida, temos duas formas de adicionar essa translação à distorção. Ou modificando os coeficientes da projeção em perspectiva de forma apropriada (não é fácil). Ou podemos simplesmente somar as quantidades de translação a cada uma das coordenadas de destino do original (muito fácil). Aqui está o resultado do segundo caso (somar translações às coordenadas de destino)... |
magick align_blue.png \
\( align_red.png -alpha set -virtual-pixel transparent \
+distort Perspective '0,0 31.408223,15.334305
0,%h 35.408223,43.334305
%w,0 89.408223, 9.334305
%w,%h 84.408223,51.334305 ' \
\) -background none -layers merge +repage align_persp_move.png
![[IM Output]](../static/img/layers/align_persp_move.png)
À direita, recortei e escalei o resultado ao redor dos pontos de controle para mostrar que eles estão perfeitamente alinhados! |
magick align_persp_shape.png -crop 19x19+50+17 +repage \
-scale 500% align_persp_shape_mag.png
![[IM Output]](../static/img/layers/align_persp_shape_mag.png)
Como se pode ver, temos um alinhamento perfeito dos dois pixels, sem qualquer transbordamento subpixel para um dos lados. Até o menor desalinhamento apareceria como uma coloração assimétrica em um dos lados do pixel central. Essa ampliação até mostra uma leve diferença assimétrica entre os lados esquerdo e direito da cruz vermelha, devido à distorção de perspectiva. Ou seja, é essa a precisão desse teste de visualização em nível de pixel.
Um problema semelhante, porém mais simples, é examinado em Posicionamento de Texto usando Distorção.
Evaluate-Sequence - Métodos Diretos de Merge de Múltiplas Imagens
Os métodos "[-evaluate-sequence](https://imagemagick.org/command-line-options/#evaluate-sequence) " são projetados para mesclar múltiplas imagens de mesmo tamanho de formas bem específicas. De certo modo, é uma combinação dos Operadores Evaluate e Function com as técnicas de Composição de múltiplas imagens que vimos acima. Muitos dos métodos fornecidos podem até ser realizados usando as técnicas normais de composição em camadas de múltiplas imagens, mas nem todos. O operador usa os mesmos métodos que o "[-evaluate](https://imagemagick.org/command-line-options/#evaluate)", então você pode obter uma lista deles usando "-list Evaluate". Embora alguns deles (como 'Mean' e 'Medium') só sejam realmente úteis quando usados com este operador.
Média (Mean) de múltiplas imagens
Essencialmente, tanto o antigo "-evaluate-sequence mean" quanto o mais novo "[-evaluate-sequence](https://imagemagick.org/command-line-options/#evaluate-sequence) **mean**" criam uma média de todas as imagens fornecidas. Por exemplo, aqui está uma média da imagem da rosa usando todas as suas versões Espelhadas na Vertical e na Horizontal. |
magick rose: -flip rose: \( -clone 0--1 -flop \) \
-evaluate-sequence mean average.png
![[IM Output]](../static/img/layers/average.png)
Fazer a média de centenas de imagens de uma mesma cena fixa pode ser usado para remover a maioria dos efeitos transitórios, como pessoas em movimento, tornando-os menos importantes. No entanto, as áreas que recebem muitos efeitos transitórios podem deixar um 'borrão fantasmagórico' que pode ser muito difícil de remover. Como as sequências de vídeo são notoriamente ruidosas quando se olha para os quadros individuais, você pode fazer a média de vários quadros consecutivos, porém inalterados, para produzir um resultado muito melhor, mais limpo e mais nítido. Matt Leigh, da Universidade do Arizona, relata que usou essa técnica para melhorar a resolução de imagens de microscópio. Ele tira múltiplas imagens do mesmo 'alvo' e depois faz a média de todas elas para aumentar a relação sinal/ruído dos resultados. Ele sugere que outros também possam achar isso útil para esse propósito. Uma alternativa para fazer a média de duas imagens é usar uma operação de imagem "composite -blend 50%", que funciona com duas imagens de tamanhos diferentes. Veja o exemplo de Mesclar Duas Imagens para mais detalhes. O Fórum de Discussão do IM teve uma discussão sobre fazer a média de uma sequência 10 quadros por vez, a fim de fazer a média de milhares de imagens sem esgotar a memória do computador (o que a deixaria muito lenta). Relacionada a isso, e contendo matemática relevante, está a discussão Don't load all images at once. Outra alternativa ao uso de 'mean' é usar o mais novo Operador Poly, que pode ponderar cada imagem individualmente.
Valor Máx/Mín de múltiplas imagens
Os métodos 'Max ' e 'Min ' obtêm os valores máximos (mais claros) e mínimos (mais escuros) de uma sequência de imagens. Novamente, eles são basicamente equivalentes a usar os Métodos de Composição Lighten e Darken, mas com múltiplas imagens. Com a seleção correta da cor da tela de fundo, você poderia usar o Operador Flatten com o método de composição equivalente. |
magick rose: -flip rose: \( -clone 0--1 -flop \) \
-evaluate-sequence max max.png
magick rose: -flip rose: \( -clone 0--1 -flop \) \
-evaluate-sequence min min.png
![[IM Output]](../static/img/layers/min.png)
AVISO: Isto não é uma seleção de pixels (por intensidade), mas uma seleção de valores. Isso significa que a imagem de saída poderia resultar nos valores individuais de vermelho, verde e azul de imagens diferentes, produzindo uma nova cor não encontrada em nenhuma das imagens de entrada. Se você precisar dos pixels selecionados por intensidade máx/mín, veja o Método de Composição Lighten por Intensidade.
Pixel Mediano por Intensidade
O "[-evaluate-sequence](https://imagemagick.org/command-line-options/#evaluate-sequence) **Median**" procurará o pixel que tem a intensidade do pixel do meio dentre todas as imagens fornecidas. Ou seja, para cada posição, ele coleta e ordena a intensidade de pixel de cada uma das imagens. Em seguida, escolhe o pixel que fica no meio da sequência. Também pode ser usado como alternativa a simplesmente fazer a média dos pixels de uma coleção de imagens. Isso poderia ser usado, por exemplo, combinando uma imagem com duas imagens 'limitantes', superior e inferior. Como o pixel será o de intensidade do meio, você obterá ou o pixel da imagem original, ou um pixel das imagens 'limitantes'. Em outras palavras, você pode usar isso para 'limitar' a intensidade da imagem original. Estranho, mas verdadeiro. Para um número par de imagens, o pixel do lado mais claro do meio será selecionado. Assim, com apenas duas imagens, este operador será equivalente a um "lighten por intensidade" pixel a pixel. O ponto-chave é que cada pixel virá completamente de uma imagem, ordenado por intensidade. A cor exata de cada pixel virá completamente de uma das imagens dadas; assim, nenhuma cor nova é gerada. Por exemplo, aqui estão os pixels de intensidade mediana da imagem da rosa usando todas as suas versões Espelhadas na Vertical e na Horizontal. Note como ela não é tão suave, mas pode ter fronteiras nítidas, pois se baseia nas intensidades dos pixels. |
magick rose: -flip rose: \( -clone 0--1 -flop \) \
-evaluate-sequence median median.png
Adicionar Múltiplas Imagens
O método 'Add ', é claro, simplesmente somará todas as imagens.
magick ... -evaluate-sequence add ...
O que é uma versão mais rápida (mais direta) do que usar o Flatten para fazer a Composição Plus de todas as imagens...
magick ... -background black -compose plus -layers flatten ...
Fique atento: somar imagens dessa forma pode facilmente ultrapassar o Quantum Range da imagem e, por isso, ela pode ser 'recortada', a menos que você use uma versão HDRI do IM. É por isso que uma Média, ou Mean é geralmente usada em seu lugar, pois ela divide todas as imagens igualmente para garantir que a imagem resultante não seja recortada. Outra alternativa é usar o mais novo Operador Poly, que pode ponderar cada imagem individualmente.
Subtrair Múltiplas Imagens
O método 'Subtract ' subtrai cada imagem da primeira. Ou pelo menos é isso que ele deveria fazer. Internamente, ele tem os argumentos trocados e está subtraindo os resultados anteriores da imagem seguinte. Arrggggg! No entanto, usando uma peculiaridade do Método de Composição Linear Burn, você pode subtrair a segunda imagem e as posteriores da primeira. Basicamente, Negando todas as imagens exceto a primeira e definindo um 'white' (zero negado) como cor de fundo inicial, você pode então usar o Flatten para subtrair todas as imagens da primeira.
magick ... \
-negate \( -clone 0 -negate \) -swap 0 +delete \
-compose LinearBurn -background white -flatten \
...
Multiplicar/Dividir Múltiplas Imagens
'Multiply ' e 'Divide ' são aceitos como métodos pelo "[-evaluate-sequence](https://imagemagick.org/command-line-options/#evaluate-sequence)", mas geram resultados inesperados e estranhos, pois usam o valor de cor real das imagens em vez do valor de cor normalizado, assim como faz o "[-evaluate](https://imagemagick.org/command-line-options/#evaluate)". Como resultado, a escala da multiplicação e da divisão fica grande demais. Isso poderia ser classificado como um bug. Nesse meio-tempo, é melhor usar o método 'flatten' equivalente para o Multiply, que funciona como esperado.
magick ... -background white -compose multiply -layers flatten ...
Poly - Mesclar Múltiplas Imagens com um Polinômio
Muito relacionado ao "[-evaluate-sequence](https://imagemagick.org/command-line-options/#evaluate-sequence)", e especificamente ao método 'mean' (média de imagens), está o operador "[-poly](https://imagemagick.org/command-line-options/#poly)" (adicionado no IM v6.8.0-5). A esse operador é dada uma lista de dois números para cada imagem na memória: um para fornecer um peso multiplicativo a cada imagem, e também um expoente de potência a cada imagem. Isso permite mesclar uma lista de imagens como se cada imagem fosse a entrada variável de uma equação polinomial. Os valores de cor de cada imagem são tratados como se fossem um valor normalizado de 0 a 1. Com cada par de valores, a cor da imagem (normalizada) é primeiro elevada ao segundo expoente de 'potência' e depois ponderada (multiplicada) pelo primeiro número. Se o expoente for '1', o valor é apenas multiplicado pela ponderação dada. No entanto, se o expoente for '0', o peso passa a ser o valor final, produzindo uma adição de constante de cor normalizada (valor de 0.0 a 1.0). Uma imagem de um único pixel pode ser fornecida na sequência de imagens atual e pode ser usada para adicionar uma cor específica, com um valor de cor normalizado diferente para cada canal (usando peso e expoente = 1.0). Ou você pode fornecer uma imagem "NULL:' (ou qualquer outra imagem descartável) e usar um expoente de 0.0. Isso adicionará apenas o fator de ponderação dado como constante. A imagem final é gerada a partir da primeira imagem (e de seu tamanho e demais metadados), assim como ocorre com o Operador FX Faça-Você-Mesmo. Por exemplo... |
magick rose: granite: null: -poly '1,1 2,1 -1.0,0' poly_rose.png
![[IM Output]](../static/img/layers/poly_rose.png)
Isto pega um 'rose:' (sem modificação, usando peso 1 e potência 1), soma a ele o dobro dos valores de cor da imagem 'granite:' (peso=2) e, por fim, subtrai um valor de 1 usando uma imagem 'null:', com expoente 0 (ignora a entrada de imagem) e valor de ponderação de -1.0. A imagem resultante é equivalente a...
rose + 2.0*granite - 1.0
ou
rose + 2.0*(granite-0.5)
Em outras palavras, a imagem da rosa recebe uma sobreposição de textura granulada de granito (com um viés de cinza de 50%). Isso é, na verdade, exatamente como um efeito de iluminação de composição '[Hard_Light](compose.html#hardlight)' muito forte, mas com uma ponderação bem explícita da sobreposição de granito. A principal diferença disso em relação a outras operações de múltiplas imagens é a capacidade de ponderar cada imagem individualmente, mas realizar todos os cálculos em uma única operação de processamento de imagem, sem a necessidade de imagens intermediárias extras. Isso evita qualquer arredondamento de quantum, recorte ou outros efeitos nos resultados finais, em uma versão não-HDRI do ImageMagick. (Veja Efeitos de Quantum). Pode ser usado, por exemplo, para realizar uma média ponderada de grandes quantidades de imagens, como fazer a média de grupos menores de imagens e depois fazer a média desses grupos entre si.
![[IM Output]](../static/img/layers/append_row.gif)
![[IM Output]](../static/img/layers/compose_resize.gif)
![[IM Output]](../static/img/layers/mosaic_clip.gif)
![[IM Output]](../static/img/layers/coalesce_none.gif)
![[IM Output]](../static/img/layers/coalesce_bgnd.gif)
![[IM Output]](../static/img/layers/flatten_xor.png)
![[IM Output]](../static/img/layers/overlap_canvas.jpg)
![[IM Output]](../static/img/layers/image_circle.png)
![[IM Output]](../static/img/layers/append_diy.png)
![[IM Output]](../static/img/layers/append_offset.gif)
![[IM Output]](../static/img/layers/overlapped_polaroids.jpg)
![[IM Output]](../static/img/layers/map_push_pin.jpg)
![[Data File]](../static/img/layers/map_venice_pins.txt.gif)
![[IM Output]](../static/img/layers/map_venice_pins.jpg)
![[IM Output]](../static/img/layers/align_blue.png)
![[IM Output]](../static/img/layers/align_red.png)
![[IM Text]](../static/img/layers/align_persp_verbose.txt.gif)
![[IM Text]](../static/img/layers/align_persp_coord.txt.gif)
![[IM Output]](../static/img/layers/max.png)
![[IM Output]](../static/img/layers/median.png)