⚠️ Ini adalah situs terjemahan tidak resmi dan tidak berafiliasi dengan ImageMagick Studio LLC. Untuk informasi resmi, lihat halaman asli (https://imagemagick.org/fx/).

Operator gambar efek khusus FX • Anatomi ekspresi FX

Operator gambar efek khusus FX menerapkan ekspresi matematis ke setiap kanal piksel pada gambar. Bahasa ekspresi FX menyediakan cara yang ampuh dan fleksibel untuk memanipulasi gambar, sehingga Anda dapat melakukan berbagai operasi dan transformasi pada gambar Anda. Gunakan FX untuk:

  • membuat kanvas, gradien, dan colormap matematis
  • memindahkan nilai warna antara gambar dan kanal
  • mentranslasikan, membalik, mencerminkan, memutar, mengubah skala, men-shear, dan secara umum mendistorsi gambar
  • menggabungkan atau mengomposisikan beberapa gambar sekaligus
  • mengonvolusikan atau menggabungkan piksel-piksel tetangga
  • menghasilkan metrik gambar atau 'sidik jari'

Operator ini melakukan perulangan atas seluruh piksel gambar dan seluruh kanal setiap piksel, lalu mengembalikan gambar baru berisi hasilnya. Ekspresi dapat merujuk pada gambar mana pun dalam urutan gambar (image sequence), tetapi yang dikembalikan hanya salinan gambar pertama dengan pembaruan yang sesuai dengan ekspresi Anda.

Ekspresi bisa jadi sederhana:

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

Di sini, kita mengonversi gambar hitam menjadi gambar biru navy:

black ==> navy

Atau, ekspresi bisa juga rumit:

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

Ekspresi ini menghasilkan versi kontras tinggi dari gambar sumber:

rose ==> rose-sigmoidal

Ekspresi dapat menyertakan penugasan variabel (variable assignment). Penugasan, dalam banyak kasus, mengurangi kompleksitas ekspresi dan memungkinkan beberapa operasi yang mungkin tidak dapat dilakukan dengan cara lain. Sebagai contoh, mari kita buat gradien 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

Perintah di atas mengembalikan gambar berikut:

radial-gradient

Ekspresi FX ini menambahkan noise acak ke gambar:

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

Skrip FX ini menggunakan perulangan (loop) untuk membuat himpunan 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

Skrip FX ini mencetak 10 bilangan prima pertama:

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:

Untuk contoh lebih lanjut, lihat Using FX, The Special Effects Image Operator.

Opsi -fx menggantikan urutan gambar mana pun dengan klon gambar pertama yang telah diperbarui dengan hasil ekspresi. Jika Anda lebih suka menerapkan ekspresi ke setiap gambar dalam urutan tersebut, gunakan +fx sebagai gantinya.

Ekspresi FX diinterpretasikan dalam satu thread (single-thread), tetapi dieksekusi dalam banyak thread kecuali ekspresi tersebut menyertakan fungsi debug().

Bagian berikutnya membahas bahasa ekspresi FX.

Anatomi ekspresi FX

Bahasa ekspresi FX

Bahasa ekspresi FX secara formal didefinisikan di sini:

angka:
bilangan bulat, bilangan floating point, notasi ilmiah (+/- wajib, misalnya 3.81469e-06), akhiran angka Sistem Internasional (misalnya KB, Mib, GB, dll.)
konstanta:
E (bilangan Euler), Epsilon, Opaque, Phi (rasio emas), Pi, QuantumRange, QuantumScale, Transparent
operator FX (menurut urutan prioritas):
^ (pangkat), uner -, , /, % (modulo), +, -, <<, >>, <, <=, >, >=, +=, -=, =, /=, %=, <<= , >>=, &=, |=, ++, --, ==, !=, & (AND bitwise), | (OR bitwise), && (AND logis), || (OR logis), ~ (NOT logis), ?: (kondisional ternary)
array:
gambar menyediakan penyimpanan array (misalnya p[-1,-1].r) yang dibatasi oleh lebar dan tingginya. Urutan gambar merepresentasikan beberapa array (misalnya u.p[0,0].r, v.p[0,0].r). Penyimpanan dibatasi pada nilai Quantum, misalnya [0..65535] untuk build Q16 dan floating point untuk build yang mengaktifkan HDRI.
fungsi matematika:
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()
fungsi kanal:
mendefinisikan hingga 5 kanal piksel
nama warna:
red, cyan, black, dll.
fungsi warna:
srgb(), srgba(), rgb(), rgba(), cmyk(), cmyka(), hsl(), hsla(), dll.
nilai heksadesimal warna:

ccc, #cbfed0, #b9e1cc00, dll.

simbol:

u: gambar pertama dalam daftar
v: gambar kedua dalam daftar
s: gambar saat ini dalam daftar (untuk %[fx:], jika tidak = u)
t: indeks gambar saat ini (s) dalam daftar
n: jumlah gambar dalam daftar
i: offset kolom
j: offset baris
p: piksel yang digunakan (absolut atau relatif terhadap piksel saat ini)
w: lebar gambar ini
h: tinggi gambar ini
z: kedalaman kanal
r: nilai merah (dari RGBA), dari piksel tertentu atau piksel saat ini
g: hijau
b: biru
a: alpha
o: opasitas
c: nilai cyan dari warna CMYK piksel
y: kuning
m: magenta
k: hitam
all: semua kanal
this: kanal ini
intensity: intensitas piksel
hue: hue piksel
saturation: saturasi piksel
lightness: kecerahan piksel
luma: luma piksel
page.width: lebar halaman
page.height: tinggi halaman
page.x: offset x halaman
page.y: offset y halaman
printsize.x: ukuran cetak x
printsize.y: ukuran cetak y
resolution.x: resolusi x
resolution.y: resolusi y
depth: kedalaman gambar
extent: cakupan (extent) gambar
minima: minima gambar
maxima: maksima gambar
mean: rata-rata gambar
median: median gambar
standard_deviation: deviasi standar gambar
kurtosis: kurtosis gambar
skewness: skewness gambar (tambahkan penentu kanal untuk menghitung statistik kanal tersebut, misalnya depth.r)
iterator:
do(), for(), while()
atribut gambar:
s.depth, s.kurtosis, s.maxima, s.mean, s.minima, s.resolution.x, s.resolution.y, s.skewness, s.standard_deviation
pengaturan pengguna:

definisikan simbol Fx sebagai pengaturan pengguna, misalnya

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

Ekspresi FX

Ekspresi FX dapat menyertakan kombinasi apa pun dari hal-hal berikut:

x ^ y
pemangkatan (x pangkat y)
( ... )
pengelompokan
x * y
perkalian
x / y
pembagian
x % y
modulo
x + y
penjumlahan
x - y
pengurangan
x << y
pergeseran kiri
x >> y
pergeseran kanan
x < y
relasi boolean, mengembalikan nilai 1.0 jika x < y, jika tidak 0.0
x <= y
relasi boolean, mengembalikan nilai 1.0 jika x <= y, jika tidak 0.0
x > y
relasi boolean, mengembalikan nilai 1.0 jika x > y, jika tidak 0.0
x >= y
relasi boolean, mengembalikan nilai 1.0 jika x >= y, jika tidak 0.0
x == y
relasi boolean, mengembalikan nilai 1.0 jika x == y dalam batas epsilon (1e-12), jika tidak 0.0. Dua nilai dianggap sama jika selisihnya berada dalam kisaran sekitar 1e‑12.
x != y
relasi boolean, mengembalikan nilai 1.0 jika x != y dalam batas epsilon (1e-12), jika tidak 0.0
x & y
AND biner
x | y
OR biner
x && y
konektor AND logis, mengembalikan nilai 1.0 jika x > 0 dan y > 0, jika tidak 0.0
x || y
konektor OR logis (inklusif), mengembalikan nilai 1.0 jika x > 0 atau y > 0 (atau keduanya), jika tidak 0.0
~x
operator NOT logis, mengembalikan nilai 1.0 jika bukan x > 0, jika tidak 0.0
+x
plus uner, mengembalikan 1.0*nilai
-x
minus uner, mengembalikan -1.0*nilai
condition ? true-statements : false-statements
ekspresi kondisional ternary, mengembalikan true-statements jika condition != 0, jika tidak false-statements
x = y
penugasan (assignment); variabel satu karakter dicadangkan, sebagai gantinya gunakan 2 karakter atau lebih, hanya kombinasi huruf (misalnya Xi, bukan X1)
x ; y
pemisah pernyataan
phi
konstanta (1.618034...)
pi
konstanta (3.14159265359...)
e
konstanta (2.71828...)
QuantumRange
konstanta nilai piksel maksimum (255 untuk Q8, 65535 untuk Q16)
QuantumScale
konstanta 1.0/QuantumRange
intensity
intensitas piksel yang nilainya mengikuti opsi -intensity.
hue
hue piksel
saturation
saturasi piksel
lightness
kecerahan piksel; setara dengan 0.5max(red,green,blue) + 0.5min(red,green,blue)
luminance
luminans piksel; setara dengan 0.212656red + 0.715158green + 0.072186*blue
red, green, blue, etc.
nama warna

ccc, #cbfed0, #b9e1cc00, etc.

 nilai heksadesimal warna
rgb(), rgba(), cmyk(), cmyka(), hsl(), hsla()
fungsi warna
s, t, u, v, n, i, j, w, h, z, r, g, b, a, o, c, y, m, k
simbol
abs(x)
fungsi nilai absolut
acos(x)
fungsi arkus kosinus
acosh(x)
fungsi kosinus hiperbolik invers
airy(x)
Fungsi Airy (max=1, min=0); airy(x)=[jinc(x)]2=[2j1(pix)/(pi*x)]2
alt(x)
fungsi alternasi tanda (mengembalikan 1.0 jika int(x) genap, -1.0 jika int(x) ganjil)
asin(x)
fungsi arkus sinus
asinh(x)
fungsi sinus hiperbolik invers
atan(x)
fungsi arkus tangen
atanh(x)
fungsi tangen hiperbolik invers
atan2(y,x)
fungsi arkus tangen dua variabel
ceil(x)
nilai bilangan bulat terkecil yang tidak lebih kecil dari argumen
channel(...)
mendukung nol hingga lima argumen, misalnya channel(0.1) mengatur kanal pertama ke 0.1 dan menolkan kanal lainnya.
clamp(x)
membatasi nilai (clamp)
cos(x)
fungsi kosinus
cosh(x)
fungsi kosinus hiperbolik
debug(x)
mencetak x (berguna untuk men-debug ekspresi Anda)
do(statements, condition)
mengulang selama kondisi tidak sama dengan 0
drc(x,y)
kompresi rentang dinamis (kurva knee); drc(x,y)=(x)/(y*(x-1)+1); -1<y<1
epoch(date-time)
mengonversi properti date-time menjadi jumlah detik sejak epoch, 00:00:00 UTC
erf(x)
fungsi error
exp(x)
fungsi eksponensial natural (e pangkat x)
floor(x)
nilai bilangan bulat terbesar yang tidak lebih besar dari argumen
for(initialize, condition, statements)
mengulang selama kondisi tidak sama dengan 0
gauss(x)
fungsi Gauss; gauss(x)=exp(-xx/2)/sqrt(2pi)
gcd(x,y)
pembagi persekutuan terbesar (FPB) (Catatan penerjemah: naskah asli menulis "denominator", seharusnya "divisor")
hypot(x,y)
akar kuadrat dari x² + y²
if(condition, nonzero-statements, zero-statements)
mengevaluasi ekspresi bergantung pada kondisi
int(x)
fungsi bilangan bulat terbesar (mengembalikan bilangan bulat terbesar yang kurang dari atau sama dengan x)
isnan(x)
mengembalikan 1.0 jika x adalah NaN, jika tidak 0.0
j0(x)
fungsi Bessel dari x jenis pertama orde 0
j1(x)
fungsi Bessel dari x jenis pertama orde 1
jinc(x)
fungsi jinc (max=1, min=-0.1323); jinc(x)=2j1(pix)/(pi**x)
ln(x)
fungsi logaritma natural
log(x)
logaritma basis 10
logtwo(x)
logaritma basis 2
ln(x)
logaritma natural
magicktime()
waktu saat ini dalam detik sejak epoch, 00:00:00 UTC
max(x, y)
nilai maksimum dari x dan y
min(x, y)
nilai minimum dari x dan y
mod(x, y)
fungsi sisa bagi bilangan floating-point
not(x)
mengembalikan 1.0 jika x nol, jika tidak 0.0
pow(x,y)
fungsi pangkat (x pangkat y)
rand()
nilai yang terdistribusi merata pada interval [0.0, 1.0) dengan periode 2 pangkat 128 dikurangi 1
round()
membulatkan ke nilai bilangan bulat, terlepas dari arah pembulatan
sign(x)
mengembalikan -1.0 jika x kurang dari 0.0, jika tidak 1.0
sin(x)
fungsi sinus
sinc(x)
fungsi sinc (max=1, min=-0.21); sinc(x)=sin(pix)/(pix)
squish(x)
fungsi squish; squish(x)=1.0/(1.0+exp(-x))
sinh(x)
fungsi sinus hiperbolik
sqrt(x)
fungsi akar kuadrat
tan(x)
fungsi tangen
tanh(x)
fungsi tangen hiperbolik
trunc(x)
membulatkan ke bilangan bulat, ke arah nol
while(condition, statements)
mengulang selama kondisi tidak sama dengan 0
image.depth, image.kurtosis, image.maxima, image.mean, image.median, image.minima, image.resolution.x, image.resolution.y, image.skewness, image.standard_deviation
atribut gambar

Semantik ekspresi mencakup aturan-aturan berikut:

  • simbol tidak peka huruf besar/kecil (case insensitive)
  • hanya boleh ada satu kondisional ternary (misalnya x ? y : z) per pernyataan
  • pernyataan berupa penugasan (assignment) atau ekspresi akhir yang dikembalikan
  • penugasan memulai sebuah pernyataan; ini bukan operator
  • variabel satu karakter dicadangkan. Penugasan ke built-in yang dicadangkan akan memicu exception; misalnya r=3.0; r mengembalikan Attempted assignment to non-UserSymbol 'r' at '3.0'.
  • operator uner memiliki prioritas lebih rendah daripada operator biner; artinya, minus uner (negasi) memiliki prioritas lebih rendah daripada pemangkatan, sehingga -3^2 ditafsirkan sebagai -(3^2) = -9. Gunakan tanda kurung untuk memperjelas maksud Anda (misalnya (-3)^2 = 9).
  • berhati-hatilah saat menggunakan simbol garis miring ('/'). Rangkaian karakter 1/2x ditafsirkan sebagai (1/2)x. Penafsiran sebaliknya harus ditulis secara eksplisit sebagai 1/(2x). Sekali lagi, penggunaan tanda kurung membantu memperjelas maksud dan sebaiknya digunakan setiap ada kemungkinan salah tafsir.
  • Karena -- adalah operator dekremen variabel, gunakan tanda kurung untuk mengurangkan bilangan negatif, misalnya -4-(-5).

Gambar sumber

Simbol u dan v masing-masing merujuk pada gambar pertama dan kedua dalam urutan gambar saat ini. Untuk merujuk pada gambar tertentu dalam urutan, tambahkan indeksnya ke referensi gambar mana pun (biasanya u), dengan indeks nol untuk awal urutan. Indeks negatif dihitung dari akhir. Misalnya, u[0] adalah gambar pertama dalam urutan, u[2] adalah yang ketiga, u[-1] adalah gambar terakhir, dan u[t] adalah gambar saat ini. Gambar saat ini juga dapat dirujuk dengan s. Jika nomor urutan melebihi panjang urutan, hitungannya akan berputar kembali (wrap around). Jadi dalam urutan 3 gambar, u[-1], u[2], dan u[5] semuanya merujuk ke gambar yang sama (yang ketiga).

Sebagai contoh, kita membentuk gambar dengan merata-ratakan gambar pertama dan gambar ketiga (gambar kedua (indeks 1) diabaikan dan dibuang begitu saja):

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

Secara default, gambar tempat p, r, g, b, a, dll. diterapkan adalah gambar saat ini s dalam daftar gambar. Ini setara dengan u, kecuali saat digunakan dalam escape sequence %[fx:...].

Penting untuk dicatat peran khusus yang dimainkan oleh gambar pertama. Ini adalah satu-satunya gambar dalam urutan gambar yang dimodifikasi; gambar lainnya hanya digunakan untuk datanya. Sebagai contoh ilustratif, perhatikan berikut ini, dan perhatikan bahwa pengaturan -channel red menginstruksikan -fx untuk hanya memodifikasi kanal hijau; tidak ada perubahan pada kanal merah atau biru. Ada baiknya merenungkan mengapa hasilnya tidak simetris.

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

Mengakses piksel

Semua nilai warna dinormalisasi ke rentang 0.0 hingga 1.0. Kanal alpha berkisar dari 0.0 (sepenuhnya transparan) hingga 1.0 (sepenuhnya opak).

Piksel diproses satu per satu, tetapi piksel lain pada gambar dapat ditentukan menggunakan indeks piksel yang direpresentasikan oleh p. Misalnya,

p[-1].g      nilai hijau piksel yang tepat di sebelah kiri piksel saat ini
p[-1,-1].r   nilai merah piksel yang berada secara diagonal kiri-atas dari piksel saat ini

Untuk menentukan posisi absolut, gunakan kurung kurawal, bukan kurung siku.

p{0,0}.r     nilai merah piksel di pojok kiri atas gambar
p{12,34}.b   nilai piksel biru pada kolom nomor 12, baris 34 gambar

Nilai posisi berupa bilangan bulat mengambil warna piksel yang dirujuk, sedangkan nilai posisi non-bilangan-bulat mengembalikan warna yang dicampur (blended) sesuai pengaturan -interpolate saat ini.

Posisi di luar batas gambar mengambil nilai yang ditentukan oleh pengaturan opsi -virtual-pixel.

Tentukan u.r untuk menentukan kanal merah gambar saat ini. Jika Anda tidak menentukan penentu (qualifier) kanal, Anda akan mendapatkan kanal saat ini. Gunakan mean.this untuk mengatur kanal output menjadi rata-rata kanal input itu sendiri. Gunakan mean.all untuk mengatur rata-rata keseluruhan kanal input.

Menerapkan ekspresi ke kanal gambar terpilih

Gunakan pengaturan -channel untuk menentukan kanal output dari hasilnya. Jika tidak ada kanal output yang diberikan, hasilnya diterapkan pada semua kanal kecuali kanal opasitas. Misalnya, untuk mengganti kanal merah alpha.png dengan rata-rata kanal hijau dari gambar alpha.png dan beta.png, gunakan:

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

Hasil

Operator -fx mengevaluasi ekspresi yang diberikan untuk setiap kanal (diatur oleh -channel) dari setiap piksel pada gambar pertama (u) dalam urutan tersebut. Nilai yang dihitung disimpan sementara dalam salinan (klon) gambar pertama tersebut hingga semua piksel selesai diproses, setelah itu satu gambar baru ini menggantikan daftar gambar dalam urutan gambar saat ini. Dengan demikian, pada contoh sebelumnya, versi terbaru alpha.png menggantikan kedua gambar asli, alpha.png dan beta.png, sebelum disimpan sebagai gamma.png.

Gambar saat ini s diatur ke gambar pertama dalam urutan (u), dan t ke indeksnya, 0. Simbol i dan j merujuk pada piksel yang sedang diproses.

Untuk digunakan dengan -format, escape nilai %[fx:] dievaluasi hanya satu kali untuk setiap gambar dalam urutan gambar saat ini. Saat setiap gambar dalam urutan tersebut dievaluasi, s dan t secara berturut-turut merujuk pada gambar saat ini dan indeksnya, sedangkan i dan j diatur ke nol, dan kanal saat ini diatur ke merah (-channel diabaikan). Contoh:

$ 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

Di sini kita menggunakan indeks gambar untuk memutar setiap gambar secara berbeda, dan menggunakan -set dengan indeks gambar untuk mengatur delay yang berbeda pada gambar pertama dalam animasi:

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

Contoh ini menguji perbedaan antara dua gambar, diukur dengan RMSE. Jika perbedaannya lebih besar dari 0.1, ekspresi ini mengembalikan 1; jika tidak, mengembalikan 0:

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

Escape warna %[pixel:] atau %[hex:] dievaluasi satu kali per gambar dan per kanal warna dalam gambar tersebut (-channel diabaikan). Nilai yang dihasilkan kemudian dikonversi menjadi string warna (nama warna atau nilai warna heksadesimal). Simbol i dan j diatur ke nol, dan s serta t masing-masing merujuk pada gambar dan indeks saat ini secara berurutan.

Metode epoch() menerima properti date-time, misalnya:

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