ImageMagick 範例 --
影像變形
- 索引
-
ImageMagick 範例 前言與索引
-
簡單影像變形(重新排列像素順序)
-
旋轉和剪切
-
圓形變形
-
動畫 (有趣的例子)
簡單影像變形
簡單影像變形運算子僅會重新排列影像中的像素。像素數量甚至影像大小都保持不變。關鍵特性是影像不會遺失任何資訊,僅會重新排列,並且可以很容易地恢復正常,而不會損失任何品質(儲存時不包括類似 JPEG 的失真壓縮)。基本上,它只是重新排列像素,而不會破壞、覆蓋、複製或合併顏色,也不會以其他方式修改原始影像的內容。只是在影像中移動像素位置。![[IM 輸出]](../images/koala.gif)
翻轉和鏡像
對於這些範例,讓我們使用這張可愛的無尾熊影像…最簡單的影像扭曲是重新排列影像中的像素,使其「-flip 」上下顛倒。
|
![]() |
或者,使用「-flop 」,您可以產生鏡像影像。
|
![]() |
![]() ![]() |
在 IM v6.6.6-5 之前,「-flip 」和「-flop 」運算子都不會修改影像相對於可能存在的較大虛擬畫布的虛擬畫布偏移量 |
轉置和橫向,對角線
「-transpose
」和「-transverse
」影像運算會產生影像的對角線鏡像。「-transpose 」會沿著影像左上角到右下角的對角線鏡像影像。
|
![]() |
而「-transverse 」會沿著影像左下角到右上角的對角線鏡像影像。
|
![]() |
![]() ![]() |
在 IM v6.6.6-5 之前,「-transpose 」和「-transverse 」運算子都不會修改影像相對於可能存在的較大虛擬畫布的虛擬畫布偏移量 |
矩形旋轉
上述所有四種類型的運算基本上都會產生原始影像的鏡像影像。「-rotate
」運算子提供了影像的其他非鏡像版本,包括原始影像本身。
magick koala.gif -rotate 0 rotate_0.gif magick koala.gif -rotate 90 rotate_90.gif magick koala.gif -rotate 180 rotate_180.gif magick koala.gif -rotate -90 rotate-90.gif magick koala.gif -rotate 360 rotate_360.gif |
![[IM Output]](rotate_0.gif)
![[IM Output]](rotate_90.gif)
![[IM Output]](rotate_180.gif)
![[IM Output]](rotate-90.gif)
![[IM Output]](rotate_360.gif)
-rotate
」僅在您使用 90 度倍數的旋轉角度時才是簡單扭曲。任何其他角度都會在影像中引入其他更複雜的像素級扭曲。請參閱下面的旋轉。![]() ![]() |
您可能會注意到正旋轉角度是順時針方向的,這在邏輯上似乎不正確。 然而,在內部,它在數學上是正確的,並且是由於使用了負 Y 軸造成的。 也就是說,Y 軸從頂部的 0 開始,向下為正。 因此,坐標系是反轉的,因此旋轉角度在數學上也是反轉的。 |
![]() ![]() |
數位照片也可以旋轉以匹配記錄的 相機方向,方法是使用「-auto-orient 」運算子。 這是 IM v6.2.7-8 中新增的功能。 |
像壞掉的電視一樣滾動影像
您也可以水平「-roll 」影像(就像不同步的電視)。 滾動量(影像位移)以像素為單位。
|
![]() |
當然,您也可以將影像側向滾動...
|
![]() |
或者通過使用負數像素,您可以朝相反方向滾動它。
|
![]() |
-tile-offset
」設定所定義的,當通過「-tile
」選項讀入平鋪影像時要應用多少滾動量。 簡單影像變形摘要
所有這些運算子最重要的方面是,您可以通過許多不同的方式將它們全部加在一起,以便結果完全就像根本沒有執行任何操作一樣。
|
![]() |
旋轉和剪切
雖然 簡單失真運算子(上文)保留了影像大小和顏色,但下一組則不會。 這些運算子的結果不適合原始大小,甚至不適合影像的原始柵格網格。旋轉影像 --簡單的影像旋轉
正如您在上面看到的,「-rotate
」運算子可以在您以 90 度為單位旋轉影像時執行簡單的、保留影像的扭曲。但是,對於其他角度,旋轉後的影像將無法很好地放入矩形影像中。 因此,為了確保不會丟失任何影像數據,最終影像的大小會適當放大,以便容納旋轉後的影像。
|
![]() |
ImageMagick 添加的額外空間使用當前的「-background 」顏色設定著色。 允許您指定要填充到角落的顏色。
|
![]() |
當然,如果您想用透明顏色填充,您需要確保影像可以處理透明度(通過啟用添加 Alpha 通道),並且保存為可以處理透明度的影像格式。
|
![]() |
![]() ![]() |
在 6.1.2 版本之前,「-rotate 」無法正確處理透明度,會在旋轉影像的角落產生黑色和透明條紋。 這個問題的解決方法相當複雜,需要將 Alpha 通道與顏色分開旋轉。 |
-crop
" 將圖像恢復為原始大小。如果您不知道原始大小,可以使用 Alpha 合成技巧(請參閱「Src
」合成方法)將圖像恢復為原始大小。
|
![]() |
-rotate
" 運算子也接受兩個額外的標誌。如果在旋轉參數中添加「>
」符號(在數字之前或之後),則僅當圖像的寬度大於高度時才會旋轉圖像。也就是說,「90>
」只會將「橫向」(寬)樣式的圖像旋轉為「縱向」(高)樣式的圖像,以便所有圖像都是「縱向」樣式。另一個標誌「<
」則相反,僅旋轉高度大於寬度的圖像。例如,「90<
」將確保所有圖像都是「橫向」。此標誌的另一個用途是將「縱向」和「橫向」圖像旋轉不同的角度。也就是說,您可以給出兩個不同的 "-rotate
" 操作,以便您將「縱向」朝一個方向旋轉,將「橫向」朝另一個方向旋轉。數位照片也可以透過使用 "-auto-orient
" 運算子旋轉以匹配 相機方向(基於圖像的 EXIF 中繼資料)。但是請記住,儲存回 JPEG 格式可能不是一個好主意。 旋轉運算子內部
從 IMv7.7.3-4 開始,旋轉運算子 現在使用 扭曲運算子 和 縮放-旋轉-平移 (SRT) 扭曲。以下是使用底層 SRT 扭曲 進行更直接的旋轉。
|
![]() |
或者使用扭曲運算子的「+」版本來調整畫布大小。
|
![]() |
剪切圖像 -線性位移
"-shear
" 運算子會取得每一列(或每一行)像素並沿著滑動,以便每一列(或每一行)相對於相鄰列(或相鄰行)偏移相同的量。它的兩個參數以角度表示。與 "-rotate
" 一樣,該操作會增加結果圖像的大小,以免遺失任何資訊。然而,剪切更為複雜,因為它實際上是一個雙重操作。
magick koala.gif -background Blue -shear 20 shear_rot.gif magick koala.gif -background Blue -shear 20x0 shear_x.gif magick koala.gif -background Blue -shear 0x50 shear_y.gif magick koala.gif -background Blue -shear 20x50 shear_xy.gif magick koala.gif -background Blue -shear 20x0 -shear 0x50 shear_xy2.gif magick koala.gif -background Blue -shear 0x50 -shear 20x0 shear_yx.gif |
![[IM Output]](shear_rot.gif)
![[IM Output]](shear_x.gif)
![[IM Output]](shear_y.gif)
![[IM Output]](shear_xy.gif)
![[IM Output]](shear_xy2.gif)
![[IM Output]](shear_yx.gif)
-shear
"(第四張圖)實際上等同於先進行 X 軸剪切,然後進行 Y 軸剪切(並進行適當的圖像裁剪),如倒數第二張圖所示。請注意,剪切的順序會產生不同的結果。如果只提供一個數字(參數中沒有任何「x
」,如第一張圖所示),則 "-shear
" 會將其應用於 X 和 Y 方向,作為一種簡陋的旋轉方式。當然,"-background " 顏色設定用於添加的額外空間的顏色。
|
![]() |
![]() ![]() |
在 IM 6.1.2 版本之前,"-shear " 不處理透明度。這個問題的解決方法相當複雜,需要將 Alpha 色板與顏色分開進行剪切。 |
-shear
" 並不是旋轉圖像的正確方法。要真正使用剪切來正確旋轉圖像,你需要以 "-shear {X}x{Y} -shear {X}x0 -crop ...
" 的形式執行多個剪切操作,但是要找出「{X}
」、「{Y}
」和最終裁剪的適當值需要一些三角學知識。旋轉運算符實際上曾經以這種方式實現,並且執行此操作的 API 函數仍然可用,但不再從命令列中提供。![]() ![]() |
請注意,在 X 方向上進行剪切不會影響圖像的高度,而在 Y 方向上進行剪切不會影響圖像的寬度。結果是圖像中某些對象所覆蓋的區域不會改變(只有包含圖像的周圍容器會改變)。 |
![]() ![]() |
剪切運算符是作為源圖像的直接「扭曲」(僅扭曲單個行和列中的像素)來實現的。因此,它不使用插值設定或虛擬像素設定。 因此,添加到圖像中的區域僅由當前的 " -background " 顏色填充,並且沒有提供保留圖像原始顏色的方法。 |
使用剪切的等距立方體
雖然剪切不是最漂亮或最簡單的操作器,但这並不代表你不能用它們做一些奇特的事情。以下是如何使用 "-shear
" 建立等距立方體的範例。Windows 批次檔範例 所開發,收錄於他為 IM 範例撰寫的在 Windows 下使用 IM中。請注意,以上圖片並未正確接合。它們應該使用正片 Alpha 合成,但卻使用了覆蓋。如需更多資訊,請參閱對齊兩個遮罩影像。因此,您可能會在正確對齊三個影像時遇到問題,導致間隙或影像重疊。由於定位僅限於整數定位,因此這個問題可能會特別嚴重。在這種情況下,使用更大的尺寸、更容易管理的座標,以及稍微調整數學計算,將有所幫助。合併影像後,將結果縮小到最終大小將使接合處的任何輕微偏差變得清晰可辨。另一個類似的範例是使用仿射變形和正確的 Alpha 合成,請參閱使用仿射分層的 3D 立方體。這個方法可以大幅簡化產生上述立方體所需的影像處理。波浪影像 - 正弦波位移
"-wave " 運算子和 "-shear " 類似,它會將「線性位移」新增至影像。然而,此運算子只會根據正弦波函數垂直位移像素列。"-wave " 運算子有兩個參數。第一個是像素向上或向下位移的最大高度或「振幅」,而第二個是正弦函數的「波長」(以像素為單位)。
|
![]() |
請注意,由於像素可以位移到指定的「振幅」,因此即使實際上不需要額外的空間,也會始終在影像的頂部和底部添加該空間。例如,通過調整參數使「波長」為影像寬度的兩倍,您可以將影像變成弧形。
|
![]() |
在這種情況下,可以使用 "-chop "、"-shave ",或者甚至 "-trim " 運算來移除未使用的空間。讓我們通過使用負振幅來翻轉弧線,並使用 "-chop " 移除 "-wave " 運算子添加的未使用空間,來清理先前的範例。
|
![]() |
當然,可以使用 "-background " 顏色設定來定義添加到影像的額外空間。
|
![]() |
從上面的範例中可以看出,"-wave " 只在垂直或「Y」方向上應用。如果要在 X 方向上添加波浪,則需要在應用波浪之前和之後旋轉影像。
|
![]() |
-wave
" 的另一個限制是波浪只能從零開始。也就是說,最左邊的列沒有位移,而接下來的幾列向下位移(正 X 方向),除非您為初始垂直偏移指定負「振幅」。基本上,"-wave " 運算子(目前)不允許您為正弦函數的開始指定偏移量。但是,可以使用 "-splice " 添加然後移除影像偏移量來修正此問題。
|
![]() |
-wave
」不會使用目前的虛擬像素設定來定義添加區域的顏色,但它會查看目前的插值設定,將顏色從來源映射到生成的圖像。這意味著波浪往往會在圖像的垂直帶中輕微模糊像素。圓形扭曲
到目前為止,圖像扭曲相當輕微,圖像數據幾乎沒有拉伸、擴展或壓縮。也就是說,數據幾乎保持不變。接下來的幾個圖像運算符可能會導致圖像失真,以至於無法確定原始圖像。顏色扭曲成一片模糊。它們還會將扭曲效果限制在一個圓形區域內,而圖像矩形邊緣的原始圖像幾乎沒有扭曲。這意味著,您可以使用區域運算符在較小的區域上使用這些運算符,並且結果仍將融入原始圖像,而不會看起來像是:被剪切、扭曲並粘貼回原位。也就是說,它們被稱為「局部」扭曲,因為它們可以用於扭曲圖像的較小區域。向內凹陷影像
「-implode 」運算符扭曲圖像,以便將所有像素拉向中心。它有點像在圖像中心放置一個真空吸塵器或「黑洞」,然後將像素吸向它。但是,建議一開始只使用非常小的值,然後慢慢增加這些值,直到獲得所需的結果。大多數新手用戶往往會使用過大的值,並對結果感到失望。例如,這是一個典型的圖像內爆...
|
![]() |
使用越來越大的值基本上會將圓圈中的所有像素吸入虛無。
|
![]() |
1.0
」的「-implode
」值也會受到虛擬像素設定的影響,因為算法開始對實際圖像本身邊界以外的顏色進行參考。由於默認的「-virtual-pixel
」設置為「邊緣」,因此圖像上的邊緣顏色或周圍邊框可能會對結果產生重大影響。例如,這兩張圖像是相同的,只是其中一張添加了白色邊框。這基本上顯示了使用從圖像本身邊界以外查找的顏色的區域。該區域通常由「-virtual-pixel
」設定定義。
|
![]() ![]() |
背景
」)將產生與添加「-border
」相同的效果,但不會放大圖像。其他虛擬像素設置可以在中央內爆區域產生更有趣的效果。例如,使用「平鋪
」設置可以添加高度扭曲的圖像副本。例如,在這裡,我使用此設置內爆了簡單的框圖像...
|
![]() |
-virtual-pixel
」效果。隨著內爆到一個小區域的像素數量增加,並且內爆參數的大小變得非常大,結果開始呈現「像素化」的外觀。為了獲得更好、更一致的結果,您可以使用一種稱為超採樣的技術來增加內爆處理的像素數量。基本上,通過使用更大的圖像(如有必要,放大源圖像),進行扭曲,然後將結果縮小到其最終大小,您將產生更好的結果。
|
![]() |
通過在被內爆的圖像周圍使用更大的「-border 」(邊框),然後再次將其移除,您也可以將圖像的邊緣向內彎曲到中心。
|
![]() |
從 IM 6.2.1 版開始,您也可以使用透明邊框,或具有透明度的圖像...
|
![]() |
向外凸出影像
通過對「-implode 」(內爆)運算符使用負值,您可以使圖像爆炸。然而,這更像是放大圖像的中心,將所有中間半徑的像素推向邊緣,而不是真正的爆炸。
|
![]() |
使用更大的值基本上會將圖像最中心的像素放大到一個圓圈中,該圓圈的大小是最小圖像尺寸的三分之二。
|
![]() |
|
![]() |
旋轉影像漩渦
「-swirl 」(旋轉)運算符的作用類似於蛋糕攪拌器。它會將圖像繞圈旋轉您作為參數給出的度數。
|
![]() |
通過添加邊框並與「-implode 」(內爆)結合使用,您可以呈現出漩渦將圖像吸入虛無的景象。
|
![]() |
動畫(有趣的例子)
最後,讓我們生成一些這些變形的 GIF 動畫。為此,我生成了一些簡單的 shell 腳本來生成動畫圖像,您也可以下載這些腳本並使用您自己的測試圖像進行試驗。這讓我想起了一個重點。如果使用這些變形生成一系列圖像,最好始終從原始起始圖像進行變形,而不是反覆遞增地變形圖像。對於旋轉圖像尤其如此,其中結果會有一些模糊,儘管在任何單獨的操作中都是最小的,但是,如果您反覆這樣做,這就是結果。所有腳本都使用「生成的“magick
”命令」技術來創建動畫。也就是說,shell 腳本會創建一個長的單命令,然後執行該命令。這避免了生成臨時文件的需要,儘管可能難以調試。另一種選擇是使用方法,稱為 MIFF 圖像流,它在循環中生成單個圖像,並將其「管道化」到最終的「合併」命令中。這在範例「分層圖像的程式化定位」和「地圖中的圖釘」中有更清楚的說明。
![]() |
shell 腳本「animate_mixer 」中的每一幀都是通過在原始圖像上使用「-swirl 」(旋轉)生成的。旋轉動畫沿一個方向進行,然後再返回以形成連續循環。這實際上是 IM 中非常典型的扭曲動畫範例。這種方法的一種變體是讓動畫反向扭曲成不同但相似的圖像。 |
![]() |
這個 shell script「animate_whirlpool 」不僅對每個圖像幀使用「-swirl 」,還會使用遞增參數大小的「-implode 」。我為添加的空間使用了「lightblue 」邊框顏色,以顯示整個圖像將被「吸入排水管」,但我應該使用相同的白色背景顏色,以獲得更好、更逼真的效果。 |
![]() |
圖像中間的爆炸(請參閱腳本「animate_explode 」)。圖像再次被放大,因此整個圖像都被炸開,並且在中心繪製一個彩色點以定義最終顏色。 |
![]() |
使用 shell script「animate_flex 」,通過正負改變「-wave 」函數的振幅,可以上下彎曲圖像的中心。 |
![]() |
使用 shell script「animate_flag 」,我創建了一個「偏移波」動畫,使圖像像旗幟一樣飄揚。通過垂直偏移圖像的每一幀,使左側邊緣保持不變,並可能添加旗桿,可以改進動畫。但是,這需要您以數學方式確定該偏移量,這可能會很棘手。 |
![]() |
腳本「animate_rotate 」生成了這個旋轉動畫,但會使用原始圖像裁剪每一幀,如上所述,以保留原始圖像大小。
|
![]() |
作為比較,以下是使用默認設置和「-distort SRT {angle} 」命令生成的無尾熊旋轉。用於生成它的腳本是「animate_distort_rot 」。請注意,使用這種旋轉方法時,圖像清晰度更高,並且沒有前一版本中明顯的旋轉「抖動」。 |
額外動畫和影片
![[IM 輸出]](../images/swirl_video.gif)
-swirl
」扭曲運算符創建了一個漂亮的影片,該影片是使用 IM OCaml API 腳本製作的。選擇右側的 GIF 動畫以下載完整版的影片。 您可以製作一部展示扭曲映射技術的優秀影片嗎?您在網路上其他地方看過嗎?請發送郵件給我。