Color Modes - ImageMagick 圖像庫

FX 特效影像運算子

FX 特效影像運算子FX 表達式的剖析

FX 特效影像運算子 將數學表達式應用於影像的每個像素通道。 FX 表達式語言提供了一種強大且靈活的影像處理方式,允許您對影像執行各種操作和轉換。使用 FX 可以

  • 創建畫布、漸層、數學顏色映射
  • 在影像和通道之間移動顏色值
  • 平移、翻轉、鏡像、旋轉、縮放、剪切以及對影像進行一般變形
  • 將多個影像合併或合成在一起
  • 將相鄰像素進行卷積或合併
  • 生成影像度量或「指紋」

該運算子會循環處理影像中的所有像素以及每個像素的所有通道,並返回一個包含結果的新影像。表達式可以引用影像序列中的任何影像,但只會返回第一個影像的副本,並根據您的表達式進行適當的更新。

表達式可以很簡單

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

在這裡,我們將黑色轉換為深藍色影像

    black ==> navy

或者表達式可以很複雜

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

此表達式會產生原始影像的高對比度版本

    rose ==> rose-sigmoidal

表達式可以包含變數賦值。在大多数情况下,赋值可以降低表达式的复杂性,并允许执行一些其他方式无法实现的操作。例如,讓我們創建一個徑向漸層

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

上面的命令返回此影像

    radial-gradient

此 FX 表達式會將隨機雜訊添加到影像中

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

此 FX 腳本利用迴圈來創建茱莉亞集合

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

此 FX 腳本會打印前 10 個質數

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:

有關更多範例,請參閱使用 FX,特效影像運算子

-fx 選項會將任何影像序列替換為第一個影像的副本,並使用表達式的結果進行更新。如果您希望將表達式應用於序列中的每個影像,請改用 +fx

FX 表達式是在單線程中解釋的,但是,除非表達式包含 debug() 函數,否則它會在多線程中執行。

下一節將討論 FX 表達式語言。

FX 表達式的剖析

FX 表達式語言

正式的 FX 表達式語言定義如下

數字
整數、浮點數、科學記數法(需要 +/-,例如 3.81469e-06)、國際單位制數字後綴(例如 KB、Mib、GB 等)
常數
E(歐拉數)、Epsilon、Opaque、Phi(黃金比例)、Pi、QuantumRange、QuantumScale、Transparent
FX 運算子(按優先順序排列)
^(冪)、一元 -、*、/、%(模數)、+、-、<<、>>、<、<=、>、>=、+=、-=、*=、/=、%=、<<=、>>=、&=、|=、++、--、==、!=、&(位元 AND)、|(位元 OR)、&&(邏輯 AND)、||(邏輯 OR)、~(邏輯 NOT)、?:(三元條件)
陣列
影像提供由其寬度和高度限制的陣列存儲(例如 p[-1,-1].r)。影像序列表示多個陣列(例如 u.p[0,0].r、v.p[0,0].r)。存儲空間限制為 Quantum 值,例如 Q16 版本為 [0..65535],啟用 HDRI 的版本為浮點數。
數學函數
abs(), acos(), acosh(), airy(), alt(), asin(), asinh(), atan(), atanh(), atan2(), ceil(), clamp(), cos(), cosh(), debug(), drc(), erf(), exp(), floor(), gauss(), gcd(), hypot(), int(), isnan(), j0(), j1(), jinc(), ln(), log(), logtwo(), max(), min(), mod(), not(), pow(), rand(), round(), sign(), sin(), sinc(), sinh(), sqrt(), squish(), tan(), tanh(), trunc()
通道函數
定義最多 5 個像素通道
顏色名稱
紅色、青色、黑色等
顏色函數
srgb(), srgba(), rgb(), rgba(), cmyk(), cmyka(), hsl(), hsla() 等
顏色十六進制值
#ccc、#cbfed0、#b9e1cc00 等
符號
u:清單中的第一個影像
v:清單中的第二個影像
s:清單中的當前影像(對於 %[fx:],否則 = u)
t:當前影像 (s) 在清單中的索引
n:清單中的影像數量
i:欄位偏移
j:列偏移
p:要使用的像素(相對於當前像素的絕對位置或相對位置)
w:此影像的寬度
h:此影像的高度
z:通道深度
r:紅色值(來自 RGBA),特定像素或當前像素的紅色值
g:綠色
b:藍色
a:Alpha
o:不透明度
c:像素的 CMYK 顏色的青色值
y:黃色
m:洋紅色
k:黑色
all:所有通道
this:此通道
intensity:像素強度
hue:像素色調
saturation:像素飽和度
lightness:像素亮度
luma:像素亮度
page.width:頁面寬度
page.height:頁面高度
page.x:頁面 x 偏移
page.y:頁面 y 偏移
printsize.x:x 列印尺寸
printsize.y:y 列印尺寸
resolution.x:x 解析度
resolution.y:y 解析度
depth:影像深度
extent:影像範圍
minima:影像最小值
maxima:影像最大值
mean:影像平均值
median:影像中位數
standard_deviation:影像標準差
kurtosis:影像峰度
skewness:影像偏度(新增通道說明符以計算該通道的統計數據,例如 depth.r)
迭代器
do()、for()、while()
影像屬性
s.depth、s.kurtosis、s.maxima、s.mean、s.minima、s.resolution.x、s.resolution.y、s.skewness、s.standard_deviation
使用者設定
將 Fx 符號定義為使用者設定,例如
magick ... -set option:wd1 "%[fx:w/2]" -resize "%[fx:wd1-5]" ...

FX 運算式

FX 運算式可以包含以下項目的任意組合

x ^ y
指數 (xy)
( ... )
分組
x * y
乘法
x / y
除法
x % y
模數
x + y
加法
x - y
減法
x << y
左移
x >> y
右移
x < y
布林關係,如果 x < y,則傳回值 1.0,否則傳回 0.0
x <= y
布林關係,如果 x <= y,則傳回值 1.0,否則傳回 0.0
x > y
布林關係,如果 x > y,則傳回值 1.0,否則傳回 0.0
x >= y
布林關係,如果 x >= y,則傳回值 1.0,否則傳回 0.0
x == y
布林關係,如果 x == y,則傳回值 1.0,否則傳回 0.0
x != y
布林關係,如果 x != y,則傳回值 1.0,否則傳回 0.0
x & y
二進制 AND 運算
x | y
二進制 OR 運算
x && y
邏輯 AND 連接詞,如果 x > 0 且 y > 0,則傳回值 1.0,否則為 0.0
x || y
邏輯 OR 連接詞(包含),如果 x > 0 或 y > 0(或兩者皆是),則傳回值 1.0,否則為 0.0
~x
邏輯 NOT 運算子,如果 not x > 0,則傳回值 1.0,否則為 0.0
+x
單元正號,傳回 1.0*值
-x
單元負號,傳回 -1.0*值
條件式 ? 真值敘述 : 假值敘述
三元條件運算式,如果 條件式 != 0,則傳回值 真值敘述,否則為 假值敘述
x = y
賦值;單一字元變數為保留字,請改用 2 個或更多字元,僅限字母組合(例如 Xi 而不是 X1)
x ; y
敘述分隔符號
黃金比例
常數 (1.618034...)
圓周率
常數 (3.14159265359...)
自然對數的底數
常數 (2.71828...)
像素值範圍
常數最大像素值(Q8 為 255,Q16 為 65535)
像素值比例
常數 1.0/像素值範圍
強度
像素強度,其值遵守 -intensity 選項。
色相
像素色相
飽和度
像素飽和度
明度
像素明度;相當於 0.5*max(red,green,blue) + 0.5*min(red,green,blue)
亮度
像素亮度;相當於 0.212656*red + 0.715158*green + 0.072186*blue
red, green, blue
顏色名稱
#ccc, #cbfed0, #b9e1cc00
顏色十六進制值
rgb(), rgba(), cmyk(), cmyka(), hsl(), hsla()
顏色函數
s, t, u, v, n, i, j, w, h, z, r, g, b, a, o, c, y, m, k
符號
abs(x)
絕對值函數
acos(x)
反餘弦函數
acosh(x)
反雙曲餘弦函數
airy(x)
艾里函數 (最大值=1,最小值=0); airy(x)=[jinc(x)]2=[2*j1(pi*x)/(pi*x)]2
alt(x)
正負號交替函數(如果 int(x) 為偶數,則傳回 1.0,如果 int(x) 為奇數,則傳回 -1.0)
asin(x)
反正弦函數
asinh(x)
反雙曲正弦函數
atan(x)
反正切函數
atanh(x)
反雙曲正切函數
atan2(y,x)
兩個變數的反正切函數
ceil(x)
不小於參數的最小整數值
channel(...)
支援零到五個參數,例如,channel(0.1) 將第一個通道設定為 0.1,並將其他通道歸零。
clamp(x)
限制值
cos(x)
餘弦函數
cosh(x)
雙曲餘弦函數
debug(x)
印出 x(對於除錯運算式很有用)
do(敘述, 條件式)
當條件式不等於 0 時重複執行
drc(x,y)
動態範圍壓縮(拐點曲線);drc(x,y)=(x)/(y*(x-1)+1); -1<y<1
erf(x)
誤差函數
exp(x)
自然指數函數 (ex)
floor(x)
不大於參數的最大整數值
for(初始化, 條件式, 敘述)
當條件式不等於 0 時重複執行
gauss(x)
高斯函數;gauss(x)=exp(-x*x/2)/sqrt(2*pi)
gcd(x,y)
最大公因數
hypot(x,y)
x2+y2 的平方根
if(條件, 非零語句, 零語句)
根據條件解釋表達式
int(x)
最大整數函數(傳回小於或等於 x 的最大整數)
isnan(x)
如果 x 為 NAN,則傳回 1.0,否則傳回 0.0
j0(x)
x 的第一類 0 階貝索函數
j1(x)
x 的第一類 1 階貝索函數
jinc(x)
jinc 函數(最大值 = 1,最小值 = -0.1323);jinc(x)=2*j1(pi*x)/(pi**x)
ln(x)
自然對數函數
log(x)
以 10 為底的對數
logtwo(x)
以 2 為底的對數
ln(x)
自然對數
max(x, y)
xy 的最大值
min(x, y)
xy 的最小值
mod(x, y)
浮點數餘數函數
not(x)
如果 x 為零,則傳回 1.0,否則傳回 0.0
pow(x,y)
冪函數 (xy)
rand()
在區間 [0.0, 1.0) 上均勻分佈的值,週期為 2 的 128 次方減 1
round()
四捨五入至整數值,不論捨入方向
sign(x)
如果 x 小於 0.0,則傳回 -1.0,否則傳回 1.0
sin(x)
正弦函數
sinc(x)
sinc 函數(最大值 = 1,最小值 = -0.21);sinc(x)=sin(pi*x)/(pi*x)
squish(x)
squish 函數;squish(x)=1.0/(1.0+exp(-x))
sinh(x)
雙曲正弦函數
sqrt(x)
平方根函數
tan(x)
正切函數
tanh(x)
雙曲正切函數
trunc(x)
四捨五入至整數,朝向零
while(條件, 語句)
當條件式不等於 0 時重複執行
image.depth、image.kurtosis、image.maxima、image.mean、image.median、image.minima、image.resolution.x、image.resolution.y、image.skewness、image.standard_deviation
影像屬性

表達式語義包含以下規則

  • 符號不區分大小寫
  • 每個語句只有一個三元條件式(例如 x ? y : z)
  • 語句是賦值或要傳回的最終表達式
  • 賦值開始一個語句,它不是運算子
  • 單字元變數是保留的。對保留的內建函數進行賦值會引發異常;例如 r=3.0; r 會傳回「在「3.0」嘗試賦值給非 UserSymbol 的「r」」。
  • 一元運算子的優先順序低於二元運算子,也就是說,一元減號(否定)的優先順序低於冪,因此 -3^2 會被解釋為 -(3^2) = -9。使用括號來釐清您的意圖(例如 (-3)^2 = 9)。
  • 使用斜線(「/」)符號時必須小心。字元字串 1/2x 會被解釋為 (1/2)x。相反的解釋應該明確寫成 1/(2x)。同樣地,使用括號有助於釐清含義,並且應該在任何可能產生誤解的情況下使用。
  • 由於 -- 是變數遞減運算子,因此請使用括號來減去負數,例如 -4-(-5)

來源影像

符號 uv 分別表示當前影像序列中的第一個和第二個影像。通過在任何影像參考(通常為 u)後附加其索引來引用序列中的特定影像,序列開頭的索引為零。負索引從結尾開始計數。例如,u[0] 是序列中的第一個影像,u[2] 是第三個影像,u[-1] 是最後一個影像,而 u[t] 是當前影像。當前影像也可以由 s 引用。如果序列號超過序列長度,則計數會循環。因此,在 3 個影像的序列中,u[-1]u[2]u[5] 都指向同一個(第三個)影像。

舉例來說,我們透過平均第一個影像和第三個影像來形成一個影像(第二個(索引 1)影像會被忽略並捨棄)

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

預設情況下,應用 prgba 等的影像是影像列表中的當前影像 s。這等同於 u,除非在跳脫序列 %[fx:...] 中使用。

重要的是要注意第一個影像所扮演的特殊角色。這是影像序列中唯一被修改的影像,其他影像僅用於其數據。作為一個說明性範例,請考慮以下內容,並注意設定 -channel red 指示 -fx 僅修改綠色通道;紅色或藍色通道中的任何內容都不會改變。思考為什麼結果不對稱是有益的。

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

存取像素

所有顏色值都被標準化到 0.0 到 1.0 的範圍內。Alpha 通道範圍從 0.0(完全透明)到 1.0(完全不透明)。

像素會逐一處理,但可以使用由 p 表示的像素索引來指定影像的不同像素。例如,

p[-1].g      green value of pixel to the immediate left of the current pixel
p[-1,-1].r   red value of the pixel diagonally left and up from current pixel

要指定絕對位置,請使用大括號而不是方括號。

p{0,0}.r     red value of the pixel in the upper left corner of the image
p{12,34}.b   blue pixel value at column number 12, row 34 of the image

位置的整數值會擷取所參考像素的顏色,而非整數位置值則會根據當前的 -interpolate 設定傳回混合顏色。

影像邊界外的像素位置會擷取由 -virtual-pixel 選項設定決定的值。

指定 u.r 來指定當前影像的紅色通道。如果沒有指定通道限定符,則會取得當前通道。使用 mean.this 將輸出通道設定為僅輸入通道的平均值。使用 mean.all 設定輸入通道的整體平均值。

套用表達式以選擇影像通道

使用 -channel 設定來指定結果的輸出通道。如果沒有給出輸出通道,則結果會設定為除透明度通道之外的所有通道。例如,要將 alpha.png 的紅色通道替換為影像 alpha.pngbeta.png 的綠色通道的平均值,請使用

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

結果

-fx 運算子會針對序列中第一個影像 (u) 的每個像素的每個通道(由 -channel 設定)評估給定的表達式。計算出的值會暫時儲存在該第一個影像的副本(複製)中,直到所有像素都已處理完畢,之後這個新的單一影像會替換當前影像序列中的影像列表。因此,在先前的範例中,alpha.png 的更新版本會在儲存為 gamma.png 之前替換兩個原始影像 alpha.pngbeta.png

當前影像 s 設定為序列中的第一個影像 (u),而 t 設定為其索引 0。符號 ij 引用正在處理的當前像素。

當與 -format 一起使用時,值轉義符 %[fx:] 只會針對目前影像序列中的每個影像評估一次。評估序列中的每個影像時,st 會依序指向目前影像及其索引,而 ij 則設定為零,並且目前通道設定為紅色(-channel 會被忽略)。範例:

$ 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

在這裡,我們使用影像索引來 旋轉 每個影像,並使用 -set 搭配影像索引來設定動畫中第一個影像的不同 暫停延遲

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

此範例測試兩個影像之間的差異,以 RMSE 測量。如果差異大於 0.1,則傳回 1;否則傳回 0

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

顏色轉義符 %[pixel:]%[hex:] 會針對每個影像以及該影像中的每個顏色通道評估一次(-channel 會被忽略),然後將產生的值轉換為顏色字串(已命名的顏色或十六進制顏色值)。符號 ij 設定為零,而 st 則依序指向每個目前的影像及其索引。