⚠️ Ceci est un site de traduction non officiel, sans lien avec ImageMagick Studio LLC. Pour des informations officielles, consultez la page originale (https://imagemagick.org/fx/).

Anatomie d'une expression FX

L'opérateur d'image à effets spéciaux FX • Anatomie d'une expression FX

L'opérateur d'image à effets spéciaux FX applique une expression mathématique à chaque canal de pixel d'une image. Le langage d'expression FX offre un moyen puissant et flexible de manipuler les images, vous permettant d'effectuer un large éventail d'opérations et de transformations sur vos images. Utilisez FX pour :

  • créer des toiles, des dégradés, des cartes de couleurs mathématiques
  • déplacer des valeurs de couleur entre images et canaux
  • translater, retourner, refléter, pivoter, mettre à l'échelle, cisailler et, de manière générale, déformer des images
  • fusionner ou composer plusieurs images ensemble
  • convoluer ou fusionner des pixels voisins
  • générer des métriques d'image ou des « empreintes »

Cet opérateur parcourt en boucle tous les pixels d'une image et tous les canaux de chaque pixel, puis renvoie une nouvelle image contenant les résultats. L'expression peut référencer n'importe quelle image de la séquence d'images, mais seule une copie de la première image est renvoyée, mise à jour conformément à votre expression.

L'expression peut être simple :

magick -size 64x64 canvas:black -channel blue -fx "1/2" fx_navy.png

Ici, nous convertissons une image noire en une image bleu marine :

black ==> navy

Ou l'expression peut être complexe :

magick rose: \
  -fx "(1.0/(1.0+exp(10.0*(0.5-u)))-0.006693)*1.0092503" \
  rose-sigmoidal.png

Cette expression produit une version à fort contraste de l'image source :

rose ==> rose-sigmoidal

L'expression peut inclure des affectations de variables. Les affectations réduisent, dans la plupart des cas, la complexité d'une expression et permettent certaines opérations qui ne seraient pas possibles autrement. Par exemple, créons un dégradé radial :

magick -size 70x70 canvas: \
  -fx "Xi=i-w/2; Yj=j-h/2; 1.2*(0.5-hypot(Xi,Yj)/70.0)+0.5" \
  radial-gradient.png

La commande ci-dessus renvoie cette image :

radial-gradient

Cette expression FX ajoute du bruit aléatoire à une image :

magick photo.jpg -fx 'iso=32; rone=rand(); rtwo=rand(); \
  myn=sqrt(-2*ln(rone))*cos(2*Pi*rtwo); myntwo=sqrt(-2*ln(rtwo))* \
  cos(2*Pi*rone); pnoise=sqrt(p)*myn*sqrt(iso)* \
  channel(4.28,3.86,6.68)/255; max(0,p+pnoise)' noisy.png

Ce script FX utilise une boucle pour créer un ensemble de Julia :

magick -size 400x400 xc:gray -fx " \
  Xi=2.4*i/w-1.2; \
  Yj=2.4*j/h-1.2; \
  for (pixel=0.0, (hypot(Xi,Yj) < 2.0) && (pixel < 1.0), \
    delta=Xi^2-Yj^2; \
    Yj=2.0*Xi*Yj+0.2; \
    Xi=delta+0.4; \
    pixel+=0.00390625 \
  ); \
  pixel == 1.0 ? 0.0 : pixel" \
  \( -size 1x1 xc:white xc:red xc:orange xc:yellow xc:green1 xc:cyan xc:blue \
     xc:blueviolet xc:white -reverse +append -filter Cubic -resize 1024x1! \) \
  -clut -rotate -90 julia-set.png

Julia Fractals

Ce script FX affiche les 10 premiers nombres premiers :

magick xc:gray -fx " \
  for (prime=2, prime < 30, composite=0; \
    for (nn=2, nn < (prime/2+1), if ((prime % nn) == 0, composite++, ); nn++); \
      if (composite <= 0, debug(prime), ); prime++)" null:

Pour plus d'exemples, consultez Using FX, The Special Effects Image Operator.

L'option -fx remplace toute séquence d'images par un clone de la première image, mis à jour avec les résultats de l'expression. Si vous préférez appliquer l'expression à chaque image de la séquence, utilisez plutôt +fx.

L'expression FX est interprétée dans un seul thread ; elle est cependant exécutée dans plusieurs threads, à moins que l'expression n'inclue la fonction debug().

La section suivante décrit le langage d'expression FX.

Anatomie d'une expression FX

Le langage d'expression FX

Le langage d'expression FX formel est défini ici :

numbers:
entier, virgule flottante, notation scientifique (+/- requis, p. ex. 3.81469e-06), suffixes numériques du Système international (p. ex. KB, Mib, GB, etc.)
constants:
E (nombre d'Euler), Epsilon, Opaque, Phi (nombre d'or), Pi, QuantumRange, QuantumScale, Transparent
FX operators (in order of precedence):
^ (puissance), - unaire, , /, % (modulo), +, -, <<, >>, <, <=, >, >=, +=, -=, =, /=, %=, <<= , >>=, &=, |=, ++, --, ==, !=, & (ET binaire), | (OU binaire), && (ET logique), || (OU logique), ~ (NON logique), ?: (conditionnel ternaire)
array:
une image offre un stockage en tableau (p. ex. p[-1,-1].r) borné par sa largeur et sa hauteur. Une séquence d'images représente plusieurs tableaux (p. ex. u.p[0,0].r, v.p[0,0].r). Le stockage est limité aux valeurs Quantum, p. ex. [0..65535] pour les compilations Q16 et virgule flottante pour les compilations avec HDRI activé.
math functions:
abs(), acos(), acosh(), airy(), alt(), asin(), asinh(), atan(), atanh(), atan2(), ceil(), clamp(), cos(), cosh(), debug(), drc(), epoch(), erf(), exp(), floor(), gauss(), gcd(), hypot(), int(), isnan(), j0(), j1(), jinc(), ln(), log(), logtwo(), magicktime(), max(), min(), mod(), not(), pow(), rand(), round(), sign(), sin(), sinc(), sinh(), sqrt(), squish(), tan(), tanh(), trunc()
channel functions:
définir jusqu'à 5 canaux de pixel
color names:
red, cyan, black, etc.
color functions:
srgb(), srgba(), rgb(), rgba(), cmyk(), cmyka(), hsl(), hsla(), etc.
color hex values:

ccc, #cbfed0, #b9e1cc00, etc.

symbols:

u: première image de la liste
v: deuxième image de la liste
s: image courante de la liste (pour %[fx:], sinon = u)
t: index de l'image courante (s) dans la liste
n: nombre d'images dans la liste
i: décalage de colonne
j: décalage de ligne
p: pixel à utiliser (absolu ou relatif au pixel courant)
w: largeur de cette image
h: hauteur de cette image
z: profondeur de canal
r: valeur rouge (de RGBA), d'un pixel spécifique ou courant
g: vert
b: bleu
a: alpha
o: opacité
c: valeur cyan de la couleur CMYK du pixel
y: jaune
m: magenta
k: noir
all: tous les canaux
this: ce canal
intensity: intensité du pixel
hue: teinte du pixel
saturation: saturation du pixel
lightness: clarté du pixel
luma: luma du pixel
page.width: largeur de la page
page.height: hauteur de la page
page.x: décalage x de la page
page.y: décalage y de la page
printsize.x: taille d'impression x
printsize.y: taille d'impression y
resolution.x: résolution x
resolution.y: résolution y
depth: profondeur de l'image
extent: étendue de l'image
minima: minimum de l'image
maxima: maximum de l'image
mean: moyenne de l'image
median: médiane de l'image
standard_deviation: écart-type de l'image
kurtosis: kurtosis de l'image
skewness: asymétrie de l'image (ajoutez un spécificateur de canal pour calculer une statistique sur ce canal, p. ex. depth.r)
iterators:
do(), for(), while()
image attributes:
s.depth, s.kurtosis, s.maxima, s.mean, s.minima, s.resolution.x, s.resolution.y, s.skewness, s.standard_deviation
user settings:

définir des symboles Fx comme paramètres utilisateur, p. ex.

magick ... -set option:wd1 "%[fx:w/2]" -resize "%[fx:wd1-5]" ...

L'expression FX

Une expression FX peut inclure n'importe quelle combinaison des éléments suivants :

x ^ y
exponentiation (x puissance y)
( ... )
groupement
x * y
multiplication
x / y
division
x % y
modulo
x + y
addition
x - y
soustraction
x << y
décalage à gauche
x >> y
décalage à droite
x < y
relation booléenne, renvoie 1.0 si x < y, sinon 0.0
x <= y
relation booléenne, renvoie 1.0 si x <= y, sinon 0.0
x > y
relation booléenne, renvoie 1.0 si x > y, sinon 0.0
x >= y
relation booléenne, renvoie 1.0 si x >= y, sinon 0.0
x == y
relation booléenne, renvoie 1.0 si x == y à epsilon près (1e-12), sinon 0.0. Deux valeurs sont égales lorsque leur différence est inférieure à environ 1e‑12.
x != y
relation booléenne, renvoie 1.0 si x != y à epsilon près (1e-12), sinon 0.0
x & y
ET binaire
x | y
OU binaire
x && y
connecteur ET logique, renvoie 1.0 si x > 0 et y > 0, sinon 0.0
x || y
connecteur OU logique (inclusif), renvoie 1.0 si x > 0 ou y > 0 (ou les deux), sinon 0.0
~x
opérateur NON logique, renvoie 1.0 si non x > 0, sinon 0.0
+x
plus unaire, renvoie 1.0*valeur
-x
moins unaire, renvoie -1.0*valeur
condition ? true-statements : false-statements
expression conditionnelle ternaire, renvoie true-statements si condition != 0, sinon false-statements
x = y
affectation ; les variables d'un seul caractère sont réservées, utilisez plutôt 2 caractères ou plus, en combinaisons de lettres uniquement (p. ex. Xi et non X1)
x ; y
séparateur d'instruction
phi
constante (1.618034...)
pi
constante (3.14159265359...)
e
constante (2.71828...)
QuantumRange
constante de valeur maximale de pixel (255 pour Q8, 65535 pour Q16)
QuantumScale
constante 1.0/QuantumRange
intensity
intensité du pixel dont la valeur respecte l'option -intensity.
hue
teinte du pixel
saturation
saturation du pixel
lightness
clarté du pixel ; équivalente à 0.5max(red,green,blue) + 0.5min(red,green,blue)
luminance
luminance du pixel ; équivalente à 0.212656red + 0.715158green + 0.072186*blue
red, green, blue, etc.
noms de couleurs

ccc, #cbfed0, #b9e1cc00, etc.

 valeurs de couleur hexadécimales
rgb(), rgba(), cmyk(), cmyka(), hsl(), hsla()
fonctions de couleur
s, t, u, v, n, i, j, w, h, z, r, g, b, a, o, c, y, m, k
symboles
abs(x)
fonction valeur absolue
acos(x)
fonction arc cosinus
acosh(x)
fonction cosinus hyperbolique inverse
airy(x)
fonction d'Airy (max=1, min=0) ; airy(x)=[jinc(x)]2=[2j1(pix)/(pi*x)]2
alt(x)
fonction d'alternance de signe (renvoie 1.0 si int(x) est pair, -1.0 si int(x) est impair)
asin(x)
fonction arc sinus
asinh(x)
fonction sinus hyperbolique inverse
atan(x)
fonction arc tangente
atanh(x)
fonction tangente hyperbolique inverse
atan2(y,x)
fonction arc tangente de deux variables
ceil(x)
plus petite valeur entière non inférieure à l'argument
channel(...)
prend de zéro à cinq arguments, p. ex. channel(0.1) règle le premier canal à 0.1 et met les autres canaux à zéro.
clamp(x)
limite la valeur
cos(x)
fonction cosinus
cosh(x)
fonction cosinus hyperbolique
debug(x)
affiche x (utile pour déboguer votre expression)
do(statements, condition)
itère tant que la condition n'est pas égale à 0
drc(x,y)
compression de plage dynamique (courbe en genou) ; drc(x,y)=(x)/(y*(x-1)+1); -1<y<1
epoch(date-time)
convertit une propriété date-time en nombre de secondes depuis l'époque, 00:00:00 UTC
erf(x)
fonction d'erreur
exp(x)
fonction exponentielle naturelle (e puissance x)
floor(x)
plus grande valeur entière non supérieure à l'argument
for(initialize, condition, statements)
itère tant que la condition n'est pas égale à 0
gauss(x)
fonction gaussienne ; gauss(x)=exp(-xx/2)/sqrt(2pi)
gcd(x,y)
plus grand commun diviseur
hypot(x,y)
racine carrée de x2+y2
if(condition, nonzero-statements, zero-statements)
interprète l'expression selon la condition
int(x)
fonction partie entière (renvoie le plus grand entier inférieur ou égal à x)
isnan(x)
renvoie 1.0 si x est NAN, 0.0 sinon
j0(x)
fonctions de Bessel de x du premier type d'ordre 0
j1(x)
fonctions de Bessel de x du premier type d'ordre 1
jinc(x)
fonction jinc (max=1, min=-0.1323) ; jinc(x)=2j1(pix)/(pi**x)
ln(x)
fonction logarithme naturel
log(x)
logarithme en base 10
logtwo(x)
logarithme en base 2
ln(x)
logarithme naturel
magicktime()
l'heure actuelle en secondes depuis l'époque, 00:00:00 UTC
max(x, y)
maximum de x et y
min(x, y)
minimum de x et y
mod(x, y)
fonction reste en virgule flottante
not(x)
renvoie 1.0 si x vaut zéro, 0.0 sinon
pow(x,y)
fonction puissance (x puissance y)
rand()
valeur uniformément distribuée sur l'intervalle [0.0, 1.0) avec une période de 2 puissance 128 -1
round()
arrondit à la valeur entière, quel que soit le sens d'arrondi
sign(x)
renvoie -1.0 si x est inférieur à 0.0, sinon 1.0
sin(x)
fonction sinus
sinc(x)
fonction sinc (max=1, min=-0.21) ; sinc(x)=sin(pix)/(pix)
squish(x)
fonction squish ; squish(x)=1.0/(1.0+exp(-x))
sinh(x)
fonction sinus hyperbolique
sqrt(x)
fonction racine carrée
tan(x)
fonction tangente
tanh(x)
fonction tangente hyperbolique
trunc(x)
arrondit à l'entier, vers zéro
while(condition, statements)
itère tant que la condition n'est pas égale à 0
image.depth, image.kurtosis, image.maxima, image.mean, image.median, image.minima, image.resolution.x, image.resolution.y, image.skewness, image.standard_deviation
attributs de l'image

La sémantique de l'expression inclut ces règles :

  • les symboles sont insensibles à la casse
  • un seul conditionnel ternaire (p. ex. x ? y : z) par instruction
  • les instructions sont des affectations ou l'expression finale à renvoyer
  • une affectation commence une instruction, ce n'est pas un opérateur
  • les variables d'un seul caractère sont réservées. Les affectations à des fonctions intégrées réservées lèvent une exception ; p. ex. r=3.0; r renvoie Attempted assignment to non-UserSymbol 'r' at '3.0'.
  • les opérateurs unaires ont une priorité inférieure aux opérateurs binaires, c'est-à-dire que le moins unaire (négation) a une priorité inférieure à l'exponentiation, donc -3^2 est interprété comme -(3^2) = -9. Utilisez des parenthèses pour clarifier votre intention (p. ex. (-3)^2 = 9).
  • il faut être prudent avec le symbole barre oblique ('/'). La chaîne de caractères 1/2x est interprétée comme (1/2)x. L'interprétation contraire doit être écrite explicitement 1/(2x). Là encore, l'usage des parenthèses aide à clarifier le sens et devrait être employé chaque fois qu'il y a un risque de mauvaise interprétation.
  • Comme -- est l'opérateur de décrémentation de variable, utilisez des parenthèses pour soustraire un nombre négatif, p. ex. -4-(-5).

Images sources

Les symboles u et v se réfèrent respectivement à la première et à la deuxième image de la séquence d'images courante. Pour référencer une image particulière d'une séquence, ajoutez son index à n'importe quelle référence d'image (généralement u), l'index zéro correspondant au début de la séquence. Un index négatif compte depuis la fin. Par exemple, u[0] est la première image de la séquence, u[2] la troisième, u[-1] la dernière image, et u[t] l'image courante. L'image courante peut aussi être référencée par s. Si le numéro de séquence dépasse la longueur de la séquence, le décompte est rebouclé. Ainsi, dans une séquence de 3 images, u[-1], u[2] et u[5] se réfèrent tous à la même image (la troisième).

À titre d'exemple, nous formons une image en faisant la moyenne de la première et de la troisième image (la deuxième image (index 1) est ignorée et simplement écartée) :

magick image1.jpg image2.jpg image3.jpg -fx "(u+u[2])/2" image.jpg

Par défaut, l'image à laquelle p, r, g, b, a, etc. s'appliquent est l'image courante s de la liste d'images. Cela équivaut à u, sauf lorsqu'on l'utilise dans une séquence d'échappement %[fx:...].

Il est important de noter le rôle particulier joué par la première image. C'est la seule image de la séquence d'images qui est modifiée ; les autres images ne sont utilisées que pour leurs données. À titre d'exemple illustratif, considérez ce qui suit, et notez que le réglage -channel red indique à -fx de ne modifier que le canal vert ; rien dans les canaux rouge ou bleu ne changera. Il est instructif de réfléchir à la raison pour laquelle le résultat n'est pas symétrique.

magick logo: -flop logo: -resize "20%" -channel green -fx "(u+v)/2" image.jpg

logo-sm-flop.png logo-sm.png ==> logo-sm-fx.png

Accès aux pixels

Toutes les valeurs de couleur sont normalisées dans la plage 0.0 à 1.0. Le canal alpha varie de 0.0 (entièrement transparent) à 1.0 (entièrement opaque).

Les pixels sont traités un à la fois, mais on peut spécifier un pixel différent d'une image à l'aide d'un index de pixel représenté par p. Par exemple :

p[-1].g      valeur verte du pixel immédiatement à gauche du pixel courant
p[-1,-1].r   valeur rouge du pixel en diagonale en haut à gauche du pixel courant

Pour spécifier une position absolue, utilisez des accolades plutôt que des crochets.

p{0,0}.r     valeur rouge du pixel du coin supérieur gauche de l'image
p{12,34}.b   valeur de pixel bleu à la colonne 12, ligne 34 de l'image

Des valeurs entières de la position récupèrent la couleur du pixel référencé, tandis que des valeurs de position non entières renvoient une couleur mélangée selon le réglage -interpolate courant.

Une position hors des limites de l'image récupère une valeur dictée par le réglage de l'option -virtual-pixel.

Spécifiez u.r pour désigner le canal rouge de l'image courante. Si vous ne spécifiez pas de qualificateur de canal, vous obtenez le canal courant. Utilisez mean.this pour régler le canal de sortie à la moyenne du seul canal d'entrée. Utilisez mean.all pour régler la moyenne globale des canaux d'entrée.

Appliquer une expression à des canaux d'image sélectionnés

Utilisez le réglage -channel pour spécifier le canal de sortie du résultat. Si aucun canal de sortie n'est indiqué, le résultat est appliqué à tous les canaux à l'exception du canal d'opacité. Par exemple, pour remplacer le canal rouge de alpha.png par la moyenne des canaux verts des images alpha.png et beta.png, utilisez :

magick alpha.png beta.png -channel red -fx "(u.g+v.g)/2" gamma.png

Résultats

L'opérateur -fx évalue l'expression donnée pour chaque canal (défini par -channel) de chaque pixel de la première image (u) de la séquence. Les valeurs calculées sont temporairement stockées dans une copie (clone) de cette première image jusqu'à ce que tous les pixels aient été traités, après quoi cette nouvelle image unique remplace la liste des images de la séquence d'images courante. Ainsi, dans l'exemple précédent, la version mise à jour de alpha.png remplace les deux images d'origine, alpha.png et beta.png, avant d'être enregistrée sous gamma.png.

L'image courante s est réglée sur la première image de la séquence (u), et t sur son index, 0. Les symboles i et j référencent le pixel courant en cours de traitement.

Pour une utilisation avec -format, l'échappement de valeur %[fx:] est évalué une seule fois pour chaque image de la séquence d'images courante. Lorsque chaque image de la séquence est évaluée, s et t se réfèrent successivement à l'image courante et à son index, tandis que i et j sont réglés à zéro et le canal courant est réglé sur rouge (-channel est ignoré). Un exemple :

$ magick canvas:'rgb(25%,50%,75%)' rose: -colorspace gray  \
  -format 'Red channel of NW corner of image #%[fx:t] is %[fx:s]\n' info:
Red channel of NW corner of image #0 is 0.464883
Red channel of NW corner of image #1 is 0.184582

Ici, nous utilisons les index d'image pour pivoter chaque image différemment, et nous utilisons -set avec l'index d'image pour définir un délai de pause différent sur la première image de l'animation :

magick rose: -duplicate 29 -virtual-pixel Gray -distort SRT '%[fx:360.0*t/n]' \
  -set delay '%[fx:t == 0 ? 240 : 10]' -loop 0 rose.gif

Cet exemple teste la différence entre deux images, mesurée par RMSE. Si la différence est supérieure à 0.1, il renvoie 1 ; sinon il renvoie 0 :

magick water.png reference.png -metric RMSE -compare -format "%[fx:%[distortion]>0.1]" info:

L'échappement de couleur %[pixel:] ou %[hex:] est évalué une fois par image et par canal de couleur de cette image (-channel est ignoré). Les valeurs générées sont ensuite converties en une chaîne de couleur (un nom de couleur ou une valeur de couleur hexadécimale). Les symboles i et j sont réglés à zéro, et s et t se réfèrent à chaque image courante successive et à son index.

La méthode epoch() prend une propriété date-time, par exemple :

magick rose.png -precision 16 -format '%[fx:epoch(%%[date:modify])]' info: