Ejemplos de ImageMagick -- Efectos mediante mapeo de imágenes
- Prefacio e índice de los ejemplos de ImageMagick
- Introducción al mapeo de imágenes
- Distorsionar imágenes mediante mapeo de imágenes
- Mapas de búsqueda de distorsión absoluta
- Mapas de distorsión absoluta
- Composición de distorsión absoluta
- El mapa de distorsión sin efecto, de nuevo
- Problemas con los mapas de distorsión
- Definir los píxeles indefinidos mediante una máscara
- Imagen de distorsión unificada
- Mapa de distorsión de reloj de arena
- Mapa de distorsión esférica
- Mapa de distorsión de arco circular
- Operador de composición Displace
- Ejemplos simples de desplazamiento
- Graficar con desplazamiento
- Desplazamiento de áreas
- Reflejos en agua ondulada
- Mapas de desplazamiento bidimensionales
- Desplazamiento cilíndrico
- Desenfoque con relación de aspecto variable
- Desenfoque con ángulo variable
Distorsionar o modificar una imagen usando algún tipo de imagen «mapa» secundaria que controla el proceso. Ya sea reemplazando colores, desenfocando la imagen de forma variable, o distorsionando imágenes especificando las coordenadas de origen de forma absoluta o relativa.
Introducción
Como ha visto en las secciones anteriores sobre Composición, Deformación simple y Distorsión, puede modificar imágenes de muchas maneras distintas. Sin embargo, todas ellas se limitan a los métodos concretos que vienen integrados en ImageMagick. Incluso puede «crear su propia» distorsión de imagen con el operador casero «FX», o modificar directamente los valores de una imagen con operadores como Evaluate o Function, o incluso los diversos operadores Level. No obstante, las distorsiones requieren muchos cálculos (y tiempo) para realizar su tarea, y si piensa aplicar la misma tarea a varias imágenes, hacer que IM repita todos esos cálculos puede ser una verdadera pérdida de tiempo. El otro aspecto es que resulta muy difícil limitar los efectos de la distorsión de forma libre. No puede editar ni modificar sin más la distorsión que quiere aplicar. Tiene un control limitado. El mapeo de imágenes es distinto. Usa una imagen «mapa» adicional para controlar qué partes de una imagen se van a modificar, en qué medida o de qué manera. No tiene por qué modificar la imagen entera, ni tiene por qué modificarla de alguna forma predefinida o preprogramada. Puede crear un «mapa» que modifique una imagen de CUALQUIER forma posible, sin limitación. También puede editar o modificar aún más el mapeo para ajustar o limitar su efecto, hacerlo más complejo combinando distintos mapas, o simplemente suavizar o desenfocar el efecto. Y, por último, puede guardar el mapeo para volver a usarlo más adelante. Es la imagen «mapa» la que controla los resultados. Como la modificación está controlada por el «mapa», por lo general ImageMagick necesita realizar muy pocos cálculos, por lo que el «mapeo de imágenes» es en general muy rápido. También es repetible, ya que puede aplicar el mismo mapa, por muy complejo que sea, a cualquier número de imágenes para obtener exactamente la misma modificación. Es decir, puede aplicarlo a un directorio entero de imágenes muy rápidamente. En esencia, lo que hace el mapeo de imágenes es trasladar las matemáticas lentas y complejas de un efecto concreto, desde una imagen específica, a una imagen «mapa» más general. Una vez generado ese «mapa», puede aplicarse luego a muchísimas imágenes reales muy rápidamente.
¿Qué son los mapas de imágenes?
Las imágenes de mapeo son básicamente «tablas de consulta» o LUT que definen cómo debe aplicarse un efecto concreto a una imagen píxel a píxel. Es decir, si un efecto se aplica y en qué grado lo controla por completo el mapa de imagen. En esencia, una imagen es una matriz de valores, y lo que significan esos valores depende del proceso de mapeo que se esté aplicando. Podrían indicar...
- un valor de reemplazo directo (búsqueda de color),
- de qué imagen debe provenir un color (enmascaramiento de imágenes),
- cuánto debe aclararse u oscurecerse un píxel (resaltado),
- especificar la coordenada de origen (distorsión),
- o una posición relativa a la posición actual (desplazamiento).
- cuánto desenfocar los píxeles en esta ubicación
Muchos de estos ya los hemos visto en Composición de imágenes y, en cierto sentido, el mapeo de imágenes no es más que otra forma de combinar varias imágenes. De hecho, muchas técnicas de mapeo de imágenes se implementan simplemente como métodos de composición especializados. Recuerde que la verdadera composición de imágenes consiste realmente solo en superponer de varias formas dos imágenes de color reales (en concreto, los métodos de composición alfa de Duff-Porter). El mapeo de imágenes implica, de forma más general, usar imágenes especializadas que modifican una imagen de una manera especial. La parte más difícil del mapeo de imágenes es generar un «mapa» concreto para un efecto concreto. Y ahí es donde reside buena parte del trabajo, el esfuerzo y las técnicas que se presentan en esta página. Sin embargo, una vez que tiene un mapa, puede usarlo muchas veces con muchas imágenes distintas y muy rápidamente.
Distorsionar imágenes mediante mapeo de imágenes
Si bien los distintos operadores de distorsión descritos en las secciones anteriores de los ejemplos de IM (como la Deformación simple de imágenes y las Distorsiones generales de imágenes) le limitan a los tipos de distorsión que se han programado en la biblioteca gráfica de IM, generalmente mediante ecuaciones y fórmulas matemáticas concretas, hay ocasiones en las que quiere diseñar su propia distorsión de una forma más libre y menos matemática. Por ejemplo, para generar una distorsión más compleja, como mapear una imagen sobre una forma concreta, o con un efecto de lente complejo concreto, que es más fácil de dibujar que de definir matemáticamente. A veces solo quiere poder repetir la distorsión sobre un gran número de imágenes y evitar tener que recalcularla una y otra vez. La solución es precalcular la distorsión y guardarla como una tabla de consulta (LUT) especial en forma de imagen en escala de grises. Es decir, para cada píxel de salida consultamos la LUT y luego usamos ese valor para buscar el color en la imagen de origen. O sea, se necesitan tres pasos.
- Buscar cada píxel de destino en la LUT
- Mapear el valor de la LUT a la ubicación en la imagen de origen (dos métodos)
- Buscar el color en la imagen de origen
Como se usa una imagen para la «tabla de consulta» de la distorsión, puede crear o modificar un mapa de distorsión con un editor de imágenes, como 'Gimp' o 'PhotoShop', lo que le da libertad para realizar distorsiones realmente elaboradas y complejas. Sin embargo, debe recordar que, igual que en todos los demás métodos de distorsión que hemos visto, la consulta se aplica como un mapeo inverso de píxeles. Es decir, para cada píxel de la imagen de destino, buscamos el color del píxel en la imagen de origen mediante el método de distorsión que se está aplicando. En este caso, el método consiste en buscar la coordenada de origen en la imagen de tabla de consulta proporcionada.
Ahora bien, hay dos formas de usar un mapa de imagen para determinar dónde buscar un color en la imagen de origen... de forma absoluta o relativa. Con la búsqueda de coordenadas absoluta, un mapa de distorsión convierte el valor de color de la LUT directamente en una coordenada de la imagen de origen desde la que buscar el color a usar. No importa dónde esté el color en la LUT: cada color se refiere al punto exacto de consulta a usar. Las imágenes LUT de distorsión tendrán un degradado de colores, pero cualquier deformación o distorsión de ese degradado logrará el mismo efecto cuando se aplique el mapa. Con la búsqueda de coordenadas relativa, un mapa de desplazamiento usa el valor de color para desplazar la coordenada actual y averiguar la ubicación de la imagen de origen donde buscar el color. Esto significa que se usa una imagen LUT de gris puro, en la que las zonas más claras y más oscuras definen cómo se desplazan los píxeles según el mapa, independientemente de su posición en el mapa. Ambos métodos tienen ventajas e inconvenientes, como verá.
Mapas de búsqueda de distorsión absoluta
Crear un mapa LUT de distorsión absoluta es el más sencillo de los dos métodos, tanto para entenderlo como para crear los mapas LUT de distorsión y para aplicarlo. Sin embargo, como verá, tiene un inconveniente muy serio que lo hace menos práctico que un mapa de desplazamiento relativo. El color en un punto concreto del «mapa de distorsión» se refiere directamente a una ubicación de la imagen de origen. Es decir, el degradado en escala de grises a lo largo del «mapa» define la «textura» que se va a colocar en esa ubicación. Imagine ahora que la imagen del mapa es en realidad la imagen de un objeto complejo, como una camiseta, con pliegues y ondulaciones complejos. Si esa camiseta tiene un degradado, puede mapear cualquier imagen plana sobre ella. Ese es el poder de un mapa de distorsión absoluta. Cualquier píxel «negro» de la imagen LUT (valor de color 0) se considerará el píxel más a la izquierda, es decir, la coordenada X '0' de la imagen de origen, mientras que lo que sea «blanco» en la LUT (valor 1) se considerará el píxel más a la derecha (el ancho de la imagen de origen). Tenga en cuenta que esta LUT solo buscará la posición X u horizontal del color en la imagen de origen. No cambiará la altura ni las posiciones Y de los colores. Así que probemos esto con un sencillo degradado horizontal en escala de grises como LUT.
magick koala.gif \( -size 75x75 gradient: -rotate 90 \) \
-fx 'p{v*w,j}' distort_noop.gif
Esto no produjo ningún cambio real al mapear la imagen de origen sobre la de destino. Eso se debe a que la coordenada X que buscamos en el mapa de distorsión era la misma posición desde la que buscábamos el color. Con solo voltear el degradado, la búsqueda de los píxeles también se voltea, creando una imagen reflejada. Es decir, el blanco queda a la izquierda y el «negro» a la derecha, con un degradado horizontal a lo largo de la imagen.
magick koala.gif \( -size 75x75 gradient: -rotate -90 \) \
-fx 'p{v*w,j}' distort_mirror_x.gif
Si tomamos el degradado original y lo comprimimos con un operador de realce de contraste, obtenemos una distorsión mucho más ú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 los lados de la distorsión se estiran mientras que el centro se comprime. Podemos llevar esto a dos dimensiones usando 2 mapas de distorsión, uno para ajustar la coordenada X y otro para la 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 puede ver, lo anterior recrea una variante del método de implosión, aunque solo comprimiendo las imágenes a lo largo de los ejes X e Y (de forma simultánea), en lugar de radialmente como hace el operador Implode. La clave aquí es que lo que le haga al mapa de distorsión absoluta se lo hará a la imagen final de cualquier imagen a la que lo aplique. Ese es el poder de los mapas de distorsión.
Método de composición «Distort»
Hasta ahora hemos usado el operador casero general FX para aplicar mapas de distorsión absoluta. Esto ofrece una forma de adaptar y afinar con exactitud lo que está haciendo, pero también es muy lento. El operador de composición "Distort" codifica una fórmula muy similar a la que hemos usado arriba. Aunque se ha implementado de un modo que también lo hace algo más compatible con el operador de composición "Displace" que veremos más adelante en Mapas de desplazamiento relativo.
Así que repitamos el último ejemplo de «implosión» con una composición "Distort".
magick koala.gif map_compress.gif map_compress_y.gif \
-compose Distort -define compose:args=37.5x37.5 -composite \
distort_compose.gif
Observe el uso del «ajuste Define» "compose:args" en el ejemplo anterior. Este valor es un multiplicador aplicado al degradado de la LUT que se usa (centrado en un gris perfecto). El valor usado '37.5' es la mitad del ancho y del alto de la imagen (75 píxeles). Puede cambiar ese multiplicador para ampliar o reducir la escala general de la distorsión. Si NO se definen los valores de "compose:args", se usarán por defecto los valores correctos. Si el valor se ajusta a cero, no se aplicará distorsión en esa dirección. Si quisiera ajustar automáticamente los argumentos de composición, puede usar el siguiente método equivalente Set "option:" para calcularlo... |
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)
O dejarlo sin definir para que IM calcule los valores correctos (para una Distort 2D)... |
magick koala.gif map_compress.gif map_compress_y.gif \
-compose Distort -define compose:args='' -composite \
distort_compose_default.gif
Mapa de distorsión sin efecto
Antes de continuar, me gustaría detenerme un momento y echar otro vistazo al ejemplo «sin efecto» (noop) anterior. En realidad esto desenfoca ligeramente la imagen, ya que la fórmula tal como la he descrito no es del todo correcta. Obtener la copia «sin efecto» del original es una buena prueba para comprobar que las matemáticas de su distorsión son correctas.
Es decir, dado un degradado perfecto, puede mapear cada píxel de la imagen de origen a la imagen de destino. Es decir, el valor «blanco» (o 1.0) de la LUT se mapeará exactamente al píxel más a la derecha (o más abajo) de la imagen de destino.
Para probar distorsiones sin efecto usamos una «imagen de comprobación de píxeles» (p. ej.: "pattern:gray50"), ya que revela cualquier distorsión y, por tanto, cualquier problema en las matemáticas aplicadas. Así que probemos a aplicar una distorsión sin efecto a los métodos que hemos usado hasta ahora... |
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 puede ver, AMBOS métodos no lograron reproducir la imagen de «comprobación de píxeles». Aunque lo hicieron de formas ligeramente distintas debido a cómo se calculan las coordenadas. Lo que ocurrió es que el factor de escala, de la búsqueda de color a la coordenada de píxel, está desviado en 1 píxel. Para más detalles sobre por qué ha ocurrido esto, consulte Distorsiones, coordenadas de imagen frente a coordenadas de píxel. | _La distorsión FX está centrada en la esquina superior derecha (posición de píxel 0,0) y genera píxeles virtuales duplicados a lo largo de los bordes inferior y derecho. Eso se debe a que no intenta cambiar el centro del escalado, de color de búsqueda a coordenadas de imagen. Por eso los píxeles negros siguen centrados en el píxel 0,0, aunque el escalado sea incorrecto.
El operador de composición "Distort" traslada las coordenadas de modo que el cero quede en el centro de la imagen antes de aplicar el escalado. Lo hace como parte del escalado para los «mapas de desplazamiento» (véase más adelante). Por eso el escalado inexacto desplaza los bordes de la imagen hacia dentro 1/2 píxel en cada borde, dejando correcto el centro de la imagen._
---|---
Aquí están las versiones «sin efecto perfectas» corregidas para mapas de distorsión absoluta, que en esencia usan coordenadas de imagen (ancho y alto reducidos en uno) al calcular el factor de escala entre color y 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)
De hecho, los valores por defecto de "compose:args", si no se definen, usan los valores de escala correctos. |
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 obstante, conviene señalar que estas pequeñas inexactitudes normalmente no son tan importantes al usar distorsiones, por lo que cualquier diferencia leve suele ignorarse. Simplemente téngalo presente para saberlo cuando de verdad importe.
Problemas con los mapas de distorsión
Sigamos distorsionando nuestra imagen intentando una rotación. Generar el mapa rotado para esto puede ser algo delicado, pero se puede hacer...
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
Y ahora tenemos otra forma de rotar cualquier imagen. El mayor problema de esta técnica es que, al crear nuestros mapas de distorsión mediante rotaciones, introdujimos algunos píxeles de colores extraños a lo largo de los bordes diagonales. En el último ejemplo, esto provocó que se añadieran píxeles aleatorios en una línea a lo largo de la esquina inferior derecha de la imagen. Estos colores «aleatorios» son valores de suavizado (antialiasing) que la rotación introdujo para producir una imagen «mejor». Sin embargo, para los mapas de distorsión, los píxeles de borde suavizados pueden causar verdaderos problemas. Ahora podemos intentar definir mejor los colores en los bordes de las imágenes LUT rotadas. En este caso, podemos generar una imagen de degradado más grande y luego recortar la rotación al tamaño correcto.
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
De esta forma, todos los píxeles de la LUT quedan ahora definidos correctamente sin suavizado. Esto muestra ahora un problema ligeramente distinto. Todos los píxeles de la imagen final están definidos correctamente, pero algunos píxeles no deberían formar parte de la imagen final. No tienen ningún significado real en la imagen resultante. Esto representa el mayor problema de usar una LUT para especificar las coordenadas absolutas con las que extraer de la imagen de origen. No tiene forma de especificar qué debe hacer IM en esas zonas indefinidas.
Definir los píxeles indefinidos mediante una máscara
Una forma más general de resolver el problema del «píxel indefinido» es definir un mapa de qué píxeles son realmente un resultado válido y definido en la distorsión. En otras palabras, una imagen de enmascaramiento. Por ejemplo...
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
Ahora tenemos tres imágenes implicadas en el mapa de distorsión, y el resultado se vuelve, desde luego, complejo. Por supuesto, en una situación típica probablemente no necesitará llegar tan lejos, pero para el caso general sí.
Imagen de distorsión unificada
Quizá haya notado, sin embargo, que los tres mapas son imágenes en escala de grises. Esto significa que es bastante razonable combinar todos los mapas en una única imagen de mapa de distorsión. Por ejemplo, mapeemos el «mapa de distorsión X» al canal 'red', el «mapa Y» al 'green' y la máscara al canal 'alpha' o de transparencia, lo que facilita su manejo.
magick map_rot45b_x.png map_rot45b_y.png \( map_rot45b_m.png -negate \) \
-alpha off -channel RGA -background black -combine map_rot45u.png
| El canal 'blue' de la imagen de canales combinados no está definido, así que toma su valor del color "-background" actual, que arriba he preajustado a 'black' o un valor de cero.
---|---
Ahora apliquemos este mapa de distorsión unificado a nuestra imagen de la koala. Esto, por desgracia, requiere dos pasos de procesamiento de imagen: uno para distorsionar la imagen y otro para enmascarar el 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
También puede usar el método de composición "Distort" directamente con la imagen de mapa de distorsión 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)
En la imagen del «mapa de distorsión unificado» todavía queda un canal sin usar (blue). Un uso lógico para él es como medio para añadir luces y sombras a la imagen distorsionada. (Véase Luces por superposición). Puede ver esta técnica llevada un paso más allá en el ejemplo del Mapa de distorsión esférica más abajo.
Mapa de distorsión de reloj de arena
Ahora quería un mapa de distorsión unidimensional que escalara cada fila de la imagen de forma distinta según la altura de esa fila. Algo así como producir una verdadera distorsión de espejo de feria que hace que la gente gorda parezca muy delgada. En otras palabras, una especie de distorsión de reloj de arena. Esta es una imagen LUT bastante compleja y, tras mucho experimentar, di con la siguiente expresión para generar el mapa de degradado, variable según la altura pero horizontalmente lineal. |
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)
| Al generar degradados en escala de grises, puede hacer que el operador -fx sea 3 veces más rápido con solo pedirle que genere un único canal de color, como el canal 'G' o verde en el ejemplo anterior. Ese canal puede luego separarse para formar la imagen en escala de grises necesaria. Esto puede suponer un aumento de velocidad muy grande, sobre todo al usar una fórmula "[-fx](https://imagemagick.org/command-line-options/#fx)" muy compleja.
---|---
El 'sc' es el factor de escala del reloj de arena (su valor va de 0 a 0.5) y le permite ajustar la magnitud de la distorsión. Ahora apliquemos este mapa a la imagen integrada "rose:". Tenga en cuenta que el mapa de 100x100 píxeles no coincide con la imagen de 70x46 píxeles. Esto complica las cosas, ya que tendremos que escalar el píxel actual de la imagen de origen en la proporción adecuada para que coincida con el mapa de distorsión que le damos, y así buscar la ubicación del color de ese píxel. |
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)
Si observa esto con atención, la coordenada X del píxel 'i' se multiplica por el ancho de la imagen del mapa de distorsión 'v.w' y se divide por el ancho de la imagen original 'w', para producir 'i*v.w/w'. Lo mismo ocurre con la coordenada Y del píxel, 'j*v.h/h'. Esto reescala la coordenada del píxel en la imagen de destino para que coincida con la imagen LUT de distorsión. La coordenada obtenida se escala luego multiplicando el valor de la LUT por el ancho de la imagen de origen, para convertirse en la coordenada X de la búsqueda de color. Si tiene un mapa de distorsión tanto para X como para Y, tendrá que repetir la búsqueda escalada para el mapa Y. Por supuesto, tenemos las mismas distorsiones de «borde» que vimos antes, así que cambiemos el ajuste de píxel virtual a transparencia. |
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 el uso del ajuste "-channel" para asegurar que "[-fx](https://imagemagick.org/command-line-options/#fx)" trabaje con los valores del canal alfa (transparente) de la imagen de origen y los devuelva. En concreto, los píxeles virtuales transparentes. Observe también que, al consultar el mapa de distorsión, solo consultamos el canal verde (usando 'v.p{}.g'). Si no se hace esto, se usará el mismo canal que se está procesando de la imagen de origen, y en el mapa el «alfa» no está definido. Este mapa de distorsión podría mejorarse aún más usando un degradado no lineal para que la imagen siga siendo rectangular, con más distorsión en los bordes que en el centro, y darle un aspecto más «redondeado» o «cilíndrico». ¿Alguien quiere intentarlo? Escríbame
Mapa de distorsión esférica
En el ejemplo anterior del Mapa de distorsión de reloj de arena generé un degradado que se escalaba horizontalmente mediante una curva coseno. Con un poco más de trabajo se puede generar una forma esférica en su lugar... |
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)
Tenga en cuenta, no obstante, que lo anterior no es estrictamente exacto. El degradado comprimido sigue siendo un degradado lineal, solo que comprimido para caber dentro de un círculo. Una representación más exacta probablemente requeriría la creación de un degradado no lineal. Que, en términos de posición absoluta, sería una función 'arccos()'. Ahora bien, este mapeo también tiene zonas grandes que se clasificarían como no válidas, por lo que necesitará algún tipo de enmascaramiento que defina qué píxeles serán válidos y cuáles no en la imagen final. En este caso bastará con un círculo simple. |
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)
Y para terminar, también necesitamos una luz de sombreado, como la desarrollada en Luces por superposición, para usarla con la composición Overlay o 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)
Recuerde que el sombreado anterior solo importará dentro de los límites del objeto esférico, así que el hecho de que el sombreado se desborde de esos límites no es importante. De hecho, si quiere intentar idear un mejor sombreado esférico que produzca una imagen aún más parecida a una bola, me encantaría verlo. Así que apliquemos las tres imágenes: la LUT de coordenada X, el sombreado de superposición y la máscara de transparencia, a una imagen real del tamaño adecuado (para simplificar).
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 ejemplo en particular muestra el aspecto más potente de un mapa de distorsión absoluta. Puede definir un degradado sobre cualquier objeto de forma libre (no necesariamente de forma matemática), de modo que cualquier imagen pueda mapearse sobre ese objeto, ya sean curvas, arrugas, pliegues, etc. Dicho de forma sencilla: una vez resuelto el mapeo del objeto, puede mapear cualquier imagen sobre su superficie. Luego, para que parezca más realista, puede superponer un segundo mapeo que añada luces, sombras, bordes y otras características. Por supuesto, como las tres imágenes están en escala de grises, puede combinarlas en una única imagen de mapa de distorsión unificado para almacenarla con facilidad. En este caso haré que sea una distorsión más esférica reutilizando la LUT de coordenada X también para la 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)
Es un mapa bastante bonito. Pero si intenta interpretarlo, recuerde que: los canales 'red' y 'green' son las LUT de coordenadas X e Y, 'blue' es la superposición de efectos de luces y sombras, y el canal de transparencia contiene la máscara de píxeles no válidos para la imagen final. Así que apliquémoslo con el método de composición "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
En orden...
- aplicamos el mapa de distorsión (que incluye la máscara)
- extraemos el mapa de sombreado de la imagen de mapa unificado
- aplicamos el mapa de sombreado a la imagen distorsionada
- restauramos la máscara perdida en la operación de sombreado
- eliminamos todo salvo la imagen final y la guardamos
La complejidad de esto se debe únicamente a la necesidad de extraer la máscara de sombreado y restaurar la máscara alfa que el sombreado eliminó.
Mapa de distorsión de arco circular
Solo para mostrar qué es realmente posible usando mapas de distorsión posicionales, aquí tiene una LUT de distorsión absoluta, similar a la que ofrece el método de distorsión «Arc» de más arriba. Básicamente, en lugar de calcular los mapeos de coordenadas para todos y cada uno de los píxeles de todas y cada una de las imágenes que se distorsionan, guardamos esas coordenadas calculadas en dos LUT en escala de grises de coordenadas X e Y. Es decir, precalculamos toda la distorsión en una imagen de tabla de consulta más simple, lo que permite aplicarla una y otra y otra vez, sin necesidad de más raíces cuadradas ni funciones 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
Fuente de color |
|
Ángulo - Mapa X |
|
Radio - Mapa Y |
|
Texto curvado
---|---|---|---|---|---|---
Por supuesto, generar ese mapa de distorsión fue difícil, pero una vez hecho (por cualquier medio que prefiera, incluso de forma artística con un editor de imágenes como "Gimp"), puede reutilizarlo en una enorme cantidad de imágenes.
Mapa de distorsión polar
A veces puede necesitar que la imagen de destino la defina el mapa de distorsión, en lugar de la imagen de origen, simplemente para que las cosas funcionen correctamente. Por ejemplo, si queremos mapear un texto en un círculo (lo que también se conoce como transformación polar), necesita realmente poder usar una imagen unas 3 o 4 veces más larga que alta (relación de aspecto alta), o el resultado no será muy legible. Para ello, colocamos las imágenes del mapa de distorsión antes de la imagen de origen de color, de modo que la primera imagen (mapa X) se use para fijar el tamaño del resultado final, en lugar de la imagen de origen 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 |
|
Fuente de color |
|
Texto en círculo
---|---|---|---|---|---|---
En esencia, la imagen de origen de color puede ahora tener cualquier tamaño o relación de aspecto, y todo se gestionará correctamente; sin embargo, quizá necesite ajustar la generación del mapa de distorsión para gestionar correctamente la relación de aspecto de la imagen de origen. Al generar los mapas anteriores, el valor '70' controla el tamaño final del círculo a lo largo del cual se sitúa la línea media. El valor '1.2', por su parte, controla el escalado vertical de la imagen dentro del círculo, lo que le permite ajustar la altura del texto distorsionado. |
Recuerde que esta expresión "-fx" requiere que los mapas de distorsión se den primero y que la fuente de color se dé como la tercera imagen (índice 2). No obstante, esto también significa que cualquier metadato almacenado en la imagen de origen también se perderá. |
|---|---|
| _El problema con este mapa de distorsión es que hay una disyunción de colores muy brusca en el «mapa X» (causada por una asíntota en las matemáticas). Esta línea debe permanecer nítida cuando realice cualquier búsqueda de color o redimensionado del mapa para producir una imagen más grande. Es decir, deberá asegurarse de que cualquier redimensionado o búsqueda interpolada de este mapa no produzca un color de búsqueda gris a lo largo de esa línea asintótica. |
Si genera búsquedas grises a lo largo de esta línea, obtendrá una línea de píxeles de color (extraídos del centro de la imagen) en su resultado final.
Por ello se recomienda generar siempre este mapa de distorsión al tamaño que necesite para la imagen final y no usar nunca ninguna técnica de escalado mostrada anteriormente._
---|---
Puede usar esto también para otros efectos, como un tablero de ajedrez 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)
Las dos imágenes de mapa de distorsión polar (mapa angular X y radial Y) anteriores muestran claramente los límites de las distorsiones de imagen con "-fx". Cerca del centro de la imagen, las líneas radiales se van aliasando, ya que no se produce la fusión de píxeles de áreas grandes en un solo píxel. En cambio, en los bordes de la imagen, sobre todo en las esquinas, las líneas radiales muestran un desenfoque adecuado.
La causa es que "-fx" (y la mayoría de los métodos de distorsión antiguos) solo hace búsquedas interpoladas simples y sin escalar de los colores de la imagen de origen. Esto significa que, a medida que la imagen se escala hacia un tamaño menor, los píxeles de la imagen de origen no se fusionan para producir el color correcto del píxel de destino.
Esto no es un problema en las zonas de ampliación (como en las esquinas), solo en las de compresión extrema (el centro). Por eso una solución es el uso del supermuestreo, pero lo único que hace es posponer los problemas a un nivel de compresión mayor._
---|---
| _La misma línea asintótica (cambio brusco) del mapa de distorsión (del centro a la parte inferior de la imagen) también produce un cambio de color brusco a lo largo de esa línea en el ejemplo anterior. Compare esa línea con las demás líneas radiales (como la que va del centro a la parte superior de la imagen), que se vuelven muy difusas al acercarse al borde de la imagen debido a la búsqueda interpolada ya señalada.
Esto puede ser un problema al generar un patrón circular con una imagen que pueda usarse como mosaico (como la anterior), y quizá requiera un tratamiento especial para evitar diferencias visibles en esa parte de la imagen.
Para evitarlo, puede ser mejor distorsionar la mitad superior de la imagen por separado de la mitad inferior, de modo que se evite la región asintótica.
Barajar filas
En este ejemplo hacemos algo un poco más inusual... Barajar las filas de una imagen al azar. Primero creamos un mapa que tiene un degradado para X (canal rojo) y una imagen de ruido aleatorio 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
Por desgracia, "-spread" parece incluir píxeles virtuales en su selección de píxeles a intercambiar, lo que hace que algunas filas se dupliquen y otras se pierdan por completo. En otras palabras, el mapa de imagen de «barajado» no es del todo correcto. ¿Tiene una solución mejor para barajar píxeles?
Mapas de desplazamiento por búsqueda relativa
Como puede ver, un mapa de distorsión absoluta es razonablemente fácil de crear y usar. Sin embargo, tiene un problema serio cuando una distorsión tiene regiones «indefinidas», o zonas donde la distorsión se va «fuera» de los límites normales de la imagen de origen. Un problema más serio es que siempre trabaja con degradados, que definen las coordenadas absolutas para la búsqueda de color. Ninguna parte de la imagen de mapeo es simple, ni limpia, ni fácil de modificar o editar a mano. Su creación y uso requieren técnicas y matemáticas especiales. Eso, por lo general, significa que apenas hay margen para un desarrollo «artístico». No obstante, hay otro método para usar una tabla de consulta y especificar las coordenadas desde las que obtener el color final: usar un mapa de desplazamiento relativo. En lugar de que el «mapa» defina la coordenada exacta en la que buscar el color de cada píxel en la imagen de origen, define un desfase o desplazamiento relativo a la posición actual. Ahora bien, un desfase puede ser un valor positivo o negativo, y un valor negativo requiere algo de astucia para codificarlo en un valor de color. Así que lo que se hace es definir el «gris puro» como un desplazamiento 0 de la coordenada (sin cambio). Luego se hace que el «negro» signifique el máximo desplazamiento negativo, y el «blanco» el máximo desplazamiento positivo. Esto puede ser difícil de describir, así que veamos un ejemplo. Primero creamos una imagen de prueba a la que «desplazar». |
magick -font Candice -gravity center -size 150x50 \
label:'Anthony' label.jpg
![[IM Output]](../static/img/mapping/label.jpg)
Ahora usaré algo de «magia (magick)» para crear una imagen de «gris puro» con zonas de «blanco puro» y «negro 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)
Ahora, para usar esta imagen como «mapa de desplazamiento», tomamos el «valor de gris» del mapa de desplazamiento y lo sumamos a la coordenada X y/o Y. Es decir, desplazamos la búsqueda en una cantidad relativa desde la posición actual según la «grisura» del mapa de desplazamiento. El «valor» se gestiona de forma especial, de modo que un «gris puro» significará un desplazamiento cero del punto de búsqueda (solo la coordenada Y en este caso), pero se usa un «desplazamiento máximo» para un valor «blanco» (positivo) o «negro» (negativo). Por ejemplo, apliquemos el mapa de desplazamiento a nuestra imagen "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 puede ver, las distintas partes de la imagen parecen haberse «movido» según el color del mapa de desplazamiento. Una región «blanca» sumará el «valor de desplazamiento» dado al punto de búsqueda, de modo que en esa zona cada píxel busca la imagen de origen «10» píxeles «hacia el sur» (dirección Y positiva). Como resultado, parece que la imagen de origen se movió hacia arriba. Recuerde que lo que se desplaza es la búsqueda, NO la imagen en sí, y por eso pareció moverse hacia arriba, o en dirección negativa, con el blanco. Se vio un efecto similar en las zonas con un desplazamiento «negro». La imagen de origen pareció moverse hacia abajo, porque el desplazamiento de la búsqueda se hizo en dirección negativa. Piénselo con cuidado. También notará que la «búsqueda desplazada» puede mirar de hecho más allá de los límites normales de la imagen, lo que le permite usar un ajuste de píxel virtual para controlar esos píxeles fuera de límites. Arriba simplemente pedí que se devolviera un píxel gris. El valor de «desplazamiento máximo» '10' del ejemplo anterior es muy importante: es la máxima distancia relativa que cualquier parte de la imagen de origen parece moverse, para un valor de desplazamiento «blanco puro» o «negro puro» en la imagen de mapeo. No puede desplazar la búsqueda, y por tanto la imagen de entrada, más allá de este valor. Otros tonos de gris entre los valores máximos de blanco o negro y el valor central de gris al 50% sin desplazamiento desplazarán la búsqueda en la cantidad adecuada. Así, un valor de gris al 25% desplazará la búsqueda 1/2 del valor de desplazamiento en dirección negativa, mientras que un gris al 75% la desplazará 1/2 de ese valor en dirección positiva. Este valor es una diferencia clave entre un mapa de distorsión absoluta y un mapa de desplazamiento relativo. Puede aumentar o reducir los desplazamientos relativos, distorsionando más o menos la imagen, con solo cambiar el valor de desplazamiento, sin necesidad de cambiar el mapa de desplazamiento en absoluto. Además, como un mapa de «desplazamiento cero» es simplemente un gris puro al 50% sólido, y no un degradado complejo, puede empezar con una imagen gris sencilla y aclarar u oscurecer zonas de forma artística para generar los desplazamientos deseados. Puede hacerlo simplemente dibujando formas o zonas, en lugar de necesitar una fórmula matemática compleja y exacta. Y, por último, como todos los desplazamientos son relativos, los valores descontrolados que producen los efectos de borde no generan colores de píxel descontrolados ni aleatorios. De hecho, como verá, suavizar o desenfocar los mapas de desplazamiento es en realidad algo bueno, ya que elimina el efecto de «corte» discontinuo que se ve en el ejemplo anterior. En resumen: un mapa de desplazamiento es mucho más controlable y artístico, ofrece desplazamientos localizados sin necesidad de matemáticas complejas y exigentes, y es muy tolerante con los errores, los efectos de borde o incluso el desenfoque del mapa de desplazamiento. Es ideal para distorsiones sencillas de tipo «desplazamiento», como al generar efectos de agua, olas, espejos deformantes, la curvatura de la luz, efectos de lente o efectos de vidrio esmerilado o de burbujas. Por otro lado, las distorsiones muy matemáticas, como las «polares», rotacionales y de «perspectiva», u otros mapeos 3D del mundo real, no se logran fácilmente. Lo cual no quiere decir que sea imposible, ya que más adelante mostraremos que de hecho se puede pasar de un estilo de mapa a otro, solo que es más difícil.
Método de desplazamiento por composición
Hemos usado el operador casero FX para hacer el mapeo de desplazamiento, para que pueda ver qué se hace en realidad. Pero es una técnica lenta. Existe un operador de composición integrado equivalente, "Displace". Así es como se usa...
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 el orden, especialmente en el comando "magick composite".
Usar "-set" en lugar de define también le permite usar escapes de porcentaje en el argumento. Los valores 'X ' e 'Y ' definen la dirección y el «desplazamiento máximo» que se usarán para los colores «blanco» y «negro» del mapa de desplazamiento dado. Puede definir uno o ambos valores, lo que le permite desplazar en cualquier dirección concreta. Es decir, normalmente los mapas de desplazamiento ofrecen un desplazamiento lineal en una dirección cualquiera, con una intensidad máxima controlada por los valores 'X ' e 'Y '. La «imagen de mapa» fija entonces cuánto de ese máximo se aplica, desde un máximo negativo (negro) hasta un máximo positivo (blanco), donde un gris perfecto significa ningún desplazamiento de la búsqueda para ese píxel. Por ejemplo, aquí está el mismo ejemplo de desplazamiento en Y que vimos antes... |
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)
También puede usar otros ajustes como "[-geometry](https://imagemagick.org/command-line-options/#geometry)" y "[-gravity](https://imagemagick.org/command-line-options/#gravity)" para ajustar la zona en la que el mapa de desplazamiento se superpone a la imagen. La búsqueda de píxeles resultante del mapa de desplazamiento puede seguir haciendo referencia a zonas fuera de la parte superpuesta de la imagen, duplicándolas dentro de la zona superpuesta.
Ejemplos simples de desplazamiento
Un mapa de desplazamiento formado por zonas de color planas, sin ninguna transición suave, producirá por lo general desplazamientos disjuntos (discontinuos) entre las distintas zonas de la imagen resultante, tal como vio antes. De hecho, puede producir un mapa de desplazamiento que se «fractura» como si mirara dentro de un espejo agrietado, usando esta técnica. Por ejemplo, véase el Espejo fracturado más abajo. Puede producir resultados más agradables y suaves si los colores fluyen suavemente de una zona a otra. Por ejemplo, al desenfocar el mapa de desplazamiento, genera una transición ondulada entre las zonas desplazadas... |
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)
En lugar de desplazar la imagen en dirección Y, también puede usar un mapa para desplazar la imagen en dirección X, lo que produce una especie de onda de compresión. |
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 el mismo mapa de desplazamiento para las direcciones X e Y, podemos añadir tanto una onda de compresión como una onda de amplitud. |
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 la imagen sigue desplazándose en una única dirección lineal, lo que hace que la imagen anterior se estire en la pendiente descendente y se comprima en la ascendente. Es decir, la distorsión se realiza en un ángulo o «vector», con componentes horizontal y vertical. Puede ver que este efecto se parece notablemente al de estar bajo el agua, con la imagen distorsionada por suaves ondas en la superficie del agua. Sin embargo, un mapa de desplazamiento puede contener varias copias de la imagen original, igual que ocurre en imágenes reflejadas o refractadas... |
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)
También puede crear volteos en espejo (flip o flop) de partes de la imagen usando degradados. Por ejemplo, aquí puede usar un mapa de desplazamiento lineal para copiar píxeles de un lado de la imagen al otro. |
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)
¿Puede averiguar cómo funciona este mapa de desplazamiento? Como pista, averigüe qué desplazamiento tienen el borde más a la izquierda y el más a la derecha, y luego vea cómo encaja el resto de la imagen en eso. No obstante, como aquí vuelve a usar una imagen de degradado, pierde la simplicidad de los mapas de desplazamiento. Por eso los reflejos se hacen mejor con una operación Flip directa sobre la imagen, o usando en su lugar un mapa de distorsión absoluta. Tenga en cuenta que, al voltear el degradado, encoge la imagen. |
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)
Lo anterior también muestra un problema concreto que tienen los mapas de desplazamiento. Cuando una zona (o toda) de una imagen se comprime más de un 50%, empezará a generar artefactos de aliasing. Esto es especialmente perceptible en los bordes «aliasados» en escalera que se ven con claridad. Como ya se comentó, una solución es supermuestrear el número de píxeles usados para generar cada píxel de salida. Para ello, ampliamos tanto la imagen como el mapa de desplazamiento y luego redimensionamos la imagen resultante a su tamaño más normal. Esto permite que más píxeles participen en la definición de un píxel concreto del resultado y, por tanto, produce una imagen mejor. Por ejemplo... |
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)
Un resultado mucho mejor y más suave, aunque quizá también algo borroso. Graficar un degradado De los ejemplos anteriores surgió directamente la idea de que, usando desplazamientos en Y de una simple línea, se puede generar una gráfica de los colores de un mapa de desplazamiento. Por ejemplo, aquí genero una función matemática sinc() (que se define como 'sin(x)/x') y grafico ese degradado usándolo como mapa de desplazamiento...
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 puede ver funciona, aunque no me gustaría usarlo para gráficas matemáticas. Es mejor usar un paquete de graficado adecuado. No obstante, esta técnica es útil como método rápido para representar las intensidades de una fila o columna de píxeles de una imagen. Lo que sí muestra es cómo las grandes diferencias de desplazamiento pueden producir fácilmente una discontinuidad o un resultado poco suave. Básicamente, como cada píxel individual de la «fuente de la gráfica» solo se mira de uno en uno, sin promediar, una gran diferencia en la búsqueda desplazada de un píxel al siguiente puede producir un gran cambio de color en el resultado. La moraleja es que el desplazamiento funciona mejor no solo con mapas de desplazamiento suaves, sino también desplazando imágenes que contienen zonas grandes o tonos de color. No funciona tan bien con líneas finas y marcadas. Por supuesto, puede mejorar las cosas supermuestreando de nuevo el mapa de distorsión... |
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)
El resultado es mucho mejor, aunque no tan bueno como lo que se puede lograr con un paquete de graficado. Aun así, solo se usó ImageMagick para crearlo. Aquí tiene otra versión de la misma gráfica, pero esta vez usando un color sólido, que funciona mucho mejor que desplazar una línea 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
Desplazamiento de áreas (lineal)
Probemos un problema de desplazamiento más lógico. Mover una zona de una imagen en línea recta de una ubicación a otra. Como hemos visto, una imagen de «gris puro» no provoca ningún desplazamiento, mientras que un color «blanco» provocará un desplazamiento positivo de la búsqueda desde la imagen de origen. Por ejemplo, creemos una imagen así... |
magick -size 75x75 xc:gray50 -fill white \
-draw 'circle 37,37 37,20' dismap_spot.jpg
![[IM Output]](../static/img/mapping/dismap_spot.jpg)
Ahora, cuando apliquemos esta imagen, el contenido de la zona marcada debería tener una copia de lo que aparezca en la dirección del valor de desplazamiento dado. Así que probemos con un valor de desplazamiento de X +10 e Y +10, es decir, '10x10'...
magick koala.gif dismap_spot.jpg \
-compose Displace -define compose:args=10x10 -composite \
displace_spot.png
Como puede ver, el contenido de la zona marcada contiene ahora una copia de la imagen que estaba +10,+10 píxeles al sureste. Básicamente, una imagen de la «cola» de la koala. En otras palabras, dentro del círculo la imagen se desplazó al noreste, es decir, -10,-10 píxeles. Recuerde que el desplazamiento es de la búsqueda, por lo que la imagen de origen se desplaza una cantidad negativa debido al mapeo inverso de píxeles. ¡La imagen se desplaza en dirección contraria! Observe también que lo que se mueve es la imagen dentro de la zona marcada. No está desplazando la imagen marcada, sino desplazando la imagen HACIA la zona marcada. Y, por último, observe la fuerte discontinuidad en los bordes del círculo. Las zonas dentro de la zona marcada se mueven, mientras que las de fuera permanecen exactamente como estaban. Estos son los hechos, así que vale la pena repetirlos.
El desplazamiento mueve las imágenes en dirección opuesta al valor.
Solo se desplazarán las zonas marcadas que no sean grises.
Los cambios de color bruscos producen discontinuidades bruscas en la imagen.
Así que probemos algo más práctico. Movamos el centro situado entre la nariz y los ojos de la koala, ubicado en '32,22', al centro de nuestro círculo blanco (desplazamiento positivo máximo) en '37,37'. Eso requiere un valor de desplazamiento de '-5,-15' (recuerde que la dirección es inversa)... |
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)
Y ahí tenemos una copia bien centrada de la parte central de la cabeza de la koala. Pero la imagen sigue siendo «disjunta», y usar un valor negativo no es muy agradable. La solución es usar en su lugar una mancha negra, pero también desenfocar los bordes de esa mancha. Además, hagámosla más grande para abarcar más de la cabeza de la koala. Así que aquí está nuestra imagen de «mancha de movimiento 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)
No conviene desenfocar demasiado la imagen, o el centro de la mancha dejará de ser un color negro plano. Como alternativa, podría simplemente Normalizar, aplicar un ajuste de Level inverso a la imagen para asegurar que la zona dibujada sea negra y las partes circundantes sean grises perfectos. Verá que esto se hace mucho en ejemplos posteriores. Ahora repitamos ese último desplazamiento de la «cabeza» usando nuestro mapa de desplazamiento de «mancha difusa» negra. |
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 puede ver, movemos la imagen +5,+15 hacia la zona «difusa», pero esta vez el borde de la zona es más suave y está conectado con el resto de la imagen. Por supuesto, las orejas en el borde del círculo se distorsionaron por el borde difuso, y el cuerpo de la koala también se comprimió, pero aun así es mucho mejor que lo que teníamos antes. Para evitar el «desgarro» de la imagen que se ve en el lado de salida, o que queden copias de la parte desplazada, conviene ampliar esa mancha o crear una imagen de desplazamiento de tipo degradado más compleja. Por ejemplo, suponga que quiere mover la cabeza de la koala desde su posición inicial en '32,22' al centro de la imagen en '37,37', es decir, un movimiento de +5,+15 píxeles, pero quiere ajustar toda la imagen a este cambio para lograr un efecto mucho más suave. Para ello, querrá el desplazamiento máximo del negro (un desplazamiento positivo de la imagen) en '37,37', desplazando un valor de +5,+15. Pero también querrá asegurarse de que el resto de la imagen permanezca intacto «fijando» las esquinas a un gris al 50%. Es decir, perfecto para un degradado disperso 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 puede ver, obtiene una zona de desplazamiento más grande, repartida por toda la imagen. El resultado es una imagen que cambia de forma mucho más suave que con el método de la «mancha» más ajustada usado antes. Esto es de hecho exactamente equivalente a la distorsión de Shepard, pero solo para un único punto de control en movimiento. Es también el mismo método que se usa en el script '[shapemorph](http://www.fmwconcepts.com/imagemagick/shapemorph/)' de Fred Weinhaus, pero con algo de animación. En resumen: para desplazamientos pequeños y localizados se puede usar un desplazamiento de «mancha desenfocada». Pero para desplazamientos mayores a lo largo de una distancia más grande, conviene usar un mapa de desplazamiento de degradado suave y más grande para evitar desgarrar o duplicar la imagen de origen.
En construcción
Morphing simple por desplazamiento
Modificar el tamaño de los vectores de desplazamiento
Morphing entre dos imágenes
Desplazamientos 1D aleatorios
Reflejos en agua ondulada
Como se mencionó antes, los mapas de desplazamiento son especialmente útiles para generar distorsiones de tipo agua y vidrio.
Para este ejemplo generé una imagen pequeña recortando una imagen de una flor. Ahora quiero que parezca que está sobre agua ondulada. Para generar ondas, necesito un degradado de onda senoidal del mismo tamaño, que puedo generar usando la función Evaluate Sin. El número '8' representa el número de «olas» que se añadirán al degradado. |
magick -size 150x80 gradient: -evaluate sin 8 wave_gradient.png
![[IM Output]](../static/img/mapping/wave_gradient.png)
Ahora distorsionemos esa imagen usando un vector de desplazamiento en ángulo, no solo una simple distorsión vertical u horizontal, para darle más énfasis. |
magick composite wave_gradient.png flower.jpg -displace 5x5 flower_waves.png
![[IM Output]](../static/img/mapping/flower_waves.png)
Pues bien, eso no parece muy interesante, pero ¿y si voltea esa imagen, la comprime verticalmente y la añade a la original... |
magick flower_waves.png -flip \
flower.jpg +swap -append flower_waves_2.png
![[IM Output]](../static/img/mapping/flower_waves_2.png)
Por desgracia, todavía parece bastante artificial. La razón es que el reflejo se ve igual tanto en la parte superior como en la inferior de la imagen. No tiene ninguna sensación de «profundidad». El reflejo también tiene el mismo brillo que la imagen original, lo cual rara vez es el caso. Para hacerlo más realista, necesita usar un patrón de ondas que varíe en intensidad. Lo siguiente usa unas matemáticas de degradado ingeniosas para «atenuar» el degradado de onda que usábamos arriba. Es decir, hicimos que el patrón de onda se redujera linealmente al ir de arriba abajo. Este truco asegura que las olas terminen en el color de gris puro o «sin desplazamiento» en la parte inferior de la imagen (que luego se voltea). |
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)
Así que apliquemos este degradado para formar un nuevo reflejo de la flor. También oscurecí ligeramente la imagen reflejada para representar algo de luz que se pierde en el propio agua, lo que la hace parecer más un reflejo en el agua. |
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)
Tenga en cuenta que la imagen distorsionada se voltea para formar un reflejo. Además, la imagen tendrá menos «ondas» en la parte superior del «agua», la más cercana a donde se une con la imagen original, que en la inferior. Esto le da a la distorsión una sensación de distancia respecto al observador. Puede hacerlo aún más realista distorsionando los mapas de desplazamiento de las olas con una ligera rotación, un arco, o simplemente con desplazamientos «aleatorios». Esto le dará a las olas un aspecto más natural. Aunque es mejor hacerlo antes de «atenuarlo», para que la «profundidad» se añada después. Pruébelo, experimente y cuénteme qué se le ocurre.
Futuras ondas animadas -
Usando -function Sinusoid con cambio de fase
Mapeo de desplazamiento bidimensional
Hasta ahora, todos los mapas de desplazamiento relativo solo han desplazado la imagen en una sola dirección. Aunque esa dirección puede fijarse en cualquier ángulo deseado ajustando el valor de desplazamiento o «vector» '_X_ x _Y_' adecuado. No obstante, puede producir un desplazamiento mucho más complejo, en el que la imagen se desplaza en cualquier dirección y en cualquier cantidad, usando dos desplazamientos separados. Para ello necesitamos crear dos mapas de desplazamiento, uno para cada una de las direcciones X e Y por separado. Aquí están los comandos que puede 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 el orden de las imágenes de entrada en el comando "magick composite". El orden extraño se debe a la necesidad de forzar el manejo de opciones de "magick composite", además de por razones históricas. Es vital que lo haga correctamente. Por eso le recomiendo usar el comando "magick" en lugar de "magick composite". |
Antes de IM v6.4.4, usar 2 mapas de desplazamiento separados para desplazamientos X e Y por separado era cuestión de suerte. A veces funcionaba y a veces no. No se recomienda intentar siquiera usarlo en versiones de IM anteriores a esta. |
|---|---|
| Además, igual que con los mapas de distorsión unificados, puede usar un único «mapa de desplazamiento unificado». Si solo se proporciona una imagen de desplazamiento, el desplazamiento X se buscará en el canal 'red', el desplazamiento Y se buscará en el canal 'green' y cualquier máscara alfa también se transferirá del mapa de desplazamiento a la imagen final. El canal 'blue' se ignora. | _Internamente, tanto "magick" como "magick composite" combinan en realidad las dos imágenes (si se proporcionan) para generar un «mapa de desplazamiento unificado» antes de pasárselo a la API interna. |
Esto no afecta a los «desplazamientos lineales» anteriores que vimos, ya que el mapa de desplazamiento dado era una imagen en escala de grises, por lo que los canales 'red' y 'green' eran idénticos._
---|---
Desplazamiento cilíndrico
Algo que ha surgido varias veces en los foros de IM es una forma de mapear una imagen sobre un cilindro, como para superponerla en una taza de café o una lata de refresco. Esta es la solución... |
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)
Lo anterior es muy complejo, pero en esencia usa dos desplazamientos separados de forma simultánea. Una compresión arcsin() en la dirección X y un desplazamiento de arco circular en la dirección Y. Esto es lo que hace el comando...
- Cargar la imagen "rose" y añadir algo de espacio para el desplazamiento vertical
- Crear un degradado matemático horizontal para funciones matemáticas posteriores
- magick una copia del degradado para generar un mapa de desplazamiento de compresión
- magick otra copia para un desplazamiento de arco elíptico vertical
- eliminar el degradado lineal
- preparar y realizar el desplazamiento
Resultado... Una rosa correctamente envuelta en una vista isométrica a 30 grados de un cilindro. Descomponga el comando anterior para guardar y ver los mapas de desplazamiento individuales. La clave a recordar es que el desplazamiento de dos mapas realiza las búsquedas de los valores X e Y para averiguar qué píxel debe acabar en la ubicación de la búsqueda. Recuerde que el desplazamiento no es en realidad un desplazamiento de la imagen de origen, sino un desplazamiento de la búsqueda en la imagen de origen. Este método de distorsión por desplazamiento se ha integrado en el script "[cylinderize](http://www.fmwconcepts.com/imagemagick/cylinderize/)" de Fred Wienhaus.
Espejo fracturado
Puede crear un aspecto de «espejo fracturado» en una imagen generando zonas aleatorias de desplazamientos 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
| Se generan cuatro zonas desplazadas al azar usando una imagen de color disperso de Voronoi aleatorizada. A esto se le aplica luego una distorsión de implosión para deformar esas zonas hacia el centro de la imagen. Como cada una de las cuatro zonas de color sigue siendo de color sólido, cada zona contendrá una copia sin distorsionar, pero desplazada, de la imagen original. Sin embargo, cada zona habrá desplazado la imagen de una forma distinta, igual que haría cada fragmento de un espejo fracturado. Para rematar el espejo, se usa la detección de bordes para perfilar los bordes de las regiones y, por tanto, el carácter fracturado de la imagen resultante. Es decir, las grietas también se hacen visibles. | Técnicamente, no tenía por qué separar los canales 'red' y 'green' del mapa de desplazamiento aleatorio de color generado. Podría haberlos usado directamente, ya que el desplazamiento X se busca en el canal 'red' y el desplazamiento Y se busca en el canal 'green'. Es decir, podría haber usado la imagen "mirror_areas.gif" directamente como «mapa de desplazamiento unificado». |
|---|---|
En construcción
Desplazamiento de Shepard
Desplazamientos aleatorios
Efectos de lente
Efectos de vidrio esmerilado
Efectos de dispersión (desplazamientos rotados)
Efectos de dispersión con desplazamiento aleatorizado
FUTURO: Otros posibles ejemplos de mapeo de distorsión / desplazamiento
- Trazar por raytracing un degradado sobre objetos 3D para que luego se pueda mapear CUALQUIER imagen sobre esos objetos.
- Imágenes con degradados X e Y mapeados
- Imagen de gris puro para color, luces y sombreado
Mapeo de desenfoque variable
Añadido en la versión 6.5.4-0 de ImageMagick, el método 'Blur' de "[-compose](https://imagemagick.org/command-line-options/#compose)" le ofrece un método para reemplazar cada píxel individual por un promedio gaussiano elíptico (un desenfoque) de los píxeles vecinos, según una imagen de mapeo.
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
Tenga en cuenta que esta composición de imágenes requiere el uso de un argumento operativo, que puede ajustarse de varias formas. Consulte Artefactos definidos globalmente para más detalles. Usando un mapa variable para controlar el desenfoque, puede desenfocar una parte de una imagen mientras deja otra parte completamente intacta, o puede producir efectos como el efecto Tilt-Shift, en el que una imagen del mundo real se hace parecer más bien una pequeña maqueta artificial.
Por ejemplo, aquí desenfoco la mitad de una imagen de una koala mientras dejo la otra mitad completamente sin desenfocar...
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 puede ver, cualquier píxel que fuera «blanco» en la imagen «blur_map» se desenfocó usando el valor máximo de 'sigma ' dado, mientras que lo que era «negro» no se desenfocó en absoluto. En otras palabras, tiene un desenfoque enmascarado muy sencillo. Por supuesto, esto se podría haber logrado de muchas otras formas, pero eso no explica dónde reside el poder del mapeo de desenfoque. Lo que hace que este mapeo de desenfoque sea versátil es que es variable a lo largo de la imagen. Es decir, si el color del mapeo de desenfoque es gris, obtendrá un resultado de desenfoque correspondientemente menor, usando un «vecindario» más pequeño, para ese píxel. El negro, en cambio, no se desenfoca, mientras que el blanco se desenfoca al máximo, según los valores dados. Algo a tener en cuenta es que solo las zonas desenfocadas requerirán el tiempo extra necesario. Los píxeles que no se desenfocan no necesitan este procesamiento extra. Esto hace que lo anterior sea mucho más rápido que usar una composición enmascarada, que equivale a desenfocar toda la imagen y combinar los resultados. Este ahorro de tiempo puede ser aún más importante al tratar con desenfoques grandes de zonas muy pequeñas de una imagen. Por ejemplo, hagamos que la koala se vuelva progresivamente más borrosa hacia los pies...
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
Y aquí está el mismo desenfoque de nuevo, pero mostrando cómo varía el desenfoque con la altura.
magick blur_map_bool.gif blur_map_gradient.gif \
-compose blur -define compose:args=15 -composite \
blur_edge_gradient.gif
Para un ejemplo práctico de desenfoques de mapeo variable, eche un vistazo a Efecto fotográfico Tilt-Shift y a Fuente con sombra desenfocada por distancia. Tenga en cuenta que es el vecindario alrededor de cada píxel individual el que se usa para generar el «color desenfocado» de ese píxel. Eso significa que, aunque especifique que una parte de una imagen no se desenfoque, los colores de esa zona pueden usarse como parte del desenfoque de los píxeles circundantes. Es decir, que una zona no se desenfoque no significa que sus colores no se usen como parte del resultado de otros píxeles desenfocados. O sea, los colores de la zona sin desenfocar pueden «filtrarse» a las zonas desenfocadas circundantes. Para desenfocar un fondo sin incluir los píxeles del primer plano, necesita usar una técnica de máscara de lectura que evite que se lean como parte de la operación de desenfoque.
Desenfoque elíptico
El ajuste de composición 'Blur' usa una técnica distinta de los operadores Blur o Gaussian Blur normales, ya que se implementa usando un algoritmo gaussiano de remuestreo de área elíptica que se desarrolló para el remuestreo de imágenes escaladas como parte del operador de distorsión generalizada. El área elíptica usada para el remuestreo del vecindario también hace que este método de desenfoque sea más versátil que el desenfoque «circular» uniforme normal que ofrecen los operadores "[-blur](https://imagemagick.org/command-line-options/#blur)" y "[-gaussian-blur](https://imagemagick.org/command-line-options/#gaussian-blur)". La elipse misma se define por el 'width ' (ancho) y el 'height ' (alto) de la sigma del área desenfocada. La elipse también puede rotarse desde una alineación ortogonal según el 'angle ' dado (en sentido horario). Por ejemplo, en el siguiente diagrama mostramos cómo el color desenfocado de un solo píxel obtendrá su color de un área elíptica rotada, según los valores de sigma dados. Los píxeles de esta área se promedian luego de forma ponderada según un filtro gaussiano (usando una fórmula de distancia elíptica), para producir el color desenfocado.
magick koala.gif -compose blur -define compose:args=5x1-30 -composite \) \
elliptical_blur.gif
# ... otros comandos para crear el diagrama del efecto de desenfoque ...
Como se mencionó, este es exactamente el mismo método de búsqueda de color que usa el operador de distorsión generalizada para generar los colores de sus imágenes distorsionadas, ya que permite una fusión escalada (y filtrada) de un área de la imagen de origen en un solo píxel, especialmente en distorsiones extremas como las del ejemplo de Ver horizontes lejanos. Para más detalles de este proceso, consulte Remuestreo de área y Filtros de remuestreo.
Como ejemplo de los controles elípticos disponibles para el mapeo de desenfoque variable, usemos un punto negro con el mismo mapa de desenfoque de degradado que usamos antes. Pero esta vez escalaremos una elipse horizontal larga y fina '30x0', en lugar de un círculo. El 'x0' puede parecer raro, pero básicamente significa que no debe verse ningún desenfoque vertical, solo una elipse de la menor altura necesaria para generar un buen 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 puede ver, la cantidad de desenfoque sigue variando con la imagen de mapa proporcionada, produciendo muy poco desenfoque en la parte superior de la imagen y mucho desenfoque en la inferior. Pero observe también que el borde inferior se desenfoca por igual horizontalmente en ambas direcciones, pero no verticalmente, lo que produce un corte brusco en la dirección vertical. Rotando la elipse larga y fina con un tercer argumento de angle, o definiendo directamente una elipse vertical, puede desenfocar la imagen solo 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)
No obstante, observe que el desenfoque no se aplicó por igual. La mitad superior parece menos desenfocada que la inferior, porque eso es lo que le indicó la «imagen de mapeo». Esto, a su vez, distorsiona la imagen, haciendo que parezca un poco truncada por el efecto de desenfoque. Por último, hagamos esto una vez más, pero con una elipse horizontal rotada un ángulo fijo de 45 grados. |
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)
La imagen puede parecer muy extraña, pero eso se debe a que el mapa de desenfoque variable es vertical mientras que el propio desenfoque está en ángulo, lo que produce el efecto de aspecto extraño debido a cómo no se alinean el ángulo de la elipse y el ángulo del mapa de desenfoque. | Tenga en cuenta que usar elipses largas y finas como esta es en realidad mucho más rápido que usar un único círculo grande. De hecho, el operador "[-blur](https://imagemagick.org/command-line-options/#blur)" obtiene su velocidad usando dos desenfoques separados, horizontal y vertical, mientras que el operador "[-gaussian](https://imagemagick.org/command-line-options/#gaussian)" hace una convolución bidimensional completa de una forma más simple que el método de composición 'Blur' que se acaba de describir.
---|---
Desenfoque con relación de aspecto variable
Hasta ahora hemos variado el tamaño del área elíptica usada para el desenfoque mediante el «mapa de desenfoque». Sin embargo, aunque el tamaño de la elipse e incluso su ángulo pueden rotarse, su forma y ángulo permanecían fijos. Ahora bien, el «mapa de desenfoque» es una imagen compuesta de tres canales de color: rojo, verde y azul. Como usamos una imagen en escala de grises, los tres canales de color tenían los mismos valores. Pero internamente el ancho de la elipse se escala solo con el valor del canal rojo, mientras que el alto se escala con el valor del canal verde. Cualquier efecto del valor del canal azul se ignora normalmente, salvo en un caso especial que veremos más adelante. Esto significa que la forma elíptica, o su «relación de aspecto», puede variarse usando mapas distintos para los canales rojo y verde por separado. Como en un mapa de desenfoque normal, un valor cero (o «negro» solo en ese canal) dará como resultado un ancho o alto mínimo, mientras que un valor máximo (o «blanco») dará como resultado la cantidad de desenfoque dada. Por ejemplo, aquí puedo dividir la imagen de modo que dos cuartos de la imagen se desenfoquen horizontalmente (el canal rojo es máximo) mientras hago que las otras zonas se desenfoquen verticalmente (el canal verde es máximo). Para este ejemplo generé los mapas de ancho y alto por separado, antes de combinarlos en un único y ahora colorido «mapa de desenfoque». En la práctica normal, puede crear el mapa como quiera, o incluso usar mapas preparados de antemano para efectos de desenfoque concretos.
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
Por supuesto, todavía puede fijar un ángulo a la 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)
| Before IM version 6.5.8-8 a bug was found in the handling of an angled vertical elliptical blur.
---|---
Desenfoque con ángulo variable
Hasta ahora, el ángulo de la elipse usada para desenfocar la imagen ha sido un ángulo constante en toda la imagen. Es decir, la elipse usada para el desenfoque siempre ha estado en el mismo ángulo, aunque la relación de aspecto de la elipse pueda variarse modificando los canales rojo y verde del mapa de desenfoque. A partir de IM v6.5.8-8 puede proporcionar un ángulo variable al desenfoque usando el canal azul de la imagen de mapeo de desenfoque. Esto se hace dando dos ángulos a los argumentos del desenfoque. El primer argumento de ángulo se usa para definir el ángulo de un valor cero ('0' o «negro») en el canal azul, mientras que el segundo ángulo dado se usa para definir el valor máximo («QuantumRange» o «blanco») del canal azul. Si solo se da un valor de ángulo, ese ángulo se usa para fijar los ángulos tanto del valor cero como del máximo del canal «azul», lo que básicamente significa que el ángulo queda fijo, independientemente del valor presente en el canal azul de la imagen «mapa de desenfoque». Por eso, en los ejemplos anteriores, el ángulo ha sido constante. Por ejemplo, aquí uso una elipse de desenfoque horizontal, pero luego varío el ángulo de la elipse usando el canal azul a lo largo del rango de ángulos de '+0' a '+360' alrededor del centro de la imagen. La generación del mapa usa un degradado polar, cuyos detalles puede encontrar en Degradados distorsionados. Observe cómo, al colocar ese degradado en el canal azul, uso el ajuste de color "[-background](https://imagemagick.org/command-line-options/#background)" con el operador Combine para asegurar que tanto el canal rojo como el verde se fijen a un valor máximo («blanco»), de modo que no escale la elipse en ángulo. Por supuesto, eso significa que en la imagen de mapeo final el blanco significa usar el ángulo máximo, mientras que el amarillo (o valor cero del canal azul) significa el á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
Como puede ver, el resultado es una imagen desenfocada de forma rotacional. Compare el resultado con el mapeo de desenfoque que se usó. En la parte superior de la imagen, el degradado era blanco o negro, lo que, con los argumentos usados, significa que la elipse quedaba en un ángulo de 0 o 360, por lo que la elipse permanecía horizontal. En la parte inferior, el degradado era gris puro, así que se usó un ángulo intermedio del rango dado, es decir, 180 grados. Esto significa que la elipse vuelve a ser horizontal. Pero en los laterales de la imagen, el degradado era gris al 25% o al 75%. Por tanto, el ángulo era de 90 o 270 grados, lo que hacía que la elipse rotara hacia la vertical. Todos los demás ángulos siguen el mismo patrón, haciendo que la elipse rote suavemente alrededor de la imagen. Sin embargo, ¡el centro de la imagen resultante se desenfocó de forma realmente extraña! Eso se debe a que el tamaño de la elipse permaneció constante y no se reduce adecuadamente hacia el centro de la imagen. La solución es fijar también el tamaño de la elipse usando los canales rojo y verde. Por ejemplo.
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
Un resultado mucho mejor. No obstante, observe que, aunque el resultado se ve bien, la elipse de desenfoque no está curvada en un arco como debería estar para una imagen verdaderamente desenfocada de forma rotacional. Por eso lo anterior es solo una aproximación de un verdadero desenfoque rotacional. Pero para distancias de desenfoque pequeñas (equivalentes al ángulo de desenfoque) es bastante bueno. La mejor forma de hacer desenfoques rotacionales es usar una técnica especial de distorsión polar-despolar, o el actualmente mal llamado operador Radial Blur. Cambiando el rango de ángulos usado para el ángulo de la elipse (canal azul), puede convertir fácilmente («magick») lo anterior en un desenfoque radial que se vuelve más borroso con la distancia al 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)
Pero también puede hacer mucho más que estos desenfoques radiales/rotacionales, ya que puede rotar y escalar el desenfoque en cualquier lugar y en cualquier cantidad sobre toda la imagen. Tiene el control total. Por ejemplo, puede crear una mezcla muy extraña de ambos usando un rango de ángulos distinto, de modo que el ángulo de la elipse de desenfoque no coincida con el ángulo alrededor del centro de la imagen. |
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)
Básicamente, ahora tiene el control completo de cómo y qué partes de la imagen se desenfocarán. Y con el uso de plantillas puede crear toda una biblioteca de efectos de desenfoque.
![[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)