Exemplos do ImageMagick -- Efeitos de Mapeamento de Imagem
- Prefácio e Índice dos Exemplos do ImageMagick
- Introdução ao Mapeamento de Imagem
- Distorcendo Imagens usando Mapeamento de Imagem
- Mapas de Consulta de Distorção Absoluta
- Mapas de Distorção Absoluta
- Composição de Distorção Absoluta
- Mapa de Distorção No-op Revisitado
- Problemas com Mapas de Distorção
- Definir Pixels Indefinidos usando uma Máscara
- Imagem de Distorção Unificada
- Mapa de Distorção em Ampulheta
- Mapa de Distorção Esférica
- Mapa de Distorção em Arco Circular
- Operador Composite Displace
- Exemplos Simples de Deslocamento
- Plotagem por Deslocamento
- Deslocamento de Área
- Reflexos em Água Ondulada
- Mapas de Deslocamento Bidimensionais
- Deslocamento Cilíndrico
- Desfoque com Proporção Variável
- Desfoque com Ângulo Variável
Distorcer ou modificar uma imagem usando algum tipo de imagem 'de mapeamento' secundária que controla o processo. Seja substituindo cores, desfocando a imagem de forma variável ou distorcendo imagens ao especificar as coordenadas de origem de modo absoluto ou relativo.
Introdução
Como você viu nas seções anteriores sobre Composição, Deformação Simples e Distorção, é possível modificar imagens de muitas maneiras diferentes. No entanto, todas elas estão limitadas aos métodos específicos incorporados ao ImageMagick. Você pode até criar a sua própria distorção de imagem usando o 'Operador DIY FX', ou modificar diretamente os valores de uma imagem com operadores como Evaluate ou Function, ou ainda os diversos operadores de Level. Contudo, as distorções exigem muitos cálculos (e tempo) para realizar sua tarefa e, se você pretende executar a mesma tarefa em várias imagens, fazer o IM repetir todos esses cálculos pode ser um verdadeiro desperdício de tempo. O outro aspecto é que é muito difícil limitar os efeitos da distorção de forma livre. Não é possível simplesmente editar ou modificar a distorção que se deseja aplicar. O controle é limitado. O Mapeamento de Imagem é diferente. Você usa uma imagem 'de mapeamento' adicional para controlar quais partes de uma imagem devem ser modificadas, em que medida e de que maneira. Não é necessário modificar a imagem inteira, nem modificá-la de algum modo pré-definido ou pré-programado. É possível criar um 'mapa' capaz de modificar uma imagem de QUALQUER maneira possível, sem limitação. Também é possível editar ou modificar ainda mais o mapeamento, para ajustar ou limitar seu efeito, torná-lo mais complexo, mesclar diferentes mapas ou apenas suavizar ou desfocar o efeito. E, por fim, é possível salvar o mapeamento para reutilizá-lo mais tarde. É a imagem 'de mapa' que controla os resultados. Como a modificação é controlada pelo 'mapa', normalmente há muito pouco cálculo a ser realizado pelo ImageMagick e, por isso, o 'mapeamento de imagem' costuma ser muito rápido. Ele também é repetível, pois é possível aplicar o mesmo mapa, por mais complexo que seja, a qualquer número de imagens e obter exatamente a mesma modificação. Ou seja, você pode aplicá-lo a um diretório inteiro de imagens muito rapidamente. Em essência, o que o Mapeamento de Imagem faz é transferir a matemática lenta e complexa de um determinado efeito, de uma imagem específica para uma imagem 'de mapa' mais geral. Uma vez gerado esse 'mapa', ele pode então ser aplicado a muitas imagens reais muito rapidamente.
O que são Mapas de Imagem
As imagens de mapeamento são basicamente "Tabelas de Consulta" (Look Up Tables, ou LUTs) que definem como um determinado efeito deve ser aplicado a uma imagem, pixel a pixel. Ou seja, se um efeito é aplicado e em que grau é completamente controlado pelo mapa de imagem. Essencialmente, uma imagem é um arranjo de valores, e o que esses valores significam depende do processo de mapeamento aplicado. Eles podem indicar...
- um valor de substituição direta (consulta de cor),
- de qual imagem uma cor deve vir (mascaramento de imagem),
- quanto um pixel deve ser clareado ou escurecido (realce),
- especificar a coordenada de origem (distorção),
- ou uma posição relativa à posição atual (deslocamento).
- quanto desfocar os pixels nesta posição
Muitas dessas técnicas já vimos em Composição de Imagem e, de certa forma, o mapeamento de imagem é apenas outra maneira de mesclar várias imagens. Na verdade, muitas técnicas de mapeamento de imagem são simplesmente implementadas como métodos de composição especializados! Basta lembrar que a verdadeira composição de imagem é, na realidade, apenas a sobreposição de duas imagens de cores reais de várias maneiras (especificamente os Métodos de Composição Alfa de Duff-Porter). O mapeamento de imagem, de modo mais geral, envolve o uso de imagens especializadas que modificam outra imagem de uma forma específica. A parte mais difícil do mapeamento de imagem é gerar um 'mapa' específico para um efeito específico. E é nisso que se concentra grande parte do trabalho, do esforço e das técnicas apresentadas nesta página. Uma vez que você tenha um mapa, porém, é possível usá-lo muitas vezes com muitas imagens diferentes de forma muito rápida.
Distorcendo Imagens usando Mapeamento de Imagem
Embora os diversos operadores de distorção descritos nas seções anteriores dos Exemplos do IM (como Deformação Simples de Imagens e Distorções Gerais de Imagens) sejam úteis, você fica restrito apenas aos tipos de distorção que foram programados na biblioteca gráfica do IM, geralmente usando equações e fórmulas matemáticas específicas. No entanto, há momentos em que você quer projetar sua própria distorção de uma maneira mais livre e menos matemática. Por exemplo, para gerar uma distorção mais complexa, como mapear uma imagem em uma forma específica, ou com um efeito de lente complexo específico, que é mais fácil de desenhar do que de definir matematicamente. Às vezes você quer apenas conseguir repetir sua distorção em um grande número de imagens e evitar ter de recalcular a distorção repetidamente. A solução é pré-calcular sua distorção e salvá-la como uma tabela de consulta (LUT) especial na forma de uma imagem em tons de cinza. Ou seja, para cada pixel de saída, consultamos a LUT e, então, usamos esse valor para consultar a cor na imagem de origem. Ou seja, são necessários três passos.
- Consultar cada pixel de destino na LUT
- Mapear o valor da LUT para a posição na imagem de origem (dois métodos)
- Consultar a cor na imagem de origem
Como uma imagem é usada como 'tabela de consulta' da distorção, você pode criar ou modificar o mapa de distorção usando um editor de imagens, como o 'Gimp' ou o 'PhotoShop', o que lhe dá a liberdade de fazer distorções realmente sofisticadas e complexas. É preciso lembrar, no entanto, que, assim como em todos os outros métodos de distorção que vimos, a consulta é aplicada como um Mapeamento Reverso de Pixels. Ou seja, para cada pixel na imagem de destino, consultamos a cor do pixel na imagem de origem, usando o método de distorção aplicado. Neste caso, o método é consultar a coordenada de origem a partir da Imagem de Tabela de Consulta fornecida.
Agora, há duas maneiras de usar um mapa de imagem para determinar onde, na imagem de origem, uma cor deve ser consultada... de forma absoluta ou relativa. Na consulta de coordenadas absoluta, um Mapa de Distorção converte o valor de cor da LUT diretamente em uma coordenada na imagem de origem, a partir da qual a cor a ser usada é consultada. Não importa onde a cor esteja na LUT; cada cor se refere ao ponto exato de consulta a ser usado. As imagens LUT de distorção terão um gradiente de cores, mas qualquer deformação ou distorção desse gradiente produzirá o mesmo efeito quando o mapa for aplicado. Na consulta de coordenadas relativa, um Mapa de Deslocamento usa o valor de cor para deslocar a coordenada atual e assim determinar a posição na imagem de origem onde a cor será consultada. Isso significa que se usa uma imagem LUT de cinza puro, com áreas mais claras e mais escuras definindo como os pixels devem ser deslocados pelo mapa, independentemente de sua posição no mapa. Ambos os métodos têm vantagens e desvantagens, como você verá.
Mapas de Consulta de Distorção Absoluta
Criar um Mapa LUT de Distorção Absoluta é o mais simples dos dois métodos, tanto para entender e criar os mapas LUT de distorção quanto para aplicá-los. No entanto, como você verá, ele tem uma desvantagem muito séria, o que o torna menos prático do que um Mapa de Deslocamento Relativo. É a cor em qualquer ponto específico do 'Mapa de Distorção' que se refere diretamente a uma posição na imagem de origem. Ou seja, o gradiente em tons de cinza ao longo do 'mapa' define a 'textura' que deve ser colocada naquela posição. Agora, considere que a imagem do mapa seja, na verdade, a imagem de um objeto complexo, como uma camiseta, com dobras e ondulações complexas. Se essa camiseta tiver um gradiente ao longo dela, você pode mapear qualquer imagem plana sobre a camiseta. Esse é o poder de um mapa de distorção absoluta. Qualquer pixel 'preto' na imagem LUT (valor de cor 0) será interpretado como o pixel mais à esquerda, ou coordenada X '0', da imagem de origem, enquanto tudo o que for 'branco' na LUT (valor 1) será interpretado como o pixel mais à direita (a largura da imagem de origem). Observe que esta LUT consultará apenas a posição X, ou horizontal, da cor na imagem de origem. Ela não alterará a altura nem as posições Y das cores. Então vamos experimentar isto com um simples gradiente horizontal em tons de cinza para a LUT.
magick koala.gif \( -size 75x75 gradient: -rotate 90 \) \
-fx 'p{v*w,j}' distort_noop.gif
Observe que isto não produziu nenhuma mudança real no mapeamento da imagem de origem para a imagem de destino. Isso ocorre porque a coordenada X que consultamos no mapa de distorção era a mesma posição para a qual estávamos consultando a cor. Ao simplesmente inverter o gradiente, a consulta dos pixels também é invertida, criando uma imagem espelhada. Ou seja, o branco fica à esquerda e o 'preto' à direita, com um gradiente horizontal ao longo da imagem.
magick koala.gif \( -size 75x75 gradient: -rotate -90 \) \
-fx 'p{v*w,j}' distort_mirror_x.gif
Se pegarmos o gradiente original e o comprimirmos usando um operador de realce de contraste, podemos obter uma distorção muito mais útil.
magick -size 75x75 gradient: -rotate 90 \
-sigmoidal-contrast 8,50% map_compress.gif
magick koala.gif map_compress.gif -fx 'p{v*w,j}' distort_compress.gif
Observe que as laterais da distorção são esticadas enquanto o centro é comprimido. Podemos expandir isto para duas dimensões usando 2 mapas de distorção, um para ajustar a coordenada X e o outro para a coordenada Y.
magick map_compress.gif -rotate 90 map_compress_y.gif
magick koala.gif map_compress.gif map_compress_y.gif \
-fx 'p{u[1]*w,u[2]*h}' distort_compress_2D.gif
Como você pode ver, o exemplo acima recriou uma variação do método de implosão, embora apenas comprimindo as imagens ao longo dos eixos X e Y (simultaneamente), em vez de radialmente, como faz o operador Implode. O ponto central aqui é que tudo o que você fizer no mapa de distorção absoluta será feito na imagem final, qualquer que seja a imagem a que você o aplique. Esse é o poder dos mapas de distorção.
Método de Composição 'Distort'
Até agora, temos usado o FX, Operador DIY Geral para aplicar mapas de distorção absoluta. Isso oferece uma forma de ajustar e afinar exatamente o que você está fazendo, mas também é muito lento. O Operador de Composição "Distort" codifica uma fórmula muito parecida com a que usamos acima. Porém, foi implementado de uma maneira que também o torna um pouco mais compatível com o operador de composição "Displace", que veremos mais adiante em Mapas de Deslocamento Relativo.
Então vamos repetir o último exemplo de 'implosão' usando uma composição "Distort".
magick koala.gif map_compress.gif map_compress_y.gif \
-compose Distort -define compose:args=37.5x37.5 -composite \
distort_compose.gif
Observe o uso da "Configuração Define" "compose:args" acima. Esse valor é um multiplicador aplicado ao gradiente da LUT utilizado (centrado em um cinza perfeito). O valor '37.5' usado corresponde à metade da largura e da altura da imagem (75 pixels). Você pode alterar esse multiplicador para expandir ou contrair a escala geral da distorção. Se os valores de "compose:args" NÃO forem definidos, serão adotados os valores corretos por padrão. Se o valor for definido como zero, nenhuma distorção será aplicada naquela direção. Se quiser definir os argumentos de composição automaticamente, você pode usar o seguinte método equivalente Set "option:" para calculá-lo... |
magick koala.gif map_compress.gif map_compress_y.gif \
-set option:compose:args '%[fx:w/2]x%[fx:h/2]' \
-compose Distort -composite \
distort_compose_set.gif
![[IM Output]](../static/img/mapping/distort_compose_set.gif)
Ou deixe-o indefinido para que o IM calcule os valores corretos (para uma Distort 2D)... |
magick koala.gif map_compress.gif map_compress_y.gif \
-compose Distort -define compose:args='' -composite \
distort_compose_default.gif
Mapa de Distorção No-op
Antes de prosseguirmos, gostaria de voltar um momento e observar novamente o exemplo 'noop' acima. Ele, na verdade, desfoca levemente a imagem, pois a fórmula tal como a descrevi não está exatamente correta. Obter a cópia 'no-op' do original é um bom teste para verificar se a matemática da sua distorção está correta.
Ou seja, dado um gradiente perfeito, você pode mapear cada pixel da imagem de origem para a imagem de destino. Isto é, o valor 'branco' (ou 1.0) da LUT será mapeado exatamente para o pixel mais à direita (ou mais abaixo) na imagem de destino.
Para testar distorções no-op usamos uma 'imagem de xadrez de pixels' (EX.: "pattern:gray50"), pois ela revela qualquer distorção e, portanto, qualquer problema na matemática aplicada. Então vamos tentar aplicar uma distorção no-op aos métodos que usamos até aqui... |
magick -size 75x75 pattern:gray50 \
\( gradient: -rotate 90 \) \( gradient: -flip \) \
-fx 'p{u[1]*w,u[2]*h}' distort_fx_check.gif
magick -size 75x75 pattern:gray50 \
\( gradient: -rotate 90 \) \( gradient: -flip \) \
-set option:compose:args '%[fx:w/2] x %[fx:h/2]' \
-compose Distort -composite distort_compose_check.gif
![[IM Output]](../static/img/mapping/distort_compose_check.gif)
Como você pode ver, AMBOS os métodos falharam em reproduzir a imagem de 'xadrez de pixels'. Embora tenham falhado de maneiras ligeiramente diferentes, devido à forma como as coordenadas são calculadas. O que aconteceu é que o fator de escala, da consulta de cor para a coordenada de pixel, está errado por 1 pixel. Para detalhes sobre por que isso acontece, veja Distorts, Coordenadas de Imagem vs Coordenadas de Pixel. | _A distorção FX é centrada no canto superior direito (posição de pixel 0,0) e gera pixels virtuais duplicados ao longo das bordas inferior e direita. Isso ocorre porque ela não tenta alterar o centro da escala, da cor consultada para as coordenadas de imagem usadas na consulta em si. Assim, os pixels pretos permanecem centrados no pixel 0,0, mesmo que a escala esteja errada.
O operador de composição "Distort" translada as coordenadas de modo que o zero fique no centro da imagem, antes de a escala ser aplicada. Ele faz isso como parte da escala para 'mapas de deslocamento' (veja adiante). Assim, a escala imprecisa puxa as bordas da imagem para dentro em 1/2 pixel ao longo de cada borda, mantendo o centro da imagem correto._
---|---
Aqui estão as versões corrigidas de 'no-op perfeito' para mapas de distorção absoluta, que essencialmente usam Coordenadas de Imagem (largura e altura reduzidas em um), ao calcular o fator de escala entre cor e coordenadas. |
magick -size 75x75 pattern:gray50 \
\( gradient: -rotate 90 \) \( gradient: -flip \) \
-fx 'p{u[1]*(w-1),u[2]*(h-1)}' distort_fx_check_correct.gif
magick -size 75x75 pattern:gray50 \
\( gradient: -rotate 90 \) \( gradient: -flip \) \
-set option:compose:args '%[fx:(w-1)/2] x %[fx:(h-1)/2]' \
-compose Distort -composite distort_compose_check_correct.gif
![[IM Output]](../static/img/mapping/distort_compose_check_correct.gif)
Na verdade, os valores padrão de "compose:args", quando indefinidos, usam os valores de escala corretos. |
magick -size 75x75 pattern:gray50 \
\( gradient: -rotate 90 \) \( gradient: -flip \) \
-compose Distort -define compose:args='' -composite \
distort_compose_default_check.gif
![[IM Output]](../static/img/mapping/distort_compose_default_check.gif)
No entanto, deve-se destacar que essas pequenas imprecisões normalmente não são tão importantes ao usar distorções, então qualquer pequena diferença geralmente é ignorada. Apenas tenha isso em mente para saber a respeito quando de fato importar.
Problemas com Mapas de Distorção
Vamos continuar com a distorção da nossa imagem tentando uma rotação. Para isso, gerar o mapa rotacionado pode ser um pouco complicado, mas é possível...
magick -size 75x75 gradient: -background black -rotate 45 \
-gravity center -crop 75x75+0+0 +repage map_rot45_x.png
magick map_rot45_x.png -rotate 90 map_rot45_y.png
magick koala.gif map_rot45_x.png map_rot45_y.png \
-compose Distort -composite distort_rot45.gif
E agora temos outra maneira de rotacionar qualquer imagem. O maior problema com essa técnica é que, ao criar nossos mapas de distorção usando rotações, introduzimos alguns pixels de cor estranha ao longo das bordas diagonais. No último exemplo, isso fez com que alguns pixels aleatórios fossem adicionados em uma linha ao longo do canto inferior direito da imagem. Essas cores 'aleatórias' são valores de anti-serrilhamento que a rotação introduziu para produzir uma imagem 'melhor'. Contudo, para mapas de distorção, pixels de borda com anti-serrilhamento podem causar problemas reais. Agora podemos tentar definir melhor as cores nas bordas das imagens LUT rotacionadas. Neste caso, podemos gerar uma imagem de gradiente maior e depois recortar a rotação até o tamanho correto.
magick -size 100x20 xc:white xc:black -size 115x75 gradient: \
+swap -append -rotate 45 \
-gravity center -crop 75x75+0+0 +repage map_rot45b_x.png
magick map_rot45b_x.png -rotate 90 map_rot45b_y.png
magick koala.gif map_rot45b_x.png map_rot45b_y.png \
-compose Distort -composite distort_rot45_better.png
Desta forma, todos os pixels na LUT agora estão definidos adequadamente, sem anti-serrilhamento. Isso revela um problema um pouco diferente. Todos os pixels na imagem final estão definidos corretamente, mas alguns pixels não deveriam fazer parte da imagem final. Eles não têm significado real na imagem resultante. Isso representa o maior problema de usar uma LUT para especificar as coordenadas absolutas a serem obtidas da imagem de origem. Você não tem como especificar o que o IM deve fazer nessas áreas indefinidas.
Definir Pixels Indefinidos usando uma Máscara
Uma maneira mais geral de resolver o problema do 'pixel indefinido' é definir um mapa de quais pixels são de fato um resultado válido e definido na distorção. Em outras palavras, uma imagem de mascaramento. Por exemplo...
magick -size 75x75 xc:white -background black -rotate 45 \
-gravity center -crop 75x75+0+0 +repage map_rot45b_m.png
magick distort_rot45_better.png map_rot45b_m.png \
-alpha off -compose CopyOpacity -composite distort_rot45_masked.png
Agora temos três imagens envolvidas no mapa de distorção, e o resultado está ficando bastante complexo. É claro que, numa situação típica, você provavelmente não precisará ir tão longe, mas, no caso geral, precisará.
Imagem de Distorção Unificada
Você pode, no entanto, ter notado que todos os três mapas são imagens em tons de cinza. Isso significa que é bastante razoável mesclar todos os mapas em uma única imagem de mapa de distorção. Por exemplo, vamos mapear o 'mapa de distorção X' para o canal 'red', o 'mapa Y' para o 'green' e a máscara para o canal 'alpha' ou de transparência, o que facilita o manuseio.
magick map_rot45b_x.png map_rot45b_y.png \( map_rot45b_m.png -negate \) \
-alpha off -channel RGA -background black -combine map_rot45u.png
| O canal 'blue' na Imagem de Canais Combinados não está definido, então assume o valor da cor "-background" atual, que preajustei como 'black', ou valor zero, no exemplo acima.
---|---
Agora vamos aplicar esse mapa de distorção unificado à nossa imagem do koala. Infelizmente, isso requer dois passos de processamento de imagem: um para distorcer a imagem e outro para mascarar o resultado.
magick koala.gif -alpha set map_rot45u.png \
\( -clone 0,1 -fx 'p{v.r*w,v.g*h}' \
+clone -compose Dst_In -composite \) -delete 0,1 \
distort_rot45_unified.png
Você também pode usar o método de composição "Distort" diretamente com a imagem do mapa de distorção unificado... |
magick koala.gif -alpha set map_rot45u.png \
-compose Distort -define compose:args='' -composite \
distort_rot45_compose.gif
![[IM Output]](../static/img/mapping/distort_rot45_compose.gif)
Ainda há um canal não utilizado (blue) na imagem do 'mapa de distorção unificado'. Um uso lógico para ele é como meio de adicionar realces e sombras à imagem distorcida. (Veja Realces por Overlay). Você pode ver essa técnica levada um passo adiante no exemplo do Mapa de Distorção Esférica abaixo.
Mapa de Distorção em Ampulheta
Eu queria um mapa de distorção unidimensional que escalasse cada linha da imagem de forma diferente, com base na altura daquela linha. Algo que produzisse uma verdadeira distorção de espelho de parque de diversões, que faz pessoas gordas parecerem muito magras. Em outras palavras, uma espécie de distorção em ampulheta. Esta é uma imagem LUT bastante complexa e, após muita tentativa, cheguei à seguinte expressão para gerar um mapa de gradiente com variação de altura, mas horizontalmente linear. |
magick -size 100x100 xc: -channel G \
-fx 'sc=.15; (i/w-.5)/(1+sc*cos(j*pi*2/h)-sc)+.5' \
-separate map_hourglass.png
![[IM Output]](../static/img/mapping/map_hourglass.png)
| Ao gerar gradientes em tons de cinza, você pode tornar o operador -fx 3 vezes mais rápido, simplesmente pedindo que ele gere apenas um canal de cor, como o canal 'G', ou verde, no exemplo acima. Esse canal pode então ser Separado para formar a imagem em tons de cinza necessária. Isso pode representar um ganho de velocidade muito grande, especialmente ao usar uma fórmula "[-fx](https://imagemagick.org/command-line-options/#fx)" muito complexa.
---|---
O 'sc' é o fator de escala da ampulheta (o valor varia de 0 a 0.5) e permite ajustar a magnitude da distorção. Agora vamos aplicar este mapa à imagem interna "rose:". Observe que o mapa de 100x100 pixels não corresponde à imagem de 70x46 pixels. Isso complica as coisas, pois precisaremos escalar o pixel atual da imagem de origem na medida apropriada para corresponder ao mapa de distorção fornecido, a fim de consultar a posição da cor desse pixel. |
magick rose: map_hourglass.png \
-fx 'p{ v.p{i*v.w/w,j*v.h/h}*w, j}' distort_hourglass.png
![[IM Output]](../static/img/mapping/distort_hourglass.png)
Se você observar com atenção, a coordenada X do pixel 'i' é multiplicada pela largura da imagem do mapa de distorção 'v.w' e dividida pela largura da imagem original 'w', para produzir 'i*v.w/w. O mesmo acontece com a coordenada Y do pixel, 'j*v.h/h'. Isso reescala a coordenada do pixel na imagem de destino para corresponder à imagem LUT de distorção. A coordenada consultada é então escalada multiplicando o valor da LUT pela largura da imagem de origem, para se tornar a coordenada X da consulta de cor. Se você tiver tanto um mapa de distorção X quanto um Y, então terá de repetir a consulta escalada para o mapa Y. É claro que temos as mesmas distorções de 'borda' que vimos antes, então vamos mudar a Configuração de Pixel Virtual para transparência. |
magick rose: -alpha set -virtual-pixel transparent -channel RGBA \
map_hourglass.png -fx 'p{ v.p{i*v.w/w,j*v.h/h}.g*w, j}' \
distort_hourglass2.png
![[IM Output]](../static/img/mapping/distort_hourglass2.png)
Observe o uso da configuração "-channel" para garantir que "[-fx](https://imagemagick.org/command-line-options/#fx)" funcione com valores do canal alfa (transparente) da imagem de origem e os retorne. Especificamente os pixels virtuais transparentes. Observe também que, ao consultar o mapa de distorção, consultamos apenas o canal verde (usando 'v.p{}.g'). Se isso não for feito, o mesmo canal que está sendo processado da imagem de origem será usado e, para o mapa, 'alpha' não está definido. Esse mapa de distorção poderia ser ainda melhor usando um gradiente não linear, de modo que a imagem permaneça retangular, com mais distorção nas bordas do que no meio, para dar um aspecto mais 'arredondado' ou 'cilíndrico'. Alguém gostaria de tentar? Escreva-me
Mapa de Distorção Esférica
No exemplo anterior do Mapa de Distorção em Ampulheta, gerei um gradiente que era escalado horizontalmente por uma curva cosseno. Com um pouco mais de trabalho, você pode gerar uma forma esférica... |
magick -size 100x100 xc: -channel R \
-fx 'yy=(j+.5)/h-.5; (i/w-.5)/(sqrt(1-4*yy^2))+.5' \
-separate +channel sphere_lut.png
![[IM Output]](../static/img/mapping/sphere_lut.png)
Observe, no entanto, que o exemplo acima não é estritamente preciso. O gradiente comprimido permanece um gradiente linear, apenas comprimido para caber dentro de um círculo. Uma representação mais precisa provavelmente exigiria a criação de um gradiente não linear. Que, em termos de posição absoluta, seria uma função 'arccos()'. Agora, esse mapeamento também tem algumas áreas grandes que seriam classificadas como inválidas, então precisará de algum tipo de mascaramento para definir quais pixels serão válidos e inválidos na imagem final. Um simples círculo servirá neste caso. |
magick -size 100x100 xc:black -fill white \
-draw 'circle 49.5,49.5 49.5,0' sphere_mask.png
![[IM Output]](../static/img/mapping/sphere_mask.png)
E, para completar, também precisamos de um realce de sombreamento, como o desenvolvido em Realces por Overlay, para uso pela composição Overlay ou Hardlight... |
magick sphere_mask.png \
\( +clone -blur 0x20 -shade 110x21.7 -contrast-stretch 0% \
+sigmoidal-contrast 6x50% -fill grey50 -colorize 10% \) \
-composite sphere_overlay.png
![[IM Output]](../static/img/mapping/sphere_overlay.png)
Lembre-se de que o sombreamento acima só terá efeito dentro dos limites do objeto esfera, então o fato de o sombreamento transbordar esses limites não é importante. Na verdade, se você quiser tentar criar um sombreamento esférico melhor, que produza uma imagem ainda mais parecida com uma bola, eu adoraria ver. Então vamos aplicar as três imagens: LUT da coordenada X, Sombreamento por Overlay e Máscara de Transparência; a uma imagem real do tamanho correto (por simplicidade).
magick lena_orig.png -resize 100x100 sphere_lut.png -fx 'p{ v*w, j }' \
sphere_overlay.png -compose HardLight -composite \
sphere_mask.png -alpha off -compose CopyOpacity -composite \
sphere_lena.png
Este exemplo em particular mostra o aspecto mais poderoso de um Mapa de Distorção Absoluta. Você pode definir um gradiente sobre qualquer objeto de forma livre (não necessariamente de modo matemático), de modo que qualquer imagem possa ser mapeada sobre esse objeto, sejam curvas, rugas, dobras, etc. Simplificando, uma vez resolvido o mapeamento do objeto, você pode mapear qualquer imagem sobre a sua superfície. Depois, para deixá-lo com aparência mais realista, você pode sobrepor um segundo mapeamento, para adicionar realces, sombras, bordas e outras características. É claro que, como as três imagens são em tons de cinza, você pode combiná-las em uma única imagem de Mapa de Distorção Unificado, para armazenamento fácil. Neste caso, farei uma distorção mais esférica reutilizando também a LUT da coordenada X para a coordenada Y. |
magick sphere_lut.png \( +clone -transpose \) \
sphere_overlay.png \( sphere_mask.png -negate \) \
-channel RGBA -combine spherical_unified.png
![[IM Output]](../static/img/mapping/spherical_unified.png)
É um mapa bastante bonito. Mas, ao tentar interpretá-lo, lembre-se de que: os canais 'red' e 'green' são a LUT das coordenadas X e Y, 'blue' é a sobreposição de efeitos de realce e sombra, e o canal de transparência guarda a máscara de pixels inválidos para a imagem final. Então vamos aplicá-lo usando o método de composição "Distort".
magick mandrill_grid_sm.jpg spherical_unified.png \
\( -clone 0,1 -alpha set -compose Distort -composite \) \
\( -clone 1 -channel B -separate +channel \) \
\( -clone 2,3 -compose HardLight -composite \) \
\( -clone 4,1 -compose DstIn -composite \) \
-delete 0--2 spherical_mandrill.png
Em sequência...
- aplicamos o mapa de distorção (que inclui a máscara)
- extraímos o mapa de sombreamento da imagem de mapa unificada
- aplicamos o mapa de sombreamento à imagem distorcida
- restauramos a máscara perdida pela operação de sombreamento
- apagamos tudo menos a imagem final e a salvamos
A complexidade disto se deve puramente à necessidade de extrair a máscara de sombreamento e de restaurar a máscara alfa que o sombreamento removeu.
Mapa de Distorção em Arco Circular
Apenas para mostrar o que é realmente possível usando mapas de distorção posicionais, aqui está uma LUT de distorção absoluta, semelhante à fornecida pelo 'Método de Distorção Arc' acima. Basicamente, em vez de calcular os mapeamentos de coordenadas para cada pixel de cada imagem a ser distorcida, salvamos essas coordenadas calculadas nas duas LUTs em tons de cinza das coordenadas X e Y. Ou seja, pré-calculamos toda a distorção em uma imagem de tabela de consulta mais simples, permitindo que seja aplicada repetidas e repetidas vezes, sem precisar de novas raízes quadradas ou funções trigonométricas.
magick -pointsize 30 -font Candice label:Anthony -trim +repage \
-gravity center -resize 95x95 -crop 100x100+0+0\! \
-flatten text_image.jpg
magick -size 100x100 xc: -channel G -fx 'atan(j/(i+.5))*2/pi' \
-separate -flip -flop map_p_angle.png
magick -size 100x100 xc: -channel G -fx '1-hypot(i,j)/(w*1.6)' \
-separate -transverse map_p_radius.png
magick text_image.jpg map_p_angle.png map_p_radius.png \
-fx 'p{u[1]*w,u[2]*h}' distort_p_curved.jpg
Fonte de Cor |
|
Ângulo - Mapa X |
|
Raio - Mapa Y |
|
Texto Curvado
---|---|---|---|---|---|---
É claro que gerar esse mapa de distorção foi difícil, mas, uma vez feito, por qualquer meio que você preferir (mesmo artisticamente, com um editor de imagens como o "Gimp"), você pode então reutilizá-lo em um enorme número de imagens.
Mapa de Distorção Polar
Às vezes, você pode precisar que a imagem de destino seja definida pelo mapa de distorção, e não pela imagem de origem, apenas para que as coisas funcionem corretamente. Por exemplo, se quisermos mapear um texto em um círculo (também conhecido como transformada polar), você realmente precisa poder usar uma imagem cerca de 3 a 4 vezes mais longa do que alta (proporção elevada), ou o resultado não ficará muito legível. Para isso, colocamos as imagens do mapa de distorção antes da imagem fonte de cor, de modo que a primeira imagem (mapa X) seja usada para definir o tamanho do resultado final, em vez da imagem de origem de entrada.
magick -size 100x100 xc: -channel G \
-fx 'atan2(i-w/2,h/2-j)/pi/2 + .5' \
-separate map_p_angular.png
magick -size 100x100 xc: -channel G \
-fx 'rr=hypot(i-w/2,j-h/2); (.5-rr/70)*1.2+.5' \
-separate map_p_radial.png
magick -font Candice -gravity center -size 200x50 \
label:'Around the World' text.jpg
magick map_p_angular.png map_p_radial.png text.jpg \
-fx 'u[2].p{ u*u[2].w, v*u[2].h }' distort_p_circle.jpg
Angular - Mapa X |
|
Radial - Mapa Y |
|
Fonte de Cor |
|
Texto em Círculo
---|---|---|---|---|---|---
Essencialmente, a imagem fonte de cor agora pode ter qualquer tamanho ou proporção, e tudo será tratado corretamente; no entanto, talvez você precise ajustar a geração do mapa de distorção para lidar corretamente com a proporção da imagem de origem. Na geração dos mapas acima, o valor '70' controla o tamanho final do círculo, ao longo do qual a linha média é posicionada. O valor '1.2', por outro lado, controla a escala vertical da imagem dentro do círculo, permitindo ajustar a altura do texto distorcido. |
Lembre-se de que esta expressão "-fx" exige que os mapas de distorção sejam fornecidos primeiro, e a fonte de cor seja fornecida como a terceira imagem (índice 2). No entanto, isso também significa que quaisquer metadados armazenados na imagem de origem também serão perdidos. |
|---|---|
| _O problema com este mapa de distorção é que há uma disjunção muito acentuada de cores no 'mapa X' (causada por uma assíntota na matemática). Essa linha deve permanecer nítida quando você fizer qualquer consulta de cor, ou redimensionamento do mapa, para produzir uma imagem maior. Ou seja, você precisará garantir que qualquer redimensionamento ou consulta interpolada deste mapa não produza uma cor de consulta cinza ao longo dessa linha assintótica. |
Se você gerar consultas cinza ao longo dessa linha, obterá uma linha de pixels coloridos (consultados do meio da imagem) no seu resultado final.
Por causa disso, é recomendável que você sempre gere este mapa de distorção no tamanho necessário para a imagem final, e nunca use nenhuma técnica de escala mostrada anteriormente._
---|---
Você pode usar isto para outros efeitos também, como um tabuleiro de xadrez circular... |
magick map_p_angular.png map_p_radial.png \
-size 150x90 pattern:checkerboard \
-fx 'u[2].p{ u*u[2].w, v*u[2].h }' distort_check_circle.gif
![[IM Output]](../static/img/mapping/distort_check_circle.gif)
Experimente alguns dos outros Padrões Internos que o IM fornece, junto com o exemplo acima, para outros efeitos interessantes. | _O exemplo acima mostra claramente os limites das distorções de imagem usando "-fx". Perto do centro da imagem, as linhas radiais estão ficando serrilhadas, pois não ocorre a fusão de pixels de grandes áreas em um único pixel. Por outro lado, as bordas da imagem, particularmente os cantos, mostram um desfoque adequado das linhas radiais.
A causa é que "-fx" (e a maioria dos métodos de distorção mais antigos) faz apenas consultas interpoladas simples e não escaladas das cores na imagem de origem. Isso significa que, à medida que a imagem é reduzida, os pixels da imagem de origem não são mesclados para produzir a cor correta para o pixel de destino.
Isso não é um problema para áreas de ampliação (como nos cantos), apenas de compressão extrema (centro). Assim, uma solução é o uso de Super Amostragem, mas tudo o que isso faz é adiar os problemas para um nível maior de compressão._
---|---
| _A mesma linha assintótica (mudança repentina) no mapa de distorção (do centro à parte inferior da imagem) também produz uma mudança brusca de cor ao longo dessa linha no exemplo acima. Compare essa linha com as outras linhas radiais (como a que vai do centro ao topo da imagem), que ficam muito difusas à medida que se aproximam da borda da imagem, devido à consulta interpolada observada anteriormente.
Isso pode ser um problema ao gerar um padrão circular com uma imagem que se possa ladrilhar (como a acima), e pode exigir algum tratamento especial para evitar diferenças visíveis nessa parte da imagem.
Para evitar isso, pode ser melhor distorcer a metade superior da imagem separadamente da metade inferior, de modo a evitar a região assintótica.
Embaralhando Linhas
Neste exemplo, fazemos algo um pouco mais incomum... Embaralhar as linhas de uma imagem de forma aleatória. Primeiro criamos um mapa que tem um gradiente para X (canal vermelho) e uma imagem de ruído aleatório para Y (canal verde).
magick rose: \
\( -size 46x70 gradient: -rotate -90 \) \
\( -size 1x46 gradient: -spread 23 -scale 70x46\! \) \
-compose Distort -define compose:args='' -composite \
rose_row_shuffle.png
Infelizmente, "-spread" parece incluir pixels virtuais na sua seleção de pixels a trocar, o que faz com que algumas linhas se tornem duplicadas, enquanto outras se perdem completamente. Em outras palavras, o mapa de imagem de 'embaralhamento' não está totalmente correto. Você tem uma solução melhor para embaralhar pixels?
Mapas de Deslocamento por Consulta Relativa
Como você pode ver, um Mapa de Distorção Absoluta é razoavelmente fácil de criar e usar. No entanto, ele tem um problema sério quando uma distorção possui regiões 'indefinidas', ou áreas onde a distorção sai 'para fora' dos limites normais da imagem de origem. Um problema ainda mais sério é que você está sempre lidando com gradientes, que definem as coordenadas absolutas para a consulta de cor. Nenhuma parte da imagem de mapeamento é simples, limpa ou fácil de modificar ou editar à mão. São necessárias técnicas e matemática especiais para sua criação e uso. Isso geralmente significa que há muito pouco em termos de desenvolvimento 'artístico' envolvido. Há, porém, outro método de usar uma Tabela de Consulta para especificar as coordenadas onde obter a cor final. Usando um Mapa de Deslocamento Relativo. Em vez de o 'mapa' definir a coordenada exata onde consultar a cor de cada pixel na imagem de origem, ele define, em vez disso, um offset, ou deslocamento, relativo à posição atual. Ora, um offset pode ser um valor positivo ou negativo, e um valor negativo exige um pouco de artifício para ser codificado em um valor de cor. Então, o que se faz é definir o 'cinza puro' como um deslocamento 0 da coordenada (sem alteração). Em seguida, faz-se o 'preto' significar um deslocamento negativo máximo, e o 'branco' significar um deslocamento positivo máximo. Isso pode ser difícil de descrever, então vejamos um exemplo. Primeiro criamos uma imagem de teste para 'deslocar'. |
magick -font Candice -gravity center -size 150x50 \
label:'Anthony' label.jpg
![[IM Output]](../static/img/mapping/label.jpg)
Agora usarei um pouco de 'magick' para criar uma imagem de 'cinza puro' com áreas de 'branco puro' e 'preto puro'. |
echo "P2 5 1 255\n 127 0 127 255 127" |\
magick - -scale 150x50\! -alpha off displace_map.jpg
![[IM Output]](../static/img/mapping/displace_map.jpg)
Agora, para usar esta imagem como um 'mapa de deslocamento', obtemos o 'valor de cinza' do mapa de deslocamento e o adicionamos à coordenada X e/ou Y. Ou seja, deslocamos a consulta por uma quantia relativa a partir da posição atual, de acordo com o 'grau de cinza' do mapa de deslocamento. O 'valor' é tratado de uma forma especial, de modo que um 'cinza puro' significa um deslocamento zero do ponto de consulta (apenas a coordenada Y, neste caso), mas um 'deslocamento máximo' é usado para um valor 'branco' (positivo) ou 'preto' (negativo). Por exemplo, vamos aplicar o mapa de deslocamento à nossa imagem "label". |
magick label.jpg displace_map.jpg -virtual-pixel Gray \
-fx 'dy=10*(2*v-1); p{i,j+dy}' displaced.jpg
![[IM Output]](../static/img/mapping/displaced.jpg)
Como você pode ver, as várias seções da imagem pareceram 'mover-se' de acordo com a cor do mapa de deslocamento. Uma região 'branca' adiciona o 'valor de deslocamento' dado ao ponto de consulta, então, nessa área, cada pixel consulta a imagem de origem '10' pixels 'ao sul' (direção Y positiva). Como resultado, parece que a imagem de origem se moveu para cima. Lembre-se de que é a consulta que é deslocada, NÃO a imagem em si, razão pela qual ela parece ter se movido para cima, ou em uma direção negativa, para o branco. Um efeito semelhante também foi visto nas áreas com deslocamento 'preto'. A imagem de origem pareceu mover-se para baixo, porque o deslocamento da consulta foi feito em uma direção negativa. Pense nisso com cuidado. Você também notará que a 'consulta deslocada' pode, na verdade, olhar para além dos limites normais da imagem, permitindo que você use uma configuração de Pixel Virtual para controlar esses pixels fora dos limites. No exemplo acima, apenas solicitei que fosse retornado um pixel cinza. O valor de 'deslocamento máximo' '10' no exemplo acima é muito importante, e é a distância relativa máxima que qualquer parte da imagem de origem parece mover-se, para um valor de deslocamento 'branco puro' ou 'preto puro' na imagem de mapeamento. Você não pode deslocar a consulta, e portanto a imagem de entrada, mais do que esse valor. Outros tons de cinza, entre os valores máximos de branco ou preto e o valor central de 50% de cinza (sem deslocamento), deslocam a consulta por uma quantia apropriada. Assim, um cinza de 25% desloca a consulta em 1/2 do valor de deslocamento na direção negativa, enquanto um cinza de 75% desloca em 1/2 desse valor na direção positiva. Esse valor é uma diferença fundamental entre um Mapa de Distorção Absoluta e um Mapa de Deslocamento Relativo. Você pode aumentar ou diminuir os deslocamentos relativos, tornando a imagem mais ou menos distorcida, simplesmente mudando o valor de deslocamento, sem precisar alterar o mapa de deslocamento em nada. Além disso, como um mapa de 'deslocamento zero' é apenas um cinza sólido de 50%, ou cinza puro, e não um gradiente complexo, você pode começar com uma imagem cinza simples e, artisticamente, clarear ou escurecer áreas para gerar os deslocamentos desejados. Você pode fazer isso simplesmente desenhando formas ou áreas, em vez de precisar de uma fórmula matemática complexa e exata. E, por fim, como todos os deslocamentos são relativos, valores extremos, como os produzidos por efeitos de borda, não produzem cores de pixel extremas ou aleatórias. Na verdade, como você verá, suavizar ou desfocar os Mapas de Deslocamento é, na realidade, algo bom, pois remove o efeito de 'corte' disjunto ou descontínuo que você pode ver no exemplo acima. Em resumo: um mapa de deslocamento é muito mais controlável e artístico, fornecendo deslocamentos localizados sem a necessidade de matemática complexa e exigente, e é muito tolerante quanto a erros, efeitos de borda ou mesmo ao desfoque do mapa de deslocamento. É ideal para distorções simples do tipo 'deslocamento', como ao gerar efeitos como água, ondas, espelhos distorcidos, a curvatura da luz, efeitos de lente ou efeitos de vidro fosco ou com bolhas. Por outro lado, distorções altamente matemáticas, como 'polar', rotacional e 'perspectiva', ou outros mapeamentos 3D do mundo real, não são facilmente obtidos. Isto é, não que seja impossível, pois mais adiante mostraremos que é de fato possível converter entre os dois estilos de mapa, apenas de forma mais difícil.
Método de Deslocamento por Composição
Usamos o Operador DIY FX para fazer o mapeamento de deslocamento, de modo que você possa ver o que realmente está sendo feito. Mas é uma técnica lenta. Existe, porém, um Operador de Composição equivalente e interno, "Displace". Veja como usá-lo...
magick {_image_} {_displacement_map_} \
-compose Displace -define compose:args={_X_}x{_Y_} \
-composite {_result_ +}
magick {_image_} {_displacement_map_} \
-compose Displace -set option:compose:args {_X_}x{_Y_} \
-composite {_result_ +}
magick composite {_displacement_map_} {_image_} \
-displace {_X_}x{_Y_} {_result_ +}
Observe a ordem, especialmente no comando "magick composite".
O uso de "-set" em vez de define também permite usar Escapes de Porcentagem no argumento. Os valores 'X ' e 'Y ' definem a direção e o 'deslocamento máximo' que serão usados para as cores 'branco' e 'preto' no mapa de deslocamento fornecido. Você pode definir um ou ambos os valores, de modo a permitir o deslocamento em qualquer direção específica. Ou seja, normalmente os mapas de deslocamento fornecem um deslocamento linear em alguma direção arbitrária, com uma intensidade máxima controlada pelos valores 'X ' e 'Y '. A 'imagem de mapa' então define quanto desse máximo é aplicado, de um máximo negativo (preto) a um máximo positivo (branco), com um cinza perfeito significando nenhum deslocamento da consulta para aquele pixel. Por exemplo, aqui está o mesmo exemplo de deslocamento em Y que tínhamos acima... |
magick label.jpg displace_map.jpg -virtual-pixel Gray \
-compose Displace -define compose:args=0x10 -composite \
displaced_y.jpg
![[IM Output]](../static/img/mapping/displaced_y.jpg)
Você também pode usar outras configurações, como "[-geometry](https://imagemagick.org/command-line-options/#geometry)" e "[-gravity](https://imagemagick.org/command-line-options/#gravity)", para ajustar a área em que o mapa de deslocamento é sobreposto à imagem. A consulta de pixels resultante do mapa de deslocamento ainda pode referenciar áreas fora da parte sobreposta da imagem, duplicando-as na área sobreposta.
Exemplos Simples de Deslocamento
Um mapa de deslocamento composto de áreas cruas de cores, sem qualquer transição suave, geralmente produzirá deslocamentos disjuntos (descontínuos) entre as diferentes áreas na imagem resultante, exatamente como você viu acima. Você pode, de fato, produzir um mapa de deslocamento que 'fratura', como se estivesse olhando para um espelho rachado, usando esta técnica. Por exemplo, veja o Espelho Fraturado abaixo. Você pode produzir resultados mais agradáveis e suaves se as cores fluírem suavemente de uma área para outra. Por exemplo, ao desfocar o mapa de deslocamento, você gera uma transição em forma de onda entre as áreas deslocadas... |
magick displace_map.jpg -blur 0x10 dismap_wave.jpg
magick label.jpg dismap_wave.jpg -virtual-pixel Gray \
-compose Displace -define compose:args=0x10 -composite \
displaced_wave_y.jpg
![[IM Output]](../static/img/mapping/dismap_wave.jpg)
![[IM Output]](../static/img/mapping/displaced_wave_y.jpg)
Em vez de deslocar a imagem na direção Y, você também pode usar um mapa para deslocá-la na direção X, resultando em uma espécie de onda de compressão. |
magick label.jpg dismap_wave.jpg -virtual-pixel Gray \
-compose Displace -define compose:args=10x0 -composite \
displaced_wave_x.jpg
![[IM Output]](../static/img/mapping/displaced_wave_x.jpg)
Usando o mesmo mapa de deslocamento para as direções X e Y, podemos adicionar tanto uma onda de compressão quanto uma onda de amplitude. |
magick label.jpg dismap_wave.jpg -virtual-pixel Gray \
-compose Displace -define compose:args=10x10 -composite \
displaced_wave_xy.jpg
![[IM Output]](../static/img/mapping/displaced_wave_xy.jpg)
Observe que a imagem ainda é deslocada em uma única direção linear, o que faz com que a imagem acima seja esticada na descida e comprimida na subida. Ou seja, a distorção está sendo realizada em um ângulo, ou 'vetor', com componentes tanto horizontais quanto verticais. Você pode ver que esse efeito lembra bastante algo submerso, com a imagem sendo distorcida por suaves ondulações na superfície da água. Um mapa de distorção, no entanto, pode conter várias cópias da imagem original, assim como ocorre em imagens refletidas ou refratadas... |
echo "P2 3 1 255\n 255 127 0 " | magick - -scale 150x50\! dismap_copy.jpg
magick label.jpg dismap_copy.jpg \
-compose Displace -define compose:args=66x0 -composite \
displaced_copy.jpg
![[IM Output]](../static/img/mapping/dismap_copy.jpg)
![[IM Output]](../static/img/mapping/displaced_copy.jpg)
Você também pode criar inversões ou espelhamentos de partes da imagem, usando gradientes. Por exemplo, aqui você pode usar um mapa de deslocamento linear para copiar pixels de um lado da imagem para o outro. |
magick -size 50x150 gradient: -rotate -90 -alpha off dismap_mirror.png
magick label.jpg dismap_mirror.png \
-compose Displace -define compose:args=150x0 -composite \
displaced_mirror.jpg
![[IM Output]](../static/img/mapping/dismap_mirror.png)
![[IM Output]](../static/img/mapping/displaced_mirror.jpg)
Consegue descobrir como este mapa de deslocamento funciona? Como dica, descubra qual deslocamento têm as bordas mais à esquerda e mais à direita e, depois, veja como o resto da imagem se encaixa nisso. No entanto, como você está novamente usando uma imagem de gradiente, perde a simplicidade dos mapas de deslocamento. Assim, espelhamentos são mais bem feitos usando uma Operação de Inversão direta na imagem, ou usando um Mapa de Distorção Absoluta. Observe que, ao inverter o gradiente, você encolhe a imagem. |
magick -size 50x150 gradient: -rotate 90 -alpha off dismap_shrink.png
magick label.jpg dismap_shrink.png \
-compose Displace -define compose:args=150x0 -composite \
displaced_shrink.jpg
![[IM Output]](../static/img/mapping/dismap_shrink.png)
![[IM Output]](../static/img/mapping/displaced_shrink.jpg)
O exemplo acima também demonstra um problema específico que os mapas de deslocamento têm. Quando uma área (ou toda) de uma imagem é comprimida em mais de 50%, você começará a gerar Artefatos de Serrilhamento. Isso é particularmente perceptível nas bordas 'serrilhadas' em degraus, claramente visíveis. Como discutido anteriormente, uma solução para isso é Super Amostrar o número de pixels usados para gerar cada pixel de saída. Para isso, ampliamos tanto a imagem quanto o mapa de deslocamento e, depois, redimensionamos a imagem resultante de volta ao seu tamanho mais normal. Isso permitirá que mais pixels participem da definição de um pixel específico no resultado, produzindo assim uma imagem melhor. Por exemplo... |
magick label.jpg dismap_shrink.png -resize 200% \
-compose Displace -define compose:args=400x0 -composite \
-resize 50% displaced_resize.jpg
![[IM Output]](../static/img/mapping/displaced_resized.jpg)
Um resultado muito melhor e mais suave, embora talvez um pouco difuso também. Plotando um gradiente Diretamente resultante dos exemplos acima surgiu a ideia de que, usando deslocamentos em Y de uma linha simples, você pode gerar um gráfico das cores de um mapa de deslocamento. Por exemplo, aqui gero uma função matemática sinc() (definida como 'sin(x)/x') e ploto esse gradiente usando-o como mapa de deslocamento...
magick -size 121x100 xc: -fx 'sin(i*24/w-12)/(i*24/w-12)/1.3+.2' \
gradient_sinc.gif
magick -size 121x100 xc: -draw 'line 0,50 120,50' graph_source.gif
magick graph_source.gif gradient_sinc.gif \
-compose Displace -define compose:args=0x49 -composite \
displace_graph.gif
Como você pode ver, funciona, embora eu não gostasse de usá-lo para gráficos matemáticos. É melhor usar um pacote de plotagem adequado. Esta técnica, no entanto, é útil como um método improvisado de plotar as intensidades de uma linha ou coluna de pixels em uma imagem. O que ela faz é mostrar como grandes diferenças nos deslocamentos podem facilmente produzir uma descontinuidade ou um resultado não suave. Basicamente, como cada pixel individual da "fonte do gráfico" é examinado um de cada vez, sem média, uma grande diferença na consulta deslocada de um pixel para o próximo pode produzir uma grande mudança de cor no resultado. A moral é que o deslocamento funciona melhor não apenas com mapas de deslocamento suaves, mas também ao deslocar imagens que contenham grandes áreas ou tonalidades de cor. Não funciona tão bem para linhas finas e nítidas. É claro que você pode melhorar as coisas novamente Super Amostrando o mapa de distorção... |
magick graph_source.gif gradient_sinc.gif -resize 400% \
-compose Displace -define compose:args=0x196 -composite \
-resize 25% displace_graph_2.gif
![[IM Output]](../static/img/mapping/displace_graph_2.gif)
O resultado é muito melhor, embora não tão bom quanto o que pode ser obtido usando um pacote de plotagem. Ainda assim, apenas o ImageMagick foi usado em sua criação. Aqui está outra versão do mesmo gráfico, mas desta vez usando uma cor sólida, o que funciona muito melhor do que deslocar uma linha fina. |
magick -size 121x50 xc:white xc:black -append \
gradient_sinc.gif -resize 400% \
-compose Displace -define compose:args=0x196 -composite \
-resize 25% displace_graph_3.gif
Deslocamento de Área (Linear)
Vamos tentar um problema de deslocamento mais lógico. Mover uma área de uma imagem em linha reta de uma posição para outra. Como vimos, uma imagem de 'cinza puro' não causa nenhum deslocamento, enquanto uma cor 'branca' causa um deslocamento positivo da consulta a partir da imagem de origem. Por exemplo, vamos criar uma imagem assim.... |
magick -size 75x75 xc:gray50 -fill white \
-draw 'circle 37,37 37,20' dismap_spot.jpg
![[IM Output]](../static/img/mapping/dismap_spot.jpg)
Agora, quando aplicarmos esta imagem, o conteúdo da área marcada deverá conter uma cópia do que quer que apareça na direção do valor de deslocamento dado. Então vamos tentar um valor de deslocamento de X +10 e Y +10, ou '10x10'...
magick koala.gif dismap_spot.jpg \
-compose Displace -define compose:args=10x10 -composite \
displace_spot.png
Como você pode ver, o conteúdo da área marcada agora contém uma cópia da imagem que estava +10,+10 pixels a Sudeste. Basicamente, uma imagem da 'cauda' do koala. Em outras palavras, dentro do círculo a imagem foi deslocada para Nordeste, ou -10,-10 pixels. Lembre-se de que o deslocamento é da consulta, então a imagem de origem é deslocada por uma quantia negativa, devido ao Mapeamento Reverso de Pixels. A imagem se desloca na direção contrária! Observe também que é a imagem dentro da área marcada que é movida. Você não está deslocando a imagem marcada, mas deslocando a imagem PARA DENTRO da área marcada. E, por fim, observe a descontinuidade acentuada nas bordas do círculo. As áreas dentro da área marcada são movidas, enquanto as áreas fora dela permanecem exatamente como estavam. Estes são os fatos, então vale a pena repetir.
O deslocamento move as imagens na direção oposta ao valor.
Somente as áreas marcadas que não são cinza serão deslocadas.
Mudanças bruscas de cor produzem descontinuidades bruscas na imagem.
Então vamos tentar algo mais prático. Vamos mover o centro entre o nariz e os olhos do koala, localizado em '32,22', para o centro do nosso círculo branco (deslocamento positivo total) em '37,37'. Isso requer um valor de deslocamento de '-5,-15' (lembre-se de que é uma direção invertida)... |
magick koala.gif dismap_spot.jpg \
-compose Displace -define compose:args=-5x-15 -composite \
displace_head.png
![[IM Output]](../static/img/mapping/displace_head.png)
E aí temos uma cópia bem centralizada da parte central da cabeça do koala. Mas a imagem ainda está 'disjunta', e usar um valor negativo não é muito agradável. A solução é usar um ponto preto em vez disso, mas também desfocar as bordas desse ponto. Vamos também torná-lo maior para abranger mais da cabeça do koala. Então, aqui está nossa imagem de 'ponto de movimento positivo'... |
magick -size 75x75 xc:gray50 -fill black \
-draw 'circle 37,37 37,17' -blur 0x5 dismap_area.jpg
![[IM Output]](../static/img/mapping/dismap_area.jpg)
Você não deve desfocar a imagem demais, ou o centro do ponto deixará de ser uma cor preta uniforme. Alternativamente, você poderia apenas Normalizar ou Ajustar Nível Inverso a imagem para garantir que a área desenhada seja preta e as partes ao redor sejam cinzas perfeitos. Você verá isso ser feito bastante nos exemplos posteriores. Agora vamos repetir aquele último deslocamento da 'cabeça' usando nosso mapa de deslocamento de 'ponto difuso' preto. |
magick koala.gif dismap_area.jpg \
-compose Displace -define compose:args=5x15 -composite \
displace_area.png
![[IM Output]](../static/img/mapping/displace_area.png)
Como você pode ver, movemos a imagem +5,+15 para dentro da área 'difusa', mas desta vez a borda da área é mais suave e conectada ao resto da imagem. É claro que as orelhas na borda do círculo foram distorcidas pela borda difusa, e o corpo do koala também foi comprimido, mas ainda é muito melhor do que o que tínhamos antes. Para evitar o 'rasgo' da imagem que você vê no lado de saída, ou deixar cópias da parte deslocada, você deve expandir esse ponto ou criar um tipo de imagem de deslocamento em gradiente mais complexo. Por exemplo, suponha que você queira mover a cabeça do koala da sua posição inicial em '32,22' para o centro da imagem em '37,37', ou um movimento de +5,+15 pixels, mas queira ajustar toda a imagem a essa mudança, para dar um efeito muito mais suave. Para isso, você vai querer o deslocamento máximo de preto (um deslocamento positivo da imagem) em '37,37', deslocando por um valor de +5,+15. Mas você também vai querer garantir que o resto da imagem permaneça intacto, 'fixando' os cantos em 50% de cinza. Isso é perfeito para um Gradiente Esparso Interpolado de Shepard.
magick -size 75x75 xc: -sparse-color Shepards \
'37,37 black 0,0 gray50 74,74 gray50 0,74 gray50 74,0 gray50' \
dismap_move.jpg
magick koala.gif dismap_move.jpg \
-compose Displace -define compose:args=5x15 -composite \
displace_move.png
Como você pode ver, você obtém uma área maior de deslocamento, espalhada por toda a imagem. O resultado é uma imagem que muda de forma muito mais suave do que o método de 'ponto' mais restrito usado antes. Isso é, na verdade, exatamente equivalente à Distorção de Shepard, mas apenas para um único ponto de controle em movimento. É também exatamente o mesmo método usado no script '[shapemorph](http://www.fmwconcepts.com/imagemagick/shapemorph/)' de Fred Weinhaus, mas com alguma animação. Em resumo: para pequenos deslocamentos localizados, podem ser usados deslocamentos de 'ponto desfocado'. Mas, para deslocamentos maiores ao longo de uma distância mais longa, deve ser usado um mapa de deslocamento em gradiente suave maior, para evitar o rasgo ou a duplicação da imagem de origem.
Em Construção
Morphing Simples por Deslocamento
Modificando o Tamanho dos Vetores de Deslocamento
Morphing entre Duas Imagens
Deslocamentos 1D Aleatórios
Reflexos em Água Ondulada
Como mencionado antes, os mapas de deslocamento são especialmente úteis para gerar distorções semelhantes a água e vidro.
Para este exemplo, gerei uma imagem pequena Recortando uma imagem de flor. Agora quero fazer com que pareça estar sobre uma água ondulada. Para gerar ondulações, preciso de um gradiente em onda senoidal do mesmo tamanho, que posso gerar usando a Função Evaluate Sin. O número '8' representa o número de 'ondas' que serão adicionadas ao gradiente. |
magick -size 150x80 gradient: -evaluate sin 8 wave_gradient.png
![[IM Output]](../static/img/mapping/wave_gradient.png)
Agora vamos distorcer essa imagem usando um vetor de deslocamento angulado, e não apenas uma distorção vertical ou horizontal simples, de modo a dar mais ênfase. |
magick composite wave_gradient.png flower.jpg -displace 5x5 flower_waves.png
![[IM Output]](../static/img/mapping/flower_waves.png)
Isso não parece muito interessante, mas e se você inverter essa imagem, comprimi-la verticalmente e anexá-la à original... |
magick flower_waves.png -flip \
flower.jpg +swap -append flower_waves_2.png
![[IM Output]](../static/img/mapping/flower_waves_2.png)
Infelizmente, ainda parece bastante artificial. A razão é que o reflexo parece igual tanto no topo quanto na base da imagem. Não há nenhuma sensação de 'profundidade'. O reflexo também tem o mesmo brilho da imagem original, o que raramente é o caso. Para torná-lo mais realista, você precisa usar um padrão de ondulação que varie em intensidade. O exemplo a seguir usa uma Matemática de Gradientes sofisticada para 'atenuar' o gradiente de ondas que usávamos acima. Ou seja, fizemos o padrão de ondas ficar linearmente menor à medida que vai do topo para a base. Esse artifício garante que as ondas terminem na cor de cinza puro, ou 'sem deslocamento', na base da imagem (que depois é invertida). |
magick -size 150x80 gradient: \
\( wave_gradient.png \
+clone -compose multiply -composite \) \
\( -clone 0 -negate -evaluate divide 2 \
-clone 1 -compose plus -composite \) \
-delete 0-1 waves_decreasing.png
![[IM Output]](../static/img/mapping/waves_decreasing.png)
Então vamos aplicar este gradiente para formar um novo reflexo da flor. Também escureci ligeiramente a imagem refletida para representar parte da luz sendo perdida na própria água, fazendo com que pareça mais um reflexo na água. |
magick flower.jpg waves_decreasing.png \
-compose Displace -define compose:args=8x8 -composite \
-flip +level 0,80% \
flower.jpg +swap -append flower_in_water.png
![[IM Output]](../static/img/mapping/flower_in_water.png)
Observe que a imagem distorcida é Invertida para formar um reflexo. Além disso, a imagem terá menos 'ondulações' no topo da 'água', mais próximo de onde ela se junta à imagem original, do que na base. Isso dá à distorção uma sensação de distância do observador. Você pode torná-la ainda mais realista distorcendo os mapas de deslocamento de ondas com uma leve rotação, arco, ou apenas com deslocamentos 'aleatórios'. Isso dará às ondas um aspecto mais natural. Embora seja melhor fazer isso antes da 'atenuação', de modo que a 'profundidade' seja adicionada depois. Experimente, teste e me conte o que você conseguir.
Futuras Ondulações Animadas -
Usando -function Sinusoid com mudança de fase
Mapeamento de Deslocamento Bidimensional
Até agora, todos os mapas de deslocamento relativo deslocaram a imagem em apenas uma direção. Embora essa direção possa ser ajustada para qualquer ângulo desejado, definindo o valor de deslocamento, ou 'vetor', '_X_ x _Y_' apropriado. No entanto, você pode produzir um deslocamento muito mais complexo, em que a imagem é deslocada em qualquer direção por qualquer quantia, usando dois deslocamentos separados. Para isso, precisamos criar dois mapas de deslocamento, um para cada uma das direções X e Y separadamente. Aqui estão os comandos que você pode usar...
magick {_image_} {_X displacement_} {_Y displacement_} \
-compose Displace -define compose:args={_X_}x{_Y_} \
-composite {_result_ +}
magick {_image_} {_X displacement_} {_Y displacement_} \
-compose Displace -set option:compose:args {_X_}x{_Y_} \
-composite {_result_ +}
composite {_X displacement_} {_image_} {_Y displacement_} \
-displace {_X_}x{_Y_} {_result_ +}
Observe a ordem das imagens de entrada no comando "magick composite". A ordem estranha é causada pela necessidade de abusar do tratamento de opções do "magick composite", bem como por razões históricas. É vital que você acerte isso. Por causa disso, recomendo que você use o comando "magick", em vez de "magick composite". |
Antes do IM v6.4.4, usar 2 mapas de deslocamento separados para deslocamentos X e Y separados era algo incerto. Às vezes funcionava, às vezes não. Não é recomendável nem tentar usá-lo em versões do IM mais antigas que esta. |
|---|---|
| Além disso, assim como nos Mapas de Distorção Unificados, você pode usar um único "Mapa de Deslocamento Unificado". Se apenas uma imagem de deslocamento for fornecida, o deslocamento X será consultado no canal 'red', o deslocamento Y será consultado no canal 'green', e qualquer máscara alfa também será transferida do mapa de deslocamento para a imagem final. O canal 'blue' é ignorado. | _Internamente, tanto o "magick" quanto o "magick composite" na verdade mesclam as duas imagens (se fornecidas), de modo a gerar um 'mapa de deslocamento unificado', antes de passá-lo para a API interna. |
Isso não afeta os 'deslocamentos lineares' anteriores que vimos, pois o mapa de deslocamento fornecido era uma imagem em tons de cinza, então tanto o canal 'red' quanto o 'green' eram idênticos._
---|---
Deslocamento Cilíndrico
Algo que surgiu várias vezes nos fóruns do IM é uma maneira de mapear uma imagem sobre um cilindro, como para sobrepô-la a uma caneca de café ou a uma lata de refrigerante. Esta é a solução... |
magick rose: -background black -gravity south -splice 0x8 \
\( +clone -sparse-color barycentric '0,0 black 69,0 white' \) \
\( -clone 1 -function arcsin 0.5 \) \
\( -clone 1 -level 25%,75% \
-function polynomial -4,4,0 -gamma 2 \
+level 50%,0 \) \
-delete 1 \
-virtual-pixel black -define compose:args=17x7 \
-compose Displace -composite rose_cylinder.png
![[IM Output]](../static/img/mapping/rose_cylinder.png)
O exemplo acima é muito complexo, mas, em essência, usa dois deslocamentos separados simultaneamente. Uma compressão arcsin() na direção X e um deslocamento em arco circular na direção Y. Aqui está o que o comando faz...
- Carregar a imagem "rose" e adicionar algum espaço para o deslocamento vertical
- Criar um gradiente matemático horizontal para funções matemáticas posteriores
- magick uma cópia do gradiente para gerar um mapa de deslocamento de compressão
- magick outra cópia para um deslocamento em arco elíptico vertical
- remover o gradiente linear
- preparar e executar o deslocamento
Resultado... Uma rosa envolvida corretamente em uma visão isométrica de 30 graus de um cilindro. Desmembre o comando acima para salvar e visualizar os mapas de deslocamento individuais. O ponto a lembrar é que o deslocamento por dois mapas realiza as consultas dos valores tanto X quanto Y, para determinar qual pixel deve terminar na posição da consulta. Lembre-se de que o deslocamento não é, na verdade, um deslocamento da imagem de origem, mas um deslocamento da consulta na imagem de origem. Este método de distorção por deslocamento foi incorporado ao script "[cylinderize](http://www.fmwconcepts.com/imagemagick/cylinderize/)" de Fred Wienhaus.
Espelho Fraturado
Você pode criar um aspecto de 'espelho fraturado' em uma imagem gerando áreas aleatórias de deslocamentos X e Y.
magick dragon_sm.gif -sparse-color voronoi ' \
%[fx:rand()*w],%[fx:rand()*h] red
%[fx:rand()*w],%[fx:rand()*h] lime
%[fx:rand()*w],%[fx:rand()*h] black
%[fx:rand()*w],%[fx:rand()*h] yellow
' -interpolate integer -implode 1 mirror_areas.gif
magick mirror_areas.gif -channel R -separate mirror_dismap_x.gif
magick mirror_areas.gif -channel G -separate mirror_dismap_y.gif
magick composite mirror_dismap_x.gif dragon_sm.gif mirror_dismap_y.gif -alpha off \
-background white -virtual-pixel background -displace 7 \
mirror_displaced.gif
magick mirror_areas.gif -edge 1 -threshold 20% \
-evaluate multiply .7 -negate mirror_cracks.gif
magick composite mirror_displaced.gif mirror_cracks.gif -compose multiply \
mirror_cracked.gif
| Quatro áreas deslocadas aleatoriamente são geradas usando uma imagem de Cor Esparsa Voronoi randomizada. Em seguida, aplica-se uma Distorção de Implosão para deformar essas áreas em direção ao centro da imagem. Como cada uma das quatro áreas coloridas permanece com cores sólidas, cada área conterá uma cópia não distorcida, mas deslocada, da imagem original. No entanto, cada área terá deslocado a imagem de uma forma diferente, assim como cada estilhaço de um espelho fraturado o faria. Para finalizar o espelho, usa-se a Detecção de Bordas para contornar as bordas das regiões e, assim, a natureza fraturada da imagem resultante. Ou seja, as rachaduras também se tornam visíveis. | Tecnicamente, eu não precisava separar os canais 'red' e 'green' no mapa de deslocamento aleatório colorido que foi gerado. Eu poderia tê-los usado diretamente, já que o deslocamento X é consultado no canal 'red' e o deslocamento Y é consultado no canal 'green'. Ou seja, eu poderia ter usado a imagem "mirror_areas.gif" diretamente como um "mapa de deslocamento unificado". |
|---|---|
Em Construção
Deslocamento de Shepards
Deslocamentos Aleatórios
Efeitos de Lente
Efeitos de Vidro Fosco
Efeitos de Dispersão (deslocamentos rotacionados)
Efeitos de Dispersão com Deslocamento Aleatório
FUTURO: Outros possíveis exemplos de mapeamento distort / displace
- Traçar por raytrace um gradiente sobre objetos 3D para que, mais tarde, QUALQUER imagem possa ser mapeada sobre esses objetos.
- Imagens com gradientes X e Y mapeados
- Imagem em Cinza Puro para cor, realces e sombreamento
Mapeamento de Desfoque Variável
Adicionado ao ImageMagick versão 6.5.4-0, o método 'Blur' de "[-compose](https://imagemagick.org/command-line-options/#compose)" oferece uma maneira de substituir cada pixel individual por uma Média Gaussiana Elíptica (um desfoque) dos pixels vizinhos, de acordo com uma imagem de mapeamento.
magick composite -blur {_Xscale_}[x{_Yscale_}[+{_angle_}]] blur_map image result
magick image blur_map \
-define compose:args='{_Xscale_}[x{_Yscale_}[+{_angle_}]]' \
-compose blur -composite result
magick image blur_map \
-set option:compose:args '{_Xscale_}[x{_Yscale_}[+{_angle_}]]' \
-compose blur -composite result
Observe que esta Composição de Imagem requer o uso de um argumento operacional, que pode ser definido de várias maneiras. Veja Artefatos Definidos Globalmente para mais detalhes. Ao usar um mapa variável para controlar o desfoque, você pode desfocar uma parte de uma imagem enquanto deixa outra parte completamente intacta, ou produzir efeitos como o Efeito Tilt-Shift, em que uma imagem do mundo real é feita para parecer mais um pequeno modelo artificial.
Por exemplo, aqui desfoco uma metade de uma imagem de um koala, deixando a outra metade completamente sem desfoque...
magick -size 37x75 xc:black -size 38x75 xc:white +append blur_map_bool.gif
magick koala.gif blur_map_bool.gif \
-compose blur -define compose:args=3 -composite \
blur_koala_bool.gif
Como você pode ver, qualquer pixel que fosse 'branco' na imagem 'blur_map' foi desfocado usando o valor máximo de 'sigma ' fornecido, enquanto tudo o que fosse 'preto' não foi desfocado. Em outras palavras, você tem um desfoque mascarado muito simples. É claro que isso poderia ter sido obtido de muitas outras maneiras, mas isso não explica onde está o poder do mapeamento de desfoque. O que torna esse mapeamento de desfoque versátil é que ele é variável ao longo da imagem. Ou seja, se a cor do mapeamento de desfoque for cinza, você obterá um resultado desfocado correspondentemente menor, usando uma 'vizinhança' menor, para aquele pixel. O preto, porém, não é desfocado, enquanto o branco é desfocado ao máximo, pelos valores fornecidos. Uma coisa a observar é que apenas as áreas desfocadas exigirão o tempo extra necessário. Os pixels que não são desfocados não precisam desse processamento extra. Isso torna o exemplo acima muito mais rápido do que usar um Composite Mascarado, que equivale a desfocar a imagem inteira e mesclar os resultados. Essa economia de tempo pode ser ainda mais importante ao lidar com grandes desfoques de áreas muito pequenas de uma imagem. Por exemplo, vamos deixar o koala progressivamente mais desfocado em direção aos pés...
magick -size 75x75 gradient:black-white blur_map_gradient.gif
magick koala.gif blur_map_gradient.gif \
-compose blur -define compose:args=3 -composite \
blur_koala_gradient.gif
E aqui está o mesmo desfoque novamente, mas mostrando como o desfoque varia com a altura.
magick blur_map_bool.gif blur_map_gradient.gif \
-compose blur -define compose:args=15 -composite \
blur_edge_gradient.gif
Para um exemplo prático de Desfoques Mapeados Variáveis, dê uma olhada no Efeito Tilt Shift em Fotos e na Fonte com Sombra Desfocada por Distância. Observe que é a vizinhança em torno de cada pixel individual que é usada para gerar a 'cor desfocada' daquele pixel. Isso significa que, mesmo que você especifique que alguma parte de uma imagem não deve ser desfocada, as cores dessa área não desfocada podem ser usadas como parte do desfoque dos pixels vizinhos. Ou seja, só porque uma área não é desfocada não significa que as cores dessa área não sejam usadas como parte do resultado de outros pixels desfocados. Isto é, as cores da área não desfocada podem 'vazar' para as áreas desfocadas ao redor. Para desfocar um fundo sem incluir os pixels de primeiro plano, você precisa usar uma Técnica de Read Mask para impedir que sejam lidos como parte da operação de desfoque.
Desfoque Elíptico
A configuração de composição 'Blur' usa uma técnica diferente da dos Operadores Blur ou Gaussian Blur normais, pois é implementada usando um algoritmo Gaussiano de Reamostragem de Área Elíptica desenvolvido para a reamostragem de imagens escaladas, como parte do Operador de Distorção Generalizado. A área elíptica usada para a reamostragem da vizinhança também torna este método de desfoque mais versátil do que um desfoque 'circular' uniforme normal, fornecido pelos operadores "[-blur](https://imagemagick.org/command-line-options/#blur)" e "[-gaussian-blur](https://imagemagick.org/command-line-options/#gaussian-blur)". A própria elipse é definida pela 'largura ' e pela 'altura ' do sigma da área desfocada. A elipse também pode ser rotacionada a partir de um alinhamento ortogonal pelo 'ângulo ' fornecido (no sentido horário). Por exemplo, no diagrama a seguir mostramos como a cor desfocada de um único pixel obtém sua cor a partir de uma área elíptica rotacionada, com base nos valores de sigma fornecidos. Os pixels dessa área são então combinados por média ponderada, de acordo com um Filtro Gaussiano (usando uma fórmula de distância elíptica), para produzir a cor desfocada.
magick koala.gif -compose blur -define compose:args=5x1-30 -composite \) \
elliptical_blur.gif
# ... other commands to create diagram of blur effect ...
Como mencionado, este é exatamente o mesmo método de consulta de cor usado pelo Operador de Distorção Generalizado para gerar as cores de suas imagens distorcidas, pois permite uma fusão escalada (e filtrada) de uma área da imagem de origem em um único pixel, especialmente em distorções extremas como as exemplificadas em Visualizando Horizontes Distantes. Para mais detalhes sobre esse processo, veja Reamostragem de Área e Filtros de Reamostragem.
Como exemplo dos controles elípticos disponíveis para o mapeamento de desfoque variável, vamos usar um ponto preto com o mesmo mapa de desfoque em gradiente que usamos antes. Mas, desta vez, escalaremos uma elipse horizontal longa e fina '30x0', em vez de um círculo. O 'x0' pode parecer estranho, mas basicamente significa que nenhum desfoque vertical deve aparecer, apenas uma elipse com a menor altura necessária para gerar um bom resultado.
magick -size 75x75 xc: -draw 'circle 36,36 36,8' black_circle.gif
magick black_circle.gif blur_map_gradient.gif \
-compose blur -define compose:args=15x0 -composite \
blur_horizontal.gif
Como você pode ver, a quantidade de desfoque ainda varia com a imagem de mapa fornecida, produzindo muito pouco desfoque no topo da imagem e muito desfoque na base. Mas observe também que a borda inferior é desfocada horizontalmente de forma igual em ambas as direções, mas não verticalmente, produzindo um corte nítido na direção vertical. Rotacionando a elipse longa e fina, ao fornecer um terceiro argumento de ângulo, ou definindo diretamente uma elipse vertical, você pode desfocar a imagem apenas verticalmente... |
magick black_circle.gif blur_map_gradient.gif \
-compose blur -define compose:args=0x15 -composite \
blur_vertical.gif
![[IM Output]](../static/img/mapping/blur_vertical.gif)
Observe, no entanto, que o desfoque não foi aplicado de forma igual! A metade superior parece menos desfocada do que a inferior, porque foi isso que a 'imagem de mapeamento' mandou fazer. Isso, por sua vez, distorce a imagem, fazendo-a parecer um pouco truncada pelo efeito de desfoque. Por fim, vamos fazer isto mais uma vez, mas com uma elipse horizontal rotacionada por um ângulo fixo de 45 graus. |
magick black_circle.gif blur_map_gradient.gif \
-compose blur -define compose:args=15x0+45 -composite \
blur_angle.gif
![[IM Output]](../static/img/mapping/blur_angle.gif)
A imagem pode parecer muito estranha, mas isso ocorre porque o mapa de desfoque variável é vertical, enquanto o próprio desfoque é angulado, produzindo o efeito de aparência estranha, devido à forma como o ângulo da elipse e o ângulo do mapa de desfoque não se alinham. | Observe que usar elipses longas e finas como esta é, na verdade, muito mais rápido do que usar um único círculo grande. De fato, o operador "[-blur](https://imagemagick.org/command-line-options/#blur)" obtém sua velocidade usando dois desfoques separados, horizontal e vertical, enquanto o operador "[-gaussian](https://imagemagick.org/command-line-options/#gaussian)" faz uma convolução 2D completa, de maneira mais simples do que o método de composição 'Blur' que acabamos de descrever.
---|---
Desfoque com Proporção Variável
Até agora, variamos o tamanho da área elíptica usada para o desfoque por meio do 'mapa de desfoque'. No entanto, embora o tamanho da elipse e até seu ângulo possam ser rotacionados, sua forma e ângulo permanecem fixos. Ora, o 'mapa de desfoque' é uma imagem composta por três canais de cor: vermelho, verde e azul. Como usamos uma imagem em tons de cinza, os três canais de cor tinham os mesmos valores. No entanto, internamente a largura da elipse é escalada apenas pelo valor do canal vermelho, enquanto a altura é escalada pelo valor do canal verde. Qualquer efeito do valor do canal azul é normalmente ignorado, exceto em um caso especial que veremos mais adiante. Isso significa que a forma elíptica, ou sua 'proporção', pode ser variada usando mapas diferentes para os canais vermelho e verde individuais. Como em um mapa de desfoque normal, um valor zero (ou 'preto' apenas naquele canal) resultará em largura ou altura mínima, enquanto um valor máximo (ou 'branco') resultará na quantidade de desfoque fornecida. Por exemplo, aqui posso dividir a imagem de modo que dois quartos da imagem sejam desfocados horizontalmente (canal vermelho máximo), enquanto as outras áreas são desfocadas verticalmente (canal verde máximo). Para este exemplo, gerei os mapas de largura e altura separadamente, antes de Combiná-los em um único mapa de desfoque, agora colorido. Na prática normal, você pode criar o mapa da maneira que quiser, ou mesmo usar mapas pré-preparados para efeitos de desfoque específicos.
magick -size 2x2 pattern:gray50 -sample 75x75! blur_map_r.gif
magick blur_map_r.gif -negate blur_map_g.gif
magick blur_map_r.gif blur_map_g.gif -background black \
-channel RG -combine blur_map_aspect.gif
magick black_circle.gif blur_map_aspect.gif \
-compose blur -define compose:args=10x10 -composite \
blur_aspect.gif
Você pode, é claro, ainda definir um ângulo fixo para a elipse. |
magick black_circle.gif blur_map_aspect.gif \
-compose blur -define compose:args=15x15+45 -composite \
blur_aspect_angle.gif
![[IM Output]](../static/img/mapping/blur_aspect_angle.gif)
| Antes da versão 6.5.8-8 do IM, foi encontrado um bug no tratamento de um desfoque elíptico vertical angulado.
---|---
Desfoque com Ângulo Variável
Até agora, o ângulo da elipse usada para desfocar a imagem tem sido um ângulo constante em toda a imagem. Ou seja, a elipse usada para o desfoque sempre esteve no mesmo ângulo, embora a proporção da elipse possa ser variada modificando os canais vermelho e verde do mapa de desfoque. A partir do IM v6.5.8-8, você pode fornecer um ângulo variável ao desfoque, usando o canal azul da imagem de mapeamento de desfoque. Isso é feito fornecendo dois ângulos aos argumentos do desfoque. O primeiro argumento de ângulo é usado para definir o ângulo para um valor zero ('0' ou 'preto') no canal azul, enquanto o segundo ângulo fornecido é usado para definir o valor máximo ('QuantumRange' ou 'branco') do canal azul. Se apenas um valor de ângulo for fornecido, esse ângulo é usado para definir os ângulos tanto para o valor zero quanto para o valor máximo do canal 'azul', o que basicamente significa que o ângulo se torna fixo, independentemente do valor presente no canal azul da imagem 'mapa de desfoque'. É por isso que, nos exemplos anteriores, o ângulo tem sido constante. Por exemplo, aqui uso uma elipse de desfoque horizontal, mas depois vario o ângulo da elipse usando o canal azul, ao longo da faixa de ângulo de '+0' a '+360' em torno do centro da imagem. A geração do mapa usa um gradiente polar, cujos detalhes podem ser encontrados em Gradientes Distorcidos. Observe como, ao colocar esse gradiente no canal azul, uso a configuração de cor "[-background](https://imagemagick.org/command-line-options/#background)" com o Operador Combine para garantir que tanto o canal vermelho quanto o verde sejam definidos como valor máximo ('branco'), de modo que não escale a elipse angulada. É claro que isso significa que, na imagem de mapeamento final, o branco significa usar o ângulo máximo, enquanto o amarelo (ou valor zero no canal azul) significa o ângulo mínimo.
magick -size 100x300 gradient: -rotate 90 \
+distort Polar '36.5,0,.5,.5' +repage -flop gradient_polar.jpg
magick gradient_polar.jpg -background white \
-channel B -combine blur_map_angle.jpg
magick koala.gif blur_map_angle.jpg \
-compose blur -define compose:args=5x0+0+360 -composite \
blur_rotated.jpg
O resultado, como você pode ver, é uma imagem com desfoque rotacional. Compare o resultado com o mapeamento de desfoque que foi usado. No topo da imagem, o gradiente era branco ou preto, o que, com os argumentos usados, significa que a elipse foi angulada a 0 ou 360, então a elipse permaneceu horizontal. Na base, o gradiente era cinza puro, então um ângulo intermediário na faixa fornecida foi usado, ou 180 graus. Isso significa que a elipse é novamente horizontal. Mas nas laterais da imagem, o gradiente era cinza de 25% ou 75%. Assim, o ângulo era 90 ou 270 graus, fazendo a elipse rotacionar verticalmente. Todos os outros ângulos seguem o mesmo padrão, fazendo a elipse rotacionar suavemente ao redor da imagem. No entanto, o centro da imagem resultante foi desfocado de forma muito estranha! Isso ocorre porque o tamanho da elipse permaneceu constante e não fica adequadamente menor em direção ao meio da imagem. A solução é também definir o tamanho da elipse usando os canais vermelho e verde. Por exemplo.
magick -size 106x106 radial-gradient: -negate \
-gravity center -crop 75x75+0+0 +repage gradient_radial.jpg
magick gradient_radial.jpg gradient_radial.jpg gradient_polar.jpg \
-channel RGB -combine blur_map_polar.jpg
magick koala.gif blur_map_polar.jpg \
-compose blur -define compose:args=10x0+0+360 -composite \
blur_polar.jpg
Um resultado muito melhor. Observe, no entanto, que, embora o resultado pareça bom, a elipse de desfoque não está adequadamente curvada em arco, como deveria estar para uma imagem com desfoque rotacional verdadeiro. Assim, o exemplo acima é apenas uma aproximação de um verdadeiro desfoque rotacional. Mas, para pequenas distâncias de desfoque (equivalentes ao ângulo de desfoque), é bastante bom. A melhor forma de fazer desfoques rotacionais é usar uma Técnica de Distorção Polar-Depolar especial, ou o atualmente mal nomeado Operador Radial Blur. Ao alterar a faixa de ângulo usada para o ângulo da elipse (canal azul), você pode facilmente converter o exemplo acima em um desfoque radial que fica mais desfocado conforme a distância do centro. |
magick koala.gif blur_map_polar.jpg \
-compose blur -define compose:args=5x0+90+450 -composite \
blur_radial.jpg
![[IM Output]](../static/img/mapping/blur_radial.jpg)
Mas você também pode fazer muito mais do que esses desfoques radiais/rotacionais, pois pode rotacionar e escalar o desfoque em qualquer lugar, por qualquer quantia, ao longo de toda a imagem. Você tem controle total. Por exemplo, pode criar uma mistura muito estranha dos dois usando faixas de ângulo diferentes, de modo que o ângulo da elipse de desfoque não corresponda ao ângulo em torno do centro da imagem. |
magick koala.gif blur_map_polar.jpg \
-compose blur -define compose:args=10x0+0+180 -composite \
blur_weird.jpg
![[IM Output]](../static/img/mapping/blur_weird.jpg)
Basicamente, você agora tem controle completo de como e de quais partes da imagem serão desfocadas. E, com o uso de modelos, você pode criar toda uma biblioteca de efeitos de desfoque.
![[IM Output]](../static/img/images/koala.gif)
![[IM Output]](../static/img/mapping/map_gradient_x.gif)
![[IM Output]](../static/img/mapping/distort_noop.gif)
![[IM Output]](../static/img/mapping/map_gradient-x.gif)
![[IM Output]](../static/img/mapping/distort_mirror_x.gif)
![[IM Output]](../static/img/mapping/map_compress.gif)
![[IM Output]](../static/img/mapping/distort_compress.gif)
![[IM Output]](../static/img/mapping/map_compress_y.gif)
![[IM Output]](../static/img/mapping/distort_compress_2D.gif)
![[IM Output]](../static/img/mapping/distort_compose.gif)
![[IM Output]](../static/img/mapping/distort_compose_default.gif)
![[IM Output]](../static/img/mapping/distort_fx_check.gif)
![[IM Output]](../static/img/mapping/distort_fx_check_correct.gif)
![[IM Output]](../static/img/mapping/map_rot45_x.png)
![[IM Output]](../static/img/mapping/map_rot45_y.png)
![[IM Output]](../static/img/mapping/distort_rot45.gif)
![[IM Output]](../static/img/mapping/map_rot45b_x.png)
![[IM Output]](../static/img/mapping/map_rot45b_y.png)
![[IM Output]](../static/img/mapping/distort_rot45_better.png)
![[IM Output]](../static/img/mapping/map_rot45b_m.png)
![[IM Output]](../static/img/mapping/distort_rot45_masked.png)
![[IM Output]](../static/img/mapping/map_rot45u.png)
![[IM Output]](../static/img/mapping/distort_rot45_unified.png)
![[IM Output]](../static/img/img_photos/lena_orig.png)
![[IM Output]](../static/img/mapping/sphere_lena.png)
![[IM Output]](../static/img/img_photos/mandrill_grid_sm.jpg)
![[IM Output]](../static/img/mapping/spherical_mandrill.png)
![[IM Output]](../static/img/images/rose.png)
![[IM Output]](../static/img/mapping/rose_row_shuffle.png)
![[IM Output]](../static/img/mapping/gradient_sinc.gif)
![[IM Output]](../static/img/mapping/graph_source.gif)
![[IM Output]](../static/img/mapping/displace_graph.gif)
![[IM Output]](../static/img/mapping/displace_graph_3.gif)
![[IM Output]](../static/img/mapping/displace_spot.png)
![[IM Output]](../static/img/mapping/dismap_move.jpg)
![[IM Output]](../static/img/mapping/displace_move.png)
![[IM Output]](../static/img/mapping/mirror_areas.gif)
![[IM Output]](../static/img/mapping/mirror_dismap_x.gif)
![[IM Output]](../static/img/images/dragon_sm.gif)
![[IM Output]](../static/img/mapping/mirror_dismap_y.gif)
![[IM Output]](../static/img/mapping/mirror_displaced.gif)
![[IM Output]](../static/img/mapping/mirror_cracks.gif)
![[IM Output]](../static/img/mapping/mirror_cracked.gif)
![[IM Output]](../static/img/mapping/blur_map_bool.gif)
![[IM Output]](../static/img/mapping/blur_koala_bool.gif)
![[IM Output]](../static/img/mapping/blur_map_gradient.gif)
![[IM Output]](../static/img/mapping/blur_koala_gradient.gif)
![[IM Output]](../static/img/mapping/blur_edge_gradient.gif)
![[IM Output]](../static/img/mapping/elliptical_average.gif)
![[IM Output]](../static/img/mapping/black_circle.gif)
![[IM Output]](../static/img/mapping/blur_horizontal.gif)
![[IM Output]](../static/img/mapping/blur_map_r.gif)
![[IM Output]](../static/img/mapping/blur_map_g.gif)
![[IM Output]](../static/img/mapping/blur_map_aspect.gif)
![[IM Output]](../static/img/mapping/blur_aspect.gif)
![[IM Output]](../static/img/mapping/gradient_polar.jpg)
![[IM Output]](../static/img/mapping/blur_map_angle.jpg)
![[IM Output]](../static/img/mapping/blur_rotated.jpg)
![[IM Output]](../static/img/mapping/gradient_radial.jpg)
![[IM Output]](../static/img/mapping/blur_map_polar.jpg)
![[IM Output]](../static/img/mapping/blur_polar.jpg)