Ejemplos de ImageMagick -- Transformaciones de imagen
- Convertir imágenes en botones realzados o hundidos
- Añadir un borde interior
- Dispersión aleatoria de píxeles
- Transformación de foto con viñeta
- Transformación Polaroid compleja
- Pintura al óleo, manchas de color
- Carboncillo, boceto artístico de una escena
- Transformación de boceto a lápiz
- Relieve, crear una impresión metálica
- Stegano, ocultar secretos dentro de una imagen
- Cifrar los datos de la imagen
- Pixelar imágenes
- Rejillas de píxeles
- Detector de bordes Canny
- Contornos de bordes a partir de figuras con antialias
- Contornos de bordes a partir de figuras de mapa de bits
- Bordes con un conversor de ráster a vector
- Detector de líneas de Hough
- Figuras con Shade enmascaradas
- Imágenes de figuras con Shade
- Redondear los bordes de Shade
- Crear realces de superposición
- Expresiones FX como escapes de porcentaje
- Métodos integrados de tipo FX
-
Evaluate, operaciones matemáticas simples
Set, Add, Subtract, Multiply, Divide * Funciones matemáticas de Evaluate
Pow, Log, Sin, Cos * Function, Evaluate de múltiples argumentos
- Multiplicar degradados con bias
- Sumar degradados con bias
- Modulación de frecuencia
Estas operaciones producen grandes cambios en la apariencia general de la imagen, ya sea con fines visuales o de efectos artísticos. Sin embargo, aunque el aspecto general de la imagen ha cambiado, a menudo de forma drástica, la imagen original en sí suele seguir siendo visible en el resultado.
Transformaciones de tipo artístico
Bordes realzados o hundidos
El operador «[-raise](https://imagemagick.org/command-line-options/#raise)» es una transformación de imagen tan sencilla que casi no lo parece. Lo único que hace es añadir un realce de bisel rectangular a una imagen existente. |
magick rose: -raise 5 rose_raise.gif
![[IM Output]](../static/img/transform/rose_raise.gif)
Se puede generar un efecto hundido e invertido usando la forma «plus» del operador… |
magick rose: +raise 5 rose_sunken.gif
![[IM Output]](../static/img/transform/rose_sunken.gif)
Este operador se parece un poco a enmarcar una imagen, pero en lugar de añadir píxeles extra como borde, el operador «[-raise](https://imagemagick.org/command-line-options/#raise)» recolorea los píxeles del borde de la imagen. Esto lo convierte en una transformación de imagen. | De hecho, elenmarcado de imágenes se logra añadiendo un borde y luego realzándolo.
---|---
| El operador solo funciona con imágenes rectangulares y fallará con imágenes de fondo transparente, ya que las modificaciones de color también serán transparentes. Básicamente, es un operador bastante tonto.
---|---
Añadir un borde interior
En lugar de colocar un borde alrededor del exterior de la imagen, el usuario quería superponer un borde directamente sobre los propios bordes de la imagen. Para lograr este efecto, la solución fue dibujar un rectángulo que se alinease con precisión con las dimensiones de la imagen. Como la imagen «rose» integrada mide 70×46 píxeles, la superposición resultante coincide exactamente con esas dimensiones. |
magick rose: -fill none -stroke navy -strokewidth 11 \
-draw 'rectangle 0,0 69,45' inside_border.jpg
![[IM Output]](../static/img/transform/inside_border.jpg)
El ancho del borde añadido se controla con el «[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)» del rectángulo. Es decir
{stroke width} = {border width} * 2 - 1
Por tanto, el borde de 6 píxeles anterior necesitaba un «[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)» de 11. Si no conoces el tamaño de la imagen, puedes recortar (shave) la imagen y luego añadir el borde de la forma habitual. Esto es probablemente más fácil, aunque quizá no tan versátil. |
magick rose: -bordercolor green -shave 6x6 -border 6x6 inside_border2.jpg
Dispersión aleatoria de píxeles
El operador «[-spread](https://imagemagick.org/command-line-options/#spread)» reemplaza cada píxel por el color de un píxel cercano elegido al azar de la imagen de origen. Esta selección aleatoria se realiza según el uso de la interpolación de píxeles y el ajuste de píxel virtual. Por ejemplo… |
magick -size 80x40 xc:red xc:blue -append -spread 5 spread_interpolated.png
![[IM Output]](../static/img/transform/spread_interpolated.png)
Si examinaras los píxeles de la imagen, verías que algunos pueden tener una mezcla de colores rojo y azul. Es decir, están interpolados, no simplemente dispersados o intercambiados. Esto es más pronunciado con valores de distancia pequeños. Ten en cuenta también que «[-spread](https://imagemagick.org/command-line-options/#spread)» hace uso del ajuste de píxel virtual. |
magick -size 80x80 xc: -virtual-pixel black -spread 10 spread_virtual.png
![[IM Output]](../static/img/transform/spread_virtual.png)
Como puedes ver, obtienes un borde aleatorio, formado en su mayoría por píxeles virtuales de negro puro, aunque hay algunos píxeles grises interpolados a partir de la frontera entre los píxeles reales de la imagen y los píxeles virtuales. Para conseguir un efecto de dispersión de píxeles más tradicional, puedes evitar esta mezcla de colores forzando la consulta de color de píxeles concretos con «[-interpolate](https://imagemagick.org/command-line-options/#interpolate) [Nearest](misc.html#nearest)». Para evitar los problemas con los píxeles virtuales y el posible «sesgo de color del borde», te recomiendo usar «[-virtual-pixel](https://imagemagick.org/command-line-options/#virtual-pixel) [Mirror](misc.html#mirror)». Así se obtiene una dispersión aleatoria de píxeles más tradicional… |
magick rose: -interpolate nearest -virtual-pixel mirror \
-spread 5 spread_rose.png
En construcción
El principal problema de lo anterior es que puedes perder algunos datos de píxeles de la imagen. Es decir, los píxeles no se «intercambian», sino que se copian al azar, lo que significa que un píxel concreto de la imagen puede quedar duplicado o perderse. A partir de IM v6.9.2-2 puedes usar «[+spread](https://imagemagick.org/command-line-options/#spread)» para intercambiar realmente los píxeles dentro de la imagen, lo que significa que ningún píxel de la imagen quedará duplicado o perdido. Todos los píxeles de la imagen original siguen presentes, solo que desplazados a una nueva posición. Sin embargo, por la forma en que se procesan los píxeles, estos pueden quedar «doblemente intercambiados». Es decir, un píxel concreto puede intercambiarse y luego ser seleccionado para intercambiarse de nuevo con un píxel posterior. Eso significa que un píxel concreto podría desplazarse más lejos de lo solicitado por el argumento de dispersión. Este doble intercambio también implica que los píxeles tienden a desplazarse más hacia la esquina inferior derecha. Ese movimiento se equilibra, por supuesto, con un desplazamiento menor de un gran número de píxeles hacia la esquina superior izquierda. Por ejemplo, aquí disperso los píxeles con el original antepuesto como referencia. |
magick -size 40x40 xc:red xc:blue -append \
\( +clone +spread 5 \) +append spread_bias.png
![[IM Output]](../static/img/transform/spread_bias.png)
Observa cómo algunos píxeles rojos se dispersan más hacia abajo, aunque también aparecen algunos píxeles azules que se dispersan hacia arriba más de lo esperado (si bien hacia el lado izquierdo de la imagen). Este problema es más pronunciado cuando usas un argumento de distancia menor para la dispersión. Una solución a este problema del doble intercambio no es fácil, y estamos buscando un algoritmo de «barajado de área limitada» para resolverlo. Pero, mientras tanto, al menos puedes mitigar el sesgo direccional aplicando la dispersión dos veces, con una distorsión Transverse (espejo diagonal de arriba a la izquierda a abajo a la derecha) entre medias. |
magick -size 40x40 xc:red xc:blue -append \
\( +clone +spread 5 -transverse -spread 5 -transverse \) \
+append spread_no_bias.png
![[IM Output]](../static/img/transform/spread_no_bias.png)
Por supuesto, esto hace que la dispersión sea más pronunciada y menos lineal, pero al menos queda sin sesgo direccional ni duplicación/pérdida de píxeles. La adición anterior se desarrolló a partir de una discusión del foro: t=28043, discusión del foro de IM rearrange vertical pixel row .
Transformación de foto con viñeta
Un operador especial para hacer que una imagen sea circular con un contorno suave y difuminado. |
magick rose: -background black -vignette 0x5 rose_vignette.gif
![[IM Output]](../static/img/transform/rose_vignette.gif)
Usando un sigma de cero (o muy pequeño) puedes eliminar el desenfoque y generar marcos elípticos u ovalados. Sin embargo, ten en cuenta que en realidad no utiliza la mayor elipse posible, así que quizá quieras hacerlo a mano. |
magick rose: -background black -vignette 0x0 rose_vignette_0.gif
![[IM Output]](../static/img/transform/rose_vignette_0.gif)
Puedes usarlo con transparencia (y formato PNG)… |
magick rose: -alpha Set -background none -vignette 0x3 rose_vignette.png
![[IM Output]](../static/img/transform/rose_vignette.png)
Un método alternativo para los argumentos consiste en usar un número muy grande para el segundo componente sigma y luego usar el primero, radius , para definir la extensión del desenfoque. Esto produce una distribución «lineal» en lugar de la distribución gaussiana más habitual en el difuminado de la viñeta. |
magick rose: -background black -vignette 5x65000 rose_vignette_linear.gif
![[IM Output]](../static/img/transform/rose_vignette.gif)
Otra técnica para una viñeta más rectangular, que produce bordes suaves en la imagen, se demuestra en Miniaturas con bordes suaves.
Transformación Polaroid compleja
Gracias al trabajo realizado por Timothy Hunter (conocido por RMagick), se añadió a IM v6.3.2 un operador de transformación «[-polaroid](https://imagemagick.org/command-line-options/#polaroid)».
Polaroid® es una marca registrada de Polaroid Corporation.
Por ejemplo, aquí le doy un aspecto Polaroid a la miniatura de una foto. La imagen mira hacia lo alto de la escalera de caracol (hacia abajo), dentro del Arco de Triunfo, París. ¡Es una escalera muy larga! |
magick spiral_stairs_sm.jpg -thumbnail 120x120 \
-bordercolor white -background black +polaroid poloroid.png
![[IM Output]](../static/img/transform/poloroid.png)
| Observa que la imagen resultante tiene una sombra semitransparente, así que tienes que usar una imagen en formato PNG o «[-flatten](https://imagemagick.org/command-line-options/#flatten)» el resultado sobre un color de fondo fijo para los formatos GIF o JPG.
---|---
Este operador es muy complejo, ya que añade un borde (según el ajuste «[-bordercolor](https://imagemagick.org/command-line-options/#bordercolor)»), «curva» el papel y añade una curvatura inversa a la sombra. El color de la sombra se puede controlar con el ajuste de color «[-background](https://imagemagick.org/command-line-options/#background)». Como viste antes, la forma «plus» del operador rotará el resultado en una cantidad aleatoria. Este operador hace que un índice de fotos resulte mucho más interesante y menos estático de lo que se obtendría de otro modo. La forma «minus» del operador te permite controlar el ángulo de rotación de la imagen. |
magick spiral_stairs_sm.jpg -thumbnail 120x120 \
-bordercolor AliceBlue -background SteelBlue4 -polaroid 5 \
poloroid_5.png
![[IM Output]](../static/img/transform/poloroid_5.png)
Si la imagen tiene metadatos «[-caption](https://imagemagick.org/command-line-options/#caption)», ese texto también se añadirá al borde inferior del marco Polaroid, mediante el operador de creación de imagen «[caption:](text.html#caption)». Es decir, se ajustará por palabras al ancho de la foto. |
magick -caption '%c %f\n%wx%h' spiral_stairs_sm.jpg -thumbnail 120x120 \
-bordercolor Lavender -background gray40 +polaroid \
poloroid_captioned.png
![[IM Output]](../static/img/transform/poloroid_captioned.png)
Los demás ajustes de texto estándar (según «[caption:](text.html#caption)») te permiten controlar el aspecto del pie de foto añadido. |
magick spiral_stairs_sm.jpg -thumbnail 120x120 -font Candice -pointsize 18 \
-bordercolor Snow -background black -fill dodgerblue -stroke navy \
-gravity center -set caption "Spiral Stairs\!" -polaroid 10 \
poloroid_controls.png
![[IM Output]](../static/img/transform/poloroid_controls.png)
| _El atributo de metadatos de imagen «[-caption](https://imagemagick.org/command-line-options/#caption)» se usó debido al uso interno del generador de texto a imagen «[caption:](text.html#caption)».
Por otro lado, el comando IM «[montage](montage.html#montage)» usa «[-label](https://imagemagick.org/command-line-options/#label)», ya que emplea el generador de texto a imagen «[label:](text.html#label)», que no ajusta por palabras._
---|---
La transformación usa las distorsiones de cizalla Rotate y Wave para añadir un poco de «curvatura» a la foto, lo que tiende a producir líneas horizontales de borrosidad en el texto de la imagen generada. Este es un problema bien conocido de distorsión de imagen (véase Rotar una línea fina), y se puede resolver con una técnica de supermuestreo. Básicamente generamos el Polaroid al doble del tamaño que realmente queremos y luego redimensionamos la imagen a su tamaño normal final. La reducción del tamaño de la imagen agudiza de hecho la imagen resultante y, lo que es más importante, el texto del pie. Sin embargo, para que esto funcione no solo necesitamos una imagen de al menos el doble del tamaño final, sino que también puede que necesitemos un borde más grande para la imagen, y dibujar el texto al doble de su «[-density](https://imagemagick.org/command-line-options/#density)» normal. No aumentes el «[-pointsize](https://imagemagick.org/command-line-options/#pointsize)» de la fuente, ya que eso no agranda el texto exactamente de la misma manera. |
magick -caption 'Spiral Staircase, Arc de Triumph, Paris, April 2006' \
spiral_stairs_sm.jpg -thumbnail 240x240 \
-bordercolor Lavender -border 5x5 -density 144 \
-gravity center -pointsize 8 -background black \
-polaroid -15 -resize 50% poloroid_modified.png
![[IM Output]](../static/img/transform/poloroid_modified.png)
Como puedes ver, aunque usamos un tamaño de fuente mucho menor, el texto del pie es muy nítido, claro y legible. Lo mismo ocurre con cualquier otro detalle fino que pudiera estar presente en la imagen original. La única desventaja de esto es que la sombra de la imagen resultante será más pequeña y menos difusa. Para tener un control total de la transformación Polaroid, puedes realizar tú mismo todos los pasos implicados. La técnica original está documentada en la página de Tim Hunter, RMagick Polaroid Effect. Los pasos son: crear y anteponer el pie, añadir bordes, curvar la foto con wave, añadir una sombra curvada en sentido inverso y, por último, rotar la imagen. Para más ejemplos y otros métodos caseros, véase Ejemplos de miniaturas Polaroid y Un montaje de fotos Polaroid. También puede que te interesen algunos de los ejemplos Polaroid en RubbleWeb IM Examples, Other.
Pintura al óleo, manchas de color
El operador «[-paint](https://imagemagick.org/command-line-options/#paint)» está diseñado para convertir imágenes en pinturas hechas aplicando gruesas «manchas» de pintura a un lienzo. El resultado es la fusión de los colores vecinos en áreas más grandes de un solo color.
magick rose: -paint 1 rose_paint_1.gif
magick rose: -paint 3 rose_paint_3.gif
magick rose: -paint 5 rose_paint_5.gif
magick rose: -paint 10 rose_paint_10.gif
magick rose: -blur 0x3 -paint 10 rose_blur_paint_10.gif
Observa que con un radio grande para las manchas de pintura, estas empiezan a adquirir un aspecto cuadrado. Este efecto se puede suavizar algo desenfocando ligeramente la imagen de antemano, como se muestra en la última imagen de arriba. Es un efecto interesante y podría usarse para crear imágenes de fondo extrañas y maravillosas. Por ejemplo, mira su uso en Ejemplos de fondos. Una última advertencia. Aunque se supone que «[-paint](https://imagemagick.org/command-line-options/#paint)» produce áreas de un único color sólido, con valores de radio grandes tiende a producir un degradado vertical en algunas zonas. Esto es muy molesto y puede que sea un error. ¿Alguien lo sabe? Hay alternativas al uso de «[-paint](https://imagemagick.org/command-line-options/#paint)». Una es usar «-statistic Mode» en su lugar, que asigna a cada píxel el «color predominante» dentro del vecindario rectangular dado, y puede producir un resultado más agradable. |
magick rose: -statistic Mode 10 rose_paint_mode.gif
![[IM Output]](../static/img/transform/rose_paint_mode.gif)
Otra es usar algunos de los métodos de morfología y, más concretamente, la variante de intensidad para imágenes en color. Aquí, por ejemplo, hay una morfología «OpenIntensity» sobre la rosa. |
magick rose: -morphology OpenI Disk rose_paint_open.gif
![[IM Output]](../static/img/transform/rose_paint_open.gif)
Y aquí uso «CloseIntensity» con un «Disk» ligeramente más pequeño. |
magick rose: -morphology CloseI Disk:2.5 rose_paint_close.gif
![[IM Output]](../static/img/transform/rose_paint_close.gif)
No tienes por qué usar «discos», sino que puedes diseñar tu propio núcleo con forma de «pincel» para las manchas que crea. Por ejemplo, ¿qué tal usar un pincel de línea diagonal?
Carboncillo, boceto artístico de una escena
El efecto de carboncillo pretende simular el boceto al carboncillo de un artista a partir de la imagen dada. El operador «[-charcoal](https://imagemagick.org/command-line-options/#charcoal)» es, en algunos aspectos, similar a las transformaciones de detección de bordes usadas por la visión por computador. Básicamente intenta convertir los bordes y contornos principales de los objetos de la imagen en tonos de lápiz y carboncillo. Se supone que el único argumento representa el grosor de las líneas del borde.
magick rose: -charcoal 1 rose_charcoal_1.gif
magick rose: -charcoal 3 rose_charcoal_3.gif
magick rose: -charcoal 5 rose_charcoal_5.gif
| Para un mejor ejemplo del uso de una transformación de carboncillo sobre una imagen real, véase Boceto al carboncillo de una foto. | Técnicamente, el operador «[-charcoal](https://imagemagick.org/command-line-options/#charcoal)» es un operador «[-edge](https://imagemagick.org/command-line-options/#edge)» con algo de umbralización aplicada a una conversión a escala de grises de la imagen original. |
|---|---|
Transformación de boceto a lápiz
El operador «[-sketch](https://imagemagick.org/command-line-options/#sketch)» aplica básicamente un patrón de trazos de línea a una imagen para generar algo que parece un boceto artístico a lápiz. Los argumentos controlan la longitud y el ángulo de los trazos. Sin embargo, conviene aplicarlo a una imagen más grande con sombreados y detalles definidos. Véase Boceto a lápiz para un ejemplo completo de este operador y de cómo funciona internamente.
Relieve, crear una impresión metálica
El operador «[-emboss](https://imagemagick.org/command-line-options/#emboss)» intenta generar el efecto de una impresión por ácido de una imagen en escala de grises sobre una lámina de metal. En muchos aspectos es muy similar al operador «[-shade](https://imagemagick.org/command-line-options/#shade)» que veremos más abajo, pero sin los bordes de aspecto 3D. Su argumento es un radio/sigma, donde solo el sigma es importante. No he encontrado que el argumento sea muy útil, y de hecho puede que tenga errores. El argumento también cambió en una versión reciente de IM. Simplemente no sé qué está pasando. Ayúdame a entenderlo si puedes.
magick rose: -emboss 0x.5 rose_emboss_0x05.gif
magick rose: -emboss 0x.9 rose_emboss_0x09.gif
magick rose: -emboss 0x1 rose_emboss_0x10.gif
magick rose: -emboss 0x1.1 rose_emboss_0x11.gif
magick rose: -emboss 0x1.2 rose_emboss_0x12.gif
magick rose: -emboss 0x2 rose_emboss_0x20.gif
El operador trabaja en escala de grises, lo que significa que se aplicará por separado a los tres canales de color. Por eso solo debería aplicarse a imágenes en escala de grises. Como viste antes, las imágenes en color pueden producir efectos extraños.
magick rose: -colorspace Gray -emboss 0x.5 rose_g_emboss_0x05.gif
magick rose: -colorspace Gray -emboss 0x.9 rose_g_emboss_0x09.gif
magick rose: -colorspace Gray -emboss 0x1 rose_g_emboss_0x10.gif
magick rose: -colorspace Gray -emboss 0x1.1 rose_g_emboss_0x11.gif
magick rose: -colorspace Gray -emboss 0x1.2 rose_g_emboss_0x12.gif
magick rose: -colorspace Gray -emboss 0x2 rose_g_emboss_0x20.gif
Si alguien sabe exactamente qué se supone que hace el algoritmo de emboss,
por favor háganmelo saber.
Stegano, ocultar una imagen secreta dentro de una imagen
El operador «[-stegano](https://imagemagick.org/command-line-options/#stegano)» es en realidad más bien un operador «divertido». Por ejemplo, un espía podría usarlo para ocultar información en el «caos» de una imagen aleatoria. Primero una advertencia…
No uses JPEG, GIF ni ningún otro formato de imagen «con pérdida» con Stegano
Por ejemplo, generemos un mensaje críptico (imagen) que quieras enviar a tu colega espía… | |
magick -gravity center -size 50x40 label:"Watch\nthe\nPidgeon" message.gif
magick identify message.gif
Ten en cuenta que también necesitaremos el tamaño de la imagen del mensaje (36x43 píxeles), de ahí el identify anterior. A continuación, lo colocamos dentro de alguna imagen con cierto desplazamiento. El desplazamiento (y el tamaño del mensaje) que se usa es la «clave» criptográfica del mensaje oculto. |
magick composite message.gif rose: -stegano +15+2 rose_message.png
![[IM Output]](../static/img/transform/rose_message.png)
Ahora puedes enviar esa imagen a tu compañero, que presumiblemente ya conoce el tamaño y el desplazamiento del mensaje. Podemos recuperar el mensaje oculto en la imagen… |
magick -size 50x40+15+2 stegano:rose_message.png message_recovered.gif
![[IM Output]](../static/img/transform/message_recovered.gif)
Cuanto mayor sea la imagen contenedora, mejor será la imagen recuperada, así que ocultar imágenes pequeñas dentro de otras más grandes es mejor que el ejemplo mostrado arriba. Solo para mostrarte cómo se distribuyó el mensaje oculto por toda la imagen contenedora, hagamos una comparación de la imagen combinada con la original. | |
magick compare -metric PAE rose: rose_message.png rose_difference.png
Lo que muestra cómo la imagen del mensaje se cifró y se distribuyó por toda la imagen contenedora para ocultarla. Además, la métrica «PAE» que devuelve lo anterior muestra que la mayor diferencia fue de un solo valor de color de los valores de color de 8 bits usados para esta imagen. Es decir, minúscula. Tan minúscula que un pequeño cambio o modificación en la imagen destruirá el mensaje oculto en su interior. Es una diferencia tan pequeña que ni siquiera puedes usar JPEG con su compresión con pérdida como formato de imagen, ni ningún otro formato de imagen con pérdida (incluido GIF) para la imagen contenedora. Además, si tuvieras la «clave de desplazamiento» equivocada, no obtendrías el mensaje… |
magick -size 50x40+14+2 stegano:rose_message.png message_bad.gif
![[IM Output]](../static/img/transform/message_bad.gif)
También puedes limitar en qué zona de la imagen se oculta el mensaje usando un ajuste de región. El mismo ajuste será necesario al intentar recuperar el mensaje. Esto probablemente haría que encontrar y descodificar el mensaje oculto en una imagen grande, sobre todo si se restringe a una zona «recargada», fuera un orden de magnitud más difícil de determinar. Sin embargo, ten en cuenta que esta no es una técnica criptográficamente muy segura. Especialmente si la imagen de origen original también está disponible. El análisis de frecuencia de la imagen suele revelar a un atacante que hay un mensaje oculto. Como método de protección de derechos de autor de imágenes, el operador Stegano también es inútil, ya que el menor cambio en la imagen destruirá el mensaje y, por tanto, su eficacia. Como herramienta de espionaje tampoco es muy buena, con un número tan pequeño de «combinaciones» para una imagen de tamaño razonable. Cualquiera que sepa más o menos lo que estás haciendo podría descifrarlo rápidamente. Mejor quédate con los métodos criptográficos conocidos y probados con el tiempo. Su único uso práctico real es como herramienta divertida o como forma de añadir cantidades muy pequeñas de ruido a una imagen existente.
Cifrar los datos de la imagen
Los operadores «[-encipher](https://imagemagick.org/command-line-options/#encipher)» y «[-decipher](https://imagemagick.org/command-line-options/#decipher)» básicamente cifran los datos de la imagen en un revoltijo ininteligible. Es decir, el contenido de la imagen en sí deja de ser reconocible por completo hasta que la imagen se descifra más tarde. Esto puede usarse, por ejemplo, para proteger imágenes sensibles en servicios públicos, de modo que solo quien tenga la frase de contraseña secreta pueda verlas después. Pero primero una advertencia…
No uses JPEG, GIF ni ningún otro formato de imagen «con pérdida» con el cifrado
Por ejemplo, ciframos esa imagen de mensaje secreto que creamos arriba, usando una frase de contraseña que he guardado en un archivo no tan «secreto», «pass_phrase.txt».
magick message.gif -encipher pass_phrase.txt \
-depth 8 png24:message_hidden.png
| _La imagen cifrada da por hecho que se guarda en un formato de archivo de imagen de 8 bits. Por eso se recomienda forzar esa limitación estableciendo «[-depth](https://imagemagick.org/command-line-options/#depth) 8» antes de guardar el archivo de salida final.
También se necesitaba «png24» en lo anterior para asegurar que la salida no sea una imagen de paleta o con mapa de colores «png8:», que tampoco funciona correctamente._
---|---
Como puedes ver, la imagen resultante parece basura completa, sin ninguna indicación del contenido real de la imagen. Ahora puedes publicar esa imagen en la web, y solo alguien que conozca la frase de contraseña original exacta podrá restaurar los datos de la imagen… |
magick message_hidden.png -decipher pass_phrase.txt message_restored.gif
![[IM Output]](../static/img/transform/message_restored.gif)
Sin embargo, ten en cuenta que si los datos de la imagen se corrompen de algún modo, no podrás restaurarla. Eso incluye si el PNG se guarda usando un tipo de formato de imagen en escala de grises. Por eso solo se puede usar un formato de imagen sin pérdida, como PNG, MIFF, TIFF o incluso texto de enumeración de píxeles. Sin embargo, usar un formato de imagen con pérdida, como JPEG, PNG8 y GIF, corromperá los datos de la imagen y, por tanto, destruirá el cifrado resultante. Ten en cuenta que cualquier metadato que pueda estar describiendo la imagen seguirá estando en claro. Eso significa que podrías cifrar imágenes usando la propia cadena «comment» de la imagen como frase de contraseña, o usar ese comentario cifrado con alguna contraseña más corta. Es una idea sencilla que podría hacer la frase de contraseña más variable. Cifrar una imagen puede ser solo un paso. Llevar el resultado un poco más allá puede producir una imagen que no se descifre sin algún procesamiento extra. Por ejemplo, aquí uso algunas distorsiones simples no destructivas para confundir a quien intente descifrar la imagen de la forma normal.
echo "password" | magick message.gif -encipher - \
-transpose -depth 8 png24:message_obfuscate.png
echo "password" | magick message_obfuscate.png -transpose \
-decipher - message_restored_2.png
Si no incluyeras el «[-transpose](https://imagemagick.org/command-line-options/#transpose)» en el comando de descifrado anterior, la imagen no se habría descifrado correctamente. Ten en cuenta también que, debido al cifrado en flujo utilizado (véase la nota de experto más abajo), usar simplemente un «[-roll](https://imagemagick.org/command-line-options/#roll)» de algún tipo no impedirá que la imagen se descifre, al menos parcialmente. Observa que en lo anterior no usé un archivo para guardar la «frase de contraseña», sino que introduje la frase en el comando «magick» mediante la entrada estándar, lo que te permite usar algún otro programa o comando para obtener la frase del usuario, generarla o algún otro método, en lugar de usar un archivo de texto con la frase de contraseña en claro. La frase de contraseña también podría generarse a partir de otros archivos e imágenes descargables libremente. Por ejemplo, podrías descifrar tu imagen usando la firma o la cadena de comentario de una imagen de referencia conocida y descargable libremente. Por ejemplo, aquí uso la firma de la imagen «rose.gif» para cifrar y luego descifrar la imagen «message.gif».
magick identify -format %# rose.gif |\
magick message.gif -encipher - -depth 8 png24:message_signed.png
magick identify -format %# rose.gif |\
magick message_signed.png -decipher - message_restored_3.png
A partir de IM v6.4.8-0, el archivo usado por «[-encipher](https://imagemagick.org/command-line-options/#encipher)» y «[-decipher](https://imagemagick.org/command-line-options/#decipher)» puede ser un archivo binario. Por eso podrías incluso usar directamente una imagen como frase de contraseña.
magick message.gif -encipher rose.gif -depth 8 png24:message_binary.png
magick message_binary.png -decipher rose.gif message_restored_4.png
| Antes de IM v6.4.8-0, un archivo binario se detenía en el primer carácter «NULL» que encontraba. Algo que ocurriría bastante pronto si se usaba una imagen PNG.
---|---
Esta técnica es exacta (a menos que parte de los datos se destruyera durante la transmisión). Por eso puedes usarla para cifrar una imagen que contenga otra información oculta, como una imagen Stegano. Esto significa que, aunque las autoridades descifren la imagen o te obliguen a revelar la contraseña, verán una imagen real, pero esa imagen quizá no sea la imagen oculta final. | Los operadores «[-encipher](https://imagemagick.org/command-line-options/#encipher)» y «[-decipher](https://imagemagick.org/command-line-options/#decipher)» se añadieron en IM v6.3.8-6, pero requerían incluir una opción «--enable-cipher» en la configuración de compilación. Sin embargo, en IM v6.4.6 (¿cuándo cambió?) este elemento de configuración dejó de ser necesario y se convirtió en un ajuste de configuración estándar. Por eso probablemente puedas usarlo de inmediato.
---|---
| _El cifrado se implementó usando un cifrado en flujo autosincronizable implementado a partir de un cifrado en bloque.
Esto significa que aún puedes descifrar incluso una descarga parcial de la imagen, que se destruyó por un error de transmisión, aunque parte de la imagen pueda haberse destruido. Tampoco necesitas descargar la imagen completa para descifrar y examinar las partes que se descargaron correctamente.
Pero sí necesitas la frase de contraseña para tener alguna posibilidad de descifrar la imagen con éxito, ya que es un cifrado muy, muy fuerte.
Pixelar una imagen
Pixelar una imagen se usa básicamente para convertir una imagen en un conjunto de grandes «píxeles» de color que solo muestra un contorno vago de la imagen original. Ambas técnicas implican encoger la imagen (para generar menos píxeles) y luego ampliarlos de tal modo que se cree un «bloque de píxeles» usando un operador de escalado o un operador de muestreo para generar el bloque de color. Es solo la forma en que se reduce la imagen lo que determina exactamente qué color se usará. Una sola muestra de píxel, o un color promedio fusionado.
magick rose: -sample 25% -scale 70x46\! rose_pixelate_sampled.gif
magick rose: -scale 25% -scale 70x46\! rose_pixelate_scaled.gif
magick rose: -resize 25% -scale 70x46\! rose_pixelate_resized.gif
Como puedes ver, las áreas «muestreadas» tendrán «píxeles» mucho más definidos (con aliasing), mientras que las otras dos usan un color fusionado o promediado, que tiende a producir una representación de color más apagada pero más precisa para cada «píxel». Véase también Proteger el anonimato de alguien para un ejemplo del uso de esto solo en una zona enmascarada más pequeña de la imagen, como la cara de una persona.
Rejillas de píxeles
Hacer una rejilla con una imagen es muy similar a pixelarla. En este caso solo queremos ampliar la imagen para generar una vista distintiva a nivel de píxel de los detalles de una imagen. Normalmente, una imagen muy pequeña. La forma más sencilla es como en el ejemplo anterior: simplemente escalar una imagen pequeña para ampliar los píxeles.
magick rose: -crop 10x10+12+20 +resize grid_input.png
magick grid_input.png -scale 1000% grid_scale.png
El problema de un escalado simple es que en las zonas donde los píxeles son de color similar, puedes tener dificultades para ver los «bloques de píxeles» individuales. Lo que necesitamos es añadir un borde alrededor de los píxeles para separarlos. Para esto necesitamos superponer una máscara de mosaico generada. Véase Embaldosar con una imagen ya en memoria para diversos métodos de usar una imagen de mosaico generada en un único comando. Aquí generamos una «rejilla» blanca sobre negro que se superpone mediante composición Screen (superponer el blanco, dejando las zonas negras como están). |
magick -size 10x10 xc: -draw 'rectangle 1,1 9,9' -write mpr:block +delete \
grid_input.png -scale 1000% -size 101x101 tile:mpr:block \
+swap -compose screen -composite grid_blocks.png
![[IM Output]](../static/img/transform/grid_blocks.png)
Observa que el tamaño usado para generar el mosaico es _escala_ *_tamaño_imagen_ +_tamaño_hueco_ (en este caso 10*10+1 => 101). También intercambié las dos imágenes para que el tamaño de la imagen final provenga de la imagen del mosaico, en lugar de la imagen escalada, que es un píxel más pequeña. Sin embargo, esto puede perder los metadatos de imagen que hubiera en la imagen original, ya que usé la imagen embaldosada como destino. Aquí genero «puntos» circulares de color, pero esta vez usé una composición Multiply (superponer el negro, dejando las zonas blancas como están). |
magick -size 10x10 xc: -draw 'circle 5,5 1,3' -negate \
-write mpr:spot +delete \
grid_input.png -scale 1000% -size 101x101 tile:mpr:spot \
+swap -compose multiply -composite grid_spots.png
![[IM Output]](../static/img/transform/grid_spots.png)
Puedes hacer transparente el borde de la rejilla negando también la superposición embaldosada (las zonas negras se vuelven transparentes) y usar una composición CopyOpacity en lugar de Multiply. También se pueden añadir otros colores, pero para que esto funcione tienes que usar una imagen de mosaico que realmente contenga transparencia real. Para ello necesitas convertir la imagen de mosaico en blanco y negro en una máscara con forma. Por ejemplo, aquí uso el operador básico de morfología para generar «agujeros» en forma de diamante en una superposición de color. Para ello se dibuja un único píxel «semilla» y se expande usando un núcleo de morfología Diamond. |
magick -size 10x10 xc: -draw 'point 5,5' -morphology Erode:4 Diamond \
-background Navy -alpha shape -write mpr:diamond +delete \
grid_input.png -scale 1000% -splice 1x1+0+0 \
-size 101x101 -background none tile:mpr:diamond \
-alpha set -compose Over -composite grid_diamonds.png
![[IM Output]](../static/img/transform/grid_diamonds.png)
| Ten en cuenta que el codificador «tile:» reemplazará cualquier transparencia de la imagen con el color de fondo actual. Si quieres preservar la transparencia de la imagen embaldosada, establece «-background none» o «-compose Src». La primera opción es más fácil.
---|---
Ten en cuenta que, técnicamente, el modelado por alfa se puede hacer antes de guardar la imagen del mosaico, o después de embaldosar la imagen del mosaico, antes de superponerla. La elección es tuya. Una última técnica consiste en usar un filtro de remuestreo malo para producir un fallo de remuestreo que genere círculos con aliasing de cada píxel. No es una gran técnica (hacer mal uso de un fallo del procesamiento de imágenes), pero sí forma una rejilla de píxeles.
Espaciar los mosaicos
Un problema similar es espaciar una rejilla de mosaicos en una imagen. Esto no consiste simplemente en escalar píxeles individuales a «bloques de píxeles», sino en insertar espacio entre zonas rectangulares de una imagen. Es decir, insertar (splice) píxeles extra en una imagen a intervalos regulares. Actualmente la mejor solución es dividir la imagen en filas y columnas, insertar el espaciado extra en cada mosaico y luego unir (append) los mosaicos de nuevo. Por ejemplo…
magick rose: -background SkyBlue \
-crop 10x0 +repage -splice 3x0 +append \
-crop 0x10 +repage -splice 0x3 -append \
grid_tile.png
Aquí hay otro método que también separa la imagen original en mosaicos, pero luego usa algunas expresiones FX caseras para calcular la nueva posición de un mosaico a partir de su antigua posición. |
magick rose: -crop 10x10 \
-set page '+%[fx:page.x+3*page.x/10]+%[fx:page.y+3*page.y/10]' \
-background skyblue -layers merge +repage grid_tile_fx.png
![[IM Output]](../static/img/transform/grid_tile_fx.png)
El número «3» de arriba es el ancho del hueco a añadir, y «10» es el tamaño del mosaico. Lo único que necesitas es añadir un borde u otro contorno al resultado. Con un poco más de trabajo, incluso puedes añadir algo de «temblor» aleatorio a la colocación de cada mosaico en la rejilla anterior, para un efecto menos regular. El problema de ambos métodos es que generar muchas imágenes pequeñas solo para volver a unirlas genera mucho trabajo. Especialmente con tamaños de mosaico muy pequeños. Un método mejor que se ha propuesto es una extensión especial del operador Splice, en la discusión del foro de IM Splice (adding tile gridding gaps).
Transformaciones de visión por computador
Detección de bordes
El operador «[-edge](https://imagemagick.org/command-line-options/#edge)» resalta las zonas con degradados de color dentro de una imagen. Es un operador en escala de grises, por lo que se aplica por separado a cada uno de los tres canales de color.
magick mask.gif -edge 1 mask_edge_1.gif
magick mask.gif -edge 2 mask_edge_2.gif
magick mask.gif -edge 3 mask_edge_3.gif
magick mask.gif -edge 10 mask_edge_10.gif
Como puedes ver, ¡el borde solo se añade a zonas con un degradado de color que es más del 50 % blanco! No sé si esto es un error o intencionado, pero significa que el borde de arriba se sitúa casi por completo en las partes blancas de la imagen de máscara original. Este hecho puede ser extremadamente importante al usar los resultados del operador «[-edge](https://imagemagick.org/command-line-options/#edge)». Por ejemplo, si realizas la detección de bordes en una imagen que contiene un contorno negro, el operador «[-edge](https://imagemagick.org/command-line-options/#edge)» «duplicará» las líneas negras, produciendo un resultado extraño.
magick piglet.gif -colorspace Gray -edge 1 -negate piglet_edge.gif
Sin embargo, al negar la imagen antes de hacer la detección de bordes, las líneas duplicadas se dirigen hacia el interior y se unen, eliminando el efecto de «línea doble». |
magick piglet.gif -colorspace Gray \
-negate -edge 1 -negate piglet_edge_neg.gif
![[IM Output]](../static/img/transform/piglet_edge_neg.gif)
He comprobado que los bordes tienden a ser demasiado nítidos, generando un borde poco suave en las imágenes resultantes. Por eso encuentro que un desenfoque muy, muy ligero del resultado mejora bastante el aspecto. |
magick piglet_edge_neg.gif -blur 0x.5 piglet_edge_blur.gif
![[IM Output]](../static/img/transform/piglet_edge_blur.gif)
Aquí he aplicado la detección de bordes a una imagen en color, y a una versión en escala de grises, para mostrarte sus efectos en imágenes de tipo fotográfico.
magick rose: -edge 1 rose_edge.gif
magick rose: -colorspace Gray -edge 1 rose_edge_grey.gif
Como puedes ver, sin convertir la imagen a escala de grises, los bordes de los distintos canales de color se generan de forma completamente independiente unos de otros.
Detector de bordes Canny
A partir de IM v6.8.9-0, IM ahora admite el detector de bordes Canny. (Véase Ejemplos del anuncio en el foro de IM). Este es un algoritmo de detección de bordes muy avanzado, que produce líneas únicas muy fuertes (binarias) de un píxel de ancho en todos los bordes nítidos, con muy poca interferencia de ruido. Por ejemplo, aquí lo aplicamos a las imágenes de prueba que usamos arriba…
magick mask.gif -canny 0x1+10%+30% mask_canny.gif
magick piglet.gif -canny 0x1+10%+30% piglet_canny.gif
magick piglet.gif -negate -canny 0x1+10%+30% piglet_canny_neg.gif
magick rose: -canny 0x1+10%+30% rose_canny.gif
Como puedes ver, produce un resultado mucho más nítido que el operador Edge de arriba. El borde difuso con antialias tiene poco o ningún efecto sobre el resultado, produciendo finas líneas de mapa de bits. Además, como muestra la imagen del cerdito, no se sitúa en un lado concreto como hacía el operador de bordes anterior. En consecuencia, negar la imagen de entrada no tiene efecto. Pero, como todos los detectores de bordes, puede tener problemas con imágenes del mundo real con fondos «recargados», como la imagen integrada de la rosa. Este resultado limpio es muy importante más adelante en la detección de líneas de Hough.
Contornos de bordes a partir de figuras con antialias
El mayor problema de los métodos normales de detección de bordes es que el resultado tiene mucho aliasing. Es decir, genera un efecto de píxeles muy escalonado, independientemente de si la figura es suave (con antialias) o tiene aliasing. Por ejemplo, aquí hay un bocadillo de diálogo suave y con antialias (el carácter «(» de la fuente «WebDings»). |
magick -size 80x80 -gravity center -font WebDings label:')' voice.gif
![[IM Output]](../static/img/transform/voice.gif)
Y aquí está su imagen con los bordes detectados… |
magick voice.gif -edge 1 -negate voice_edge.gif
![[IM Output]](../static/img/transform/voice_edge.gif)
Como puedes ver, tiene un aspecto horrible, con algo de antialias menor en el exterior del borde y un aspecto totalmente con aliasing (escalonado) en el interior de la línea. Negar la imagen generó un contorno similar alrededor del exterior de la imagen, pero también tiene un fuerte aliasing fuera de la línea. |
magick voice.gif -negate -edge 1 -negate voice_edge_negate.gif
![[IM Output]](../static/img/transform/voice_edge_negate.gif)
Una alternativa, cuando ya tienes una imagen con un borde con antialias, es generar la imagen de diferencia respecto a un clon «desplazado» de la figura original. Por ejemplo, aquí hallamos la imagen de diferencia entre la imagen original y otra que se ha desplazado (o «temblado») un píxel a la derecha. |
magick voice.gif \( +clone -roll +1+0 \) -compose difference -composite \
-negate voice_jitter_horiz.gif
![[IM Output]](../static/img/transform/voice_jitter_horiz.gif)
Ten en cuenta que esto no produce un buen borde para los bordes con pendiente horizontal. Sin embargo, combinando una imagen de diferencia desplazada en horizontal y otra en vertical, podemos obtener un contorno con antialias muy bueno de la figura. |
magick voice.gif \
\( -clone 0 -roll +1+0 -clone 0 -compose difference -composite \) \
\( -clone 0 -roll +0+1 -clone 0 -compose difference -composite \) \
-delete 0 -compose screen -composite -negate voice_jitter_edge.gif
![[IM Output]](../static/img/transform/voice_jitter_edge.gif)
Esta técnica también tiene la ventaja de funcionar tanto si la máscara está negada como si no. Sin embargo, ten en cuenta que el resultado tiene un desplazamiento de 1/2 píxel respecto a la imagen original, por lo que puede requerir algún procesamiento de «distorsión» adicional para realinear la figura original, o el contorno, si hay que combinar ambos para obtener el resultado deseado.
Contornos de bordes a partir de figuras de mapa de bits
Las imágenes de mapa de bits son mucho más difíciles, ya que no tienen píxeles con antialias que puedan usarse para producir un contorno suave. Por ejemplo, aquí hay una elegante figura de «corazón» extraída de la fuente «WebDings» (el carácter «Y»). Sin embargo, la generé a propósito como un mapa de bits con aliasing, para simular una imagen de mapa de bits horrible descargada de la red. Como el contorno de una imagen GIF que contiene transparencia. |
magick +antialias -size 80x80 -gravity center \
-font WebDings label:Y heart.gif
![[IM Output]](../static/img/transform/heart.gif)
Así que tenemos esta imagen horrible, pero queremos hallar el contorno de la imagen en lugar de su figura. El uso directo de la detección de bordes solo generará un borde de mapa de bits puro alrededor del exterior de la figura del mapa de bits. |
magick heart.gif -edge 1 -negate heart_edge.gif
![[IM Output]](../static/img/transform/heart_edge.gif)
Un borde negado genera una imagen de borde, pero para el interior de la zona negra. |
magick heart.gif -negate -edge 1 -negate heart_edge_negate.gif
![[IM Output]](../static/img/transform/heart_edge_negate.gif)
Al sumar las dos imágenes anteriores obtienes un borde de 2 píxeles centrado en el borde de la figura del mapa de bits. |
magick heart.gif \( +clone -negate \) -edge 1 \
-compose add -composite -negate heart_edge_double.gif
![[IM Output]](../static/img/transform/heart_edge_double.gif)
Como puedes ver, la imagen resultante tiene mucho aliasing, con efectos «escalonados» en el contorno, aunque la imagen original en sí no está tan mal en este aspecto. Esta no es una buena solución. Se puede crear un borde algo mejor usando un método de morfología «[EdgeIn](morphology.html#edge-in)», u otros similares. |
magick heart.gif -negate -morphology EdgeIn Diamond -negate heart_edgein.gif
![[IM Output]](../static/img/transform/heart_edgein.gif)
Y se puede lograr un efecto similar simplemente usando redimensionados para desenfocar el borde de la manera adecuada, antes de usar un Solarize para extraer los píxeles de gris medio que forman el borde. Se puede generar un borde más grueso añadiendo un ajuste «-filter Cubic», o algún otro filtro de remuestreo. |
magick heart.gif -resize 400% -resize 25% \
-solarize 50% -evaluate multiply 2 -negate heart_resize.gif
![[IM Output]](../static/img/transform/heart_resize.gif)
O, para un efecto más difuso y controlado, puedes simplemente desenfocar la figura y extraer el borde de forma similar. Encuentro que un desenfoque de «0.7» es más o menos el mejor, con un límite de 3 píxeles para acelerar las cosas. |
magick heart.gif -blur 3x.7 -solarize 50% -level 50%,0 heart_blur.gif
![[IM Output]](../static/img/transform/heart_blur.gif)
Observa el uso del operador Level, que es el equivalente del «-evaluate multiply 2 -negate» usado en el ejemplo anterior. Con un borde con antialias puedes ahora volver a añadir la figura original si solo quieres suavizar la figura original en lugar de obtener su contorno. Solo recuerda que el contorno se sitúa exactamente a lo largo del borde de la imagen original, por lo que será medio píxel más grande que en los ejemplos anteriores. ¿Conoces alguna otra forma de generar un contorno con antialias a partir de una figura (con antialias o de mapa de bits)? Si es así, envíamela a mí o al foro de IM. Se te dará crédito.
Bordes usando un conversor de ráster a vector
Una de las soluciones más ideales es usar un programa de conversión de ráster a vector ajeno a IM para convertir esta figura de mapa de bits en un contorno vectorial. Entre los programas capaces de hacerlo están: «ScanFont», «CorelTrace», «Streamline» de Adobe y «[Vector Magic](http://vectormagic.com/home)». No obstante, la mayoría de ellos cuestan al menos algo de dinero. «VectorMagick» y otro programa de trazado, «AutoTracer», tienen conversores de imágenes en línea de uso gratuito. Otras soluciones gratuitas son «[AutoTrace](http://autotrace.sourceforge.net/)» o «[PoTrace](http://potrace.sourceforge.net/)». Se agradecen más sugerencias. Estos programas de trazado son sencillos de usar, pero normalmente requieren alguna forma de preparación previa y posterior de la imagen. Tienen un número limitado de formatos de entrada y producen una imagen vectorial que creará una forma «suavizada» de la imagen de entrada. Prefiero «AutoTrace», ya que no escala los datos SVG resultantes y produce así un grosor de línea estándar; sin embargo, no puedes usarlo en una «tubería». Para obtener los mejores resultados, conviene asegurarse de alimentarlo solo con una imagen de mapa de bits básica, lo que podemos garantizar umbralizando la imagen de entrada mientras la convertimos a un formato de imagen que autotrace entienda. Luego puedo convertir esa imagen en una imagen vectorial SVG.
magick heart.gif -colorspace gray -threshold 50% heart_tmp.pbm
autotrace -output-format svg -output-file heart.svg heart_tmp.pbm
magick heart.svg heart_svg.gif
rm -f heart_tmp.pbm
| | | ![[IM Text]](../static/img/transform/heart.svg.gif)
A partir de IM v6.4.2-6 puedes realizar la secuencia anterior directamente usando el delegado de entrada de imagen «autotrace:». Esto solo requiere que el comando «autotrace» esté instalado. Por ejemplo |
magick autotrace:heart.gif heart_traced.gif
![[IM Output]](../static/img/transform/heart_traced.gif)
Si tu IM se compiló con la biblioteca de delegado «[AutoTrace](http://autotrace.sourceforge.net/)», también puedes hacer que IM genere directamente la imagen SVG a partir de una imagen en memoria. Para más detalles, véase Manejo de la salida SVG. Por ejemplo…
magick heart.gif heart_2.svg
Ahora la salida SVG representará, por supuesto, una versión suavizada de la imagen original, que no es lo que realmente queremos en este ejemplo. Pero como ahora tenemos la forma del mapa de bits en forma vectorial , podemos simplemente ajustar los atributos «style» del SVG para «stroke» (trazar) el contorno, en lugar de «fill» (rellenar) la figura. El SVG modificado puede entonces volver a alimentarse a ImageMagick para recrear la imagen ráster del contorno limpio. Por ejemplo… |
cat heart.svg |
sed 's/"fill:#000000[^"]*"/"fill:none; stroke:black;"/' |
magick svg:- heart_outline.gif
![[IM Output]](../static/img/transform/heart_outline.gif)
Sí, es un poco engorroso, pero el resultado suave y con antialias bien merece el esfuerzo. Estaría bien que el contorno o alguna otra modificación pudiera especificarse como opciones del propio comando «autotrace», pero actualmente no es una función disponible. También puedes modificar más la salida SVG para engrosar el borde, o especificar algún otro color de trazo o de fondo, o cambiar el color de relleno de la figura del borde vectorial. Por ejemplo, aquí generamos un contorno más grueso de la figura con un relleno rojo, todo bien suavizado con antialias. |
cat heart.svg |
sed 's/"fill:#000000;[^"]*"/"fill:red; stroke:black; stroke-width:5;"/' |
magick svg:- heart_outline_thick.gif
![[IM Output]](../static/img/transform/heart_outline_thick.gif)
Un corazón de aspecto tan perfecto no podría haberse generado a partir de una figura de mapa de bits de ninguna otra manera. También podríamos simplemente extraer el elemento de ruta «d="..."» para usarlo directamente como cadena de ruta SVG en el comando Draw. Esto te permitiría usar cualquiera de los demás ajustes de dibujo de IM con ese contorno vectorial, dándote control total del resultado final. Para otro ejemplo del uso del programa «[AutoTrace](http://autotrace.sourceforge.net/)», véase Esqueleto usando Autotrace.
Detector de líneas de Hough
El detector de líneas de Hough («[-hough-lines](https://imagemagick.org/command-line-options/#hough-lines)», añadido en IM v6.8.9-1) es una transformación muy compleja con muchas etapas (para más detalles, véase Wikipedia, Hough Transform). Básicamente está diseñado para examinar una imagen, buscar líneas blancas sobre fondo negro e intentar devolver la ubicación exacta de cualquier segmento de línea (secuencias lineales de píxeles) presente en la imagen. Esto puede ser muy importante para cosas como eliminar las rotaciones de una imagen, o determinar la transformación de perspectiva de una imagen, para poder repetirla o eliminarla. Aquí está el conjunto completo de opciones del operador
-background {_background_} -stroke {_line_color_} -hough-lines {_W_}x{_H_}+{_threshold_}
Los colores (background y line_color) se usan para establecer los colores de las líneas en la imagen resultante (si realmente las dibujas). El argumento del operador de Hough (W}x{H}+{threshold) se usa para definir el tamaño y el umbral del filtro empleado para hallar «picos» en la «imagen de búsqueda» intermedia. Es decir, controla con qué precisión «encuentra» realmente las líneas que intentamos detectar (véase más abajo). Ajustarías estos valores para ayudar a hallar las líneas. Por ejemplo, intentemos hallar las líneas en una imagen con forma rectangular. Primero necesitamos reducir la imagen a líneas, y para un resultado limpio se recomienda el detector de bordes Canny.
magick shape_rectangle.gif -canny 0x1+10%+30% rectangle.gif
Ahora apliquemos el detector de líneas de Hough a esta imagen. |
magick rectangle.gif -background black -stroke red \
-hough-lines 5x5+20 rectangle_lines.gif
![[IM Output]](../static/img/transform/rectangle_lines.gif)
Como puedes ver, se hallaron 5 líneas, 2 de las cuales están muy juntas. La razón de la línea extra es que el rectángulo de la imagen no es perfecto. Ahora bien, aunque muestro un resultado de imagen ráster (GIF), el operador de Hough en realidad genera una imagen vectorial en formato Magick Vector Graphics. Esto significa que puedes listar la información de las líneas para su posterior procesamiento.
magick rectangle.gif -background black -stroke red \
-hough-lines 5x5+20 rectangle_lines.mvg
Ten en cuenta que las líneas se dibujan de un borde (con valores en coma flotante) a otro borde de la imagen. Y a partir de esto puedes ver que la segunda y la tercera línea son las dos que están juntas. El comentario en la salida MVG te da el número acumulado de píxeles que la línea «toca» en la imagen, y es por tanto un buen indicador de lo fuerte que es la línea en la imagen. Este valor siempre será mayor que el valor de umbral que des al operador «[-hough-line](https://imagemagick.org/command-line-options/#hough-line)». A partir de esto puedes ver que la primera y la última línea (que son coincidencias cercanas) tienen ambas más o menos la misma intensidad, por lo que sería difícil elegir una sobre la otra. Si esto te ocurre, te sugiero que intentes mejorar tu paso de detección de bordes. Ten en cuenta que la imagen MVG no tiene ningún color definido. Los ajustes de color de este ejemplo en realidad no se usaron. Los colores solo se usan si realmente «dibujas» los vectores al convertir el resultado anterior en una imagen «ráster», como hicimos antes. También puedes ver la «imagen de búsqueda» intermedia, o «acumulador», que busca píxeles blancos en todas las orientaciones, usando un define especial. |
magick rectangle.gif \
-define hough-lines:accumulator=true -hough-lines 5x5+20 \
-delete 0 -contrast-stretch 0.1% rectangle_accumulator.gif
![[IM Output]](../static/img/transform/rectangle_accumulator.gif)
El define simplemente añadirá la «imagen de búsqueda» al resultado de la imagen, que en este caso eliminamos. También aplicamos algo de contraste a los «valores acumulados» para hacerlos más visibles. Esta es la imagen sobre la que busca el argumento del detector de Hough. La imagen siempre tiene 180 píxeles de ancho (1 píxel por cada grado de ángulo de línea), mientras que la altura es el doble de la longitud diagonal de la imagen. Por eso la ubicación del pico definirá directamente el ángulo de la línea, y la distancia perpendicular de la línea respecto al punto central de la imagen de entrada. Es decir, la coordenada X es el ángulo en grados, y la coordenada Y la distancia desde el centro, desde -distancia diagonal hasta +distancia diagonal. Si miras de cerca el pico inferior derecho, puedes ver por qué acabamos con dos líneas en lugar de una. El pico aquí está «duplicado» con un pequeño hueco entre ambos. El algoritmo se basa en el script «[houghlines](http://www.fmwconcepts.com/imagemagick/houghlines/)» de Fred Wienhaus, aunque con un manejo distinto de la acumulación de la «distancia perpendicular».
Umbralización adaptativa local
En construcción
El operador «[-lat](https://imagemagick.org/command-line-options/#lat)» intenta umbralizar de forma adaptativa cada píxel según el valor de los píxeles de una ventana circundante. Esto se usa habitualmente para umbralizar imágenes con un fondo desigual (es decir, iluminación desigual). Se basa en la suposición de que los píxeles de una ventana pequeña tendrán aproximadamente el mismo color de fondo y aproximadamente el mismo color de primer plano.
Por ejemplo.
magick input.png -lat 17 output.png
En lo anterior se usa una «ventana» cuadrada de 17 píxeles para determinar el color promedio de la imagen en cada punto; si el píxel es más oscuro que ese promedio, se vuelve negro; si es más claro que ese promedio, se vuelve blanco. Un tamaño de ventana pequeño hará que el umbral sea más sensible a pequeños cambios de iluminación, es más rápido de calcular, pero se ve afectado negativamente por el ruido de la imagen.
Ejemplo
Un tamaño de ventana mayor hará que el umbral sea menos sensible a pequeños cambios de iluminación, es más lento de calcular y menos afectado por el ruido de la imagen. Esto tiene el efecto de hacer que la selección del valor de umbral sea más o menos sensible a pequeños cambios en los valores de los píxeles.
Ejemplo
La ventana no tiene por qué ser cuadrada. Por ejemplo...
magick input.png -lat 15x25 output.png
También puedes proporcionar un desplazamiento que se sumará al color promedio calculado, haciendo que el valor de umbral local de cada píxel sea más claro o más oscuro. Esto puede usarse, por ejemplo, para reducir el efecto del ruido o el efecto de pequeños cambios en los valores de los píxeles.
magick input.png -lat 15x25+2%
Estos pequeños cambios suelen producirse cuando se usa un escáner o una cámara digital para adquirir la imagen. Usa un valor de desplazamiento positivo para hacer que la umbralización adaptativa sea menos sensible a pequeñas variaciones en los valores de los píxeles. Usa un umbral negativo para hacer que el umbral adaptativo sea más sensible a pequeñas variaciones en los valores de los píxeles. Como alternativa, se podría reducir el ruido de la imagen antes de procesarla con «-lat».
En resumen, cada píxel se umbraliza usando la siguiente lógica:
AVG = valor promedio de cada píxel en la ventana
IF (el píxel de entrada es > AVG + OFFSET)
El píxel de salida es NEGRO
else
El píxel de salida es BLANCO
---
Una alternativa es restar una copia desenfocada de la imagen original
usando una resta (Modulus), y luego umbralizar.
magick rose: -colorspace gray -lat 10x10+0% x:
es aproximadamente equivalente a...
magick rose: -colorspace gray \( +clone -blur 10x65535 \) \
-compose subtract -composite -threshold 50% x:
El especial "-blur 10x65535" es un desenfoque de promedio lineal que se limita a una
ventana de 10x10.
La composición 'Subtract', al ser una operación matemática de tipo módulo,
envuelve los valores que se vuelven negativos de vuelta a un valor mayor que el 50%.
Si quieres incluir un desplazamiento, puedes hacerlo restando también una imagen de fondo
de color sólido usando un -flatten... por ejemplo
magick rose: -colorspace gray -lat 10x10+10% x:
es aproximadamente equivalente a...
magick rose: -colorspace gray \( +clone -blur 10x65535 \) \
-compose subtract -background gray10 -flatten -threshold 50% x:
Lo anterior se modificó a partir de notas iniciales proporcionadas por D Hobson dhobson@yahoo.com
-adaptive-sharpen
Enfoca las imágenes solo alrededor de los bordes
-segment cluster-threshold x smoothing-threshold
Segmentación del espacio de color (no de los objetos de la imagen)
Esto puede producir una salida muy verbosa.
Aplica el "algoritmo fuzzy c-means" si quieres saber más.
También relacionado está -despeckle. para eliminar píxeles sueltos de color erróneo.
Generar un estereograma 3d de dos imágenes (una para cada ojo)
Esto también se conoce como anaglifo
magick composite left.jpg right.jpg -stereo anaglyph.jpg
Realce 3D con Shade
Uso de Shade
Siempre he pensado que el operador «[-shade](https://imagemagick.org/command-line-options/#shade)» es uno de los operadores más interesantes que ofrece ImageMagick. La documentación de este operador solo daba una pista aproximada de sus capacidades. Me costó mucha investigación personal entender el operador, e incluso averiguar cómo aprovechar mejor la potencia que puede ofrecer a los usuarios de IM. Básicamente, lo que hace este operador es suponer que la imagen dada es algo llamado «campo de alturas». Es decir, una imagen en escala de grises que representa la superficie de algún objeto o terreno. El color «white» representa el punto más alto de una imagen, mientras que «black» el punto más bajo. Esta representación surge de la investigación en visión por computador de 1980, donde se usaba una foto con una fuerte «luz de cámara», que hacía brillantes los puntos cercanos y oscuros los puntos lejanos. |
Como «[-shade](https://imagemagick.org/command-line-options/#shade)» necesita una imagen en escala de grises, el operador eliminará automáticamente cualquier color de la imagen de entrada. Del mismo modo, cualquier transparencia que pueda haber en la imagen es completamente inútil y el operador la ignora. |
|---|---|
Ahora bien, «[-shade](https://imagemagick.org/command-line-options/#shade)» toma este campo de alturas en escala de grises y proyecta una luz sobre él. El resultado es una representación de las sombras de luz que se producirían así. Recuerda que debes pensar en la imagen de entrada como una «superficie» para que la salida tenga algún sentido. Para nuestras demostraciones necesitaremos una imagen de «campo de alturas», así que dibujemos una. |
magick -font Candice -pointsize 64 -background black -fill white \
label:A -trim +repage -bordercolor black -border 10x5 \
shade_a_mask.gif
![[IM Output]](../static/img/transform/shade_a_mask.gif)
Esta imagen también equivale a una «máscara» de una figura, y a menudo no solo se usa como entrada de «[-shade](https://imagemagick.org/command-line-options/#shade)», sino también para enmascarar imágenes y recortar la misma figura de los resultados sombreados. Véase Enmascarar una imagen Shade más abajo. Para el operador «[-shade](https://imagemagick.org/command-line-options/#shade)», esta imagen parecerá una llanura negra plana, con una meseta blanca plana que se eleva verticalmente hacia arriba. Así, solo los bordes de esta imagen producirán efectos interesantes. Con este fin, los dos argumentos definen la dirección desde la que brilla la luz. El primer argumento es la dirección desde la que viene la luz. Así, un ángulo de «0» grados será desde el este (o la izquierda), «90» es en sentido antihorario desde el norte (o la parte superior), y así sucesivamente. Por ejemplo…
magick shade_a_mask.gif -shade 0x45 shade_direction_0.gif
magick shade_a_mask.gif -shade 45x45 shade_direction_45.gif
magick shade_a_mask.gif -shade 90x45 shade_direction_90.gif
magick shade_a_mask.gif -shade 135x45 shade_direction_135.gif
magick shade_a_mask.gif -shade 180x45 shade_direction_180.gif
Te haces una idea. La luz puede venir de cualquier dirección. El otro argumento es la elevación , y representa el ángulo que la fuente de luz forma con el suelo. Puedes pensar en ello como la altura del sol durante el día, de modo que «0» es el amanecer y «90» es justo encima de la cabeza.
![[diagram]](../static/img/img_diagrams/shade_elevation.gif)
magick shade_a_mask.gif -shade 90x0 shade_elevation_0.gif
magick shade_a_mask.gif -shade 90x15 shade_elevation_15.gif
magick shade_a_mask.gif -shade 90x30 shade_elevation_30.gif
magick shade_a_mask.gif -shade 90x45 shade_elevation_45.gif
magick shade_a_mask.gif -shade 90x60 shade_elevation_60.gif
magick shade_a_mask.gif -shade 90x75 shade_elevation_75.gif
magick shade_a_mask.gif -shade 90x90 shade_elevation_90.gif
Como puedes ver, con una elevación de «0» la figura solo se resalta en el lado desde el que viene la luz. Todo lo demás es negro, ya que no incide luz sobre ninguna otra superficie. A esto lo llamo un «realce de amanecer» y tiene sus propios usos especiales. Esto nos lleva al primer punto a destacar. Una imagen a la que se aplica «[-shade](https://imagemagick.org/command-line-options/#shade)» tendrá a menudo más zonas oscuras o en sombra que zonas resaltadas. El sombreado no es uniforme. A medida que la luz se eleva sobre la imagen de «campo de alturas», el brillo general de la imagen se volverá más blanco, hasta que, en el «mediodía pleno» o una elevación de «90», cualquier zona plana queda de un blanco brillante, y solo las pendientes y los bordes se sombrean a un color gris, con un gris medio como máximo, o cambio de pendiente de tipo «acantilado». Esta imagen de «mediodía» es otro caso especial que se parece un poco a un sistema de detección de bordes, aunque tiene entre 2 y 4 píxeles de ancho para bordes nítidos. He usado esta imagen en el pasado para generar una máscara del borde biselado de las imágenes «[-shade](https://imagemagick.org/command-line-options/#shade)», de modo que las zonas planas queden transparentes. Si el ángulo de elevación supera los «90» grados, obtendrás el mismo resultado que si la luz viniera de la otra dirección. Por eso el argumento «0x135» producirá exactamente el mismo resultado que «180x45». Un ángulo de elevación negativo también producirá los mismos resultados, como si la luz viniera desde abajo, sobre una superficie de tipo «translúcido». Por eso «0x-45» será lo mismo que «0x45». En otras palabras, para un sombreado concreto suele haber otros 4 argumentos que también producen el mismo resultado. A partir de lo anterior, consideraría que un argumento de «120x45» es más o menos el mejor para el uso directo de la salida de shade. Por ejemplo, aquí crea un texto biselado…
magick -size 320x100 xc:black \
-font Candice -pointsize 72 -fill white \
-draw "text 25,65 'Anthony'" \
-shade 120x45 shade_anthony.jpg
Uno de los principales problemas de «[-shade](https://imagemagick.org/command-line-options/#shade)» es el grosor del bisel que realmente se produce. Un borde nítido como el que usé arriba siempre producirá un bisel de unos 4 píxeles de ancho, tanto hacia dentro como hacia fuera de la zona enmascarada. No hay forma de ajustar este grosor, salvo redimensionar las imágenes antes y después de usar el operador «[-shade](https://imagemagick.org/command-line-options/#shade)». Si quieres averiguar lo brillantes que serán las «zonas planas» para un ángulo de iluminación de elevación concreto, puedes usar el siguiente comando, para sombrear una superficie plana de color sólido.
magick -size 50x50 xc:white -draw 'circle 25,25 20,10' \
-blur 0x2 -shade 0x45 -gravity center -crop 1x1+0+0 txt:-
Como puedes ver, una elevación de «45» grados produce un color plano bastante brillante de alrededor de un 70 % de gris, que es un nivel de gris razonable para la visualización general. Sin embargo, si planeas usar shade para generar realces 3D de diversas figuras, entonces el nivel de gris real se vuelve muy importante. Esto lo veremos más adelante en Crear realces de superposición. Es decir, básicamente eso es todo respecto al operador «[-shade](https://imagemagick.org/command-line-options/#shade)». Sin embargo, usarlo de forma efectiva presenta toda una gama de técnicas y posibilidades, que veremos a continuación.
Enmascarar figuras sombreadas
Como se mencionó antes, a menudo se usa una simple figura de «máscara» con «[-shade](https://imagemagick.org/command-line-options/#shade)» para generar efectos 3D complejos a partir de una figura sencilla. Por ejemplo, hagamos esto con una imagen de máscara sombreada directamente.
magick shade_direction_135.gif shade_a_mask.gif \
-alpha Off -compose CopyOpacity -composite shade_beveled.png
Observa que aproximadamente la mitad del bisel generado por el operador «[-shade](https://imagemagick.org/command-line-options/#shade)» cae en realidad fuera de la zona enmascarada. En otras palabras, un bisel recto se reduce a la mitad al enmascararlo. Por otro lado, la imagen de shade vertical o de «mediodía» (usando un ángulo de elevación de «90» grados) puede usarse para extraer solo el borde biselado, dejando el centro de la imagen hueco.
magick shade_direction_135.gif \
\( shade_elevation_90.gif -normalize -negate \) \
-alpha Off -compose CopyOpacity -composite shade_beveled_edge.png
Sin embargo, ten en cuenta que la imagen de shade de «mediodía», aunque proporciona una forma de enmascarar la ubicación (e intensidad) de los efectos del operador «[-shade](https://imagemagick.org/command-line-options/#shade)», en realidad no cubre por completo esos efectos. Combinando la imagen de shade de «mediodía» con la máscara original, puedes aumentar ligeramente el tamaño de esa máscara para producir una imagen biselada mejor enmascarada.
![[IM Output]](../static/img/transform/shade_direction_180.gif)
magick shade_direction_135.gif \
\( shade_elevation_90.gif -normalize -negate \
shade_a_mask.gif -compose screen -composite \) \
-alpha Off -compose CopyOpacity -composite shade_beveled_plus.png
![[IM Output]](../static/img/transform/shade_beveled_plus.png)
Recuerda que con IM v6 puedes generar la imagen de «shade» que generé antes, toda en el mismo comando. Por eso lo anterior podría haberse generado por completo desde cero. Por ejemplo. |
magick -font Candice -pointsize 72 -background black -fill white \
label:X -trim +repage -bordercolor black -border 10x5 \
\( -clone 0 -shade 135x45 \) \
\( -clone 0 -shade 0x90 -normalize -negate \
-clone 0 -compose screen -composite \) \
-delete 0 -alpha Off -compose CopyOpacity -composite \
shade_beveled_X.png
Imágenes de figuras con Shade
El operador de extracción de alfa no solo extraerá el canal alfa de una imagen con forma como una máscara en escala de grises, sino que también tiene el efecto secundario de preservar la forma en el canal alfa «desactivado». Como está «desactivado», muchos operadores de procesamiento de imágenes no lo tocarán, incluido «[-shade](https://imagemagick.org/command-line-options/#shade)», preservando su detalle. Lo que esto significa es que, para imágenes con forma, puedes extraer la forma, hacer el trabajo y luego simplemente recuperar la transparencia DESPUÉS de haber terminado todo el procesamiento de imágenes, ¡simplemente activando el alfa de nuevo! Por ejemplo, aquí dibujo un «corazón» sobre un fondo transparente, hago algo de desenfoque y sombreado de la imagen, y luego restauro el contorno original con forma de la imagen. |
magick -size 100x100 -gravity center -background None \
-font WebDings label:Y \
-alpha Extract -blur 0x6 -shade 120x21 -alpha On \
-normalize +level 15% -fill Red -tint 100% shade_heart.png
![[IM Output]](../static/img/transform/shade_heart.png)
Lo único que puedo decir es ¡VAYA, qué ahorro de tiempo! Mucho más sencillo que el comando anterior con todo su procesamiento extra y la clonación de imágenes.
Redondear los bordes de Shade
Como viste en el último ejemplo, al desenfocar la máscara de forma de la imagen, la «pendiente» de los «acantilados» del borde se suaviza, como si el tiempo los hubiera desgastado. Esto produce un bonito efecto redondeado en la imagen de shade.
magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
shade_circle_mask.gif
magick shade_circle_mask.gif -shade 120x45 shade_blur_0.gif
magick shade_circle_mask.gif -blur 0x1 -shade 120x45 shade_blur_1.gif
magick shade_circle_mask.gif -blur 0x2 -shade 120x45 shade_blur_2.gif
magick shade_circle_mask.gif -blur 0x3 -shade 120x45 shade_blur_3.gif
magick shade_circle_mask.gif -blur 0x4 -shade 120x45 shade_blur_4.gif
magick shade_circle_mask.gif -blur 0x5 -shade 120x45 shade_blur_5.gif
Como puedes ver, el desenfoque no solo redondea los bordes, sino que atenúa los efectos de iluminación. Puedes maximizar el contraste del resultado normalizándolo, de modo que los puntos más brillantes y más oscuros vuelvan a los colores blanco y negro puros respectivamente.
magick shade_blur_3.gif -normalize shade_blur_3n.gif
El único inconveniente de esto es que también suele oscurecer la imagen sombreada. Esto es algo que tendremos que tener en cuenta en Crear realces de superposición. Terminemos esta imagen de shade enmascarándola también directamente…
magick shade_blur_3n.gif shade_circle_mask.gif \
-alpha Off -compose CopyOpacity -composite shade_blur_3n_mask.png
Como puedes ver, desenfocar la imagen de máscara redondea los bordes de la figura resultante de forma muy agradable.
Crear realces de superposición
La salida del operador «[-shade](https://imagemagick.org/command-line-options/#shade)» es muy bonita, pero rara vez quieres en realidad una simple imagen en escala de grises de tu figura. Lo que necesita es algo de color. Esto, sin embargo, no es tan fácil, ya que las dos formas principales de añadir color, tinte de color de los tonos mediospara recolorear una escala de grises, o la composición alfa «Overlay», para reemplazar las zonas grises con una imagen, dependen ambas de una forma especial de imagen en escala de grises. Es decir, un gris de tono medio perfecto («grey50») se reemplaza por el color o la imagen, mientras que los grises más blancos o más oscuros aclaran y oscurecen el color o la imagen según corresponda. Estas imágenes especiales de «realce de superposición» en escala de grises, con grises de tono medio perfecto para las zonas sin modificar, no son tan sencillas de crear usando «[-shade](https://imagemagick.org/command-line-options/#shade)». No obstante, las siguientes son algunas de las formas más sencillas que he descubierto. Usar un ángulo de iluminación con elevación de 30 grados con «[-shade](https://imagemagick.org/command-line-options/#shade)» es una manera de producir un gris de tono medio perfecto para las zonas planas de la figura sombreada. Por ejemplo, aquí sombreo una imagen y luego extraigo el píxel superior izquierdo para comprobar el color resultante de una parte «plana» de la imagen.
![[IM Output]](../static/img/transform/shade_blur_5.gif)
| |
magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
-blur 0x2 -shade 120x30 shade_30.png
magick shade_30.png -gravity center -crop 1x1+0+0 txt:-
Por desgracia, cambiar el efecto de redondeo del «[-blur](https://imagemagick.org/command-line-options/#blur)» en el comando anterior también tiende a variar la intensidad del realce resultante de la imagen de shade. Es decir, usar un desenfoque grande no solo produce un borde de aspecto bien redondeado, sino que también hace que el realce sea tan tenue que resulta casi invisible. Esto significa que necesitas añadir mucho más contraste a la salida de la imagen «[-shade](https://imagemagick.org/command-line-options/#shade)» producida, para que el realce sea efectivo como imagen de superposición. Para solucionarlo necesitamos una forma de eliminar este efecto de contraste del ajuste de redondeo. La forma habitual de hacerlo es simplemente «[-normalize](https://imagemagick.org/command-line-options/#normalize)» la imagen, pero hacer esto con una imagen de shade de 30 grados hace que las zonas «planas» dejen de ser un gris perfecto. Por ejemplo… | |
magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
-blur 0x2 -shade 120x30 -normalize shade_30_norm.png
magick shade_30_norm.png -gravity center -crop 1x1+0+0 txt:-
Sin embargo, tras algo más de experimentación, descubrí que usar un ángulo de elevación de shade de 21,78 grados, una vez normalizado, produce el gris de tono medio perfecto deseado, así como un buen efecto de realce intenso. | |
magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
-blur 0x2 -shade 120x21.78 -normalize shade_21_norm.png
magick shade_21_norm.png -gravity center -crop 1x1+0+0 txt:-
Como la imagen de shade ahora se pasa por el operador «[-normalize](https://imagemagick.org/command-line-options/#normalize)», el valor de «[-blur](https://imagemagick.org/command-line-options/#blur)» usado para «redondear los bordes» ya no afectará a la intensidad final del resultado. Un método mucho mejor. En resumen, normalizar una imagen de shade desplazará los tonos medios lejos de un color gris perfecto. Ahora podemos ajustar la intensidad de salida de los realces producidos de forma completamente independiente de los demás ajustes. Normalmente, como el resultado normalizado es extremo, necesitaremos una desnormalización controlada, o control de anticontraste, para reducir el realce al nivel deseado. El método más simple para ajustar el realce resultante es tintar de color la imagen con un gris perfecto. Esto desplazará todos los niveles de color de la imagen hacia el color gris de tono medio central y puro. Por ejemplo…
magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
\( +clone -blur 0x2 -shade 120x21.78 -normalize \) \
+swap -alpha Off -compose CopyOpacity -composite shade_tint_0.png
magick shade_tint_0.png -fill grey50 -colorize 10% shade_tint_10.png
magick shade_tint_0.png -fill grey50 -colorize 30% shade_tint_30.png
magick shade_tint_0.png -fill grey50 -colorize 50% shade_tint_50.png
magick shade_tint_0.png -fill grey50 -colorize 80% shade_tint_80.png
Una alternativa a simplemente tintar el realce de forma lineal es reducir su efecto general preservando los puntos brillantes/oscuros extremos del realce usando contraste sigmoidal no lineal en su lugar. Esto debería dar un aspecto más «natural» al efecto de realce, y puede hacer el realce más brillante, como si la superficie fuera más reflectante. Sin embargo, para que esta técnica sea más efectiva, debemos asegurarnos de no tener colores blanco y negro puros en el resultado de shade. Esto se puede lograr usando primero un «[-contrast-stretch](https://imagemagick.org/command-line-options/#contrast-stretch)» de «0%» en lugar de «[-normalize](https://imagemagick.org/command-line-options/#normalize)», y desnormalizando también ese resultado en una pequeña cantidad, como hicimos antes. Esto puede parecer que solo añade complejidad a la generación de la imagen de superposición de realce, pero enfatizar los puntos brillantes del realce hace que el procesamiento extra merezca la pena. Por ejemplo…
magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
\( +clone -blur 0x2 -shade 120x21.78 -contrast-stretch 0% \) \
+swap -alpha Off -compose CopyOpacity -composite shade_sig_0.png
magick shade_sig_0.png -sigmoidal-contrast 10x50% shade_sig-10.png
magick shade_sig_0.png -sigmoidal-contrast 5x50% shade_sig-5.png
magick shade_sig_0.png -sigmoidal-contrast 2x50% shade_sig-2.png
magick shade_sig_0.png +sigmoidal-contrast 2x50% shade_sig+2.png
magick shade_sig_0.png +sigmoidal-contrast 5x50% shade_sig+5.png
magick shade_sig_0.png +sigmoidal-contrast 10x50% shade_sig+10.png
Como puedes ver, el realce general se reduce en intensidad, pero el punto brillante de la luz reflejada permanece tan brillante como siempre, solo que reducido en tamaño. El resultado es un aspecto «brillante» mucho más natural en la figura. El único inconveniente de esta técnica es que también se genera un «punto» de sombra, aunque a menudo no es tan perceptible. Por último, podemos combinar un «punto de realce» con una reducción general del realce para producir un conjunto de controles de generación de superposición de realce muy configurable…
![[IM Output]](../static/img/transform/shade_tint_80.png)
magick -size 50x50 xc:black -fill white -draw 'circle 25,25 20,10' \
\( +clone -blur 0x4 -shade 120x21.78 -contrast-stretch 0% \
+sigmoidal-contrast 7x50% -fill grey50 -colorize 10% \) \
+swap -alpha Off -compose CopyOpacity -composite shade_overlay.png
- En resumen, el ejemplo anterior tiene cuatro controles distintos…
- "
[blur](https://imagemagick.org/command-line-options/#blur)" : Redondear los bordes de la figura (0.001=biselado 2=suavizado 10=redondeado) - "
[shade](https://imagemagick.org/command-line-options/#shade)" : La dirección desde la que viene la luz (120=arriba-izquierda 60=arriba-derecha) - "
[sigmoidal](https://imagemagick.org/command-line-options/#sigmoidal-contrast)" : Control reflectante de la superficie, puntos de realce (1=plano 5=bueno 10=reflectante ) - "
[colorize](https://imagemagick.org/command-line-options/#colorize)" : Contraste general del realce ( 0%=brillante 10%=bueno 50%=tenue )
Ten en cuenta que, aunque los ejemplos anteriores se han recortado a la forma original de «círculo», la transparencia solo debe restaurarse DESPUÉS de aplicar la composición «Overlay», no antes. Además, si planeas usar un realce repetidamente sobre la misma figura (tras realizar cualquier rotación), puedes pregenerar la superposición de realce una vez para cada figura que planees usar, guardando el resultado para reutilizarlo varias veces. Un ejemplo de esta reutilización de superposiciones de sombreado es la generación de carátulas de DVD en 3D a partir de imágenes de origen planas en los foros de discusión de IM. También te recomiendo encarecidamente que experimentes con las técnicas anteriores, ya que son clave para hacer que tus imágenes con forma plana parezcan mucho más realistas. Si se te ocurren otras ideas para el realce, házmelo saber.
FUTURO:
Tintar de color la imagen de superposición
Composición alfa Overlay con una imagen
Usar un realce Shade de amanecer
En Enmascarar imágenes Shade, más arriba, mostramos lo útil que puede resultar una imagen de shade de «mediodía» o «mediodía pleno» (usando una elevación de «90») para enmascarar la ubicación y la extensión de los efectos producidos por «[-shade](https://imagemagick.org/command-line-options/#shade)». Sin embargo, las imágenes de shade horizontales o de «amanecer» (usando una elevación de «0») de una figura también pueden ser bastante útiles. Pueden usarse, por ejemplo, como máscara para imágenes blancas o negras a fin de generar efectos de realce y de sombreado separados en las figuras. Esto también puede usarse para asegurar que una figura reciba cantidades aproximadamente iguales de zonas claras y oscuras (o incluso cantidades desiguales), ya que las produzco por separado pero de forma completamente controlada.
FUTURO: más detalle aquí
Véase el primer Logo 3D avanzado para un ejemplo del uso de esta técnica.
Usar FX, el operador de imagen casero. El operador de lista de imágenes «[-fx](https://imagemagick.org/command-line-options/#fx)» es un operador casero general que no encaja en ninguna categoría específica de operadores de IM, ya que puede usarse para crear casi cualquier operación de imagen. Hay ejemplos de su uso a lo largo de estas páginas, pero aquí veremos específicamente sus capacidades y cómo puedes usarlas. El comando es tan genérico en sus capacidades que puede:
- crear lienzos, degradados, mapas de color matemáticos.
- mover valores de color entre imágenes y canales.
- ajustar los colores de una imagen de casi cualquier forma imaginable
- trasladar, voltear, reflejar, rotar, escalar, cizallar y distorsionar imágenes en general.
- fusionar o componer varias imágenes juntas.
- embaldosar imágenes de formas extrañas y maravillosas.
- convolucionar o fusionar píxeles vecinos.
- generar métricas o «huellas dactilares» de imágenes
- comparar imágenes de formas inusuales.
Por supuesto, muchas de estas técnicas ya forman parte de IM, produciendo un resultado más rápido y flexible. Pero si algo no está integrado, «[-fx](https://imagemagick.org/command-line-options/#fx)» te permite generar tu propia versión de la operación deseada. De hecho, yo y otros lo hemos usado a menudo para prototipar nuevas operaciones que luego se integran en la biblioteca central de IM. Como ejemplo, véase Reemplazo casero de un nuevo tramado ordenado, donde usé «[-fx](https://imagemagick.org/command-line-options/#fx)» para desarrollar una versión revisada del operador «[-ordered-dither](https://imagemagick.org/command-line-options/#ordered-dither)». El operador, en esencia, te permite realizar operaciones matemáticas de forma libre sobre una o más imágenes. Para el resumen oficial del comando, véase FX, el operador de imagen de efectos especiales en el sitio web de ImageMagick.
Uso básico de FX
El comando toma una secuencia de imágenes con tantas imágenes de entrada como quieras. Normalmente una o dos imágenes, y reemplaza TODAS las imágenes de entrada con una copia de la primera imagen, que se ha modificado con los resultados de la función «[-fx](https://imagemagick.org/command-line-options/#fx)». Es decir, cualquier metadato presente en la primera imagen se preservará en el resultado del operador «[-fx](https://imagemagick.org/command-line-options/#fx)». Para facilitar el uso matemático, todos los valores de color proporcionados se normalizan a un rango de valores de 0,0 a 1,0. También se espera que los resultados estén en este rango. Esto incluye el canal de transparencia o alfa, que va de 0,0 (totalmente transparente) a 1,0 (totalmente opaco). Los valores representan la «transparencia alfa» y son en realidad el negativo de cómo IM almacena normalmente la transparencia internamente (como valores de mate). Sin embargo, en esta forma es matemáticamente más correcto y más fácil de usar. El ajuste «[-channel](https://imagemagick.org/command-line-options/#channel)» define qué canal o canales de la primera imagen (también llamada la imagen «cero» o «u») se reemplazan con el resultado del operador «[-fx](https://imagemagick.org/command-line-options/#fx)». Esto está limitado, por defecto, solo a los canales de color («RGB») de la imagen original. Cualquier transparencia existente en esa imagen no se modificará, a menos que se cambie el ajuste «[-channel](https://imagemagick.org/command-line-options/#channel)» para incluir el canal alfa («A»). La expresión se ejecuta una vez por cada píxel, así como una vez por cada canal de color del píxel que se está procesando. Además, como la expresión se vuelve a analizar cada vez que se ejecuta, una expresión compleja podría tardar algo en procesar una imagen grande. Por ejemplo, aquí definimos una imagen negra, pero luego establecemos el canal azul a la mitad de brillo para formar un color «azul marino» en su lugar. |
magick -size 64x64 xc:black -channel blue -fx '1/2' fx_navy.gif
![[IM Output]](../static/img/transform/fx_navy.gif)
Y aquí tomamos un degradado de negro a blanco y luego establecemos los canales azul y verde a cero, de modo que se convierte en un degradado de negro a rojo. |
magick -size 64x64 gradient:black-white \
-channel blue,green -fx '0' fx_red.gif
![[IM Output]](../static/img/transform/fx_red.gif)
| _Para hacer que el ajuste «-channel» se parezca más al operador «-fx», acepta cualquier combinación de las letras «RGBA» para especificar los canales a los que los operadores deben limitar sus acciones.
Esto significa que, para limitar la salida de «-fx» solo a los canales azul y verde, ahora puedes decir «-channel BG» en lugar del más largo «-channel blue,green»._
---|---
Podríamos haber generado los ejemplos anteriores sin usar «[-fx](https://imagemagick.org/command-line-options/#fx)», pero poder hacer esto a una imagen existente es lo que lo convierte en un potente operador de imagen. La función puede, de hecho, leer y usar CUALQUIER píxel, o color específico, de CUALQUIERA de las imágenes que ya están en la secuencia de imágenes actual en memoria. A la primera imagen, la «cero», se le da el nombre especial de «u». A la segunda imagen, «v». Las demás imágenes en memoria pueden referenciarse mediante un índice. Así, «u[3]» es la cuarta imagen de la secuencia de imágenes actual, mientras que «u[-1]» es la última imagen de la secuencia. Este es el mismo esquema de indexación que usan los operadores de lista de imágenes, así que deberías sentirte como en casa. Si no se dan otros calificadores, el valor de color usado es el mismo color usado en la imagen especificada. Es decir, a menos que digas específicamente que quieres usar el color rojo, usará el valor de color del canal de color que el comando esté procesando en ese momento. Es decir, aplicará la expresión al valor del color azul cuando esté procesando el canal azul. A menos que se le indique lo contrario, procesará cada uno de los valores de color RGB (según el ajuste «[-channel](https://imagemagick.org/command-line-options/#channel)» por defecto), para todos y cada uno de los píxeles de la imagen. Es decir, 3wh cálculos que modifican todos los valores de la imagen según la expresión dada. Por ejemplo, aquí tomamos la imagen «rose:» integrada en IM y multiplicamos todos los valores de píxel por 50 %. |
magick rose: -fx 'u*1.5' fx_rose_brighten.gif
![[IM Output]](../static/img/transform/fx_rose_brighten.gif)
En el ejemplo anterior, cada uno de los valores individuales de rojo, verde y azul se multiplicó por 1,5. Si el valor resultante queda fuera del rango de 0 a 1, se limitará al límite correspondiente (1,0 en este caso), a menos que estés usando la versión HDRI de ImageMagick por defecto. En Ajustes de color matemáticos e Histograma de curvas se exploran muchas otras fórmulas «[-fx](https://imagemagick.org/command-line-options/#fx)» para recolorear imágenes. Como también podemos referenciar cualquier imagen de la secuencia de imágenes actual como parte de la expresión para modificar la primera imagen, podemos fusionar dos, o incluso más imágenes, de casi cualquier forma que queramos. Aquí generamos una imagen de carta de color negro-rojo-azul, copiando el canal azul de un degradado negro-azul (rotado) en el degradado negro-rojo anterior que generamos arriba.
magick -size 64x64 gradient:black-blue -rotate -90 fx_blue.gif
magick fx_red.gif fx_blue.gif \
-channel B -fx 'v' fx_combine.gif
| _Por supuesto, podríamos haber usado simplemente unmétodo de composición de copia de canal en su lugar, que sería mucho más rápido. Pero no es la cuestión.
Aunque lo contrario también es cierto. Casi cualquier operación de imagen de IM podría reemplazarse por una función FX equivalente.
_
---|---
Ahora bien, la segunda imagen anterior solo se usa como imagen de origen. Lo que realmente ocurre es que «[-fx](https://imagemagick.org/command-line-options/#fx)» primero crea una copia únicamente de la primera imagen. Luego modifica esa imagen según la fórmula, usando todas las demás imágenes dadas. Y, por último, descarta todas las imágenes de entrada, reemplazándolas con la copia modificada de la primera imagen. También puedes calcular valores según la ubicación de cada píxel dentro de la imagen. Los valores «i,j» son la posición actual del píxel que se procesa, mientras que «w,h» dan el tamaño de la imagen (la primera imagen, a menos que se dé un calificador de imagen específico). Por ejemplo, aquí generamos una imagen de degradado casera. |
magick rose: -channel G -fx 'sin(pi*i/w)' -separate fx_sine_gradient.gif
![[IM Output]](../static/img/transform/fx_sine_gradient.gif)
O algo más complejo usando ambos valores de posición «i,j». |
magick -size 80x80 xc: -channel G -fx 'sin((i-w/2)*(j-h/2)/w)/2+.5'\
-separate fx_2d_gradient.gif
![[IM Output]](../static/img/transform/fx_2d_gradient.gif)
Al generar degradados en escala de grises, puedes hacer que el operador -fx funcione unas 3 veces más rápido, simplemente pidiéndole que procese solo un canal de color, como el canal «G» o verde del ejemplo anterior. Ese canal puede luego separarse para generar la imagen final en escala de grises. Esto puede representar un aumento de velocidad muy grande, sobre todo al usar una fórmula «[-fx](https://imagemagick.org/command-line-options/#fx)» muy compleja. Para más degradados generados con FX, véanse los ejemplos en Crea tus propios degradados. Puedes usar la información de posición para consultar píxeles específicos de la imagen de origen usando la sintaxis «p{x,y}». Por ejemplo, puedes crear fácilmente tu propia función de tipo «imagen espejo» (como el operador de imagen «[-flop](https://imagemagick.org/command-line-options/#flop)»), que reemplaza cada píxel con los valores de color de la posición «espejo» del origen original. |
magick rose: -fx 'p{w-i-1,j}' fx_rose_mirror.gif
![[IM Output]](../static/img/transform/fx_rose_mirror.gif)
Este tipo de «distorsión de imagen» se hizo más potente al crear el mapeo de imagen de distorsión, u otros tipos de tablas de consulta de valores, en forma de imágenes. En Patrones de tramado caseros y mapas de umbral se ofrecen ejemplos de cómo hacerlo, donde se usa FX para reemplazar colores específicos por patrones de otras imágenes. Ahora bien, el tamaño de la imagen final generada por una expresión FX es el mismo que el de la primera imagen dada, por lo que, para generar una imagen más grande, tendrás que establecer la primera imagen al tamaño que quieras. En este tipo de situación, se puede usar una segunda imagen (o incluso una tercera) como fuente de color (de ahí el intercambio en el siguiente ejemplo). Por ejemplo, aquí redimensionamos la imagen de la rosa (usando escalado o redimensionado interpolado) para generar una imagen más grande. |
magick rose: -size 120x80 xc: +swap \
-fx 'v.p{ (i+.5)*v.w/w-.5, (j+.5)*v.h/h-.5 }' \
fx_scaled.png
![[IM Output]](../static/img/transform/fx_scaled.png)
Observa cómo se realiza la consulta de píxeles; puede parecer complejo, pero es la forma correcta de escalar (distorsionar) una imagen. Básicamente, todos los valores «0.5» extra añadidos a la expresión son necesarios para convertir correctamente entre las coordenadas de píxel usadas para las coordenadas de entrada «i,j» y la consulta de ubicación «v.p{...}», mientras que las coordenadas de imagen, matemáticamente más correctas, se necesitan para los cálculos matemáticos reales (el escalado). Lo anterior es, de hecho, la metodología exacta que usa cualquier forma de distorsión de imagen. Puedes ver este equivalente FX para la mayoría de las distorsiones activando el resumen verboso de distorsión. Esto informa de un equivalente FX para la mayoría de las distorsiones de imagen, como forma de comprobar que la distorsión hace lo que se espera. El uso del operador casero FX para hacer distorsiones de imagen muestra lo potente que es realmente este operador. Si no fuera por este operador, dudo que muchas de las nuevas operaciones, como las distorsiones, sparse-color o los tramados ordenados, se hubieran añadido a la biblioteca central de ImageMagick. Aquí hay algo un poco más sencillo: intercambiar los canales rojo y azul de la imagen de la rosa. A ver si averiguas cómo funciona. |
magick rose: \( +clone -channel R -fx B \) \
+swap -channel B -fx v.R fx_rb_swap.gif
![[IM Output]](../static/img/transform/fx_rb_swap.gif)
| _Una forma más rápida y mejor de hacer lo mismo es usar «[-separate](https://imagemagick.org/command-line-options/#separate)» y «[-combine](https://imagemagick.org/command-line-options/#combine)»). Véase Combinar imágenes de canal RGB. Como alternativa, también puedes usar un «[-color-matrix](https://imagemagick.org/command-line-options/#color-matrix)» para hacer lo mismo aún más rápido.
¿Ves aquí una tendencia?_
---|---
Como el ajuste «[-channel](https://imagemagick.org/command-line-options/#channel)» por defecto limita la salida del operador «[-fx](https://imagemagick.org/command-line-options/#fx)» solo a los tres canales de color, esto significa que, si quieres afectar al canal alfa o de transparencia, debes especificarlo explícitamente cambiando el ajuste de canal. Por ejemplo, hagamos una imagen «rose:» semitransparente, estableciendo todos los valores del canal alfa a la mitad. |
magick rose: -alpha set -channel A -fx '0.5' fx_rose_trans.png
![[IM Output]](../static/img/transform/fx_rose_trans.png)
Ten en cuenta que, para que lo anterior funcione correctamente, necesitaba asegurarme de que la «rose:» tuviera realmente un canal alfa con el que «[-fx](https://imagemagick.org/command-line-options/#fx)» pudiera trabajar. Lo hice con el operador de control del canal alfa. Esta capacidad del operador «[-fx](https://imagemagick.org/command-line-options/#fx)» de manipular los canales RGBA de una imagen lo hace perfecto para manipular canales y máscaras.
A partir de IM 6.2.10 puedes añadir asignaciones de variables a las expresiones «[-fx](https://imagemagick.org/command-line-options/#fx)», lo que te permite reducir la complejidad de algunas expresiones, que de otro modo serían básicamente imposibles. Por ejemplo, aquí creo un degradado basado en la distancia desde un punto concreto (asignado a las variables «xx» e «yy»). Sin el uso de las variables, esta fórmula podría haberse vuelto muy difícil de leer. |
magick -size 100x100 xc: -channel G \
-fx 'xx=i-w/2; yy=j-h/2; rr=hypot(xx,yy); (.5-rr/70)*1.2+.5' \
-separate fx_radial_gradient.png
![[IM Output]](../static/img/transform/fx_radial_gradient.png)
| Debido al sencillo manejo de tokenización que usa «[-fx](https://imagemagick.org/command-line-options/#fx)», los nombres de variable solo pueden constar de letras y no deben contener números. Además, como muchas letras sueltas se usan para variables internas que acceden a la información de la imagen, se recomienda que los nombres de variable tengan al menos dos letras. Por eso uso «xx» e «yy» en lugar de solo «x» o «y».
---|---
| _La función «[-fx](https://imagemagick.org/command-line-options/#fx)» «rr=hypot(xx,yy)» se añadió en IM v6.3.6 para acelerar la expresión, muy usada, «rr=sqrt(xx*xx+yy*yy)».
Por supuesto, si necesitas la distancia al cuadrado, deberías evitar la función «hypot()» y la función sqrt() que esta implica._
---|---
Para más ejemplos de expresiones realmente complejas, véase Degradados caseros más complejos, que serían imposibles sin asignaciones con múltiples sentencias. Lo mismo ocurre con la forma FX de la distorsión de perspectiva. A partir de la versión IM 6.3.0-1, la complejidad de las expresiones «[-fx](https://imagemagick.org/command-line-options/#fx)» empezó a requerir archivos externos, por lo que ahora se puede usar el estándar «@_nombre_de_archivo_» para leer la expresión de un archivo. |
echo "u*2" | magick rose: -fx "@-" fx_file.png
![[IM Output]](../static/img/transform/fx_file.png)
Esto también significa que puedes usar scripts más complejos para generar las expresiones FX específicas de un trabajo concreto. Internamente, el archivo simplemente se lee en una cadena y se interpreta como de costumbre. Otros ajustes importantes para «[-fx](https://imagemagick.org/command-line-options/#fx)» son «[-virtual-pixel](https://imagemagick.org/command-line-options/#virtual-pixel)» e «[-interpolate](https://imagemagick.org/command-line-options/#interpolate)». El ajuste de píxel virtual permite establecer qué colores o resultados de imagen deben devolverse cuando las coordenadas de consulta quedan fuera de la zona cubierta por la imagen de entrada. Esto permite establecer efectos de borde para cosas como desenfoques, así como embaldosar una imagen sobre un área mayor. El ajuste de interpolación permite especificar cómo debe IM mezclar los colores de los píxeles vecinos cuando las coordenadas de consulta (valores en coma flotante) caen entre las coordenadas enteras de los píxeles de la imagen de entrada. Para más información, véase Consulta de píxel interpolada. | Se añadieron más funciones en diversos momentos
IM v6.3.6 : hypot()
IM v6.7.3-4 : while(), not(), guass(), squish()
---|---
Depuración de FX
«debug(_expr_)» es, en esencia, una forma de imprimir un valor en coma flotante cada vez que se calcula la expresión FX. Esto, a su vez, proporciona un método para depurar tus expresiones. Sin embargo, puedes limitar la salida de «debug()» usando una expresión ternaria if-else. Por ejemplo, esto imprimirá los valores de color en coma flotante del píxel 10,10 de la imagen «rose:» integrada. El resultado de imagen en sí se ignora usando el manejador de imagen «[NULL:](files.html#null)». |
magick rose: -fx 'i==10&&j==10?debug(u):1; u' null:
![[IM Output]](../static/img/transform/fx_debug.txt.gif)
Recuerda que la salida va a la salida de error estándar, no a la salida estándar normal, de modo que puedes usar esto en una tubería de comandos sin problemas. Observa cómo la expresión FX se ejecutó tres veces, una por cada canal solo para ese único píxel. Multiplica eso por el número de píxeles y podrás imaginar la longitud de la salida si «debug()» no se hubiera limitado a un solo píxel, incluso para esta imagen tan pequeña.
Operaciones integradas de tipo FX
El operador [-fx](https://imagemagick.org/command-line-options/#fx) representa una forma de desarrollar nuevas funciones de procesamiento de imágenes que antes no existían en ImageMagick. El resultado de ese desarrollo por parte de los usuarios ha permitido a ImageMagick expandirse, con nuevas funciones y métodos, como la tabla de consulta de color («[-clut](https://imagemagick.org/command-line-options/#clut)»). Sin embargo, por lo general, una vez que un nuevo método se ha estabilizado usando «[-fx](https://imagemagick.org/command-line-options/#fx)», la expresión se convierte en una operación integrada más rápida, normalmente añadida como parte de un grupo de operadores similares. Estos incluyen los siguientes operadores generales de imagen y sus métodos… -evaluate | Funciones de modificación directa de píxeles, valores de color y canales.
(Véase Evaluate más abajo).
---|---
-function | Funciones más complejas de modificación de píxeles, valores de color y canales.
(Véase Function más abajo).
-evaluate-sequence | Fusionar matemáticamente una secuencia de múltiples imágenes
(Véase Evaluate-Sequence más abajo).
-sparse-color | Operador general de recoloreado de imágenes.
(Véase Degradados de color disperso )
-compose | Método general de combinación y superposición de múltiples imágenes.
(Véase Composición alfa).
-distort | Operador general de distorsión de imágenes, usando mapeo de píxeles invertido.
(Véase el operador Distort )
-morphology | Función general de convolución/morfología de efecto de área.
(Véase el operador Morphology y el operador Convolve )
A medida que la gente desarrollaba nuevos tipos de operaciones de imagen, normalmente las prototipaba primero usando un operador «[-fx](https://imagemagick.org/command-line-options/#fx)». Cuando lo tienen resuelto, ese «método» se convierte en un nuevo operador integrado superrápido en la biblioteca central de ImageMagick. Los usuarios pueden contribuir con sus propias expresiones «[-fx](https://imagemagick.org/command-line-options/#fx)» (u otras funciones definidas) que crean que serían una adición útil a IM, pero que aún no están cubiertas por otros operadores de imagen; si pueden manejarse con uno de los operadores generalizados anteriores, debería ser razonablemente fácil añadirlas. Por ejemplo, yo mismo necesité una operación de tipo «enmascarar si el color es similar» para comparar dos imágenes. Esto se ha añadido como un nuevo método de «[-compose](https://imagemagick.org/command-line-options/#compose)», «[ChangeMask](compose.html#changemask)». Esto, a su vez, me permitió añadir una optimización de transparencia más compleja para animaciones GIF. Si la velocidad y la complejidad de «[-fx](https://imagemagick.org/command-line-options/#fx)» empiezan a convertirse en un problema, probablemente sea mejor pasar a un lenguaje de scripting de API como PerlMagick. Un ejemplo de esto usando PerlMagick, «[pixel_fx.pl](https://github.com/ImageMagick/ImageMagick/blob/main/PerlMagick/demo/pixel-fx.pl)», forma parte de la distribución de esa API.
Expresiones FX como escapes de formato y anotación
A partir de la versión IM 6.2.10, ahora puedes usar expresiones FX dentro de cadenas de escape de propiedades de imagen como las que usan los argumentos «[-format](https://imagemagick.org/command-line-options/#format)» y «[-annotate](https://imagemagick.org/command-line-options/#annotate)». La secuencia de escape «%[fx:...]» se reemplaza por un número como valor en coma flotante, calculado una vez por cada imagen de la secuencia de imágenes actual. La expresión FX, sin embargo, se modifica ligeramente durante el procesamiento. En concreto…
- Las coordenadas del píxel actual «
i», «j» se fijan al valor 0, así que, por sí sola, una variable de imagen solo devuelve el valor del píxel 0,0, a menos que se use un índice «p{}». - A menos que se seleccione un canal de color, solo se devuelve el valor del canal rojo.
- La referencia de imagen por defecto «
s» se establece en la imagen actual que se está anotando o identificando. - El índice «
t» devuelve el índice de la imagen referida por «s».
| Antes de IM v6.6.8-6, tanto el valor de la expresión FX «t» (índice de imagen) como «n» (número total de imágenes) estaban rotos, y solo devolvían un valor de 0 y 1 respectivamente para TODAS las imágenes. Lo mismo ocurre con los escapes de porcentaje equivalentes «%p» y «%n».
---|---
Por ejemplo, aquí «[-annotate](https://imagemagick.org/command-line-options/#annotate)» cada imagen con el color de su esquina superior izquierda. |
magick -size 150x25 xc:DarkRed xc:Green xc:Blue \
-fill white -gravity center \
-annotate 0 '%[fx:t] / %[fx:n] : %[fx:r],%[fx:g],%[fx:b]' \
annotate_fx_%d.gif
![[IM Output]](../static/img/transform/annotate_fx_2.gif)
Observa cómo el texto que se escribe es distinto para cada imagen, ya que «r» es en realidad equivalente a «s.p{0,0}.r». Lo mismo ocurre con los valores de los canales de color «g» y «b». Por supuesto, cada uno devuelve un valor normalizado en el rango de 0,0 a 1,0. Para facilitar la salida de los valores de color de píxeles específicos, también se añadió un escape «%[pixel:...]» en IM v6.3.0. Este operador llama a la expresión FX dada una vez por cada canal de cada imagen, y formatea el valor devuelto en un color que IM puede manejar como argumento de color.
magick -size 300x100 gradient:yellow-limegreen \
-gravity NorthWest -annotate 0 '%[pixel:s.p{0,0}]' \
-gravity Center -annotate 0 '%[pixel:s.p{0,50}]' \
-gravity SouthEast -annotate 0 '%[pixel:s.p{0,99}]' \
annotate_pixel.gif
Puedes simplemente sacar el resultado directamente usando un «[-format](https://imagemagick.org/command-line-options/#format)» con el comando «[identify](basics.html#identify)». |
magick identify -format '%[fx:atan(1)*4]' null:
![[IM Output]](../static/img/transform/fx_math.txt.gif)
Esto calculará y devolverá matemáticamente el valor de PI , aunque este valor está disponible como la variable integrada «pi». Puedes generar números aleatorios. Por ejemplo, para generar un entero entre -5 y 10 inclusive. Aquí uso el equivalente «[info:](https://usage.imagemagick.org/files/#info:)» del comando «magick identify». |
magick xc: -format '%[fx:int(rand()*16)-5]' info:
![[IM Output]](../static/img/transform/fx_rand.txt.gif)
Para más métodos, véase Alternativas a Identify: opciones de salida de texto. Véase también Borde con esquinas redondeadas, que usó una expresión FX para generar una cadena de dibujo basada en la información de ancho y alto de la imagen. Puedes calcular posiciones de imágenes usando fórmulas FX o incluso posicionar usando el tamaño y la ubicación de otras imágenes (véase Posiciones calculadas incrementalmente). También puedes usar escapes FX en escapes de porcentaje de nombre de archivo para generar nuevos archivos basados en valores calculados. Para un ejemplo, véase el último ejemplo en Recorte en mosaico.
Todo lo anterior ejecutará esencialmente el «[-format](https://imagemagick.org/command-line-options/#format)» y, por tanto, cualquier expresión FX que contenga, una vez por cada imagen de la secuencia de imágenes actual. El operador «[-print](https://imagemagick.org/command-line-options/#print)» funciona de forma muy parecida a «[-identify](https://imagemagick.org/command-line-options/#identify)», salvo que solo se ejecuta una vez, con acceso a TODAS las imágenes de la secuencia de imágenes actual. Con este operador puedes usar «u[{i}]» para acceder a valores de cualquier imagen, a diferencia de lo anterior.
Las expresiones FX pueden aplicarse a imágenes en otros espacios de color, así que puedo, por ejemplo, averiguar el valor del «matiz» (en el canal «rojo») de tres colores distintos. |
magick xc:red xc:green xc:blue -colorspace HSL \
-format '%[fx: s.r ]\n' info:
![[IM Output]](../static/img/transform/fx_hues.txt.gif)
También puedes usar IM para algunas operaciones matemáticas directas de color, como averiguar el color promedio de «gold», «yellow» y «khaki». |
magick xc: -format '%[pixel:(gold+yellow+khaki)/3]' info:
![]()
Mientras que esto muestra cómo se ve el color en comparación con los tres colores de origen… |
magick xc:gold xc:yellow xc:khaki +append \
\( xc: -fx '(gold+yellow+khaki)/3' \) \
-scale 90x30\! -append fx_hues.png
![[IM Output]](../static/img/transform/fx_hues.png)
También puedes usar «[-print](https://imagemagick.org/command-line-options/#print)» para imprimir información. Esto se aplica solo una vez sobre toda la secuencia de imágenes. Eso significa que puedes usar este operador para calcular expresiones «%[fx:...]» mucho más complejas que involucren varias imágenes.
Acceder a datos de otras imágenes
Sin embargo, hay un problema serio al usar expresiones con escape FX. IM no tiene acceso directo a las demás imágenes de la secuencia de imágenes actual cuando estás creando imágenes. Esto, por lo general, simplemente no se necesita en la creación típica de imágenes, ya que las imágenes nuevas no suelen depender de imágenes previas en memoria. Básicamente, si quieres obtener el color de un píxel específico de una imagen distinta a la que estás dibujando (como antes), o estás creando una imagen nueva, las funciones centrales de IM no tienen un enlace directo a la información deseada. Por ejemplo, si intentas crear una etiqueta con el color del píxel 12,26 de la imagen «rose:» integrada (un píxel azulado), ¡el enfoque directo fallará! |
magick rose: label:'%[pixel:p{12,26}]' -delete 0 label_fx_direct.gif
![[IM Output]](../static/img/transform/label_fx_direct.gif)
Pues bien, la imagen de la rosa en realidad no contiene ningún píxel negro, así que el resultado anterior era erróneo. La forma de arreglar esto es extraer la información deseada y guardarla en los metadatos globales de IM. Esto se pasa a todas las subrutinas de la biblioteca central, incluidas las de creación de imágenes. |
magick rose: -set option:mylabel '%[pixel:u.p{12,26}]' -delete 0 \
label:'%[mylabel]' label_fx_indirect.gif
![[IM Output]](../static/img/transform/label_fx_indirect.gif)
Esto no es intuitivo, pero ahora obtenemos el resultado correcto. La etiqueta especial «option:» le indica a la opción «[-set](https://imagemagick.org/command-line-options/#set)» que quieres que el ajuste dado se guarde como un artefacto global, en lugar de como una cadena de «atributo» o «propiedades» de imagen, igual que puede hacer «[-define](https://imagemagick.org/command-line-options/#define)». Sin embargo, la forma «[-set](https://imagemagick.org/command-line-options/#set)» te permite expandir escapes de porcentaje al establecer el artefacto, cosa que «[-define](https://imagemagick.org/command-line-options/#define)» no hace. Cuando el operador «label:» expande sus escapes de porcentaje, la «clave» dada se busca primero como «atributo» o «propiedades» por imagen, pero si no encuentra nada, buscará entonces la «clave» en los ajustes globales de artefacto. Por eso se usa el «artefacto» global que creamos a partir de la imagen anterior, aunque esa imagen ya no esté presente en el momento en que se creó el artefacto. Básicamente, los ajustes de «artefacto» son globales durante la vida del comando «magick» y, por tanto, pueden usarse para pasar información de una imagen a otra. Para las API programadas, esta situación puede evitarse, ya que puedes leer los datos necesarios directamente de la imagen y generar tú mismo la cadena de la etiqueta, sin necesidad de que IM almacene esa información de forma tan enrevesada.
Evaluate y Function, modificadores de canal de forma libre
Como el operador FX es un manejador de expresiones interpretadas, se añadió el operador «[-evaluate](https://imagemagick.org/command-line-options/#evaluate)» para permitirte hacer modificaciones de imagen simples más rápidamente. Más tarde se añadió un operador «[-function](https://imagemagick.org/command-line-options/#function)» más complejo en IM v6.4.8-8, para permitir mayor flexibilidad en ajustes de imagen complejos. Estos dos operadores, junto con otros operadores de ajuste de nivel de imagen como «[-negate](https://imagemagick.org/command-line-options/#negate)», «[-level](https://imagemagick.org/command-line-options/#level)», serán probablemente más útiles para pequeños retoques de imágenes en escala de grises, antes de aplicar esas imágenes. Especialmente en imágenes en escala de grises como las que se usan para eliminación de fondo, superposiciones de realce y sombra y la generación y el ajuste fino de mapas de imagen.
Evaluate, operaciones matemáticas simples
El operador «[-evaluate](https://imagemagick.org/command-line-options/#evaluate)» es básicamente una versión rápida, pero muy simple, del operador «[-fx](https://imagemagick.org/command-line-options/#fx)» (de hecho, precede a su adición a IM por solo un par de meses). Sin embargo, está limitado a una única operación simple, usando un solo número constante proporcionado por el usuario. Puedes averiguar qué funciones se han integrado en evaluate usando
magick -list evaluate
Esto incluye las funciones matemáticas típicas «add», «subtract», «multiply» y «divide», contra valores constantes. A diferencia del operador [-fx](https://imagemagick.org/command-line-options/#fx), los valores no se normalizan a un rango de 0 a 1, sino que se mantienen como los valores de color reales de la imagen. Por eso, restar un valor de 50 en un IM Q8 (véase Calidad y profundidad) resultará en una resta grande, pero para una versión Q16 de IM solo será un cambio pequeño y apenas perceptible. Sin embargo, si añades un «%» al argumento, ese argumento representará un porcentaje del valor de color máximo (conocido como «QuantumRange», que es igual a «2 _quality_ -1»). Esto significa que puedes hacer que tus argumentos de «[-evaluate](https://imagemagick.org/command-line-options/#evaluate)» sean independientes del nivel de calidad de IM, usando porcentajes de forma adecuada para los métodos de evaluate apropiados. Por ejemplo, reemplazar simplemente todos los valores de color de una imagen por un nivel de gris del 50 % es muy sencillo y muy rápido, usando «Set » |
magick rose: -evaluate set 50% rose_set_gray.gif
![[IM Output]](../static/img/transform/rose_set_gray.gif)
El operador «[-evaluate](https://imagemagick.org/command-line-options/#evaluate)» también incluye las funciones matemáticas típicas «add», «subtract», «multiply» y «divide». Por ejemplo, para reducir a la mitad el contraste de la imagen, puedes «divide » entre «2» y luego «add » «25%» para volver a centrarla en torno al gris perfecto. |
magick rose: -evaluate divide 2 -evaluate add 25% rose_de-constrast.gif
![[IM Output]](../static/img/transform/rose_de-constrast.gif)
Esto es un par de órdenes de magnitud más rápido que usar directamente el operador «[-fx](https://imagemagick.org/command-line-options/#fx)» con «u/2+.25». Por eso deberías usar este operador con preferencia sobre «[-fx](https://imagemagick.org/command-line-options/#fx)» siempre que sea posible. El principal problema de «[-evaluate](https://imagemagick.org/command-line-options/#evaluate)» es que todos los resultados se recortan a los límites de 0 a «QuantumRange» (a menos que estés usando una versión HDRI de ImageMagick), ya que cada valor modificado se vuelve a guardar en los datos de la imagen. Eso significa que, tras cualquier operación «[-evaluate](https://imagemagick.org/command-line-options/#evaluate)» individual, los valores podrían quedar recortados por el «QuantumRange». Por eso, si intentas aplicar una función de mejora de contraste (equivalente a «[-fx](https://imagemagick.org/command-line-options/#fx) '2*u-.25'») directamente tal cual, no obtendrás los resultados correctos, ya que el valor duplicado se recortará antes de hacer la resta. |
magick rose: -evaluate multiply 2 -evaluate subtract 25% \
rose_contrast.gif
![[IM Output]](../static/img/transform/rose_contrast.gif)
Primero, el «multiply » recortará todos los valores de color grandes al valor máximo, y luego el «subtract» recortará los valores del límite inferior. El resultado es un recorte incorrecto de los límites superiores, produciendo un resultado oscuro y con el color distorsionado. La solución directa es «subtract » primero la constante apropiada (haciendo el recorte final, pero correcto, de los límites inferiores), antes de multiplicar, usando efectivamente la fórmula equivalente «(u-.125)*2» |
magick rose: -evaluate subtract 12.5% -evaluate multiply 2 \
rose_contrast2.gif
![[IM Output]](../static/img/transform/rose_contrast2.gif)
Sin embargo, hay muchas alternativas a este problema de «recorte». La primera lógica es el más reciente método de función polinómica (véase más abajo). Otras alternativas incluyen también usar operadores de ajuste de nivel o incluso un ajuste de nivel por color, para especificar simplemente los valores de color originales que quieres estirar, para que rellenen todo el rango de color. Básicamente, ten cuidado con el recorte de valores de color al usar varios métodos de «[-evaluate](https://imagemagick.org/command-line-options/#evaluate)».
El operador «[-evaluate](https://imagemagick.org/command-line-options/#evaluate)», al igual que «[-fx](https://imagemagick.org/command-line-options/#fx)» (y la mayoría de los operadores de bajo nivel de IM), se ve afectado por «[-channel](https://imagemagick.org/command-line-options/#channel)». Esto te permite controlar la transparencia alfa de una imagen por separado de los canales de color. Y sí, como «[-fx](https://imagemagick.org/command-line-options/#fx)», la transparencia se trata como «valores alfa» y no como un valor de «mate». Por ejemplo, para hacer una imagen 50 % transparente, como parte de una operación de tipo Dissolve. |
magick rose: -alpha set -channel A -evaluate divide 2 rose_transparent.png
![[IM Output]](../static/img/transform/rose_transparent.png)
El resultado es una imagen semitransparente, lo que significa que, al mostrarse, la mitad del color que ves es el color de fondo de la página web. Por eso la imagen mostrada se atenúa hacia el color de fondo. A menudo también he comprobado que suele ser más fácil usar «[-evaluate](https://imagemagick.org/command-line-options/#evaluate)» sobre los canales de color individuales antes de separar los distintos canales en imágenes separadas para fines específicos (véase Separar canales). Por ejemplo, aquí lo uso para hacer una forma rápida, pero inusual, de conversión a escala de grises. Básicamente multiplico cada canal por la cantidad apropiada, luego separo y sumo los canales para producir una imagen que se ha convertido a escala de grises usando un conjunto específico de proporciones de color. |
magick test.png -channel R -evaluate multiply .2 \
-channel G -evaluate multiply .5 \
-channel B -evaluate multiply .3 \
-channel RGB -separate -background black -compose plus -flatten gray_253.png
Funciones matemáticas de Evaluate
Dentro de Evaluate también hay un conjunto de funciones matemáticas de propósito especial. Estas funciones se implementan para usar, en general, un valor de color normalizado (rango de 0 a 1), con la salida de nuevo normalizada para ajustarse al rango de color completo de la imagen. La función de contraste sigmoidal es también un ejemplo de este ajuste de función matemática.
Potencia
La función «Pow » (añadida en IM v6.4.1-9), por ejemplo, trabaja con valores de color normalizados y permite a los usuarios hacer modificaciones de brillo de la imagen. Es exactamente equivalente a la función pow() de C (usando valores de color normalizados en un rango de 0 a 1)
value = pow(value, constant)
Por eso, para crear un degradado «parabólico» puedes usar un argumento de «2». O usar un valor de «0.5» para crear un degradado de «raíz cuadrada». Por ejemplo…
magick -size 20x600 gradient: -rotate 90 gradient.png
magick gradient.png -evaluate Pow 2 eval_pow_parabola.png
magick gradient.png -evaluate Pow 0.5 eval_pow_sq_root.png
| Las tres imágenes inferiores muestran el perfil del degradado producido, tanto en una gráfica como en la propia imagen original. Esto facilita ver cómo se modificó una imagen de degradado para convertirse en otra. Se generó usando el programa de trazado de gráficasGnuplot, mediante el script «[im_profile](../static/img/scripts/im_profile)» del directorio Scripts de los ejemplos de IM.
---|---
Esto es en realidad equivalente al operador de ajuste de gamma, pero con el argumento invertido. Por ejemplo, una operación «-gamma 2» sería equivalente a una función «-evaluate pow 0.5» o de «raíz cuadrada». Del mismo modo, «-gamma 0.5» equivale a elevar al cuadrado usando «-evaluate pow 2». Haciendo algunas manipulaciones especiales de degradados, puedes usar este método para convertir un degradado lineal en un complejo arco circular. |
magick -size 20x300 gradient: -rotate 90 \
-evaluate Pow 2 -negate -evaluate Pow 0.5 \
-flop \( +clone -flop \) +append eval_circle_arc.png
![[IM Output]](../static/img/transform/eval_circle_arc_pf.gif)
Para quienes quieran descifrar esto, la segunda línea de arriba equivale a la expresión FX «sqrt(1-u^2)». Esto genera un único arco de cuarto de círculo, que luego se voltea y se une para producir un arco semicircular. También es mucho más rápido que usar una expresión FX, aunque requiere muchos más pasos individuales (más pequeños). Véase también la más avanzada función polinómica.
Logarítmica
La función «Log » (añadida en IM v6.4.2-1) también trabaja con valores normalizados (con un 1,0 añadido para evitar infinitos), usando la constante dada como base logarítmica. La fórmula real (con valores normalizados) es, por tanto…
value = log(value*constant+1.0)/log(constant+1.0)
Por ejemplo… |
magick gradient.png -evaluate Log 10 eval_log.png
![[IM Output]](../static/img/transform/eval_log_pf.gif)
Esto puede parecer muy similar al método Pow de Evaluate anterior, pero no es exactamente lo mismo. «Log» producirá una pendiente apreciable a medida que se acerca a «0», mientras que «Pow» producirá una pendiente vertical. El valor controla la pendiente. Una función logarítmica también está estrechamente relacionada con una función exponencial, que actualmente solo se implementa como el operador de ajuste de contraste sigmoidal. Este contiene las mismas características de pendiente que puedes ver en las curvas logarítmicas anteriores. Esto explica por qué «[-sigmoidal-contrast](https://imagemagick.org/command-line-options/#sigmoidal-contrast)» es una técnica mejor para realzar imágenes en condiciones de poca luz que un ajuste de gamma o una curva de «potencia».
Seno y coseno
A partir de IM v6.4.8-8 se añadieron los métodos «sin » y «cos ». Estos métodos toman el valor dado en la imagen y lo normalizan a un ángulo, de modo que el rango completo cubra un círculo completo de ángulos. Al resultado se le da un bias del 50 % y se escala para que vuelva a ajustarse al rango normal de valores. La constante se usa como multiplicador del valor (y, por tanto, del ángulo), de modo que «N» significa que la función recorrerá el círculo «N» veces a lo largo de todo el rango de valores. En concreto, define estas funciones (usando valores normalizados) como…
value = 0.5 * sin( constant*value*2*PI ) + 0.5
value = 0.5 * cos( constant*value*2*PI ) + 0.5
En esencia, lo que hacen estas funciones es reasignar los valores de la imagen (normalmente valores en escala de grises) a una curva seno/coseno. Por ejemplo, aquí tomo una imagen de degradado y la modifico usando estos métodos de evaluate.
magick gradient.png -evaluate sin 1 eval_sin_1.png
magick gradient.png -evaluate cos 1 eval_cos_1.png
Ahora bien, como el parámetro constante es un multiplicador de ángulo, el valor dado al método de evaluate creará esa cantidad de picos a lo largo de todo el degradado dentro de una imagen. |
magick gradient.png -evaluate cos 5 -negate eval_cos_5.png
![[IM Output]](../static/img/transform/eval_cos_5_pf.gif)
Esto es perfecto para muchas tareas, desde generar efectos de ondulación o dispersión hasta generar curvas de desplazamiento con aspecto de ondulación. Usando un multiplicador constante de «0.5» puedes convertir simplemente un degradado lineal en un degradado de curva seno, que sigue teniendo la misma pendiente que el original. Negando el resultado puedes asegurar que el degradado también tenga la pendiente correcta. |
magick gradient.png -evaluate cos 0.5 -negate eval_cos.5.png
![[IM Output]](../static/img/transform/eval_cos.5_pf.gif)
Lo cual es estupendo para generar degradados suaves para usar en fotos superpuestas. Sin embargo, estos dos últimos métodos de «[-evaluate](https://imagemagick.org/command-line-options/#evaluate)» se usan rara vez, ya que han sido reemplazados por una función Sinusoid más general (véase más abajo) que ofrece más opciones de control, más allá de una simple opción de frecuencia.
Function, Evaluate de múltiples argumentos
Los generadores de ondas anteriores resultaron extremadamente útiles, sobre todo con el mapeo de imagen de distorsión. Pero se vio que se necesitaba un control mucho más fino de las funciones, requiriendo más de un parámetro. Por eso se añadió el operador «[-function](https://imagemagick.org/command-line-options/#function)» en IM v6.4.8-9. Básicamente, «[-function](https://imagemagick.org/command-line-options/#function)» es una forma de «[-evaluate](https://imagemagick.org/command-line-options/#evaluate)» con múltiples argumentos. Sin embargo, a diferencia del operador Evaluate, estos operadores, como los operadores matemáticos, todas las funciones anteriores trabajan solo con valores de canal normalizados (rango de 0,0 a 1,0) de la imagen, lo que en la mayoría de los casos los hace más fáciles de usar.
Función polinómica
El método «polynomial » tomará cualquier número de valores y modificará los valores de color de una imagen según la expresión exacta dada, mucho más rápido de lo que puede el operador FX.
-function Polynomial a,b,c,...
Cada valor se usará como coeficiente, del orden más alto al más bajo, para producir un polinomio con el número de términos dado. Por ejemplo, un argumento de «4,-4,1» generará la expresión polinómica equivalente a la expresión «[-fx](https://imagemagick.org/command-line-options/#fx)» «4*u^2 - 4*u + 1». Si sabes matemáticas de secundaria, sabrás entonces que esta función polinómica produce una curva parabólica que va de 1,0 a 0,0 y luego de vuelta a 1,0, sobre el rango de color de entrada («u») de 0,0 a 1,0. Es decir, hará «blancos» los colores negro y blanco, y «negros» los grises perfectos. |
magick gradient.png -function Polynomial 4,-4,1 func_parabola.png
![[IM Output]](../static/img/transform/func_parabola_pf.gif)
Incluso puedes hacer un degradado mucho más complejo, por ejemplo un polinomio cuártico, que fue el resultado de generar un ajuste de nivel por curva, usando un conjunto de «puntos de control de nivel». Esto se usa normalmente para ajustar los colores de una imagen y darle diversos efectos de sombreado. |
magick gradient.png -function Polynomial '-25, 53, -36, 8.3, 0.2' \
func_quartic.png
![[IM Output]](../static/img/transform/func_quartic_pf.gif)
Por supuesto, también es posible una modificación lineal simple, exactamente como la que obtienes si usas un operador Level… |
magick gradient.png -function Polynomial '4, -1.5' func_linear.png
![[IM Output]](../static/img/transform/func_linear_pf.gif)
Sin embargo, ten en cuenta que no puedes usar «Polynomial» para hacer una operación de umbral completa, debido a la necesidad de coeficientes infinitos para lograrlo, aunque puedes aproximarte bastante. Un solo valor es, naturalmente, una constante, y resulta en una asignación directa de ese valor. En otras palabras, es como el método «[-evaluate](https://imagemagick.org/command-line-options/#evaluate) Set», en este caso a un valor de gris del 33 %. |
magick gradient.png -function Polynomial 0.33 func_constant.png
![[IM Output]](../static/img/transform/func_constant_pf.gif)
Combinando un «Polynomial» con otras funciones matemáticas puedes crear modificaciones de degradado aún más complejas. Por ejemplo, tomando la raíz cuadrada de un polinomio, puedo crear un verdadero arco circular sobre un degradado lineal. La expresión «[-fx](https://imagemagick.org/command-line-options/#fx)» equivalente «sqrt( -4*u^2 + 4*u + 0 )»… |
magick gradient.png -function Polynomial -4,4,0 -evaluate Pow 0.5 \
func_circle_arc.png
![[IM Output]](../static/img/transform/func_circle_arc_pf.gif)
Véase también el método Pow de Evaluate para una alternativa a lo anterior.
Función Sinusoid
El método de función «Sinusoid » es una versión mucho más avanzada de los métodos «sin» y «cos» de «[-evaluate](https://imagemagick.org/command-line-options/#evaluate)», y de hecho puede replicar esas funciones, pero tienes un control mucho mejor sobre cómo modifica los valores de color de una imagen.
-function Sinusoid frequency,phase,amplitude,bias
Y se implementa usando la fórmula…
value = ampl * sin(2*PI( freq*value + phase/360 ) ) + bias
Esto puede parecer complejo, pero asegura que la función sea fácil de usar. Solo el primer valor, «frequency», que funciona exactamente como se ha descrito arriba, es obligatorio, siendo todos los demás parámetros opcionales. Por defecto generará una curva seno. |
magick gradient.png -function Sinusoid 1 func_sine.png
![[IM Output]](../static/img/transform/func_sine_pf.gif)
Añadiendo un argumento «phase » en grados, puedes especificar el ángulo inicial de la curva. Lo que te permite convertir la curva seno por defecto en un coseno. |
magick gradient.png -function Sinusoid 1,90 func_cosine.png
![[IM Output]](../static/img/transform/func_cosine_pf.gif)
Ajustando la «frequency» y la «phase» puedo convertir directamente un degradado lineal en un degradado sinusoidal suave que va de negro a blanco (de mínimo a máximo a lo largo de una curva seno). Véase el método Cosine de Evaluate para un método menos directo. |
magick gradient.png -function Sinusoid 0.5,-90 func_sine_grad.png
![[IM Output]](../static/img/transform/func_sine_grad_pf.gif)
Los dos siguientes valores opcionales, «amplitude» y «bias», controlan la escala y la línea central de la curva sinusoidal. Por ejemplo, aquí hago una onda (curva coseno negada) que oscila entre el blanco y el gris (valores que van de 0.75 ±0.25, o 0.5 a 1.0), empezando y terminando en blanco. |
magick gradient.png -function Sinusoid 5,90,.25,.75 func_sine_bias.png
![[IM Output]](../static/img/transform/func_sine_bias_pf.gif)
Ten cuidado con estos últimos parámetros, ya que podrían hacer fácilmente que la forma de onda exceda los límites del rango de valores de color y, por tanto, se recorte (a menos que estés usando una versión HDRI de ImageMagick).
Función Arcsin
La función sinusoidal inversa «Arcsin » se añadió en IM v6.5.3-0. Esta es una curva especial que se necesitaba para generar un mapa de desplazamiento cilíndrico. Sus parámetros son…
-function Arcsin width,center,range,bias
Y se implementa usando la fórmula…
value = range/PI * asin(2/width*( value - center ) ) + bias
Por defecto, los valores (si no se definen) «1, 0.5, 1, 0.5» aseguran que la función quede centrada para cubrir todo el rango de color, de 0,0 a 1,1. |
magick gradient.png -function Arcsin 1 func_arcsin.png
![[IM Output]](../static/img/transform/func_arcsin_pf.gif)
Reduciendo a la mitad el «width » de la curva resultante obtienes… |
magick gradient.png -function Arcsin 0.5 func_arcsin_width.png
![[IM Output]](../static/img/transform/func_arcsin_width_pf.gif)
El «center » te permitirá reposicionar la curva según los valores de gris de entrada. |
magick gradient.png -function Arcsin 0.4,0.7 func_arcsin_center.png
![[IM Output]](../static/img/transform/func_arcsin_center_pf.gif)
El argumento «range » permite reducir el rango de salida de los valores de color, y el «bias » ajustará el centro de ese rango. |
magick gradient.png -function Arcsin 0.5,0.5,0.5,0.5 func_arcsin_range.png
![[IM Output]](../static/img/transform/func_arcsin_range_pf.gif)
Observa cómo se manejan los valores que resultan inválidos a causa de la función. Esto permite un mejor control cuando la función se usa en desplazamientos, y ofrece formas de limpiarlos. Los valores reales utilizados son «_bias_ ± _range_ /2», como cabría esperar. Ten en cuenta que si el «width » o el «range » se hacen negativos, la pendiente de la función se invertirá, como resultado de ese valor negativo. |
magick gradient.png -function Arcsin -1 func_arcsin_neg.png
Función Arctan
El método «Arctan » se añadió en IM v6.5.3-1. Sus parámetros son…
-function Arctan slope,center,range,bias
Y se implementa usando la fórmula…
value = range/PI * atan(slope*PI*( value - center ) ) + bias
Como puedes ver, es casi exactamente igual que la función «Arcsin», con solo un pequeño cambio para hacerla más útil. Incluso tiene el mismo conjunto de valores por defecto (si no se definen) «1, 0.5, 1.0, 0.5». Esto significa que, si especificas un valor de pendiente de «1.0», la pendiente del cambio del histograma producirá un cambio 1:1 en torno al gris puro (sin escalado), mientras que vuelve más grises el blanco y el negro. Por ejemplo |
magick gradient.png -function Arctan 1 func_arctan.png
![[IM Output]](../static/img/transform/func_arctan_pf.gif)
Es decir, la parte central del degradado queda en realidad sin cambios, y solo los extremos blanco y negro se descontrastan. A medida que la «slope » de la curva se hace mayor, el degradado en el centro se volverá más fuerte (más comprimido en el medio), en esa cantidad. |
magick gradient.png -function Arctan 10 func_arctan_10.png
![[IM Output]](../static/img/transform/func_arctan_10_pf.gif)
Esto, en muchos sentidos, es muy similar a un operador de modificación de color de contraste sigmoidal. Sin embargo, una función «Arctan» NUNCA alcanzará realmente los límites del rango de salida del blanco y el negro puros. Se acercará a esos límites, pero nunca los cruzará. De forma similar a las funciones anteriores (y al contraste sigmoidal), el segundo argumento ajustará la posición de la curva respecto a los valores del degradado de entrada. |
magick gradient.png -function Arctan 10,.7 func_arctan_center.png
![[IM Output]](../static/img/transform/func_arctan_center_pf.gif)
Y los dos últimos argumentos: «range » te permitirá ajustar el rango de salida de los valores que se generarán. Por ejemplo, expandiendo ligeramente este valor puedes asegurar que cubra por completo todo el rango de valores posibles. |
magick gradient.png -function Arctan 5,0.7,1.2 func_arctan_range.png
![[IM Output]](../static/img/transform/func_arctan_range_pf.gif)
Sin embargo, si lo que realmente quieres es generar una curva para modificar todo el contraste de una imagen de esta forma, es más habitual usar el operador de contraste sigmoidal, que está diseñado para ese fin. El uso más habitual de una función de degradado «Arctan» es crear una curva que se aproxime muy rápidamente a un valor específico, pero sin superarlo. Son estos valores límite los que controlan los argumentos «range » y «bias ». Por ejemplo, esta curva modificará el degradado de una imagen para producir un umbral muy nítido en torno al nivel de gris de entrada de 0,7, pero con los valores cambiando entre los límites del rango de 0,5 y 1,0 |
magick gradient.png -function Arctan 15,0.7,0.5,0.75 func_arctan_typ.png
![[IM Output]](../static/img/transform/func_arctan_typ_pf.gif)
Esto es algo que el contraste sigmoidal no puede generar.
Matemáticas con imágenes de degradado
Las funciones anteriores ofrecen algunas transformaciones muy básicas para imágenes de degradado. Pero ¿qué pasa si quieres hacer algunas matemáticas con dos o más imágenes de degradado? Es decir, modificar un degradado usando el degradado de otra imagen. Para esto necesitas usar los métodos de composición matemática especiales (como «[Plus](compose.html#plus)» y «[Divide](#divide)»). Sin embargo, antes de empezar, me gustaría darte una advertencia. Si tus imágenes de degradado son imágenes puramente en escala de grises, sin canales alfa, puedes usar los métodos de composición matemática directamente. Sin embargo, si quieres limitar estos métodos a un canal específico, o aplicarlos al canal alfa (transparencia), necesitas asegurarte de establecer el ajuste «[-channel](https://imagemagick.org/command-line-options/#channel)» apropiado, sin la marca de canal especial «Sync». Véase Matemáticas de imagen usando composición de imágenes para más detalles. Normalmente, usar los métodos de composición matemática no es realmente tan difícil. Las complicaciones surgen cuando tienes degradados que también contienen un «bias». Es decir, el degradado debería representar un valor de «cero» en el gris al 50 % y cubrir un rango de -1 (negro) a +1 (blanco). Estas imágenes se usan a menudo para el mapeo de imagen de distorsión. Por eso, hacer matemáticas con degradados con bias es el verdadero problema, y lo que veremos aquí de forma más específica.
Atenuar un degradado con bias
Por ejemplo, aquí quiero crear una onda seno, pero una que empiece pequeña y luego aumente en amplitud. Esto se conoce como «atenuar» un degradado con bias. O, dicho de otro modo, multiplicar un degradado con bias por otro degradado absoluto. ¡También es como funciona la modulación de amplitud , como en la radio AM! Así que primero necesitamos una onda seno, que podemos generar simplemente a partir de un degradado lineal…
magick -size 5x300 gradient: -rotate 90 math_linear.png
magick math_linear.png -evaluate sine 12 math_sine.png
Ahora, para atenuar esto, multiplicamos la onda seno por un degradado lineal, usando una composición alfa Multiply…
magick math_sine.png math_linear.png \
-compose Multiply -composite math_sine_2.png
Pero para usar esto en, digamos, un mapa de desplazamiento de ondas de agua, la onda debe permanecer centrada en torno a un gris perfecto. Para ello necesitamos añadir un bias a la imagen original. Esta resultó ser la misma función que usamos para multiplicar la imagen original, negada y dividida entre dos…
magick math_linear.png -negate -evaluate divide 2 math_bias.png
magick math_sine_2.png math_bias.png \
-compose Plus -composite math_attenuated.png
Y así tenemos un degradado de onda seno atenuado linealmente, apto para usar en un mapa de desplazamiento.
Por supuesto, puedes hacer todo el proceso en un solo comando, y tampoco tiene por qué ser una simple atenuación lineal. Por ejemplo, aquí atenúo la onda seno de alta frecuencia usando una onda coseno negada, en lugar de un degradado lineal.
magick math_linear.png -evaluate cos 1 -negate math_cosine_peak.png
magick math_sine.png math_cosine_peak.png \
\( -clone 0,1 -compose multiply -composite \) \
\( -clone 1 +level 50%,0 \
-clone 2 -compose plus -composite \) \
-delete 0--2 math_cosine_atten.png
A partir de IM v6.5.4-3 ya es posible hacer todos los pasos anteriores en un único método de composición, usando el método de composición Mathematics especial. Básicamente, reconociendo que una operación de atenuación es la fórmula Sc*Dc-.5*Sc+.5 o los argumentos «1,-.5,0,.5». |
magick math_sine.png math_cosine_peak.png \
-compose Mathematics -set option:compose:args 1,-.5,0,.5 \
-composite math_attenuate.png
![[IM Output]](../static/img/transform/math_attenuate_pf.gif)
El mismo resultado también se puede lograr ajustando primero el degradado de atenuación con una función polinómica y usando luego un operador de composición Exclusion para fusionar las imágenes. |
magick math_sine.png \( math_cosine_peak.png -function polynomial -.5,.5 \) \
-compose Exclusion -composite math_poly_excl.png
Multiplicar degradados con bias
Pero ¿qué pasa si AMBAS funciones tienen bias, de modo que un gris perfecto significa cero, y el negro y el blanco representan el rango de -1 a +1? Bien, esto es un poco más complejo, ya que no puedes simplemente multiplicarlas y esperar que salga bien, pues la multiplicación puede constar de valores negativos. Esto requiere cierto cuidado para asegurarte de no acabar recortando los valores y obteniendo la negación correcta de la curva en la imagen resultante. El truco es descomponer la multiplicación en varios pasos. Es decir, A × B también puede escribirse como A × abs(B) × sign(B). Haciendo esto evitas multiplicar por un valor negativo, que no se puede almacenar en una imagen de degradado normal. Así que todo lo que necesitamos es tomar uno de los degradados con bias y separarlo en dos partes para poder aplicarlas adecuadamente al otro degradado. El «sign()» de un degradado con bias, o la obtención de una máscara de qué partes son negativas, se puede extraer usando un umbral sobre el degradado al nivel del bias. Luego puedes negar selectivamente el otro degradado usando una diferencia de composición, con esa imagen de umbral. El «abs()» de un degradado con bias se puede extraer fácilmente usando Solarize, y luego negando y duplicando (usando Level) eso para obtener el valor absoluto del degradado en el rango de 0,0 a 1,0. Como también necesitaremos el desplazamiento del bias como parte de la multiplicación (igual que en Atenuar, más arriba), puedes usar directamente la salida de solarize negada y escalada a la mitad, antes de convertirla en el valor absoluto del degradado. Así que convirtamos un degradado en estos tres componentes.
magick math_cosine_peak.png -threshold 50% -negate math_m_sign.png
magick math_cosine_peak.png -solarize 50% math_m_bias.png
magick math_m_bias.png -level 50%,0 math_m_abs.png
|
| Signo del degradado
blanco = negativo
---|---|---
|
| Desplazamiento de bias
|
| Valor absoluto
Ahora que tenemos estas tres partes de una de las imágenes de degradado, podemos fusionarlas con el otro degradado. Para ello multiplicamos por el valor absoluto, volvemos a sumar el bias y luego negamos las partes que deben hacerse negativas.
magick math_sine.png math_m_abs.png \
-compose Multiply -composite math_m_1.png
magick math_m_1.png math_m_bias.png \
-compose Plus -composite math_m_2.png
magick math_m_2.png math_m_sign.png \
-compose Difference -composite math_multiply.png
¡Y eso es una multiplicación perfecta de dos imágenes de degradado con bias! Aquí está de nuevo, pero todo en un solo comando…
magick math_sine.png math_cosine_peak.png \
\( -clone 1 -threshold 50% -negate \) \
\( -clone 1 -solarize 50% \) \
\( -clone 3 -level 50%,0 \) \
\( -clone 0,4 -compose multiply -composite \
-clone 3 -compose plus -composite \
-clone 2 -compose difference -composite \) \
-delete 0--2 math_multiply_2.png
Una última nota: a diferencia de la atenuación, esta multiplicación de degradados con bias es conmutativa. Es decir, intercambiar las imágenes de entrada no afecta al resultado final. Como lo anterior es equivalente a la fórmula 2*Sc*Dc-Sc-Dc+1, a partir de IM v6.5.4-3 puedes implementar los complejos pasos anteriores como un único método de composición «[Mathematics](compose.html#mathematics)» usando el argumento «2,-1,-1,1». |
magick math_sine.png math_cosine_peak.png \
-compose Mathematics -set option:compose:args 2,-1,-1,1 \
-composite math_bias_multiply.png
![[IM Output]](../static/img/transform/math_bias_multiply_pf.gif)
Es decir, un método mucho más fácil y rápido que la docena o más de pasos necesarios sin este método de composición con argumentos. Da la casualidad de que, una vez que vi esa fórmula, me di cuenta de que resulta ser simplemente la negación del método de composición «[Exclusion](compose.html#exclusion)». Extraño, pero cierto. Por eso lo siguiente también generará la misma multiplicación con bias cero. |
magick math_sine.png math_cosine_peak.png \
-compose exclusion -composite -negate math_excl_neg.png
Sumar degradados con bias
Con la llegada del método de composición «[Mathematics](compose.html#mathematics)», sumar degradados con bias también es relativamente fácil. La fórmula FX equivalente es «u+v-0.5» o un argumento de composición de «0,1,1,-.5». Por ejemplo, lo siguiente fue un ejemplo de transformada de Fourier que había generado a mano, que requería la suma de 3 sinusoides con bias y un valor de CC constante.
magick math_linear.png -function sinusoid 3.5,0,.25 wave_1.png
magick math_linear.png -function sinusoid 1.5,-90,.13 wave_2.png
magick math_linear.png -function sinusoid 0.6,-90,.07 wave_3.png
magick wave_1.png wave_2.png wave_3.png -background gray40 \
-compose Mathematics -set option:compose:args 0,1,1,-.5 \
-flatten added_waves.png
Observa en lo anterior cómo usé el operador «[-flatten](https://imagemagick.org/command-line-options/#flatten)» con un ajuste «[-background](https://imagemagick.org/command-line-options/#background)» para implementar una composición de múltiples imágenes. O, en este caso, una «suma con bias» de todas las imágenes dadas más la constante del fondo.
Modulación de frecuencia
Al aplicar una función directamente a la salida de otra función, NO produces un resultado simple. La razón es que todas estas funciones matemáticas se aplican al «valor» de degradado de los píxeles individuales, y no al valor x del píxel en el degradado. Por ejemplo… |
magick gradient.png -evaluate sin 0.5 -normalize \
-evaluate cos 8 math_cos_var.png
![[IM Output]](../static/img/transform/math_cos_var_pf.gif)
Esto genera una función muy compleja que es esencialmente equivalente a
cos( 8 * sin( _{value}_ /2 ) )
En otras palabras, una frecuencia variable, donde la frecuencia varía con el degradado de la primera curva seno. Básicamente, cuanto más rápido cambia el degradado en la imagen original, menor es la distancia entre los picos. Sin embargo, la altura (amplitud) del pico no varía. Así es como funciona en realidad la modulación de frecuencia , donde una función aparentemente simple produce un resultado muy complejo.
En construcción
Técnicas variadas de transformación de imagen.
Estas aún no se han ejemplificado, pero son algunas transformaciones básicas
desarrolladas en IM que pueden resultar útiles. Si tienes un efecto interesante, contribúyelo.
pixelar una imagen
reducir una imagen 10 y luego escalar la imagen 10 para producir bloques
de color aproximadamente promediado.
Por ejemplo...
magick input.jpg -resize 10% -sample 1000% output.jpg
Enderezar imágenes ligeramente rotadas
-deskew {threshold}
endereza una imagen. Un umbral del 40% funciona para la mayoría de las imágenes.
Usa -set option:deskew:auto-crop {width} para recortar la imagen automáticamente. El
argumento de set es el ancho en píxeles del fondo de la imagen (p. ej. 40).
Programáticamente, recortamos automáticamente ejecutando un filtro de mediana sobre la imagen
para eliminar el ruido de sal y pimienta. Después obtenemos los límites de la imagen
del filtro de mediana con un factor de fuzz (p. ej. -fuzz 5%). Por último,
recortamos la imagen original según esos límites. El código tiene este aspecto:
median_image=MedianFilterImage(image,0.0,exception);
geometry=GetImageBoundingBox(median_image,exception);
median_image-DestoryImage(median_image);
print(" Auto-crop geometry: %lux%lu%+ld%+ld",
geometry.width,geometry.height, geometry.x,geometry.y);
crop_image=CropImage(rotate_image,&geometry,exception);
Véase [Recortar imágenes 'ruidosas'](crop.html#trim_blur)
Segmentación
mira los scripts
[divide_vert](../static/img/scripts/divide_vert)
[segment_image](../static/img/scripts/segment_image)
para algunos scripts simples que escribí para segmentar imágenes bien definidas en
partes más pequeñas. Espero incorporar funciones de segmentación simples como esta
a la biblioteca central, para permitir cosas como la subdivisión automática de
animaciones GIF, y separar imágenes y diagramas de documentos escaneados.
![[IM Output]](../static/img/transform/inside_border2.jpg)
![[IM Output]](../static/img/transform/spread_rose.png)
![[IM Output]](../static/img/images/rose.gif)
![[IM Output]](../static/img/transform/rose_paint_1.gif)
![[IM Output]](../static/img/transform/rose_paint_3.gif)
![[IM Output]](../static/img/transform/rose_paint_5.gif)
![[IM Output]](../static/img/transform/rose_paint_10.gif)
![[IM Output]](../static/img/transform/rose_blur_paint_10.gif)
![[IM Output]](../static/img/transform/rose_charcoal_1.gif)
![[IM Output]](../static/img/transform/rose_charcoal_3.gif)
![[IM Output]](../static/img/transform/rose_charcoal_5.gif)
![[IM Output]](../static/img/transform/rose_emboss_0x05.gif)
![[IM Output]](../static/img/transform/rose_emboss_0x09.gif)
![[IM Output]](../static/img/transform/rose_emboss_0x10.gif)
![[IM Output]](../static/img/transform/rose_emboss_0x11.gif)
![[IM Output]](../static/img/transform/rose_emboss_0x12.gif)
![[IM Output]](../static/img/transform/rose_emboss_0x20.gif)
![[IM Output]](../static/img/images/rose_grey.gif)
![[IM Output]](../static/img/transform/rose_g_emboss_0x05.gif)
![[IM Output]](../static/img/transform/rose_g_emboss_0x09.gif)
![[IM Output]](../static/img/transform/rose_g_emboss_0x10.gif)
![[IM Output]](../static/img/transform/rose_g_emboss_0x11.gif)
![[IM Output]](../static/img/transform/rose_g_emboss_0x12.gif)
![[IM Output]](../static/img/transform/rose_g_emboss_0x20.gif)
![[IM Output]](../static/img/transform/message.gif)
![[IM Text]](../static/img/transform/message_size.txt.gif)
![[IM Output]](../static/img/transform/rose_difference.png)
![[IM Text]](../static/img/transform/rose_diff_pae.txt.gif)
![[IM Output]](../static/img/transform/message_hidden.png)
![[IM Output]](../static/img/transform/message_obfuscate.png)
![[IM Output]](../static/img/transform/message_restored_2.png)
![[IM Output]](../static/img/transform/message_signed.png)
![[IM Output]](../static/img/transform/message_restored_3.png)
![[IM Output]](../static/img/transform/message_binary.png)
![[IM Output]](../static/img/transform/message_restored_4.png)
![[IM Output]](../static/img/transform/grid_input.png)
![[IM Output]](../static/img/transform/grid_scale.png)
![[IM Output]](../static/img/transform/grid_tile.png)
![[IM Output]](../static/img/transform/mask.gif)
![[IM Output]](../static/img/transform/mask_edge_1.gif)
![[IM Output]](../static/img/transform/mask_edge_2.gif)
![[IM Output]](../static/img/transform/mask_edge_3.gif)
![[IM Output]](../static/img/transform/mask_edge_10.gif)
![[IM Output]](../static/img/images/piglet.gif)
![[IM Output]](../static/img/transform/piglet_edge.gif)
![[IM Output]](../static/img/transform/rose_edge.gif)
![[IM Output]](../static/img/transform/rose_edge_grey.gif)
![[IM Output]](../static/img/transform/mask_canny.gif)
![[IM Output]](../static/img/transform/piglet_canny.gif)
![[IM Output]](../static/img/transform/piglet_canny_neg.gif)
![[IM Output]](../static/img/transform/rose_canny.gif)
![[IM Output]](../static/img/transform/heart_svg.gif)
![[IM Text]](../static/img/transform/heart_2.svg.gif)
![[IM Output]](../static/img/images/shape_rectangle.gif)
![[IM Output]](../static/img/transform/rectangle.gif)
![[IM Text]](../static/img/transform/rectangle_lines.mvg.gif)
![[IM Output]](../static/img/transform/shade_anthony.jpg)
![[IM Text]](../static/img/transform/shade_elevation_45.txt.gif)
![[IM Output]](../static/img/transform/shade_beveled.png)
![[IM Output]](../static/img/transform/shade_elevation_90.gif)
![[IM Output]](../static/img/transform/shade_beveled_edge.png)
![[IM Output]](../static/img/transform/shade_elevation_0.gif)
![[IM Output]](../static/img/transform/shade_elevation_15.gif)
![[IM Output]](../static/img/transform/shade_elevation_30.gif)
![[IM Output]](../static/img/transform/shade_elevation_45.gif)
![[IM Output]](../static/img/transform/shade_elevation_60.gif)
![[IM Output]](../static/img/transform/shade_elevation_75.gif)
![[IM Output]](../static/img/transform/shade_beveled_X.png)
![[IM Output]](../static/img/transform/shade_blur_3n.gif)
![[IM Output]](../static/img/transform/shade_blur_3n_mask.png)
![[IM Image]](../static/img/transform/shade_30.png)
![[IM Text]](../static/img/transform/shade_30.txt.gif)
![[IM Image]](../static/img/transform/shade_30_norm.png)
![[IM Text]](../static/img/transform/shade_30_norm.txt.gif)
![[IM Image]](../static/img/transform/shade_21_norm.png)
![[IM Text]](../static/img/transform/shade_21_norm.txt.gif)
![[IM Output]](../static/img/transform/shade_sig-10.png)
![[IM Output]](../static/img/transform/shade_sig-5.png)
![[IM Output]](../static/img/transform/shade_sig-2.png)
![[IM Output]](../static/img/transform/shade_sig_0.png)
![[IM Output]](../static/img/transform/shade_sig+2.png)
![[IM Output]](../static/img/transform/shade_sig+5.png)
![[IM Output]](../static/img/transform/shade_sig+10.png)
![[IM Output]](../static/img/transform/shade_overlay.png)
![[IM Output]](../static/img/transform/fx_blue.gif)
![[IM Output]](../static/img/transform/fx_combine.gif)
![[IM Output]](../static/img/transform/grey_253.png)
![[IM Output]](../static/img/transform/gradient.png)
![[IM Output]](../static/img/transform/eval_pow_parabola.png)
![[IM Output]](../static/img/transform/eval_pow_sq_root.png)
![[IM Output]](../static/img/transform/gradient_pf.gif)
![[IM Output]](../static/img/transform/eval_pow_parabola_pf.gif)
![[IM Output]](../static/img/transform/eval_pow_sq_root_pf.gif)
![[IM Output]](../static/img/transform/eval_sin_1.png)
![[IM Output]](../static/img/transform/eval_cos_1.png)
![[IM Output]](../static/img/transform/eval_sin_1_pf.gif)
![[IM Output]](../static/img/transform/eval_cos_1_pf.gif)
![[IM Output]](../static/img/transform/func_arcsin_neg.png)
![[IM Output]](../static/img/transform/func_arcsin_neg_pf.gif)
![[IM Output]](../static/img/transform/math_linear_pf.gif)
![[IM Output]](../static/img/transform/math_sine_pf.gif)
![[IM Output]](../static/img/transform/math_sine_2_pf.gif)
![[IM Output]](../static/img/transform/math_bias_pf.gif)
![[IM Output]](../static/img/transform/math_attenuated_pf.gif)
![[IM Output]](../static/img/transform/math_cosine_atten_pf.gif)
![[IM Output]](../static/img/transform/math_poly_excl_pf.gif)
![[IM Output]](../static/img/transform/math_m_1_pf.gif)
![[IM Output]](../static/img/transform/math_m_2_pf.gif)
![[IM Output]](../static/img/transform/math_multiply_pf.gif)
![[IM Output]](../static/img/transform/math_multiply_2_pf.gif)
![[IM Output]](../static/img/transform/math_excl_neg_pf.gif)
![[IM Output]](../static/img/transform/wave_1_pf.gif)
![[IM Output]](../static/img/transform/wave_2_pf.gif)
![[IM Output]](../static/img/transform/wave_3_pf.gif)
![[IM Output]](../static/img/transform/added_waves_pf.gif)