FX 特效影像運算子 將數學表達式應用於影像的每個像素通道。 FX 表達式語言提供了一種強大且靈活的影像處理方式,允許您對影像執行各種操作和轉換。使用 FX 可以
- 創建畫布、漸層、數學顏色映射
- 在影像和通道之間移動顏色值
- 平移、翻轉、鏡像、旋轉、縮放、剪切以及對影像進行一般變形
- 將多個影像合併或合成在一起
- 將相鄰像素進行卷積或合併
- 生成影像度量或「指紋」
該運算子會循環處理影像中的所有像素以及每個像素的所有通道,並返回一個包含結果的新影像。表達式可以引用影像序列中的任何影像,但只會返回第一個影像的副本,並根據您的表達式進行適當的更新。
表達式可以很簡單
magick -size 64x64 canvas:black -channel blue -fx "1/2" fx_navy.png
在這裡,我們將黑色轉換為深藍色影像
或者表達式可以很複雜
magick rose: \ -fx "(1.0/(1.0+exp(10.0*(0.5-u)))-0.006693)*1.0092503" \ rose-sigmoidal.png
此表達式會產生原始影像的高對比度版本
表達式可以包含變數賦值。在大多数情况下,赋值可以降低表达式的复杂性,并允许执行一些其他方式无法实现的操作。例如,讓我們創建一個徑向漸層
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
上面的命令返回此影像
此 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
此 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)
- x 和 y 的最大值
- min(x, y)
- x 和 y 的最小值
- 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)。
來源影像
符號 u 與 v 分別表示當前影像序列中的第一個和第二個影像。通過在任何影像參考(通常為 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
預設情況下,應用 p、r、g、b、a 等的影像是影像列表中的當前影像 s。這等同於 u,除非在跳脫序列 %[fx:...] 中使用。
重要的是要注意第一個影像所扮演的特殊角色。這是影像序列中唯一被修改的影像,其他影像僅用於其數據。作為一個說明性範例,請考慮以下內容,並注意設定 -channel red 指示 -fx 僅修改綠色通道;紅色或藍色通道中的任何內容都不會改變。思考為什麼結果不對稱是有益的。
magick logo: -flop logo: -resize "20%" -channel green -fx "(u+v)/2" image.jpg
存取像素
所有顏色值都被標準化到 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.png 和 beta.png 的綠色通道的平均值,請使用
magick alpha.png beta.png -channel red -fx "(u.g+v.g)/2" gamma.png
結果
-fx 運算子會針對序列中第一個影像 (u) 的每個像素的每個通道(由 -channel 設定)評估給定的表達式。計算出的值會暫時儲存在該第一個影像的副本(複製)中,直到所有像素都已處理完畢,之後這個新的單一影像會替換當前影像序列中的影像列表。因此,在先前的範例中,alpha.png 的更新版本會在儲存為 gamma.png 之前替換兩個原始影像 alpha.png 和 beta.png。
當前影像 s 設定為序列中的第一個影像 (u),而 t 設定為其索引 0。符號 i 和 j 引用正在處理的當前像素。
當與 -format 一起使用時,值轉義符 %[fx:] 只會針對目前影像序列中的每個影像評估一次。評估序列中的每個影像時,s 和 t 會依序指向目前影像及其索引,而 i 和 j 則設定為零,並且目前通道設定為紅色(-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 會被忽略),然後將產生的值轉換為顏色字串(已命名的顏色或十六進制顏色值)。符號 i 和 j 設定為零,而 s 和 t 則依序指向每個目前的影像及其索引。