ImageMagick 範例 --
多圖層

索引
ImageMagick 範例 前言和索引
圖層介紹
圖像附加 (-append)
多對圖像的合成
多圖層
圖層範例

評估序列多圖像合併
平均值、  最小值/最大值、  中位數像素、  加法、  乘法
多項式 - 使用多項式合併多個圖像
將多個圖像疊加在一起以生成更大的「合成圖像」,通常稱為使用圖像「分層」。這些範例涉及組合多個圖像「圖層」以產生最終更大、更複雜的圖像。

圖像分層介紹

如前所述,ImageMagick 處理的不是單個圖像,而是一個圖像序列或列表。這使您可以使用 IM 進行兩種非常特殊的圖像處理技術。例如,您可以將列表中的每個圖像視為時間上的一幀,這樣整個列表就可以被視為一個「動畫」。這將在其他 IM 範例頁面中進行探討。請參閱動畫基礎。或者,您可以將序列中的每個圖像視為一組透明膠片的「圖層」。也就是說,每個圖像代表最終圖像的一小部分。例如:第一個(最底層)圖層可以代表背景圖像。在其上方,您可以放置一個模糊的透明陰影。然後,下一個圖層圖像包含投射該陰影的對象。在此之上是一個圖層,其中包含寫在該對象上的一些文字。也就是說,您可以擁有一系列圖像或「圖層」,每個圖層都為更複雜的圖像添加了一部分。每個圖像圖層都可以與任何其他圖層完全獨立地移動、編輯或修改,甚至可以保存到多圖像文件(例如 TIFF:、MIFF: 或 XCF:)或單獨的圖像中,以供將來處理。這就是圖像分層的重點。只有在創建了所有圖像圖層之後,您才能平面化拼接合併所有分層圖像到一個最終圖像中。

附加圖像

在處理多張圖片時,附加可能是 ImageMagick 所提供多圖像操作中最簡單的。基本上,它將記憶體中的當前圖像序列按列或按行無縫連接起來。「-append」選項垂直附加,而加號形式「+append」則水平附加。例如,這裡我們將一組字母圖像並排附加在一起,形成一個精美的單詞,類似於「字體」中的單個「字形」或字母的連接方式。

  magick font_A.gif font_P.gif font_P.gif font_E.gif font_N.gif \
          font_D.gif font_E.gif font_D.gif +append  append_row.gif
[IM Output]
以上與字體的處理方式類似(以非常基本的方式)。與真實字體不同,您不僅限於兩種顏色,而是可以使用單個字符圖像生成一些非常精美的彩色字母。許多此類「圖像字體」都可以在網路上免費下載。您可以在 Anthony 的圖標庫 中找到一小部分,在 文字和計數器字體 中,這也是我找到上面 藍色泡泡字體 的地方。另請注意「+append」運算符是如何在所有要附加的圖像都添加到當前圖像序列之後作為最後一個操作完成的。例如,這非常適合將標籤附加到圖像...

  magick rose: -background LawnGreen label:Rose \
          -background white  -append append_label.jpg
[IM Output]
請注意,使用「-background」顏色來填充任何未填充的空間。當然,如果所有圖像的寬度都相同,則不會為此填充留下任何空間。從 IM v6.4.7-1 開始,可以使用「-gravity」設置來指定圖像的添加方式。因此,在垂直附加中,設置為「Center」會將圖像相對於最終生成的圖像居中(設置為「North」或「South」也是如此)。

  magick rose: -background LawnGreen label:Rose \
          -background white -gravity center -append \
          append_center.jpg
[IM Output]
自然,任何「East」重力設置都將圖像對齊到右側。

  magick rose: -background LawnGreen label:Rose \
          -background white -gravity east -append \
          append_east.jpg
[IM Output]
使用「+append」時,可以實現類似的垂直對齊。
在 IM v6.4.7 之前,對齊附加的圖像要困難得多,並且通常需要使用「-flop」進行右對齊。或者使用「-extent」或「-border」調整圖像寬度以進行居中對齊的附加。

例如,這適用於舊版本的 6.3.2 IM...

  magick rose: -background SkyBlue label:Rose \
          -background White -gravity center -extent 200x \
          -append -trim +repage   append_center_old.jpg
[IM Output]
您還可以在同一個命令中使用多個附加操作,而不會產生衝突或混淆操作的結果(這在 IM v6 之前並非如此)。

  magick font_{0,0,6,1,2}.gif +append  dragon_long.gif \
          -background none   -append   append_multi.gif
[IM Output]
我們將每一行圖像附加在一起,然後在下面附加一個更大的圖像。這非常簡單直接。通過使用 括號,您可以僅附加較大圖像後面的數字。例如,這裡先將所有數字附加在一起,然後再將它們垂直附加到我們之前讀取的龍圖像中。

  magick dragon_long.gif  '(' font_{0,0,6,2,9}.gif +append ')' \
          -background none   -append   append_parenthesis.gif
[IM Output]
在 UNIX shell 中使用時,上面括號中的內容必須用引號引起來,或者使用反斜杠('\')進行轉義,否則它們將被 shell 解釋為完全不同的內容。
由於只涉及兩個圖像,我們可以只使用「+swap」或「-reverse」,而不是使用括號。

附加圖像陣列

您可以進一步使用它來製作一整組圖像,並按行或按列構建它們。

  magick \( font_1.gif font_2.gif font_3.gif +append \) \
          \( font_4.gif font_5.gif font_6.gif +append \) \
          \( font_7.gif font_8.gif font_9.gif +append \) \
          \( -size 32x32 xc:none  font_0.gif +append \) \
          -background none -append   append_array.gif
[IM Output]
從技術上講,第一組括號不是必需的,因為尚未讀取任何圖像,但它使整個內容看起來一致,並顯示了命令的意圖,即創建圖像陣列。另請參閱蒙太奇拼接模式,了解創建大小相等的圖像陣列的另一種方法。
-append”運算符只會附加實際圖像,而不會使用虛擬畫布(圖像頁面)大小或圖像偏移量。但是,虛擬畫布信息似乎處於一種奇怪的狀態,畫布大小被加在一起,偏移量被設置為一些未定義的值。

這可能被視為一個錯誤,這意味著在保存之前,或者在這些信息可能變得重要的操作中使用圖像之前,應該使用“+repage”重置輸入圖像或結果圖像的虛擬畫布。

這種情況可能會在將來對操作的某些擴展中得到修復。因此建議謹慎行事,尤其是在重新附加平鋪裁剪的圖像時。

重疊附加

在 IM 論壇上,一位用戶要求提供一種簡單的方法來附加具有某些重疊區域的圖像。提供了許多解決方案。這是最簡單的解決方案之一,重疊量在單一位置給出。

  magick granite: rose: -gravity east -background none \
          \( -clone 1 -chop 30x0 \) \( -clone 0,2 +append \) \
          -delete 0,2 +swap -composite append_overlap.gif
[IM Output]
以上不需要任何通常涉及圖像大小的圖像定位計算,這將代表一個更通用的解決方案。請參閱下面的處理圖像圖層。這裡所做的就是在附加到第一張圖像之前切掉重疊的部分,生成最終的圖像大小。然後將原始圖像(帶有重力)組合在頂部以生成實際的重疊區域。它可以很容易地修改為垂直重疊,甚至相對容易地修改為從右到左的重疊。

壓縮附加

附加圖像的另一種方法是壓縮。“-smush”運算符的工作方式與附加運算符(見上文)非常相似,但它需要一個參數,即您希望圖像之間有多少空間(或反空間)。例如,讓我們用它來更簡單地說明前面的例子。

  magick granite: rose: -background none -gravity Center \
          +smush -20 smush_overlap.png
[IM Output]
這很有效,儘管這不是運算符實際設計的目的,而且它可能會慢很多。smush 實際上要做的是盡可能地將“形狀圖像”移動到一起。例如,在這裡,我生成了字母“A”和“V”,並將它們“壓縮”在一起,它們之間的空間盡可能小。

  magick -background none -pointsize 72 \
          -fill red label:A -fill blue label:V \
          +smush 0 smush_append.png
[IM Output]
請注意,這兩個字母是如何比 append 更緊密地附加在一起的,利用了圖像“形狀”的空白區域。上面間隙是由兩個字母的抗鋸齒邊緣像素造成的。也就是說,“-smush”的設計目的,儘管它需要大量的計算,所以比附加(見上文)慢很多。參數是最終位置的偏移量,通常是一個正值來生成間隙,但也可以是負值來創建重疊。

  magick -background none -pointsize 72 \
          -fill red label:A -fill blue label:V \
          +smush -15 smush_offset.png
[IM Output]
如果使用非常大的負值,則圖像可能會以未記錄的方式被裁剪。

多對圖像的合成

合成是低級操作,用於將兩張單獨的圖像合併在一起。幾乎所有的分層技術最終都會分解為一次合併兩張圖像,直到只剩下最後一張圖像。因此,讓我們先來看看執行圖像對的低級合成的方法。

使用合成命令

使用 ImageMagick 將兩個影像合併在一起的傳統方法是透過「magick composite」指令。這個指令一次只能合併兩個影像,並將每次操作的結果儲存到一個檔案中。當然,這並不妨礙您使用它來一層一層地疊加多個影像…

  magick -size 100x100 xc:skyblue composite.gif
  magick composite -geometry  +5+10 balloon.gif composite.gif composite.gif
  magick composite -geometry +35+30 medical.gif composite.gif composite.gif
  magick composite -geometry +62+50 present.gif composite.gif composite.gif
  magick composite -geometry +10+55 shading.gif composite.gif composite.gif
[IM Output]
由於所有輸入影像都會在開啟輸出影像「之前」由 ImageMagick 讀入,因此您可以將輸出結果寫入其中一個輸入影像。這讓您可以在同一個影像上反覆操作(如上所示),而不會出現問題。

請勿對「JPEG」等失真影像格式執行此操作,因為格式錯誤會累積,並且基礎影像會快速降級。
您也可以使用「-geometry」設定調整重疊影像的大小和位置。

  magick -size 100x100 xc:skyblue comp_resize.gif
  magick composite -geometry 40x40+5+10  balloon.gif comp_resize.gif comp_resize.gif
  magick composite -geometry      +35+30 medical.gif comp_resize.gif comp_resize.gif
  magick composite -geometry 24x24+62+50 present.gif comp_resize.gif comp_resize.gif
  magick composite -geometry 16x16+10+55 shading.gif comp_resize.gif comp_resize.gif
[IM Output]
magick composite」指令還有其他一些優點,您可以使用「-compose」選項控制影像繪製到背景的方式,並透過「-gravity」設定影響其相對位置。您也可以「-tile」重疊影像,使其只覆蓋背景影像,而無需指定拼貼限制。這是只有在使用「magick composite」時才可用的功能。這種方法的最大缺點是您需要使用多個指令,並且 IM 必須將工作影像寫入管道或磁碟,以便下一個指令再次讀入。如需更多使用「magick composite」指令將影像重疊在其他影像上的範例,請參閱「透過重疊影像進行註釋」和「使用重力定位影像」。

轉換的合成運算子

-composite」運算子可在「magick」指令中使用。如需更多詳細資訊,請參閱IM 中的影像合成。這讓您可以在一個指令中完成上述所有操作。

  magick -size 100x100 xc:skyblue \
          balloon.gif  -geometry  +5+10  -composite \
          medical.gif  -geometry +35+30  -composite \
          present.gif  -geometry +62+50  -composite \
          shading.gif  -geometry +10+55  -composite \
          compose.gif
[IM Output]
這首先會建立一個顏色為「skyblue」的畫布影像,然後將後續每個影像都疊加到畫布上的指定位置。現在,「-geometry」是一個非常特殊的運算子,它不僅為下一個「-composite」操作設定重疊位置,還會「-resize」目前影像序列中的「最後一個」影像(且僅限最後一個影像)。

  magick -size 100x100 xc:skyblue \
          balloon.gif  -geometry 40x40+5+10   -composite \
          medical.gif  -geometry      +35+30  -composite \
          present.gif  -geometry 24x24+62+50  -composite \
          shading.gif  -geometry 16x16+10+55  -composite \
          compose_geometry.gif
[IM Output]
請注意,建議您避免使用「-geometry」的這種「調整大小」副作用,即使它很方便。基本上,因為它更像是一種向後相容的效果,並且在某些情況下可能會產生其他效果。以下是更詳細的建議…

  magick -size 100x100 xc:skyblue \
          \( balloon.gif -resize 40x40 \) -geometry +5+10   -composite \
          \( medical.gif               \) -geometry +35+30  -composite \
          \( present.gif -resize 24x24 \) -geometry +62+50  -composite \
          \( shading.gif -resize 16x16 \) -geometry +10+55  -composite \
          compose_resize.gif
[IM Output]

繪製多個影像

同樣地,使用「magick」,您也可以使用繪製基本圖形將影像重疊到其工作畫布上。

  magick -size 100x100 xc:skyblue \
          -draw "image over  5,10 0,0 'balloon.gif'" \
          -draw "image over 35,30 0,0 'medical.gif'" \
          -draw "image over 62,50 0,0 'present.gif'" \
          -draw "image over 10,55 0,0 'shading.gif'" \
          drawn.gif
[IM Output]
當然,您也可以為重疊影像指定大小…

  magick -size 100x100 xc:skyblue \
          -draw "image over  5,10 40,40 'balloon.gif'" \
          -draw "image over 35,30  0,0  'medical.gif'" \
          -draw "image over 62,50 24,24 'present.gif'" \
          -draw "image over 10,55 16,16 'shading.gif'" \
          drawn_resize.gif
[IM Output]
「繪製的」影像也可以在重疊過程中旋轉、縮放和仿射扭曲。雖然這可能很難讓它按照您想要的方式運作。繪製的影像會受到「-gravity」的影響,就像文字一樣。

疊加多個影像

要將多個影像真正地分層需要使用特定的方法,以便將其合併在一起,而不需要分別組合每一對影像。這就是各種 -layers 運算子方法發揮作用的地方。分層影像的順序可能很重要,因此瞭解特殊的 影像序列或清單運算子 會很有幫助。請注意,「分層影像」實際上與處理「動畫影格」相同。因此,建議您也查看 動畫基礎動畫修改,以瞭解涉及處理個別「圖層」或「影格」的技術。實際上,動畫通常使用相同的 -layers 運算子來處理影像。

平面化 - 到背景圖像上

-layers flatten」影像清單運算子(或其捷徑「-flatten」)基本上會將每個給定的影像「合成」到背景上,形成單一影像。但是,影像位置是使用其目前的 虛擬畫布或頁面 位移來指定的。例如,我在這裡建立了一個漂亮的畫布,並指定了要疊加到該畫布上的每個影像。

  magick -size 100x100 xc:skyblue \
          -fill dodgerblue -draw 'circle 50,50 15,25' \
          \( -page +5+10  balloon.gif \)   \( -page +35+30 medical.gif \)  \
          \( -page +62+50 present.gif \)   \( -page +10+55 shading.gif \)  \
          -layers flatten  flatten_canvas.gif
[IM Output]
從 IM v6.3.6-2 開始,「-flatten」運算子只是「-layers 'flatten'」方法的別名。

因此,「-flatten」選項可以視為同名「-layers」方法的捷徑。
您不需要像上面那樣建立初始畫布,您可以讓「-flatten」為您建立一個。畫布顏色將是目前的「-background」顏色,而其大小由第一個影像的 虛擬畫布 大小定義。

  magick \( -page 100x100+5+10  balloon.gif \)   \( -page +35+30 medical.gif \)  \
          \( --page +62+50        present.gif \)   \( -page +10+55 shading.gif \)  \
          -background dodgerblue  -layers flatten  flatten_page.gif
[IM Output]
雖然「-gravity」設定會影響使用「-geometry」設定定義的影像位置,但不會影響使用透過「-page」設定設定的 虛擬畫布位移 的影像定位。這是此類位移定義的一部分。有關更多詳細資訊,請參閱 幾何與頁面位移

如果需要使用「-gravity」進行放置,請查看上述多影像合成方法,或特殊的 圖層合成 方法,該方法可以同時處理兩種定位方法。
如果任何影像沒有出現在定義的虛擬畫布區域中,則將根據需要剪裁或忽略它。例如,在這裡我們使用了較小的畫布尺寸,導致後面的影像沒有完全出現在該畫布上。

  magick \( -page 75x75+5+10  balloon.gif \)   \( -page +35+30 medical.gif \)  \
          \( -page +62+50 present.gif \)   \( -page +10+55 shading.gif \)  \
          -background dodgerblue  -flatten  flatten_bounds.gif
[IM Output]
Flatten 的一般用途是將多個影像「圖層」合併在一起。也就是說,您可以產生較大影像的各個部分,通常使用 括號 將影像運算子限制為正在產生的單一「圖層」影像,然後將最終結果拼合在一起。例如,一種典型用途是建立 陰影影像 圖層,並將原始影像拼合到該圖層上。例如...

  magick balloon.gif \( +clone  -background navy  -shadow 80x3+5+5 \) +swap \
          -background none   -flatten   flatten_shadow.png
[IM Output]
請注意,因為我希望陰影位於原始影像下方,所以我需要 交換 兩個影像的位置,將它們按正確的順序放置。
不建議使用 Flatten 來新增產生的 陰影影像,因為產生的陰影影像可能會有負影像位移。

陰影圖像章節中所述,推薦的解決方案是使用更進階的圖層合併技術,我們稍後會看到。
由於虛擬畫布僅包含尺寸信息,因此生成的圖像將具有該尺寸,但沒有虛擬畫布偏移,因此您無需擔心最終圖像中存在的任何偏移。這種使用虛擬畫布來定義要疊加圖像的畫布的方法意味著您可以使用它向圖像添加周圍邊框。例如,這裡我設置圖像的尺寸和虛擬偏移量以將圖像“填充”到特定尺寸。

  magick medical.gif -set page 64x64+20+20 \
          -background SkyBlue   -flatten   flatten_padding.gif
[IM Output]
當然,還有更好的方法來填充圖像,以便 IM 自動將圖像置於較大區域的中心。
奇怪的是,可以使用完全相同的處理方式將圖像“剪裁”或裁剪到小於原始圖像的虛擬畫布上。但是,在這種情況下,您需要使用負偏移量來定位“裁剪”位置,因為您要偏移圖像而不是定位裁剪“窗口”。

  magick logo:  -repage 100x100-190-60  -flatten  flatten_crop.gif
[IM Output]
當然,視口裁剪也能更好地做到這一點,而無需“-flatten”那樣進行畫布生成和疊加的額外處理。如果圖像僅部分包含在該視口中,它也不會“擴展”圖像本身以覆蓋整個視口。 “-flatten”運算符的一個常見誤用是移除圖像中的透明度。也就是說,擺脫圖像可能具有的任何透明度,但將其疊加在背景顏色上。但是,當涉及多個圖像時,這將不起作用,因此不再推薦使用。

馬賽克 - 畫布擴展

-layers mosaic”運算符(或其“-mosaic”快捷方式)更像是Flatten 運算符的擴展畫布版本。 Mosaic 運算符不是僅基於初始圖像的畫布大小創建初始畫布,而是創建一個足以容納所有圖像(僅在正方向)的畫布。例如,在這裡我什至沒有設置適當的虛擬畫布,但是“-mosaic”運算符將計算出容納所有圖像層所需的畫布大小。

  magick \( -page +5+10  balloon.gif \)   \( -page +35+30 medical.gif \)  \
          \( -page +62+50 present.gif \)   \( -page +10+55 shading.gif \)  \
          -background dodgerblue  -layers mosaic  mosaic.gif
[IM Output]
在 IM v6.3.6-2 上,“-mosaic”運算符只是“-layers 'mosaic'”的別名。

因此,“-mosaic”選項可以被視為同名“-layers”方法的快捷方式。
請注意,“-mosaic”和“-flatten”仍然會創建一個從“原點”或 0,0 像素開始的畫布。這是圖像“虛擬畫布”或“頁面”定義的一部分,因此您可以確定兩個運算符的最終圖像都沒有虛擬偏移,並且整個畫布將根據實際像素數據完全定義。另請注意,“-mosaic”只會在正方向(底部或右邊緣)擴展畫布,因為頂部和左邊緣固定在虛擬原點。當然,這意味著“-mosaic”仍然會剪切具有負偏移量的圖像……

  magick \( -page -5-10  balloon.gif \)   \( -page +35+30 medical.gif \)  \
          \( -page +62+50 present.gif \)   \( -page +10+55 shading.gif \)  \
          -background dodgerblue  -mosaic  mosaic_clip.gif
[IM Output]

合併 - 建立新的圖層圖像

-layers merge」運算子的功能幾乎與前述運算子相同,並於 IM v6.3.6-2 中加入。它只會建立一個畫布影像,其大小剛好足以容納所有指定影像及其各自的偏移量。如同 Mosaic 也會擴展畫布,但不僅限於正方向,也會擴展至負方向。基本上,這表示您在合併圖層影像時,不需要擔心裁剪、偏移或其他問題。所有影像都會根據彼此的位置進行合併。輸出結果不包含或確保原點是擴展畫布的一部分。因此,Layers Merge 的輸出可能包含「圖層偏移」,可以是正值或負值。換句話說... Layers Merge 會合併圖層影像以產生新的「圖層影像」。因此,如果您不希望在完成時出現偏移,您可能需要在最終儲存之前包含「+repage」運算子。例如,以下是我們先前使用過的同一組圖層影像...

  magick \( -page +5+10  balloon.gif \)   \( -page +35+30 medical.gif \)  \
          \( -page +62+50 present.gif \)   \( -page +10+55 shading.gif \)  \
          -background dodgerblue  -layers merge  +repage layers_merge.gif
[IM Output]
如您所見,影像的大小僅足以容納所有彼此相對放置的影像,同時我捨棄了相對於虛擬畫布原點產生的影像偏移。這種保留相對位置而不裁剪或產生不必要的額外空間,正是這個變體如此強大的原因。讓我們再試一次,給其中一張影像一個負偏移量...

  magick \( -page -5-10  balloon.gif \)   \( -page +35+30 medical.gif \)  \
          \( -page +62+50 present.gif \)   \( -page +10+55 shading.gif \)  \
          -background dodgerblue  -layers merge  +repage layers_merge_2.gif
[IM Output]
如您所見,「氣球」沒有被裁剪,只是為了保持與其他影像的相對距離而移得更遠。當然,上述範例中的「+repage」運算子會移除最終影像中的絕對虛擬畫布偏移量,只保留影像之間的相對位置。移除偏移量是因為網路瀏覽器通常無法處理影像偏移量,尤其是負的影像偏移量,除非是 GIF 動畫的一部分。但如果我沒有移除該偏移量,則所有影像都將保留在產生的單一圖層影像中虛擬畫布上的正確位置,讓您能夠繼續處理並將更多影像新增至合併的影像中。通常,您會使用「-background」顏色「None」,使合併影像中未使用的區域變成透明。當套用至單一影像時,「圖層合併」會以純色背景取代影像中的任何透明度,但會保留影像的原始大小,以及該影像中的任何偏移量。不過,影像的虛擬畫布大小可能會調整為「最適合」該影像的大小和偏移量。此運算子的最初目的是讓使用者更容易將多個變形影像合併成一個統一的整體,而無需理會個別影像的偏移量。例如,當對齊照片以形成更大的「全景」時。您可以簡單地從一個沒有變形的中心基礎影像(沒有偏移量)開始,並使用此運算子將其他已對齊並變形以符合該中心影像的影像(使用負或正偏移量)覆蓋在該基礎影像周圍。有關使用此運算子變形影像以對齊共同控制點的其他範例,請參閱 3D 等角照片立方體3D 透視方塊。其他使用此運算子的範例是產生一系列簡單的 重疊照片
The operation "-layers trim-bounds" can be used to ensure all
images get a positive offset on a minimal canvas size, while retaining there
relative positions, and without actually layer merging the images into one
final image.

This lets you then perform further processing of the images before they are
actually merged, such as placing more images relative to the that image group
but looking up the resulting virtual canvas bounds.

However if images have a transparency, it is probably a good idea to trim
that transparency from images first, making the ideal usage...

  -alpha set -bordercolor none -border 1x1 -trim -layers trim-bounds

This minimizes the image layers including any and all transparent areas of
actual image data, while ensuring everything is contained on a valid
virtual (positive) canvas of minimal size.

接合合成 - 漸進式分層

-layers coalesce」影像運算子(或其「-coalesce」捷徑)實際上是設計用於將 GIF 動畫轉換為一系列影像。如需範例,請參閱 合併動畫 以取得詳細資訊。但是,它與「-flatten」密切相關,並且在這方面對多層影像非常有用。
例如,對單個圖像使用合併圖層 (Coalesce)與使用平面化 (Flatten)並將 "-background" 顏色設定為 'None' 或 'Transparency' 的效果完全相同。也就是說,它將使用透明像素「填充」圖像的畫布。

  magick \( -page 100x100+5+10 balloon.gif \) -layers coalesce  coalesce_canvas.gif
[IM Output]
處理由多個圖層組成的圖像時,可以使用合併圖層 (Coalesce)來生成圖像的「漸進式分層」。但為此,我們需要採取一些預防措施,以禁用操作員對「GIF 動畫」的任何處理。

   magick \( -page 100x100+5+10 balloon.gif \)   \( -page +35+30 medical.gif \)  \
           \( --page +62+50       present.gif \)   \( -page +10+55 shading.gif \)  \
           -set dispose None  -coalesce  miff:- |\
     montage - -frame 4 -tile x1 -geometry +2+2 \
             -background none -bordercolor none  coalesce_none.gif
[IM Output]
在上面的例子中,我們將所有「-dispose」設定「-set」為 '無 (None)'。這實際上是告訴「-coalesce」只需將每一幀疊加在先前疊加結果的頂部。結果是第一個圖像只是圖像畫布的「填充」,背景透明。下一個圖像是在前一個圖像上疊加該圖層的結果,依此類推。圖像序列的「漸進式」平面化。因此,序列中的最後一個圖像將與您使用透明背景進行正常「-flatten」操作的結果相同。如果您使用了「-dispose」設定 '背景 (Background)',則會得到完全不同的效果。在這種情況下,「-coalesce」將僅「填充」每個圖像的畫布,就好像它們是完全獨立的圖像一樣!

  magick \( -page 100x100+5+10 balloon.gif \)   \( -page +35+30 medical.gif \)  \
          \( --page +62+50       present.gif \)   \( -page +10+55 shading.gif \)  \
          -set dispose Background  -coalesce  miff:- |\
    montage - -frame 4 -tile x1 -geometry +2+2 \
            -background none -bordercolor none  coalesce_bgnd.gif
[IM Output]
但請注意,與平面化 (Flatten)馬賽克 (Mosaic)合併 (Merge)不同,「-coalesce」操作員*不會*使用目前的「-compose」Alpha 合成設定。它僅使用「覆蓋 (Over)」合成方法,因為這是 GIF 動畫處理所必需的。將不同的「-compose」方法與更標準的圖像分層操作員一起使用是下一組範例的主題。

合成方法和分層

三種分層 (Layering)方法:平面化 (Flatten)馬賽克 (Mosaic)合併 (Merge);將使用「-compose」設定來決定用於依序疊加每個圖像的合成方法。因此,您可以將這些函數視為具有設定指定顏色的初始「-background」畫布能力的多圖像「-composite」操作員。但是,使用默認Alpha 合成 'Over' 以外的任何內容都需要在應用之前仔細考慮,否則會得到意想不到的結果。您還可能需要考慮這些操作員用於生成起始畫布的「-background」顏色的影響,每個圖像(包括第一個圖像)都將在該畫布上進行合成。例如,讓我們使用 'DstOver'... 將每個後續圖像放置在先前圖像的*下方*

  magick \( -page 100x100+5+10 balloon.gif \)   \( -page +35+30 medical.gif \)  \
          \( --page +62+50       present.gif \)   \( -page +10+55 shading.gif \)  \
          -background none  -compose DstOver  -flatten  flatten_dstover.gif
[IM Output]
在這裡,背景設定為透明,否則您將只在結果中看到背景畫布,因為所有其他圖像都已放置在此初始畫布的「下方」!如調整畫布大小至現有圖像 (Canvases Sized to an Existing Image) 中所示,這確實提供了一種使用特定顏色「清空」圖像的方法。以下是一個更實際的例子。您可以自上而下或從前景到背景的順序生成圖像,而不是先將圖像與背景畫布分層,這在某些圖像處理情況下很尷尬且不自然。

  magick rose: -repage +10+10 \
          \( +clone -background black -shadow 60x3+5+5 \) \
          \( granite: -crop 100x80+0+0 +repage \) \
          -background none  -compose DstOver -layers merge layer_dstover.gif
[IM Output]
前三行分別產生一個圖層影像,最後一行將所有圖層合併到前一個圖層之下,有效地反轉順序。

如您所見,上述影像處理比您通常看到的陰影產生更簡單、更乾淨,只需按順序將每個影像置於下方(以透明畫布開始)。

當然,我也可以輕鬆地反轉影像列表。

  magick rose: -repage +10+10 \
          \( +clone -background black -shadow 60x3+5+5 \) \
          \( granite: -crop 100x80+0+0 +repage \) \
          -reverse -layers merge layer_reverse.gif
[IM Output]
但是請記住,這只會重新排序現有影像,而不會影響分層方法建立的「起始背景畫布」。合成方法也可以用於產生一些有趣的效果。例如,如果您繪製三個圓圈,然後使用「Xor」合成方法將它們疊加,您將以最小的努力獲得一個不尋常且外觀複雜的符號。

  magick -size 60x60 \
          \( xc:none -fill blue   -draw 'circle 21,39 24,57' \) \
          \( xc:none -fill red    -draw 'circle 39,39 36,57' \) \
          \( xc:none -fill green  -draw 'circle 30,21 30,3'  \) \
          -background none  -compose Xor   -flatten  flatten_xor.png
[IM Output]

圖層合成 - 合併兩個圖層列表

在 IM v6.3.3-7 中,「-layers」方法中添加了「Composite」,允許您將兩個完全獨立的影像集組合在一起。要在命令列上執行此操作,需要一個特殊的「null:」標記影像來定義第一個*目標*影像列表的結束位置以及疊加的*來源*影像列表的開始位置。但這是此方法唯一真正的複雜之處。基本上,第一個列表中的每個影像都與第二個列表中的相應影像合成,有效地將兩個列表合併在一起。可以使用幾何偏移相對於第一個列表對第二個列表進行全局定位,就像使用普通的合成運算符一樣(見上文)。重力也使用第一個影像的畫布大小來應用,以進行計算。在此「全局偏移」之上,影像的單個虛擬偏移也會保留,因為每對影像都被合成在一起。還處理了一種特殊情況。如果其中一個影像列表只包含一個影像,則該影像將與另一個列表的所有影像合成。同樣在這種情況下,即使它不是合成的目標端,也會保留較大列表的影像元數據(例如動畫時間)。
此放置運算符更常用于合成兩個動畫時,這可以被視為一種時間上的分層影像列表。因此,在範例的動畫修改部分中有更好的示例。有關更多詳細信息,請參閱多影像 Alpha 合成

處理影像圖層

使用上述各種圖層運算符放置多個影像是非常通用的技術。它允許您單獨處理大量影像,然後在完成後將它們全部組合成一個統一的整體。到目前為止,我們已經展示了以多種不同方式合併(合成或分層)多個影像的各種方法。在這裡,我提供了一些關於如何利用這些技術的更實際的例子。

縮略圖影像的分層

您也可以使用此技術以各種複雜的方式將多個縮略圖合併在一起。在這裡,我在您閱讀和放置影像時為其添加柔和邊緣,您可以在平鋪畫布上生成相當漂亮的影像組合。

  magick -page +5+5    holocaust_tn.gif \
          -page +80+50  spiral_stairs_tn.gif \
          -page +40+105 chinese_chess_tn.gif \
          +page \
          -alpha Set -virtual-pixel transparent \
          -channel A -blur 0x10  -level 50,100% +channel \
          \( -size 200x200 tile:tile_fabric.gif -alpha Set \) -insert 0 \
          -background None -flatten  overlap_canvas.jpg
[IM Output]

影像的計算定位。

可以使用多種方式設置虛擬畫布偏移(頁面)。更具體地說,您可以「-set」為每個影像設置此屬性,甚至可以為每個影像計算不同的位置。例如,在這裡,我讀入了一大組影像(大小相同的的小圖示影像),並將它們排列成一個圓圈。

  magick {balloon,castle,eye,eyeguy,ghost,hand_point,medical}.gif \
          {news,noseguy,paint_brush,pencil,present,recycle}.gif \
          {shading,skull,snowman,storm,terminal,tree}.gif \
          \
          -set page '+%[fx:80*cos((t/n)*2*pi)]+%[fx:80*sin((t/n)*2*pi)]' \
          \
          -background none -layers merge +repage image_circle.png
[IM Output]
上述示例的關鍵在於「-set page」操作,它使用正規化的圖像索引(FX 表達式 't/n' )為每個圖像創建一個從 0.0 到接近 1.0 的值。然後,使用以百分比轉義的 FX 表達式,將此值映射到半徑為 80 像素的圓圈中以定位圖像(按角度)。計算出的位置是圖像左上角的位置(而不是其中心,儘管這是一個簡單的調整),然後將其合併以生成新圖像。定位時不考慮偏移量是正數還是負數,這就是合併圖層運算符的強大之處。也就是說,我們生成了所有圖像相對於彼此的新圖像。最後的「+repage」會移除合併圖層圖像的最終結果負偏移量,因為這不再需要,並且在查看結果圖像時可能會導致問題。請注意,第一個圖像(結果中最右邊的圖像)位於所有其他圖像的下方。如果您希望分層真正循環,以便最後一個圖像位於第一個圖像下方,則可能必須將第一個圖像一分為二,並將上半部分放在序列的末尾,以便第一個圖像的上半部分位於最後一個圖像上方,而下半部分位於第二個圖像下方。這種技術很強大,但它只能將圖像定位到整數偏移量。如果您需要對圖像進行更精確的亞像素定位,則需要將圖像扭曲(平移)到精確的亞像素位置,而不是僅僅調整其虛擬偏移量。

遞增計算位置

您可以使用 FX 表達式訪問其他圖像的一些圖像屬性,同時在處理圖像時設置圖像的屬性。這意味著您可以設置每個圖像的位置,相對於前一個圖像的計算位置。例如,這將每個圖像的位置設置為在其前一個圖像的右側。也就是說,前一個圖像的位置加上其寬度。

  magick rose: netscape: granite: \
          \
          +repage -set page '+%[fx:u[t-1]page.x+u[t-1].w]+0' \
          \
          -background none -layers merge +repage append_diy.png
[IM Output]
每個圖像都會附加到前一個圖像的位置,方法是查找該位置並添加該圖像的寬度。這個先前的位置實際上是剛剛計算出來的,因為 IM 循環瀏覽每個圖像並設置「page」(虛擬偏移量)屬性。結果是一個 DIY 的附加運算符等效項,您可以從中開發自己的變體。您應該注意,整個序列實際上是由在第一個圖像的位置計算期間設置的「u[-1].w」移動的。這應該是當前圖像序列中最後一個圖像的寬度。然而,這種整體位移會被最終的「+repage」清除。您可以使用一些額外的計算來讓它忽略此偏移量,但在上述情況下不需要。
當使用圖像索引(例如「u[t]」)時,所有圖像選擇器「u」、「v」和「s」都根據給定的「[index]」引用相同的圖像。因此,最好使用「u」(第一個或第零個圖像)作為此索引行為的助記符(以防萬一發生變化)。

有關更多信息,請參見FX,DIY 圖像運算符
以下是另一個示例。每個圖像都相對於前一個圖像偏移,使用該圖像的位置和寬度,以便計算重疊附加

magick font_[0-9].gif \
        -set page '+%[fx:u[t-1]page.x+u[t-1].w-8]+%[fx:u[t-1]page.y+4]' \
        -background none -layers merge +repage append_offset.gif
[IM Output]
這種訪問其他圖像屬性的能力也包括其他圖像的像素數據。這意味著您可以創建一個特殊的圖像,其中顏色值表示其他圖像的“映射位置”。當然,該“映射”圖像也將被定位,並且需要在執行疊加之前將其刪除。創建特殊的“映射位置”圖像的有用性是另一回事。這只是另一種可能性。

圖像的兩階段定位

您可以通過將圖像處理分為兩個步驟來簡化圖像處理。一個步驟可用於生成、扭曲、定位圖像並為其添加裝飾,最後一步將它們全部合併在一起。例如,讓我們從 照片庫 中較大的原始圖像創建 拍立得縮略圖,分別處理每個圖像(保持該方面獨立且簡單)。

  center=0   # Start position of the center of the first image.
             # This can be ANYTHING, as only relative changes are important.

  for image in ../img_photos/[a-m]*_orig.jpg
  do

    # Add 70 to the previous images relative offset to add to each image
    #
    center=`magick xc: -format "%[fx: $center +70 ]" info:`

    # read image, add fluff, and using centered padding/trim locate the
    # center of the image at the next location (relative to the last).
    #
    magick -size 500x500 "$image" -thumbnail 240x240 \
            -set caption '%t' -bordercolor Lavender -background black \
            -pointsize 12  -density 96x96  +polaroid  -resize 30% \
            -gravity center -background None -extent 100x100 -trim \
            -repage +${center}+0\!    MIFF:-

  done |
    # read pipeline of positioned images, and merge together
    magick -background skyblue   MIFF:-  -layers merge +repage \
            -bordercolor skyblue -border 3x3   overlapped_polaroids.jpg

[IM Output]
上面的腳本看起來很複雜,但實際上並非如此。它只是在循環中生成每個縮略圖圖像,同時使用 擴展 對每個圖像進行中心填充並 裁剪,以便圖像的“中心”位於虛擬畫布上的已知位置。它實際上可以計算該位置,儘管這可能需要臨時文件,因此最好確保它位於所有圖像的已知位置。然後平移圖像(使用相對“-repage”運算符,請參閱 畫布偏移),以便生成的每個圖像都位於前一個圖像右側 60 個像素處。也就是說,每個圖像中心之間的間距是固定的,而不管圖像的實際大小如何(圖像的實際大小可能會因縱橫比和旋轉而改變)。此腳本的另一個主要技巧是,您可以使用 MIFF: 文件格式將圖像直接寫入管道,而不是將每個“圖層圖像”保存到臨時文件中。一種稱為 MIFF 圖像流 的方法。這是可行的,因為“MIFF:”文件格式允許您將多個圖像簡單地連接在一起成為單個數據流,同時保留所有圖像元數據,例如其虛擬畫布偏移。此技術為許多其他腳本提供了一個良好的起點。可以生成或修改圖像,並且可以按照您喜歡的任何方式計算最終大小和位置。另一個例子是腳本“hsl_named_colors”,它獲取 ImageMagick 中的命名顏色列表,並將其排序到 HSL 色彩空間中這些顏色的圖表中。您可以在 顏色規範 中看到其輸出。其他可能性包括...
  • 使用任何類型的縮略圖(或其他 裝飾),或者直接使用原始的小縮略圖。
  • 生成圖像,使第一個圖像居中,而其他圖像像金字塔一樣排列在第一個圖像的左側和右側。
  • 通過將圖像放置在相對於彼此的特定 X 和 Y 坐標處,將圖像定位到弧線、圓形和螺旋線中。例如:博士圈日落花斐波那契螺旋線
  • 根據顏色定位圖像。例如:書籍封面
  • 按時間或提交時間定位圖像。例如:日落之年
基本上,您在虛擬畫布上定位圖像方面擁有完全的自由,然後可以簡單地讓 IM 排序出容納所有圖像所需的畫布最終大小。

地圖上的圖釘

以下是一個典型的圖層範例,在特定位置將彩色圖釘放置在地圖上。[IM 輸出] 左側是一個「圖釘」圖像。 圖釘的末端位於位置 +18+41。 我也有一張 威尼斯地圖 的圖像,並且想要在地圖上的各個點放置圖釘。 例如,「學院美術館」位於像素位置 +160+283。 若要將圖釘與該位置對齊,您需要從地圖位置減去圖釘末端的位置。 這會為我們的「圖釘」圖像產生 +142+242 的偏移量。 以下是使用分層圖像的結果

  magick map_venice.jpg    -page +142+242 push_pin.png \
          -flatten  map_push_pin.jpg
[IM Output]
這個範例來自 IM 論壇討論,使用轉換分層圖像讓我們進一步自動化這個過程。 我們有一個檔案,其中列出了我們要放置在地圖上的每個圖釘的位置和顏色。 檔案中的位置名稱未使用,僅作為列出的像素位置的參考註釋。
[Data File]
讓我們讀取這個文字檔,以在迴圈中建立「圖釘」。


  pin_x=18  pin_y=41

  cat map_venice_pins.txt |\
    while read x y color location; do

      [ "X$x" = "X#" ] && continue   # skip comments in data

      x=$(( x - pin_x ))    # magick x,y to pin image offsets
      y=$(( y - pin_y ))

      # magick 'color' to settings for color modulate (hue only)
      # assumes a pure 'red' color for the original push pin
      mod_args=$(
         magick xc:$color -colorspace HSL txt: |
           tr -sc '0-9\012' ' ' |\
             awk 'NR==1 { depth=$3 }
                  NR==2 { hue=$3;
                          print  "100,100,"  100+200*hue/depth
                        }'; )

      # re-color and position the push pin
      magick push_pin.png -repage +${x}+${y} -modulate $mod_args miff:-

    done |\
      # read pipeline of positioned images, and merge together
      magick map_venice.jpg  MIFF:-  -flatten  map_venice_pins.jpg

[IM Output]
請注意,它假設原始圖釘顏色為紅色(色調為 0),並使用 調製運算子 通過適當的縮放計算將其重新著色為其他顏色。 請注意,無操作色調變化的調製參數為 100,並以 200 的值循環(一種偽百分比值)。 未來:透視扭曲地圖,根據地圖上的「深度」調整圖釘大小,計算由於扭曲引起的圖釘位置變化,並將其「固定」到扭曲的地圖上。 以上使用了一種稱為 MIFF 圖像串流 的方法,每個圖像都在迴圈中單獨生成,然後「管道傳輸」到「分層」命令以生成最終圖像。 另一種方法(通常在 PHP 腳本中使用)是使用「生成命令」技術,該技術使用 shell 腳本生成要執行的長「magick」命令。 圖像變形動畫 中的腳本使用了這種技術。 這兩種方法都避免了生成臨時圖像的需要。

陰影層

正確處理一組重疊圖像中的半透明陰影效果實際上比看起來要困難得多。 僅僅疊加帶有陰影的照片會導致陰影被應用兩次。 也就是說,兩個重疊的陰影會變得非常暗,而在現實中,它們不會像重疊的圖像那樣完全重疊在一起。 圖像的各個部分應該只是有陰影或沒有陰影。 也就是說,陰影應該只應用於圖像的任何部分一次。 您不應該看到更暗的區域,除非您有兩個獨立的光源,這會使事情變得更加困難。 Tomas Zathurecky < tom @ ksp.sk > 接受了處理分層圖像中的陰影效果的挑戰,並開發了圖像累加器技術來解決這個問題。 基本上,我們需要一次將每個圖像添加到堆棧的底部。 當我們添加新圖像時,需要在添加新圖像之前,使用所有先前圖像的陰影使其變暗。 但是,只需要添加落在新圖像上的陰影。 沒有落在新圖像上的陰影需要被忽略,直到稍後它落在其他圖像或背景(如果有)上時。 以下是一個範例...

  magick \
    \( holocaust_tn.gif -frame 10x10+3+3 \
          -background none  -rotate 5 -repage +0+0 \) \
    \
    \( spiral_stairs_tn.gif -frame 10x10+3+3 \
          -background none -rotate -15 -repage -90+60 \) \
    \( -clone 0   -background black -shadow 70x3+4+7 \
       -clone 1   -background black -compose DstATop -layers merge \
       -trim \) \
    \( -clone 2,0 -background none  -compose Over -layers merge \) \
    -delete 0--2 \
    \
    \( chinese_chess_tn.gif -frame 10x10+3+3 \
          -background none -rotate 20 -repage +60+90 \) \
    \( -clone 0   -background black -shadow 70x3+4+7 \
       -clone 1   -background black -compose DstATop -layers merge \
       -trim \) \
    \( -clone 2,0 -background none  -compose Over -layers merge \) \
    -delete 0--2 \
    \
    \( +clone -background black -shadow 70x3+4+7 \) +swap \
    -background none -compose Over -layers merge +repage \
    layers_of_shadows.png
[IM Output]
以上程序看起來很複雜,但實際上非常簡單。 第一個圖像用於啟動圖像的累積堆棧(圖像索引 #0)。 請注意,如果您不想使用第一個圖像來初始化堆棧,我們實際上可以從單個透明像素(「-size 1x1 xc:none」)開始。 現在要將新圖像添加到圖像堆棧的底部,我們每次都應用相同的操作集...
  • 首先,將縮略圖讀入內存,並應用任何旋轉、相對位置(可以是負值)。你也可以在這個時候對圖像應用其他縮略圖操作(如果你願意的話),不過在本例中,這些操作已經執行過了。新圖像形成圖像索引#1。
  • 現在我們抓取之前的圖像堆疊(#0),生成具有適當顏色、模糊度、偏移量和環境光百分比的陰影。
  • 將此陰影疊加在新圖像(#1)上,以便僅保留落在新圖像「頂部」的陰影。我們還會(可選)對結果應用裁剪操作,以移除因陰影操作而添加的任何額外空間,形成圖像#2。
  • 現在,我們只需將新圖像(#2)添加到累積的圖像堆疊(#0)中即可。
  • 並刪除所有之前的處理圖像,最後一張除外。
要添加更多圖像,我們基本上只需重複上述操作塊。將所有圖像添加到堆疊後,只需對累積的圖像堆疊執行正常的陰影操作即可。移除任何剩餘的圖像偏移量(許多網絡瀏覽器都討厭這樣)。使用合併,我可以自動處理虛擬偏移量(尤其是負偏移量),允許您將圖像放置在相對於先前圖像位置的任何位置。它還可以正確應用陰影,這些陰影可以生成具有負偏移量的更大圖像。
現在,上述方法可以正確處理多層圖像陰影,但是,雖然陰影是偏移的,但實際上所有圖像的偏移量都是相同的!真正應該發生的是,陰影應該隨著它落在堆疊中越來越深的圖像上而變得更加偏移,並且更加模糊。也就是說,與最底部的圖像相比,頂部的圖像應該在背景上形成非常模糊的陰影。這實際上更難做到,因為您不僅需要跟踪圖像堆疊,還需要跟踪隨著圖像堆疊變大而變得「模糊」的陰影。因此,您實際上需要兩個累加器。圖像堆疊(如上所述)和陰影累積,隨著我們添加更多圖像。例如,以下是同一組圖像,但陰影會隨著深度的增加而變得更加模糊。

  magick xc:none xc:none \
    \
    \( holocaust_tn.gif -frame 10x10+3+3 \
          -background none  -rotate 5 -repage +0+0 \) \
    \( -clone 1   -background black -shadow 70x0+0+0 \
       -clone 2   -background black -compose DstATop -layers merge \
       -clone 0   -background none  -compose Over    -layers merge \) \
    \( -clone 2,1 -background none  -compose Over    -layers merge \
                  -background black -shadow 100x2+4+7 \) \
    -delete 0-2 \
    \
    \( spiral_stairs_tn.gif -frame 10x10+3+3 \
          -background none -rotate -15 -repage -90+60 \) \
    \( -clone 1   -background black -shadow 70x0+0+0 \
       -clone 2   -background black -compose DstATop -layers merge \
       -clone 0   -background none  -compose Over    -layers merge \) \
    \( -clone 2,1 -background none  -compose Over    -layers merge \
                  -background black -shadow 100x2+4+7 \) \
    -delete 0-2 \
    \
    \( chinese_chess_tn.gif -frame 10x10+3+3 \
          -background none -rotate 20 -repage +60+90 \) \
    \( -clone 1   -background black -shadow 70x0+0+0 \
       -clone 2   -background black -compose DstATop -layers merge \
       -clone 0   -background none  -compose Over    -layers merge \) \
    \( -clone 2,1 -background none  -compose Over    -layers merge \
                  -background black -shadow 100x2+4+7 \) \
    -delete 0-2 \
    \
    \( -clone 1 -background black -shadow 70x0+0+0 \
       -clone 0 -background none -compose Over -layers merge \) \
    -delete 0-1 -trim +repage \
    layers_of_deep_shadows.png
[IM Output]
仔細觀察結果。陰影的偏移量和模糊度在圖像的不同部分是不同的。相鄰層中的圖像之間的陰影非常細,但當它落在更深處的圖像甚至背景上時,陰影就會變得非常厚。當然,在本例中,陰影偏移量可能太大了,但結果看起來非常逼真,為圖層提供了更好的深度感。請注意我們如何將陰影的操作分為兩個步驟。將累積的陰影(圖像索引#1)應用於新圖像(#2)時,我們只添加環境光百分比,而不添加任何模糊或偏移量(在本例中為「70x0+0+0」)。然後將新圖像添加到累積的圖像堆疊(#0)中。但是,在將新圖像(#2)的陰影直接添加到累積的陰影(#1)之後,同樣沒有模糊或偏移量,然後我們才對所有陰影進行模糊和偏移,以形成新的累積陰影圖像。換句話說,隨著堆疊變得越來越厚,累積的陰影圖像變得越來越模糊和偏移。只有較深圖像的陰影沒有累積那麼大的效果。這個程序本質上是將陰影的應用與增量陰影累加器分開的。這使您可以控制諸如…
  • 逼真的陰影(如上所述):70x0+0+0 和 100x2+4+7
  • 恆定陰影(如基本示例):70x2+4+7 和 100x0+0+0
  • 恆定模糊,但累積偏移量:70x2+0+0 和 100x0+4+7
  • 恆定和漸進偏移量:60x0+4+7 和 100x0+1+1
  • 累積環境光效果:80x0+0+0 和 95x2+4+7
它們大多數可能不切實際,但在其他情況下可能看起來不錯。此外,在 "-compose ATOP" 合成之前設置 "-background" 顏色將允許您定義陰影的顏色(實際上是有色的環境光)。您甚至可以使用不同的顏色來處理最終落在背景圖層上的陰影(最後的 "-background black" 設置),或者完全將其關閉,使其看起來不像圖像位於任何背景之上(即漂浮在半空中)。它是高度通用的。
Tomas Zathurecky 繼續開發了另一種處理分層圖像陰影的方法,即將分層圖像列表作為一個整體來處理。這是我自己從未想過的事情。這種方法的優點是您可以將整個圖像列表作為一個整體來處理,而不必一次累積一張圖像,並且一遍又一遍地重複相同的操作塊。首先讓我們再看一下更簡單的“恆定陰影”問題。

  magick \
    \( holocaust_tn.gif -frame 10x10+3+3 \
          -background none  -rotate 5 -repage +0+0 \) \
    \( spiral_stairs_tn.gif -frame 10x10+3+3 \
          -background none -rotate -15 -repage -90+60 \) \
    \( chinese_chess_tn.gif -frame 10x10+3+3 \
          -background none -rotate 20 -repage +60+90 \) \
    \
    -layers trim-bounds \
    \
    \( -clone 0--1 -dispose None -coalesce \
       -background black -shadow 70x2+4+7 \
       xc:none +insert null: +insert +insert xc:none \) \
    -layers trim-bounds -compose Atop -layers composite \
    \
    -fuzz 10% -trim \
    -reverse -background none -compose Over -layers merge +repage \
    coalesced_shadows.png
[IM Output]
第一個操作塊只是生成分層圖像列表。它可以是一個單獨的編程循環,如前所示。操作從 "-layers trim-bounds" 開始,這是一個 邊界修剪 操作,它擴展所有圖像的虛擬畫布以包含所有圖像,並確保所有偏移量都是正數。然後將其克隆、合併 並添加陰影以創建一個單獨的漸進陰影列表。現在我們可以使用 圖層合成 將陰影和原始圖像列表合併在一起。這裡的複雜之處在於,在合併之前,我們不僅需要添加一個特殊的 'null:' 標記圖像來分隔兩個列表,還需要添加一個特殊的空白圖像 'xc:none' 以便偏移陰影列表。這樣,每個陰影圖像都將覆蓋在原始列表的下一個圖像 'ATop' 上。剩下的就是從下到上(反向)順序合併現在正確添加陰影的圖像。
要處理“深陰影”,需要 圖層計算

  magick \
    \( holocaust_tn.gif -frame 10x10+3+3 \
          -background none  -rotate 5 -repage +0+0 \) \
    \( spiral_stairs_tn.gif -frame 10x10+3+3 \
          -background none -rotate -15 -repage -90+60 \) \
    \( chinese_chess_tn.gif -frame 10x10+3+3 \
          -background none -rotate 20 -repage +60+90 \) \
    \
    \( -clone 0--1 \
       -set page '+%[fx:page.x-4*t]+%[fx:page.y-7*t]' -layers merge \) \
    -layers trim-bounds +delete \
    \
    \( -clone 0--1 \
       -set page '+%[fx:page.x-4*t]+%[fx:page.y-7*t]' \
            -dispose None -coalesce \
       -set page '+%[fx:page.x+4*t]+%[fx:page.y+7*t]' \
            -background black -shadow 70x2+4+7 \
       xc:none +insert null: +insert +insert xc:none \) \
    -layers trim-bounds -compose Atop -layers composite \
    \
    -fuzz 10% -trim \
    -reverse -background none -compose Over -layers merge +repage \
    coalesced_deep_shadows.png
[IM Output]
您可以看到以前使用過的相同操作塊集,但計算更複雜,用於設置初始 邊界修剪,以及稍後計算“漸進陰影列表”所需的偏移量。但是,目前陰影不會隨著深度而變得更加模糊。
使用 IMv7 "magick" 命令會更簡單,它允許您直接使用 'fx 計算' 作為 "-shadow" 的參數,這不僅可以讓您計算陰影隨著深度增加的更大偏移量,還可以讓您使陰影隨著深度增加而變得更加模糊。

定位扭曲的透視圖像

對齊扭曲的圖像可能很棘手,這裡我將研究如何對齊此類圖像以使其在非常特定的位置匹配。這裡我有兩張圖像,它們突出顯示了每張圖像上的特定點。
[IM Output] [IM Output]
第二個圖像是 65% 半透明的,這允許您在將其合成到藍色圖像上時看到它,因此您可以看到標記的點是否對齊。標記的控制點本身分別位於坐標 59,26(藍色)和 35,14(紅色)處。如果您只是簡單地疊加兩個圖像,則可以減去偏移量並將兩個圖像“合成”在一起,產生 +24+12 的偏移量。

  magick align_blue.png align_red.png -geometry +24+12 \
          -composite align_composite.png
[IM Output]
請注意,此偏移量可能為負數!這就是我們稍後要處理的事情。這僅在坐標是整數像素坐標時才有效。如果匹配的坐標是亞像素位置(如照片蒙太奇中的典型情況),則簡單的合成將不起作用。如果涉及任何類型的失真(這在現實生活中也很常見),它也不會很好地工作。這就是我們將要探討的問題。
當您扭曲影像時,您會希望確保兩個像素保持對齊。最佳方法是使用您要對齊的點作為扭曲控制點。這將確保它們的位置正確無誤。

  magick align_blue.png \
          \( align_red.png -alpha set -virtual-pixel transparent \
             +distort SRT '35.5,14.5  1 75  59.5,26.5' \
          \) -flatten  align_rotate.png
[IM Output]
由於扭曲會產生帶有「畫布偏移」的「圖層影像」,因此您不能僅僅使用合成來疊加影像(層級太低),而是需要使用平面化運算子,以便使用扭曲產生的偏移來定位它們。請注意我是如何在「像素」坐標中添加 0.5 的值。這是因為像素具有面積,而數學點沒有,因此如果您想要對齊像素的中心,則需要在像素內的中心「點」位置添加 0.5。有關更多資訊,請參閱影像坐標與像素坐標。上面另一個問題是被疊加的影像被藍色背景畫布影像「裁剪」了,就像合成運算子那樣。也就是說,「藍色」影像在合成過程中為結果提供了「裁剪視口」。為了防止這種情況,我們改用圖層合併,它會自動計算一個足夠大的「視口」畫布來容納所有要合成的影像。

  magick align_blue.png \
          \( align_red.png -alpha set -virtual-pixel transparent \
             +distort SRT '35.5,14.5  1 75  59.5,26.5' \
          \) -background none -layers merge +repage  align_rotate_merge.png
[IM Output]
由於「合併」的結果,影像將具有一個「負」偏移(以便保留影像的圖層位置)。為了顯示結果,我需要捨棄該偏移,因為許多瀏覽器不處理影像中的負偏移。我在儲存最終影像之前使用「+repage」來做到這一點。如果我要進行進一步的處理(不顯示網路上的結果),我會保留該偏移(移除「+repage」),以便影像位置保持在其正確且已知的位置,以供稍後處理。
現在,如果您正在進行更複雜的扭曲,例如透視,那麼上面顯示的相同技術也適用。

  magick align_blue.png \
          \( align_red.png -alpha set -virtual-pixel transparent \
             +distort Perspective '35.5,14.5  59.5,26.5
                       0,0 32,4    0,%h 14,36    %w,%h 72,53  ' \
          \) -background none -layers merge +repage  align_perspective.png
[IM Output]
這種技術的問題在於您使用內部控制點來定位透視扭曲。也就是說,影像內部的一個點和邊緣周圍的三個點。這可能會讓實際透視形狀難以控制,因為任何控制點的微小移動都可能使「自由角」發生劇烈移動。如果您正在使用大量的「已註冊點」列表來獲得更精確的「最小二乘擬合」以定位影像,那麼情況可能會更糟。在這種情況下,您感興趣的點可能不在用於扭曲影像的控制「已註冊」點附近。另一種方法是簡單地按照我們需要的方式扭曲影像,然後弄清楚我們需要如何平移生成的影像以對齊我們感興趣的點。為此,我們需要知道「感興趣點」由於扭曲而移動了多少。這是扭曲和定位影像(尤其是真實影像)時的一個實際問題。例如,在這裡我使用所有四個角扭曲影像以產生特定的(假設是所需的)扭曲形狀,但我不會嘗試在此時對齊控制點,而只是應用扭曲...

  magick align_blue.png \
          \( align_red.png -alpha set -virtual-pixel transparent \
             +distort Perspective '0,0  10,12  0,%h 14,40
                               %w,0 68,6  %w,%h 63,48 ' \
          \) -background none -layers merge +repage  align_persp_shape.png
[IM Output]
如您所見,雖然紅色影像被扭曲了,但紅色控制點的位置與我們想要對齊的藍色控制點相差甚遠。您不能僅僅測量這兩個點,因為紅色點不太可能位於精確的像素位置,而是會涉及亞像素偏移。我們需要首先準確計算紅色點的位置。為此,我們可以重新運行上述扭曲並啟用詳細模式,以獲取透視正向映射係數。然後可以使用這些係數來計算透視投影扭曲中描述的內容。

  magick align_red.png  -define distort:viewport=1x1  -verbose \
          +distort Perspective '0,0  10,12  0,%h 14,40
                                %w,0 68,6  %w,%h 63,48 ' null:
[IM Text]
我們想要的只是變形所使用的計算係數。因此,我們不需要目標圖像,所以我們只使用“null:”圖像文件格式輸出。我們還使用變形視口告訴變形它正在生成的新圖像只有一個像素大小。這樣它就可以進行變形準備和詳細報告,但只會變形單個“目標”像素,然後將其丟棄。這可以節省大量的處理時間。實際上,如果變形沒有在其計算中使用源圖像元數據(百分比轉義“%w”和“%h”所需),我們甚至不需要源圖像“align_red.png”。在這種情況下,我們也可以對輸入圖像使用單個像素的“null:”圖像。我們對這個信息收集步驟中的虛擬像素、背景或其他任何東西也不感興趣,所以我們不需要擔心設置這些功能。
現在我們可以獲得變形信息,我們需要從輸出的第 3 行和第 4 行中提取 8 個透視係數。然後可以使用這些係數將紅色控制點映射到其新的變形位置,並從中減去藍色控制點,以便獲得所需的實際平移量,以使標記的紅色坐標與藍色坐標對齊。

  bluex=59; bluey=26
  redx=35; redy=14

  magick align_red.png  -verbose \
             +distort Perspective '0,0  10,12  0,%h 14,40
                               %w,0 68,6  %w,%h 63,48 ' null: 2>&1 |\
    tr -d "',"  |\
      awk 'BEGIN   { redx='"$redx"'+0.5;   redy='"$redy"+0.5';
                     bluex='"$bluex"'+0.5; bluey='"$bluey"'+0.5; }
           NR == 3 { sx=$1; ry=$2;  tx=$3; rx=$4; }
           NR == 4 { sy=$1; ty=$2;  px=$3; py=$4; }
           END { div =  redx*px + redy*py + 1.0;
                 dx = ( redx*sx + redy*ry + tx ) / div;
                 dy = ( redx*rx + redy*sy + ty ) / div;
                 printf "red point now at %f,%f\n", dx, dy;
                 printf "translate shape by %+f %+f\n", bluex-dx, bluey-dy; }'
[IM Text]
上面使用了“tr”文本過濾器來去除輸出中的額外引號和逗號。然後,它使用“awk”程序提取係數,並進行“正向映射”紅色標記以匹配藍色標記所需的浮點數學運算。請注意,我再次在控制點的“像素坐標”中添加了 0.5,以確保像素的中心用於計算。請參閱圖像坐標與像素坐標。現在我們知道了變形圖像所需的平移量,您可以通過兩種方式將該平移添加到變形中。通過適當修改透視投影的係數(不容易)。或者我們可以簡單地將平移量添加到原始圖像的每個目標坐標中(非常容易)。以下是後者的結果(將平移添加到目標坐標中)...

  magick align_blue.png \
          \( align_red.png -alpha set -virtual-pixel transparent \
             +distort Perspective '0,0   31.408223,15.334305
                                   0,%h  35.408223,43.334305
                                   %w,0  89.408223, 9.334305
                                   %w,%h 84.408223,51.334305 ' \
          \) -background none -layers merge +repage  align_persp_move.png
[IM Output]
在右側,我裁剪並縮放了控制點周圍的結果,以顯示它們完全對齊!

  magick align_persp_shape.png -crop 19x19+50+17 +repage \
          -scale 500%   align_persp_shape_mag.png
[IM Output]
正如您所見,我們完美地對齊了兩個像素,没有任何子像素溢出到任何一側。即使是最小的未對準也會在中心像素的任一側顯示為不對稱著色。這種縮放甚至顯示出由於透視變形導致紅色十字的左側和右側之間存在輕微的不對稱差異。也就是說,這個像素級視圖測試有多精確。
使用變形進行文本定位中研究了一個類似但更簡單的問題。

評估序列 - 直接多圖像合併方法

-evaluate-sequence”方法旨在以非常特定的方式將多個相同大小的圖像合併在一起。在某些方面,它是我們上面看到的評估和函數運算符與多圖像合成技術的混合。可以使用普通的多圖像分層合成技術執行提供的方法,但並非所有方法都可以。該運算符使用與“-evaluate”相同的方法,因此您可以使用“-list Evaluate”獲取它們的列表。儘管其中一些(例如“Mean”和“Medium”)只有在此運算符中使用時才有用。

多個圖像的平均值(平均值)

基本上,較舊的「-evaluate-sequence mean」和較新的「-evaluate-sequence mean」都會建立所有提供影像的平均值。例如,以下是以玫瑰影像及其所有水平和垂直翻轉版本為例的平均值。

  magick rose: -flip rose: \( -clone 0--1 -flop \) \
          -evaluate-sequence mean  average.png
[IM Output]
將數百張相同固定場景的影像進行平均,可用於移除大多數暫時性效果,例如移動中的人,使其變得不那麼重要。但是,出現大量暫時性效果的區域可能會留下「鬼影模糊」,這些模糊可能很難移除。由於影片序列在查看個別畫格時會產生明顯的雜訊,因此您可以將多個連續但未改變的畫格進行平均,以產生更清晰銳利的結果。亞利桑那大學的 Matt Leigh 報告說,他利用這種技術來提高顯微鏡影像的解析度。他拍攝了同一個「目標」的多張影像,然後將它們全部平均起來,以提高結果的訊號/雜訊比。他建議其他人也可能會發現它對這個目的很有用。將兩張影像平均在一起的另一種方法是使用「composite -blend 50%」影像操作,它可以處理兩張不同大小的影像。有關更多詳細資訊,請參閱將兩張影像混合在一起的範例。IM 討論區有一個關於一次平均 10 個畫格的序列的討論,以便在不填滿電腦記憶體(使其速度變慢)的情況下平均數千張影像。與此相關且包含相關數學知識的討論是不要一次載入所有影像。使用「mean」的另一種替代方法是使用較新的多項式運算子,它可以分別對每個影像進行加權。

多張影像的最大/最小值

Max」和「Min」方法將從一系列影像中取得最大值(較亮)和最小值(較暗)。同樣地,它們基本上等同於使用變亮和變暗合成方法,但使用多張影像。透過選擇正確的背景畫布顏色,您可以將平面化運算子與等效的合成方法一起使用。

  magick rose: -flip rose: \( -clone 0--1 -flop \) \
          -evaluate-sequence max  max.png
[IM Output]

  magick rose: -flip rose: \( -clone 0--1 -flop \) \
          -evaluate-sequence min  min.png
[IM Output]
警告:這不是像素的選擇(按強度),而是值的選擇。這意味著輸出影像可能會產生來自不同影像的個別紅色、綠色和藍色值,從而產生在任何輸入影像中都找不到的新顏色。如果您需要按強度選擇最大/最小像素,請參閱按強度變亮合成方法

按強度排序的中位數像素

-evaluate-sequence Median」會從所有給定的圖像中尋找強度為中間像素的像素。也就是說,對於每個位置,它會收集並排序每個圖像的像素強度。然後它會選擇位於序列中間的像素。它也可以用作簡單平均多個圖像的像素的替代方法。例如,通過將圖像與兩個上部和下部「限制」圖像組合來使用。由於像素將是中間強度,因此您將獲得原始圖像中的像素或「限制」圖像中的像素。換句話說,您可以使用它來「剪切」原始圖像的強度。奇怪但真實。對於偶數個圖像,將選擇中間較亮側的像素。因此,如果只有兩張圖像,則此運算符將等效於逐像素「按強度變亮」。關鍵是每個像素都將完全來自一張圖像,並按強度排序。每個像素的確切顏色將完全來自給定圖像之一,因此不會生成新顏色。例如,以下是玫瑰圖像使用其所有翻轉和翻轉版本的像素的中值強度。請注意它是如何不那麼平滑,但可以獲得清晰的邊界,因為它基於像素的強度。

  magick rose: -flip rose: \( -clone 0--1 -flop \) \
          -evaluate-sequence median  median.png
[IM Output]

新增多個圖像

Add」方法當然只是將所有圖像加在一起。

  magick ... -evaluate-sequence add ...
這是使用 Flatten 將所有圖像加法合成在一起的更快(更直接)版本...

  magick ... -background black -compose plus -layers flatten ...
請注意,以這種方式添加圖像很容易超過圖像的量子範圍,因此它可能會被「剪切」,除非您使用HDRI 版本的 IM。這就是通常使用平均值或均值的原因,因為這將平均劃分所有圖像以確保生成的圖像不會被剪切。另一種選擇是使用更新的多項式運算符,它可以單獨加權每個圖像。

減去多個圖像

Subtract」方法從第一個圖像中減去每個圖像。或者至少這就是它應該做的。在內部,它的參數被交換了,它正在從下一個圖像中減去之前的結果。啊!!!!!但是,通過使用線性加深合成方法的怪癖,您可以從第一個圖像中減去第二個和後面的圖像。基本上通過反轉除第一個圖像以外的所有圖像,並將「white」(反轉的零)設置為起始背景顏色,然後您可以使用Flatten從第一個圖像中減去所有圖像。

  magick ...  \
         -negate \( -clone 0 -negate \) -swap 0 +delete \
         -compose LinearBurn -background white -flatten \
         ...

乘以/除以多個圖像

-evaluate-sequence」接受「Multiply」和「Divide」作為方法,但它們會產生意外和奇怪的結果,因為它們使用的是圖像的實際顏色值而不是標準化顏色值,就像「-evaluate」一樣。結果,乘法和除法的規模太大。這可以歸類為錯誤。在此期間,您最好對 Multiply 使用等效的「flatten」方法,該方法確實按預期工作。

  magick ... -background white -compose multiply -layers flatten ...

多項式 - 使用多項式合併多個圖像

與「-evaluate-sequence」密切相關,特別是與「mean」方法(圖像平均),是「-poly」運算符(已添加 IM v6.8.0-5)。這個運算符會為記憶體中的每個圖像提供兩個數字的清單,一個用於提供每個圖像的乘法權重,另一個用於提供每個圖像的冪指數。這讓您可以合併圖像清單,就好像每個圖像都是多項式方程式的變數輸入一樣。每個圖像的顏色值都被視為標準化的 0 到 1 值。對於每一對值,圖像顏色(標準化)首先由第二個「冪」指數求冪,然後乘以第一個數字(加權)。如果指數為「1」,則該值僅乘以給定的權重。但是,如果指數為「0」,則權重將成為最終值,產生標準化的顏色常數加法(值介於 0.0 到 1.0 之間)。可以在當前圖像序列中提供單一像素圖像,並且可以用於添加特定顏色,每個通道具有不同的標準化顏色值。(使用權重和指數 = 1.0)。或者,您可以提供「NULL:」圖像(或任何其他垃圾圖像),並使用 0.0 的指數。這只會將給定的加權因子添加為常數。最終圖像由第一個圖像(及其大小和其他中繼資料)生成,就像使用 FX DIY 運算符 一樣。例如...

  magick rose: granite: null: -poly '1,1 2,1 -1.0,0' poly_rose.png
[IM Output]
這會採用「rose:」(使用權重 1 和冪 1 未修改),將「granite:」圖像的顏色值添加兩倍(權重 = 2),最後使用「null:」圖像減去值 1,使用指數 0(忽略圖像輸入)和加權值 -1.0。生成的圖像等效於...
rose + 2.0*granite - 1.0
rose + 2.0*(granite-0.5)
換句話說,玫瑰圖像被賦予了嘈雜的花崗岩紋理覆蓋(具有 50% 的灰色偏差)。這實際上就像非常強烈的「強光」合成照明效果,但對花崗岩覆蓋層進行了非常明確的加權。與其他多圖像操作相比,主要區別在於能夠單獨加權每個圖像,但在單個圖像處理操作中執行所有計算,而無需額外的中間圖像。在非 HDRI 版本的 ImagMagick 中,這可以避免對最終結果產生任何量子舍入、裁剪或其他影響。(請參閱 量子效應)。例如,它可以用於對大量圖像執行加權平均,例如對較小組的圖像進行平均,然後將這些組平均在一起。