ImageMagick 範例 --
圖像扭曲

索引
ImageMagick 範例前言和索引
常見扭曲技術
 
仿射矩陣變換(單獨的子目錄)
 
廣義扭曲運算符
 
扭曲方法簡介
 
仿射(三點)扭曲方法
四點扭曲方法
多項式 扭曲
圓形和徑向扭曲方法
投影扭曲
多點和自由形式扭曲
在了解了 IM 從早期版本就提供的簡單內建圖像環繞和扭曲運算符集之後,我們將深入探討圖像扭曲的內部機制和更複雜的數學原理。基於這種更深入的理解,我們將探討更通用的圖像扭曲運算符。這包括從複雜的旋轉、縮放和剪切到透視或 3D 扭曲,再到圓弧、相機鏡頭扭曲,最後到更通用的變形扭曲。

一般失真技巧

現在我們已經介紹過 IM 提供的簡單失真運算子,讓我們退一步,看看其細節,並了解圖像失真實際上是如何運作的,以及如何改進使用方式。稍後,我們將進一步探討更複雜的圖像失真方法,包括 ImageMagick 中沒有直接內建的方法。圖像處理器只有幾種基本的方法可以扭曲圖像。例如,簡單失真 運算子是透過 像素交換 來實現的。也就是說,單個像素甚至整個像素行和列只是交換位置,以實現圖像的 翻轉滾動轉置,甚至是 矩形旋轉。顏色不會改變,像素數量也保持不變。扭曲圖像的下一種方法是水平或垂直 移動或剪切 像素行和列,例如 IM 使用 圖像剪切 和上面的 波浪失真 所做的。剪切反過來提供了一種以任何給定角度 旋轉圖像 的方法,這種方法應該相當快。但是,像素移動方法僅限於那些基本的失真。例如,它無法將圖像縮放到不同的尺寸。您也無法很好地控制如何處理結果圖像中原始來源圖像未涵蓋的區域。在上述函數中,IM 只是將遺漏的區域設定為目前的背景顏色。為了能夠以更通用的方式扭曲圖像,您需要使用一種稱為 反向像素映射 的更通用的失真技巧。例如,這種方法被更複雜的 圓形失真 所使用,例如 內爆旋渦 圖像。

正向或直接像素映射

人們在嘗試扭曲圖像時,首先想到的就是將來源圖像中的每個像素直接移動到目標圖像中的新位置。事實上,這有點類似於 簡單失真圖像裁剪,甚至是扭曲向量圖像時實際發生的情況。每個像素(或坐標)只是被移動到最終圖像中的新位置。不幸的是,當您嘗試對任何不是簡單失真的東西執行此操作時,就會出現問題。例如,在這裡,我採用了一個小圖像的列舉像素列表,並更改每個像素的位置,以便將其旋轉到新的位置。

  # Rotate by 17 degrees -- get the Sine and Cosine of this angle
  sin=`magick xc: -format "%[fx:sin( 17 *pi/180)]" info:`
  cos=`magick xc: -format "%[fx:cos( 17 *pi/180)]" info:`

  # For each Pixel, rotate that pixels coordinates
  magick koala.gif  txt:- |  sed '2,$ s/,/:/' |\
    gawk -F: 'NR == 1 { print }
              NR > 1 {  x = $1-32;    y = $2-32;
                        nx = int( c*x - s*y + 32 );
                        ny = int( s*x + c*y + 32 );
                        printf( "%d,%d: %s\n", nx, ny, $3 );
              }' s=$sin c=$cos - |\
      magick -background black  txt:-   koala_rotated_direct.gif
[IM Output]
失真只是一個簡單的 17 度旋轉,但結果一點也不好。首先,每個新的像素位置都是一個浮點值,但像素只能存在於整數網格中,因此上述方法只是簡單地捨棄結果的非整數部分。第二個問題是結果充滿了沒有像素落下的孔洞。這就帶來了第三個問題。您可能沒有看到,但對於結果圖像中的每個孔洞,您還會發現另一個位置放置了兩個像素。也就是說,同一個位置有多個像素。您應該使用哪個像素值?在上面的 IM 中,只使用了為一個位置定義的最後一個像素。換句話說,結果圖像是*不完整*的,其中目標中的每個像素都不完全在其應有的位置,並且可能有多個像素,或者根本沒有像素。這些都是嚴重的問題,而且當從源圖像直接到目標圖像進行前向映射像素時,這些問題並不容易解決。也就是說,並不是說它不能工作,而且許多研究論文都在談論使用一種稱為“splatting”的技術。基本上,他們採用每個輸入像素,轉換其位置,然後在新位置繪製它,並適當擴散和混合像素顏色。這種技術在處理現實世界對象的 3D 數字化時特別有用。在這裡,您有一個已知顏色表面點的“雲”。對用戶可見的任何點都簡單地“splatted”到屏幕上,以便形成最終圖像。有足夠的點,圖像就會看起來很完整。通過交互式 3D 控制,它工作得非常好,而且速度非常快。然而,splatting 三維點超出了 IM 處理二維柵格圖像的範圍。

反向像素映射

您可以將目標圖像中每個像素的坐標映射到源圖像中的相應位置,並從源圖像中查找該像素應包含的顏色,而不是嘗試將像素映射到最終圖像中。這稱為*反向像素映射*,幾乎所有圖像失真程序都是這樣做的。由於處理了每個目標圖像像素,因此我們可以確保目標中的每個像素都只有一個顏色。因此,只要我們能夠找出每個目標像素的“源”位置,我們就可以使用您可以想像的任何數學公式將源圖像扭曲到目標圖像。
[Diagram]
總之,失真映射(反向映射)執行以下操作。
For each pixel (I,J) in the destination or output image
   Map the I,J pixel position to a X,Y pixel position in the original image
   Look up the Color of the original image at position X,Y
       Using color interpolation, work out the appropriate color.
       Or the virtual-pixel setting, if it misses the actual source image.
   Set the destination images color for pixel I,J
請注意,我在上面使用了變量名“I,J”和“X,Y”,因為這些變量映射到您通常在 FX DIY 運算符 中使用的變量名。例如,在這裡,我模擬了我之前嘗試的相同 17 度旋轉,但這次使用“-fx”運算符在源圖像中查找最接近該位置的像素。

  # Rotate by 17 degrees -- get the Sine and Cosine of this angle
  sin=`magick xc: -format "%[fx:sin( 17 *pi/180)]" info:`
  cos=`magick xc: -format "%[fx:cos( 17 *pi/180)]" info:`
  cx=37; cy=37;   # center of rotation

  magick -size 75x75 xc:       koala.gif  \
          -virtual-pixel Black  -interpolate NearestNeighbor \
          -fx "ii = i - $cx;   jj = j - $cy;
               xx =  $cos*ii +$sin*jj + $cx;
               yy = -$sin*ii +$cos*jj + $cy;
               v.p{xx,yy}" \
          koala_rotated_fx.gif
[IM Output]
您可以在 DIY 仿射失真映射 的小節中獲取有關上述 DIY 示例的更多詳細信息。如您所見,我們的圖像中不再有“孔洞”,因為為目標中的每個像素都查找了顏色。它看起來仍然不是很好,但這是調整每個像素中應該放置的確切顏色的問題。也就是說,反向像素映射不會產生孔洞或重疊像素。每個像素都有一個定義明確的顏色,從而生成完整的圖像。
正向與反向映射之間的區別很重要,因為大多數數學變換都被定義為正向映射,將單個來源 (X,Y) 位置映射到目標 (I,J) 位置。事實上,「正向映射」適用於向量圖形和繪製線條,您可以映射線條的端點並繪製它。對於任何線性變換(例如旋轉,其中線條保持筆直)尤其如此。事實上,所有基於向量的語言(例如 PostScript 和 SVG)都是這樣做的。但對於一般的點陣圖像,您必須使用「反向映射」來扭曲圖像,以便您能確定「填滿」目標圖像的所有像素。例如,如果您查看用於映射上述兩種情況下的坐標的數學,您會發現它們看起來幾乎完全相同。「旋轉」的反向映射是另一個「旋轉」,只是方向相反。如果仔細觀察,您會發現「正弦」常數被否定為正向映射版本,這足以反轉旋轉方向。這個細節很重要也很關鍵。問題並非所有正向映射變換都能很好地作為反向變換。事實上,一些正向映射沒有簡單的直接反向映射。這並不是說它不能做到,只是不簡單。另一方面,一些圖像變換作為反向映射效果很好,但沒有簡單的正向映射。所以使用反向映射方法在數學上既有優點也有缺點。
僅供參考,以下是用 通用扭曲,SRT 方法實現的更快等效方法,它對圖像執行了與上述完全相同的旋轉,並產生完全相同的結果,只是速度更快。同樣,通過使用「點」插值,顏色查找僅限於最接近映射位置的像素的顏色。這意味著圖像中不會添加任何新顏色(當我們「錯過」源圖像時除外),但您也會看到嚴重的鋸齒效應。

  magick koala.gif  -virtual-pixel Black  -interpolate NearestNeighbor \
          -filter point    -distort SRT 17    koala_rotated_srt.gif
[IM Output]
有關扭曲變換的替代討論,請參閱 Leptonica,仿射實現,特別是它對「逐點」方法的討論。另一種方法「順序」基本上是 IM 過去實現其 旋轉剪切 扭曲運算符的方式。
名稱的意義?在我的研究中,我發現這種圖像處理方法並沒有真正明確的名稱。實際的算法過程被稱為「反向像素映射」,而使用數學方程式則被稱為「幾何變換」。如果扭曲是通過各種控制點的移動來控制的,它通常被稱為「圖像扭曲」或「橡皮膜」。定義特定點的過程,通常是為了找到兩個或多個圖像之間的等效點,被稱為「圖像配準」。圖像也可以被細分為更小的簡單單元,這些單元可以使用稱為「網格化」(四邊形)和「三角網格化」(三角形)的技術單獨扭曲。通過使用小的增量扭曲和來自兩個圖像的顏色混合,您可以生成動畫的「圖像變形」,就像您在電影和音樂視頻中看到的那樣。如果使用預先準備好的映射圖像,而不是動態的數學查找,您將獲得「絕對扭曲映射」,如果查找是相對位移(50% 灰色表示沒有位移或查找坐標的變化),您將獲得「位移映射」。如果映射僅稍微修改顏色(陰影)而不是查找扭曲,您將獲得相關但不同的「凹凸表面映射」。在 3D 建模和 3D 電腦遊戲中,相同的技術也被用於在稱為「紋理映射」的方法中為平面和曲面賦予某種類型的彩色圖案。這可能涉及將圖像細分為接近單個像素的網格和網格。然後,您可以使用稱為「點樣條」的技術查看由數百萬個單點定義的對象,儘管這通常使用正向映射扭曲來應用。以上所有內容都非常密切相關,並且最基本地涉及基於將最終目標坐標映射到源圖像(或對象)來查找像素顏色。換句話說,將「目標映射到源」。應該使用哪個術語... 由您選擇。

像素顏色查找

上述反向像素映射技術仍然存在一些問題。首先,當從目標中的固定整數位置映射像素時,您最終可能會在源圖像中獲得非整數位置。也就是說,一個位置落在源圖像上各個像素之間的某個位置。為了確定應該返回什麼顏色,使用稱為插值的過程,通過混合周圍像素的顏色來確定該實際位置的最終顏色。插值設置還將處理扭曲圖像的一部分變得「拉伸」的情況,以便單個源像素在目標圖像的大面積上被塗抹。然而,簡單的插值方法不能很好地處理相反的情況。這就需要我們在下面介紹的其他技術。例如,我們在這裡再次旋轉我們的無尾熊,但這次使用「-interpolate 網格」設置來混合附近的四個像素,以便從查找中產生更好、更正確的顏色。

  magick koala.gif  -virtual-pixel Black  -interpolate Mesh \
          -filter point    -distort SRT 17    koala_rotated_mesh.gif
[IM Output]
如您所見,只要簡單地合併非整數查找點周圍最鄰近的顏色,就能大幅改善失真影像的外觀。但還有一些其他問題... 例如,當映射位置完全「錯過」來源影像時,該怎麼辦?在這種情況下,要返回什麼顏色由虛擬像素設定決定。此設定將選取一種顏色,例如來源影像的最近邊緣,假設來源影像在平面上無限平鋪(或鏡像平鋪),或使用某些特定顏色,例如「白色」、「黑色」或「透明」,或使用者定義的背景顏色。此外,也可能沒有數學上有效的座標對應於要映射的特定目標位置。例如,像素朝向透視「平面」的「天空」看(請參閱觀看遙遠的地平線),因此甚至看不到來源影像所在的「平面」。在這種情況下,虛擬像素是沒有用的,因為它確實「擊中」了 N 維空間中的來源影像平面,因此目標像素完全無效!在這種情況下,IM 會使用像素顏色的目前「-alpha set」設定。如果它「差一點」就擊中,IM 會使用影像平面的相鄰顏色對這種無效顏色進行反鋸齒處理(如果它知道如何處理的話)。它適用於透視失真。

超級採樣

插值法非常適合簡單的圖像扭曲。但如果原始圖像的一部分被壓縮到一個更小的區域,每個目標像素實際上可能需要合併原始圖像中更大的區域。請記住,像素實際上不是點,而是代表真實圖像中的一個矩形區域。這意味著在某些情況下,我們真的應該嘗試將原始圖像的大區域壓縮到一個目標像素中。當這種情況發生時,簡單的像素查找將會失敗,因為它只查找原始圖像中單個“點”的顏色(使用周圍的像素鄰域),並且不會合併和組合所有可能必須壓縮到該單個像素中的輸入圖像的顏色。這樣做的結果是,目標像素最終可能會得到原始圖像中本質上隨機的顏色,而不是所有相關顏色的平均值。這本身並沒有什麼壞處,但是當一個區域中的所有像素都這樣做的時候,你會得到看起來隨機的、孤立的像素、摩爾紋效應和鋸齒狀的“階梯”效應的圖像。細線也開始看起來更像是點線和虛線(參見採樣運算符的示例),或者可能完全消失。所有這些效應統稱為混疊偽影。解決這個問題的方法是從原始圖像中對目標圖像中的每個像素進行更多的顏色查找,以便嘗試為目標圖像中的每個像素確定更準確的顏色。最簡單的解決方案通常稱為超級採樣過採樣。請參閱維基百科關於超級採樣的條目。通過從原始圖像中獲取更多樣本,在將映射到每個目標像素的區域上,該像素的最終顏色將成為該點扭曲圖像的更準確表示。您製作的顏色樣本越多,最終的顏色就越準確,並且會產生更平滑、更逼真的外觀,儘管扭曲的速度會變慢。請記住,這種技術實際上只在原始圖像被壓縮超過 50% 的區域中改善了目標的整體外觀。在扭曲放大原始圖像或保持其大致相同比例的區域中,單個插值查找原始圖像查找通常只需一次查找即可產生良好的結果。在內爆圖像扭曲示例(以及 IM 示例中的許多其他示例)中,我簡要介紹了“超級採樣”的最簡單方法。基本上是放大輸出圖像的尺寸(或者在這種情況下只是放大輸入圖像),然後執行扭曲。在扭曲完成後,我們將圖像重新縮放到其正常大小,這將合併生成的所有額外“樣本”。例如...

  magick -size 94x94 xc:red -bordercolor white -border 3 \
          -virtual-pixel tile                -implode 4 \
          implode_tiled_box.gif
  magick -size 94x94 xc:red -bordercolor white -border 3 \
          -virtual-pixel tile  -resize 400%  -implode 4 -resize 25% \
          implode_tiled_ss.gif
[IM Output]
盒狀圖像的正常內爆
[IM Output]
超級採樣內爆
當然,您可以從更高質量(更大)的原始圖像開始,或者在之前的某些處理步驟中生成一個,而不是放大輸入圖像。如果有的話。這在旋轉文本時特別有用,因為文本通常具有非常精細的細節,需要統一保留這些細節以確保最終圖像具有良好的高質量外觀。有關這方面的示例,請參見拍立得變換
從 IM v6.4.2-6 開始,通用扭曲運算符可以直接生成放大的輸出圖像,您可以將其縮放(或調整大小)回原尺寸,以便合併和超級採樣生成的像素。請參閱扭曲比例設置,以及下一個示例。
這只是一種*超級採樣*的方法(稱為「網格」法),但此方法還有許多其他變形。 最終,這些方法可能會更直接地在 ImageMagick 中實現,但目前簡單地放大和縮放圖像效果很好,無需任何額外的編碼需求。 最後一個警告。 超級採樣受限於最終圖像中每個像素使用的採樣數量,因此也受限於最終調整大小中使用的縮放量。 這決定了失真圖像的最終「品質」。 但是通過使用更大的縮放因子,失真圖像的生成速度當然會慢得多。 但即使有更高的品質,也有其限制。 在極端情況下,超級採樣無法處理任何涉及無窮大的圖像失真(例如在內爆圖像的中心)。 在這種情況下,需要一種完全不同的技術,例如區域重新採樣提供的技術(見下文)。 總之,超級採樣可以改善只有輕微失真的圖像的外觀,例如旋轉、剪切、仿射和簡單透視。 但它對它可以改善的失真類型有限制。 自適應超級採樣 超級採樣技術可以進一步擴展。 不是僅對每個像素使用固定數量的顏色查找,而是檢查源圖像中查找之間的距離,或檢查從低級採樣返回的顏色有多接近,以查看它是否應該為該特定像素製作更多樣本。 也就是說,超級採樣的數量可以根據失真的需要做出響應,而無需了解失真本身的具體細節。 這被稱為*自適應超級採樣*。 這種技術在光線追踪器中實際上非常普遍,在光線追踪器中幾乎不可能確定在任何特定點生成的圖像有多複雜。 在這種情況下,它通常僅限於使用特定位置周圍的「顏色差異」來確定何時需要更多樣本。 如果一個像素与其相鄰像素非常不同,則在該區域中使用更多樣本來細化可能是某些 3 維對象邊緣的內容。IM 目前不支持自適應超級採樣。 雖然很有可能將其他採樣方法添加到通用失真運算符中(見下文)。 它需要對代碼進行一些功能上的重新排列,因此可能不會很快添加。 超級採樣總結 超級採樣的難點在於確定需要多少「點採樣」,以及如何將這些採樣與子像素边界排列。 以及應該應用哪種「加權」。 請參閱維基百科關於超級採樣的條目

區域重新採樣,用於更好的失真

區域重新取樣 (Area Re-sampling) 是超級取樣方法的最佳替代方案之一。它並非透過調整大小來扭曲較大的影像並對結果進行平均,而實際上是根據該點的扭曲「比例」精確地確定應該合併多少個來源影像的像素(這只是從影像中取得並平均更多樣本)以產生每個特定的輸出像素。也就是說,找出來源影像中每個輸出像素所代表的粗略「區域」,並根據重新取樣濾波器合併(過濾)該區域中的所有像素。實際上,這正是 ImageMagick 調整大小運算子(實際上是一種非常特殊的影像扭曲類型)產生如此出色結果的原因。但是,對於調整大小,您只需要計算一次整個影像中每個像素需要取樣的區域比例。它需要「取樣」的區域是來源影像中的固定大小矩形(視窗),這使得重新取樣過程變得容易,並在扭曲過程中提供捷徑。當對扭曲的影像進行區域重新取樣時,要從中獲取樣本的像素區域(視窗)不僅會改變位置,而且還會改變大小。因此,目標影像中的一個像素可能只需要合併幾個來源影像顏色,甚至只需要一個單一的插值顏色查找(例如在放大時)。而目標影像中其他位置的另一個像素,則可能需要對非常多的像素進行取樣才能產生正確的最終顏色。接近無限時,它甚至可能必須將來源影像中的所有像素都包含在取樣過程中。此外,目標像素在來源影像中表示的區域可能不是簡單的正方形、圓形,甚至橢圓形,而實際上可能是高度扭曲的形狀,具體取決於所使用的扭曲。計算和處理這種不規則的形狀可能非常耗時,或者幾乎不可能實現。[圖表] 使用來源影像的橢圓區域來計算每個目標像素的顏色,這種方法稱為橢圓加權平均 (EWA) 重新取樣,並在 PDF 研究論文「紋理映射和影像變形的基礎」中進行了概述,該論文由 _Paul Heckbert_(他也編寫了幾乎所有影像調整大小演算法都源自的「zoom」程式)撰寫。然後,這被用於定義新的 通用扭曲運算子(見下文)。橢圓是 仿射扭曲透視扭曲 的完美形狀。它對於極端的縮小特別有效(請參見下面的範例)。雖然它不是其他扭曲的完美選擇,但它通常適合許多其他扭曲,例如 弧形和極座標扭曲(但不是它們的反向),以及徑向扭曲,如 桶形失真。但它不適合非線性扭曲映射,例如 去極化Shepards 扭曲,因此它不用於這些扭曲。超級取樣沒有這種形狀問題,因為每個「樣本」都反向映射到目標影像上。所以在這種情況下,它成為更好的取樣方法。但正如前面提到的,它可能不會對所有需要的像素進行取樣,甚至可能對過多的像素進行取樣。

區域採樣與超級採樣

以下是 IM 目前提供的全部三種取樣方法,當應用於極端的無限平鋪透視影像時。有關此扭曲的詳細資訊,請參見下面的 查看遙遠的地平線

  # input image:  special checkerboard with a gold outline.
  magick -size 90x90 pattern:checkerboard -normalize -fill none \
          -stroke gold -strokewidth 3 -draw 'rectangle 0,0 89,89' \
          -fill red        -draw 'color 20,20 floodfill' \
          -fill lime       -draw 'color 40,70 floodfill' \
          -fill dodgerblue -draw 'color 70,40 floodfill' \
          checks.png

  # Using Interpolated Lookup
  magick checks.png -filter point \
          -virtual-pixel tile -mattecolor DodgerBlue \
          -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          horizon_tile_point.png

  # Using Grid Super Sampling
  magick checks.png  -filter point  -set option:distort:scale 10 \
          -virtual-pixel tile -mattecolor DodgerBlue \
          -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          -scale 10%    horizon_tile_super.png

  # Using Area Resampling (default)
  magick checks.png       -virtual-pixel tile -mattecolor DodgerBlue \
          -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          horizon_tile.png
[IM Output]
檢查影像
==> [IM Output]
插值
查找表
[IM Output]
超級採樣
x10
[IM Output]
橢圓加權區域
(EWA) 重新取樣
所有圖像都具有完全相同的失真,只是使用了不同的「重新採樣」技術。 上圖中的最後一張圖像使用了 通用失真運算器 的默認 EWA 設置,您可以看到它產生了極其高質量的結果。 然而,生成此圖像花費了 4.6 秒,如果有點慢的話(由於涉及異常的極端情況),這還不算太糟糕。 第一個圖像通過使用「-filter point」設置關閉了默認的 EWA 重新採樣。 這迫使它對每個像素使用 直接插值查找。 因此,與之相比,此圖像生成速度極快(0.51 秒),但您可以看到,隨著「縮小」(下採樣)隨著「距離」的增加而產生可怕的結果。 中間圖像與第一個圖像相同,但失真輸出圖像被放大 10 倍,然後縮放回(網格重新採樣)以匹配其他圖像。 也就是說,每個目標像素會查找和平均超過 100 個像素,以便對結果進行 超級採樣。 它生成速度相當快(1.2 秒),雖然它總體上提高了圖像質量,但這種改進是有限的。 上述示例中使用的 ×10 非常大,遠遠超過大多數超級採樣使用中使用的更典型的 3 或 4 倍縮放。 結果之間最大的區別在於,超級採樣僅在整個圖像上均勻地進行一般的質量改進。 隨著失真變得更加嚴重,它開始崩潰。 結果是在中間地帶出現了非常明顯的 重新採樣偽影,更具體地說,是在地平線之前出現了一條嚴重的摩爾紋效果。 摩爾紋效應的產生是因為每像素 10 個樣本幾乎與圖像的棋盤格圖案相匹配,從而產生扭曲的色彩效果。 另一方面,區域重新採樣更多地集中在地平線附近的問題像素(它幾乎將所有時間都花在那裡)上,而不是前景像素上,它實際上的確優於超級採樣。 基本上,以上是一個非常極端的失真,EWA 查找所花費的時間是相稱的。 更常見的是,它會產生比單個插值查找好得多的結果,因為它有效地查看了所涉及的每個像素,而在不需要它的區域中沒有使用太多樣本,就像超級採樣那樣。 總之...使用簡單的橢圓(EWA 重新採樣)或矩形(調整大小)進行「區域重新採樣」確實會產生良好的效果,因為涉及縮放、仿射或透視失真的所有源像素將被合併以產生最終的顏色單個目標像素。 在非常非線性失真的情況下,例如 去極化失真,或不確定的失真,例如 Shepard 失真 甚至光線追踪,找到正確的「區域」以對所有需要的源像素進行重新採樣變得令人望而卻步,超級採樣是改進結果的最佳方法。 但是對於直接平鋪、放大和未縮放的旋轉,可能只需要一個非常快速的單個「點」插值查找,甚至可以建議確保完美的無操作(無變化)失真(見下文)。 但是請記住,所有重新採樣技術都只是確定每個單獨像素顏色的方法。 它實際上不是圖像如何失真的一部分,除了關於目標和源之間位置的映射(如果可能的話,反之亦然)。

通用失真運算器

隨著這些示例的產生,IM 論壇 中隨之而來的討論,以及用戶對更輕鬆、更快速地進行透視和其他失真的多項請求,IM v6.3.5-1 中添加了一個新的運算器,使我們能夠更輕鬆地添加許多不同類型的圖像失真。 這個通用失真運算器被稱為「-distort」,您可以使用「-list Distort」查看您的 IM 版本上可用的失真方法。

  magick -list distort
-distort」運算子需要兩個參數,一個是如上所述的變形*方法*,另一個是字串參數,包含以逗號或空格分隔的浮點數值清單,用於控制特定的變形方法。

  magick ... -distort  {method}  "{list_of_floating_point_values}" ...
然而,給定的浮點數值數量高度取決於所使用的變形方法,它們的含義不僅取決於所選的*方法*,還取決於特定方法所需的控制點或屬性的確切數量。對於「縮放-旋轉-平移」(或簡稱「SRT」)變形尤其如此,它實際上將三個獨立的「仿射」變形組合成單個變形。許多變形*方法*採用控制點列表(以圖像坐標表示),通常這些控制點以*坐標對*的形式給出,用於控制變形如何修改圖像。這些坐標對將在稍後的使用控制點的變形中詳細介紹。

變形選項、控制和設置

最佳擬合 +Distort 標誌

默認情況下,「-distort」通常會將來源圖像變形為與原始圖像大小相同的圖像。但也有一些例外,例如「弧形」變形(一種極坐標映射變體),其中輸入來源圖像的大小在變形後的圖像中並沒有太大意義(詳情請參閱下面的弧形變形)。運算符的另一種形式「+distort」(在 IM v6.3.5-7 中添加)將嘗試調整變形圖像的大小,使其包含整個輸入圖像(如果可能),這與舊的旋轉和剪切運算符的功能非常相似。但是,這種特殊的「模式」操作更進一步,還會設置結果圖像的虛擬畫布偏移量(頁面)。這樣,您就可以稍後使用適當的Alpha 合成,根據您的控制點將此圖像圖層合併到另一個圖像上的正確位置(請參閱3D 立方體,使用仿射分層作為基本示例。此外,(根據變形方法)「+distort」會嘗試考慮來源圖像中可能存在的任何虛擬畫布偏移量,並將其用作變形過程的一部分。請參閱有關各個變形方法的說明。因此,您可能需要明智地使用「+repage」屬性設置運算符,以便在使用「最佳擬合」「+distort」形式的通用變形運算符*之前*清除或調整該偏移量。如果不需要虛擬畫布和偏移量,您可能還需要在*之後*使用它。另請參閱移除畫布/頁面幾何。對於變形本身,普通的「-distort」將忽略來源圖像中存在的任何偏移量,但會將該偏移量原封不動地複製到變形圖像中。總之...使用「-distort」將結果映射到相同大小的圖像中。並使用「+distort」嘗試自動設置輸出圖像大小,但同時也會使用和生成虛擬畫布偏移量(頁面屬性)。如果您想覆蓋此通用視口選擇,並精確控制您希望在結果中看到變形圖像的哪個大小和哪個部分,另請參閱變形視口(如下)。
注意...“+distort”生成的最佳擬合視窗比用戶通常預期的要大 2 個像素。原因是這些像素包含區域重採樣濾鏡產生的半透明像素,這些像素對於正確的“邊緣連接”和扭曲圖像的疊加至關重要。從技術上講,添加的像素數量應取決於重採樣濾鏡支援的輸出縮放比例。也就是說,由於重採樣濾鏡,像素的面積可以“擴散”多少。然而,由於每個像素的縮放比例是可變的,因此計算所需的絕對正確的額外像素數量是一個非常棘手的問題,而且通常不值得付出努力。因此,添加 2 個像素是一種“ fudge ”,因為扭曲很少會放大圖像,從而導致像素“擴散”更多。此外,由於大多數標準重採樣濾鏡都支援 2 個單位,因此添加 2 個像素是合理的。此外,由於此添加是“固定的”,因此允許用戶選擇簡單地裁剪圖像大小(以各種方式),如果他們願意的話。當放大圖像時,2 個像素的“ fudge ”顯然變得太小了。但這些是相當罕見的扭曲,如果出現問題,用戶可以定義他們自己的視窗(見下文)。扭曲圖像在虛擬畫布上的虛擬偏移量會進行調整以考慮這 2 個額外像素,因此扭曲圖像對於疊加是正確的,但對於簡單的合成則不然。但請注意,雖然裁剪修剪會保留分層圖像的位置,但剃邊切除會相對於此偏移量移動圖層圖像。

扭曲像素顏色確定

如上文反向像素映射中所述,結果圖像中的每個點都是通過首先根據所選的扭曲方法將目標圖像中像素的位置映射到源圖像中的等效(反向扭曲)位置來確定的。但是,像素的最終顏色並不像看起來那麼簡單,因為它受到許多因素的影響。

虛擬像素和平鋪

扭曲映射點可能不會命中實際的源圖像,而是位於源圖像旁邊的某個位置,甚至距離實際圖像很遠。解決方案是假設源圖像被一個“無限”或“虛擬”表面包圍,該表面由當前的“-virtual-pixel”設置定義。有關此設置效果的詳細信息和示例,請參閱虛擬像素示例。這對於生成源圖像的扭曲甚至未扭曲的圖塊圖案非常有用。有關此技術的介紹,請參見虛擬像素部分本身(未扭曲)以及下面的仿射平鋪查看遙遠的地平線

無效的扭曲像素

有時候目標像素的扭曲甚至不會「碰到」虛擬拼接圖像!當您使用某種 3D 空間扭曲方法扭曲圖像,且像素「向量」甚至沒有碰到圖像所在的來源平面時,通常會發生這種情況。基本上,扭曲的結果在數學上變得「未定義」。在這種情況下,顏色將由「-mattecolor」設定決定。例如,當您在透視扭曲中看到「天空」(例如,請參閱檢視遙遠的地平線)時,用於確定來源圖像位置的數學計算變為「未定義」(實際上已定義,但從用戶的正向視角來看是無效的)。因此,「-mattecolor」會被輸出為「天空」。實際上,透視扭曲算法還設法包含了一些靠近地平線的像素的「抗鋸齒」資訊,儘管在這種情況下並不常見。

EWA 重新採樣和濾鏡

一旦您知道目標像素「碰到」來源圖像的位置,就需要使用來源圖像中「碰到」點附近的像素來確定目標像素的顏色。通常,扭曲運算子會使用區域重新取樣方法 EWA(橢圓加權平均)來平均來源圖像的較大區域,以計算出此像素的正確顏色。您可以使用「-filter」設定來更改 EWA 重新取樣所使用的濾鏡。如需更多詳細資訊,請參閱重新取樣濾鏡,以及更具體的圓柱濾鏡。最初,圓柱高斯濾鏡被用於 EWA 重新取樣,因為這是 EWA 重新取樣原始研究論文中定義的內容。但這往往會產生非常模糊的結果,儘管它也不會產生鋸齒效應。這曾經是預設濾鏡,並且在該版本之前(現已修復)的實現錯誤會導致極度模糊。在與勞倫森大學數學教授 Nicolas Robidoux 進行了大量討論之後,從 IM v6.6.5-0 開始,圖像扭曲的預設濾鏡被替換為「Robidoux」濾鏡,這是一個非常「類似於 Mitchell」的三次濾鏡,專為 EWA 重新取樣而設計。如需此濾鏡和其他圓柱濾鏡的資訊,請參閱圓柱濾鏡。但是請注意,任何底層的加窗 Sinc 濾波器函數都會被更圓的加窗 Jinc 濾波器函數替換。因此,選擇「Lanczos」濾鏡將返回「Jinc 加窗 Jinc」濾鏡,而不是「Sinc 加窗 Sinc」濾鏡。如需更多詳細資訊,請參閱加窗 Jinc 圓柱濾鏡。旁白:「Sinc」函數實際上不能用作圓柱函數,因為該函數與網格上的徑向距離的交互作用會導致濾鏡權重形成一種形式,每當使用偶數個「波瓣」時,就會趨於抵消自身(權重總和為零)。反過來,當與像素級棋盤格「雜湊」圖案一起使用時,這會導致它嘗試生成接近無限的顏色。基本上,EWA 使用重新取樣濾鏡,就像調整大小運算子一樣,因此您也可以使用特殊的專家濾鏡選項來修改濾鏡。例如,「Gaussian」和類高斯濾鏡的模糊度可以通過濾鏡模糊設定來控制。同樣,您可以使用波瓣支援設定來控制加窗 Jinc 濾鏡(例如「Lanczos」濾鏡)的大小和強度。
有許多極端扭曲方法會自動關閉 EWA 重新取樣,並且只使用更直接的插值查找

舉例來說,去極化扭曲會產生圓弧形的重新採樣區域,這些區域與「橢圓形」(EWA) 重新採樣不太吻合。其他扭曲,例如 謝潑德,會讓「縮放因子」的計算變得極其困難,儘管未來對扭曲運算子的改進可能會使其成為可能)。

建議對這些扭曲方法使用超級採樣技術,以防止在結果中的圖像壓縮(降採樣)區域中產生嚴重的鋸齒失真

重新採樣失敗

在某些特殊情況下,EWA 重新採樣的橢圓形可能無法真正「命中」任何真實像素以建立加權平均值。基本上,橢圓形太小或太細,以至於它完全落在圖像中每個像素之間。而且由於没有任何像素顏色,因此它無法在該點為輸出圖像生成顏色。這是一種極端情況,通常不可能實現,除非您正在使用 專家濾鏡設定。但在不太可能發生的情況下,如果沒有擊中任何像素,或者濾鏡權重加起來為零,則重新採樣將失敗。在這種情況下,IM 將回退到使用簡單的直接插值查找,就像您關閉 EWA 濾波時一樣(見下文)。如果您想檢查是否發生了這種情況,可以使用特殊的 背景插值,並使用不尋常的背景顏色(例如「紅色」)來突出顯示任何此類重新採樣失敗。例如,在這裡我特意將方框濾波器的支持設置得太小,從而使重新採樣橢圓形變得如此之小。我還大幅放大了圖像,以便您可以看到哪些部分「命中了像素」,哪些部分沒有。

  magick \( xc:red   xc:white xc:black +append \) \
          \( xc:blue  xc:lime  xc:white +append \) \
          \( xc:black xc:red   xc:blue  +append \) -append \
          -filter Box -define filter:support=0.4 \
          +distort SRT 30,0  bad_box_distort.png
[IM Output]
在放大的圖像中,重新採樣圓圈要么只擊中一個像素(產生純色的鋸齒狀圓圈),要么由於圓形採樣區域完全落在像素之間而無法匹配任何像素,因此濾鏡將退回到插值顏色漸變(默認為 雙線性插值),以便為生成的圖像獲得至少一些合理有效的顏色。以下是相同的示例,但將插值方法替換為特殊的(通常無用的)背景插值(僅返回背景顏色,設置為「灰色」)。

  magick \( xc:red   xc:white xc:black +append \) \
          \( xc:blue  xc:lime  xc:white +append \) \
          \( xc:black xc:red   xc:blue  +append \) -append \
          -filter Box -define filter:support=0.4 \
          -interpolate background -background Gray \
          +distort SRT 30,0   bad_box_distort_gray.png
[IM Output]
為了獲得完整的覆蓋範圍(因此它始終至少找到一個像素),圓柱形重新採樣濾波器需要至少約 0.707 (sqrt(2)/2) 的「支持」(方框濾波器的默認值)。所有濾波器通常都比此最小支持尺寸大得多。有關示例,請參見圓柱形濾波器一節。
角落裡的小彩色點是由於虛擬像素的重新採樣優化造成的(在對純色 VP 區域進行昂貴的 EWA 重新採樣時中止)。它們會消失或隨著「-virtual-pixel」設置的不同選擇而改變。

通常這不是問題,並且僅在這裡看到,因為扭曲使用了比原始圖像稍大的「最佳擬合視口」,因此在邊緣周圍包含了一些額外的像素,在這種情況下會採樣虛擬像素。

插值或直接顏色查找

您可以使用「-filter point」來關閉濾波,從而關閉 EWA 重新採樣。完成此操作後,Imagemagick 將切換顏色查找以使用快速簡便的 像素插值。也就是說,它將僅使用對源圖像的「單點」參考來查找顏色,而無需任何「重新採樣區域」。生成的像素的顏色將使用僅基於點的最近鄰居的插值顏色。
當發生任何形式的圖像縮小或降採樣時,插值通常會導致嚴重的鋸齒效應
但對於包含最小變形的影像(例如旋轉、平鋪或*影像放大*(放大或向上取樣))來說,它的效果非常好。*超級採樣*技術可以與插值相結合,以改善在強壓縮、縮小或向下取樣區域的結果。請參閱*去極化-極化循環問題*(一種不能使用 EWA 重採樣的失真),以了解使用超級採樣來解決插值鋸齒的範例。

詳細失真摘要

通過在運行「-distort」之前設定「-verbose」(使用「+verbose」再次關閉),distort 將向標準錯誤通道輸出有關其計算的演算法和內部係數的資訊,並以指定的方式用於失真給定的影像。您可以使用這些資訊來查看和理解失真是如何工作和應用的。它也是一個偵錯工具,我們可以使用它來找出問題所在,並且作為新失真實現過程的一部分。

  magick koala.gif -verbose -distort SRT 0 +verbose  koala_noop.gif
[IM Output] ==>
[IM Text]
==> [IM Output]
注意:結果影像幾乎與輸入影像相同,但並不完全相同(請參閱下面的「無操作失真」)。
詳細輸出詳細說明了給定失真的兩種替代失真技術。一種是「仿射投影」失真,而另一種顯示了 DIY FX 運算子替代方案,詳細說明了它是如何將輸出影像 (i,j) 中的給定像素映射到輸入影像 (xx,yy) 中的插值查找的,以便變換影像。它進行重採樣橢圓計算,該計算使用複雜的數學(特徵值)來計算,它只計算源影像中未縮放的插值查找點,以確定 (i,j) 像素的顏色。兩者都提供了有關失真過程的資訊,並且可以用於提取額外資訊,以用於相同類型的其他失真。有關使用這些資訊的更複雜範例,請參閱下面的透視內部結構雙線性內部結構。有關使用 FX 命令進行影像失真的範例,另請參閱FX 影像大小調整。上面額外的「0.5」加法和減法是必需的,以便將 magick「像素座標」轉換為「影像座標」,並且是正確處理影像失真所需的。請參閱下面的影像與像素座標

無操作扭曲

上面的範例顯示了執行無操作失真的結果。也就是說,在沒有任何實際失真的情況下(僅是像素的 1 比 1 映射),通過失真運行影像(為了獲得一些次要效果)。EWA 重採樣濾波器不會重現與原始顏色完全相同的顏色,而是會使用其相鄰像素稍微模糊單個像素。這是由於使用了二維濾波器,雖然顏色模糊程度很小,但永遠無法消除。因此,要執行真正的「無操作」,我們還必須關閉 EWA 濾波並使用插值或直接顏色查找(見上文)。

  magick koala.gif -filter point -distort SRT 0  koala_noop_perfect.gif
[IM Output]
幾乎所有插值設定通常都會在精確參考源像素時提取其精確副本。但是,作為預防措施,您也可以指定最近鄰插值,以提高速度並確保僅返回精確的顏色匹配,而不管失真可能產生的任何浮點誤差。

  magick koala.gif   -filter point  -interpolate nearest \
          -distort SRT 0  koala_noop_perfect_2.gif
[IM Output]
這看起來可能適得其反,但它可以是一個非常有用的方法,可以在不實際調整原始影像資料的情況下,放大影像區域或平鋪影像(使用虛擬像素方法)。請參閱使用虛擬像素透過扭曲進行平鋪以取得相關範例。也就是說,使用扭曲運算子來實現其次要效果,例如多影像虛擬像素平鋪、影像大小放大或裁剪、新增邊框,甚至平移(以整數或甚至子像素數量)。這些操作實際上都不需要對影像進行「扭曲」,只需以某種「程式化」的方式進行「修改」。

視口,扭曲顯示位置

如上所述,使用「-distort」或「+distort」會改變「目標影像」的結果大小和位置,使其分別為:與來源影像相同(忽略任何虛擬畫布設定),或針對扭曲的來源影像進行最佳擬合計算(如果可能)。這兩點基本上定義了目標影像在生成的「扭曲空間」中所看到的部分。另一種理解方式是,目標影像是查看生成的扭曲影像的「視窗」,或者是扭曲空間中的「視口」。「distort:viewport」設定會覆蓋這兩個預設值,並允許您直接指定要查看扭曲空間的哪個部分...
-define distort:viewport=WxH+X+Y
-set option:distort:viewport WxH+X+Y
這些功能是在 IM v6.3.6-1 中新增的。它不會放大或縮放扭曲的影像,而只是指定在扭曲影像空間中查看的位置和區域(視口)。這可以用於建立特定大小的目標影像,或將視圖移至扭曲影像空間中的特定區域。這與對無限大小(由虛擬像素定義)的扭曲影像使用「視口裁剪」非常相似。例如,在這裡我們將輸出裁剪為僅包含無尾熊頭部(使用無操作扭曲)。換句話說,這只是對原始未扭曲影像進行直接的「視口裁剪」。

  magick koala.gif  -define distort:viewport=44x44+15+0 \
          -filter point -distort SRT 0  +repage koala_viewport.gif
[IM Output]
在這裡,我們擴大了視圖,以查看扭曲影像周圍的額外空間,並顯示虛擬像素設定對原始來源影像周圍無限空間的影響。

  magick koala.gif  -define distort:viewport=125x125-25-25 \
          -filter point -distort SRT 0  +repage koala_viewport_2.gif
[IM Output]
在這種情況下,它更像是使用範圍運算子來放大影像。但是,扭曲不會簡單地用背景顏色填充,而是使用虛擬像素設定填充新增的區域。在這種情況下,使用預設的「邊緣」虛擬像素設定,這會導致從原始影像邊緣的像素複製水平和垂直像素線。
您可能希望為虛擬像素設定做出更好的選擇。例如,使用「背景」設定將使此無操作扭曲的工作方式與範圍運算子幾乎完全相同。對於此影像,「白色」虛擬像素設定可能是更好的選擇。

  magick koala.gif  -define distort:viewport=125x125-25-25 \
          -virtual-pixel White -distort SRT 0  +repage koala_viewport_3.gif
[IM Output]
先前範例中的最後一個「+repage」是必需的,用於移除在使用視口設定時「-distort」會保留的視口的虛擬畫布偏移。在這種情況下,不需要此資訊。在其他情況下,例如在對扭曲的影像進行分層時,您會需要該偏移資訊。
視口選項在使用「平鋪」甚至「鏡像」虛擬像素設定時特別有用,允許您生成任何大小和不同樣式的平鋪影像。您甚至可以使用扭曲來扭曲這些平鋪影像,例如仿射平鋪下方所示的範例。

  magick koala.gif  -define distort:viewport=125x125-25-25 \
          -virtual-pixel Mirror -distort SRT 0  +repage koala_viewport_4.gif
[IM Output]

中心方形裁剪

如果您使用 "-set" 選項來設置結果圖像的「視口」,則可以在指定值中包含 百分號跳脫序列。更具體地說,您可以包含可以進行數學計算的 FX 百分號跳脫序列。這表示可以在利用當前記憶體中圖像大小等屬性的同時計算「視口」,以指定結果圖像的最終大小。這意味著什麼?這意味著「視口」可以用於生成通常需要對圖像進行一次或多次預讀(或更高級的 API 編程接口)和外部計算才能實現的特殊類型的 裁剪。例如,您可以裁剪出圖像的「中心正方形」,而無需事先知道原始圖像的大小或方向。這很複雜,因此我將視口表達式放在變量中,以便於閱讀、編寫代碼和調試,儘管它實際上只是一個常量(固定)表達式。

  size='%[fx: w>h ? h : w ]'
  offset_x='%[fx: w>h ? (w-h)/2 : 0 ]'
  offset_y='%[fx: w>h ? 0 : (h-w)/2 ]'
  viewport="${size}x${size}+${offset_x}+${offset_y}"

  magick worldmap_sm.jpg  -set option:distort:viewport "$viewport" \
          -filter point -distort SRT 0  +repage   viewport_square.gif
[IM Output] ==> [IM Output]
結果圖像是可以從任何輸入源圖像中提取的最大居中正方形,而不管該圖像的大小如何。扭曲本身實際上不會扭曲圖像,而只是複製視口覆蓋的區域。請注意,需要計算所有四個數字才能產生「中心正方形裁剪」,因為所有值都取決於圖像方向。因此,每個表達式都使用「w>h ? ... : ...」形式的「圖像方向」測試,因此結果值取決於圖像方向。
這是使用「min()」和「max()」函數而不是圖像方向測試的替代形式。

  magick worldmap_sm.jpg  -set option:distort:viewport \
    "%[fx:min(w,h)]x%[fx:min(w,h)]+%[fx:max((w-h)/2,0)]+%[fx:max((h-w)/2,0)]" \
    -filter point -distort SRT 0  +repage  viewport_square_2.gif
[IM Output]
感謝 Fred Weinhaus 的 Tidbits 頁面。在 縮略圖、方形填充和裁剪 中顯示了一種使用多種圖像處理技術來完成相同事情的技術。

長寬比裁剪

可以擴展此技術,以便將圖像中心裁剪為適合給定的縱橫比。另請參閱論壇討論 裁剪為縱橫比

其他視口示例

另請參閱下面的 圖像旋轉方法,了解有關使用視口控制結果中可見扭曲空間部分的其他示例。

輸出縮放和超級採樣

-define distort:scale=N
-set option:distort:scale N
在 IM v6.4.2-6 中添加,作為一般的輸出圖像縮放因子。這會將輸出圖像放大給定的因子,因此「-distort」將需要生成 N2 個扭曲的查找「樣本」。該數字通常是整數,但也可以是浮點放大因子。請注意,許多扭曲還允許您「縮放」結果扭曲圖像的大小,但是結果圖像大小將不受該縮放的影響(除非使用了「最佳擬合」的「+distort」)。但是,此「縮放」設置根本不會更改結果圖像的內容,而只是放大或縮小結果輸出圖像。例如,這可以與適當的「視口」一起使用,以生成可以輕鬆「-resize」到特定大小的圖像,從而允許您在不損失質量的情況下生成對扭曲圖像的受控「縮放」。
例如,我們「放大」了考拉的頭部。

  magick koala.gif -set option:distort:scale 2.5 \
          -set option:distort:viewport 44x44+15+0 \
          -distort SRT 0  +repage koala_zoom.gif
[IM Output]
請注意,雖然請求視口為 44x44 像素,但實際輸出圖像已縮放到 110x110 像素。更常見的是,它被用作扭曲操作的簡單「超級採樣」方法(見上文)。為此,使用整數「超級採樣」比例因子,並且在扭曲圖像後將其縮放回其原始大小,以合併額外的樣本並產生更高質量的結果。

  magick koala.gif -filter point -set option:distort:scale 10 \
          -distort SRT 0  -scale 10%   koala_super.gif
[IM Output]
另外,由於「超級採樣」可以提升影像品質,因此使用「區域重新採樣」就顯得多餘了(它只會降低速度),通常可以使用「-filter point」選項將其關閉(請參閱上一節)。

扭曲方法介紹

縮放-旋轉-平移 (SRT) 扭曲

SRT」或「縮放-旋轉-平移」扭曲是最簡單,但也可能是最通用的扭曲之一。(SRT 只是一個快速的簡稱)在上面的示例中,您已經看到了這種扭曲的「無操作」示例,其中圖像在沒有應用任何實際扭曲的情況下被處理,儘管它仍然會被過濾,這可能會導致一些非常輕微的模糊。以下是上述「無操作」扭曲結果的重複...

  magick koala.gif    -distort SRT 0    koala_noop.gif
[IM Output] ==> [IM Output]
請注意,由於使用區域重新採樣,圖像會稍微模糊。但是,IM 重新採樣濾鏡經過精心設計,可以最大程度地減少無操作扭曲的這種模糊,並且是正常使用所必需的。

如果為了特殊目的想要完美的「無操作」扭曲,則關閉 EWA 重新採樣。也就是說,在扭曲運算符之前指定「無操作」濾鏡「-filter Point」。

SRT」扭曲實際上是單一扭曲方法中的三種獨立扭曲,這就是為什麼它被稱為「縮放-旋轉-平移」扭曲。除了角度旋轉之外,所有參數都是可選的,這使得參數變化很大,具體取決於您提供的逗號或空格分隔參數的確切數量,最多 7 個浮點數。
-distort SRT " 
                  Angle 
 "   -> 以中心旋轉
        Scale     Angle 
  -> 以中心縮放和旋轉
X,Y               Angle 
  -> 繞給定坐標旋轉
X,Y     Scale     Angle 
  -> 繞坐標縮放和旋轉
X,Y ScaleX,ScaleY Angle 
  -> 同上
X,Y     Scale     Angle  NewX,NewY
  -> 縮放、旋轉和平移坐標
X,Y ScaleX,ScaleY Angle  NewX,NewY
  -> 同上
它的作用是獲取您選擇的圖像和一個可選的控制點。如果沒有給出控制點,則使用輸入源圖像的確切中心。圍繞該點,扭曲將按順序... 縮放圖像,旋轉圖像,然後平移或將所選控制點移動到新位置。因此得名。上面顯示的參數順序反映了實際應用於圖像的操作順序。X,Y 將變換的「中心」平移到原點,ScaleX,ScaleY 縮放圖像,Angle 旋轉圖像,然後NewX,NewY 將「中心」平移到這些坐標。也就是說,該運算符實際上代表了 4 個內部扭曲操作,所有操作都作為單一扭曲同時應用。雖然對我們人類來說,只涉及 3 種不同的扭曲。讓我們以使用「無尾熊」圖像為例...一個參數只是圍繞圖像中心進行簡單旋轉,基本上產生與舊的旋轉運算符類似的結果,但沒有任何圖像尺寸增加。

  magick koala.gif  -background skyblue  -virtual-pixel background \
          -distort ScaleRotateTranslate -110 koala_srt_rotate.png
[IM Output]
請注意,默認情況下,輸入圖像的大小也用於輸出圖像,因此旋轉後的圖像可能會被裁剪。無論圖像具有奇數還是偶數像素,它也完全居中。使用「加」形式的「+distort」和清理產生的虛擬畫布偏移,我們可以生成與普通旋轉運算符非常相似的東西。

  magick koala.gif  -background skyblue  -virtual-pixel background \
          +distort ScaleRotateTranslate -110 +repage koala_srt_rotate2.png
[IM Output]
從 IM 6.7.3-4 開始,旋轉運算符現在使用扭曲 SRT 扭曲。在此之前,它使用剪切操作,這並沒有產生良好的結果。
讓我們將其縮小 30%,但使用透明背景。

  magick koala.gif  -alpha set -virtual-pixel transparent \
          +distort ScaleRotateTranslate '.7,-110' +repage koala_srt_scale.png
[IM Output]
下一組參數將指定圖像旋轉和縮放的「中心」。 此點在圖像中稱為「控制點」或「控點」,是用於控制變形的定位點。 由於我們在此變形中使用特定點,因此請勿使用「最佳擬合」模式,以避免「虛擬偏移」的複雜性。 例如,讓我們圍繞無尾熊的「鼻子」旋轉和縮放,它位於源圖像中的 28,24 位置。 讓我們同時調整 X 和 Y 比例的不同。

  magick koala.gif  -background skyblue -virtual-pixel background \
          -distort ScaleRotateTranslate '28,24  .4,.8  -110' \
          koala_srt_center.png
[IM Output]
作為最後一個示例,讓我們還將「鼻子」移動到圖像底部附近,並將背景設置為匹配的白色背景。

  magick koala.gif  -virtual-pixel white \
          -distort ScaleRotateTranslate '28,24  .4,.8  -110  37.5,60' \
          koala_srt_trans.png
[IM Output]
請注意,最終位置也是一個浮點值。 實際上,所有參數都可以是浮點值,並且變形會產生正確的結果。 請記住,每個操作(縮放、旋轉和平移)都按此順序執行。 如您所見,此變形非常通用,雖然您可以將其視為使用三種不同方法依序對圖像進行變形,但實際上它會同時應用所有三種變形以產生顯示的結果。 這使得它比執行多個單獨的操作器更快,並且通常會產生更好的最終結果。 上面還演示了使用不同的虛擬像素設置來定義用於實際源圖像外部區域的顏色。 要查看插值對旋轉的影響,請參閱旋轉線和邊的插值。 此變形專門用於拍攝圖像並根據該對象的移動和旋轉生成動畫。 例如,我在這裡創建了一個程式化的太空船,然後我以一種非常粗略的方式對其進行動畫處理。 飛船位於 20,75 的基座上(用於初始「蹲伏」縮放),而用於移動和旋轉的普通「控點」是飛船的中心,位於原始圖像中的 20,60 處。 這些點代表控制點,通過這些點可以簡單地對對象進行動畫處理。

  magick -size 80x80 xc:skyblue -fill yellow -stroke black \
          -draw 'path "M 15,75 20,45 25,75 Z  M 10,55 30,55" ' \
          spaceship.gif
  magick spaceship.gif \
          \( -clone 0  -distort SRT '20,75  1.0,0.6  0' \) \
          \( -clone 0  -distort SRT '20,60     1     0  20,49' \) \
          \( -clone 0  -distort SRT '20,60    0.9   20  27,35' \) \
          \( -clone 0  -distort SRT '20,60    0.8   45  40,23' \) \
          \( -clone 0  -distort SRT '20,60    0.5   70  55,15' \) \
          \( -clone 0  -distort SRT '20,60    0.3   75  72,11' \) \
          \( -clone 0  -distort SRT '20,60    0.1   80  100,8' \) \
          -set delay 50  -loop 0  spaceship_launch.gif
[IM Output] ==> [IM Output]
當然,這是一個非常粗略的示例,說明如何使用「SRT」變形為靜態圖像製作動畫,但您應該明白這個意思。 您可以添加更多幀,還可以添加一些火焰和煙霧以進一步改進它(歡迎提交作品,最佳結果將與您的姓名一起添加到這裡)。

旋轉圖像的方法

圖像可以通過多種方式旋轉。 但是,僅僅簡單的旋轉可能不是您想要的結果。在不改變大小的情況下旋轉圖像...

  magick rose: -virtual-pixel black -distort SRT '20'  rotate_normal.png
[IM Output]
或者旋轉以避免裁剪任何旋轉後的圖像...

  magick rose: -virtual-pixel black +distort SRT '20'  rotate_noclip.png
[IM Output]
但是,通常您不希望看到圍繞圖像本身的「黑色」虛擬像素(或任何其他非圖像顏色)。 一種解決方案是將圖像裁剪(使用扭曲視口設置)為具有相同縱橫比的最大矩形,以便它僅包含旋轉產生的真實圖像像素。 但是,計算這個矩形相當棘手,並且在ImageMagick 論壇上使用數學幫助論壇上的一些方程式對此進行了大量討論。 在這裡,我們旋轉並以盡可能接近原始縱橫比的方式進行內部裁剪。

  angle=20
  ratio=`magick rose: -format \
     "%[fx:aa=$angle*pi/180; min(w,h)/(w*abs(sin(aa))+h*abs(cos(aa)))]" \
     info:`
  crop="%[fx:floor(w*$ratio)]x%[fx:floor(h*$ratio)]"
  crop="$crop+%[fx:ceil((w-w*$ratio)/2)]+%[fx:ceil((h-h*$ratio)/2)]"
  magick rose: -set option:distort:viewport "$crop" \
          +distort SRT $angle +repage   rotate_internal.png
[IM Output]
這看起來很複雜,但這是因為它實際上必須計算 4 個單獨的值來定義視口設置、寬度、高度和原始圖像中的偏移量。 另一種選擇是不僅旋轉圖像,而且稍微放大圖像,以便「填充」原始圖像邊界。

  angle=20
  magick rose: -distort SRT \
     "%[fx:aa=$angle*pi/180;(w*abs(sin(aa))+h*abs(cos(aa)))/min(w,h)], $angle" \
     rotate_correction.png
[IM Output]
最後一個選項最適合用於照片的細微旋轉校正,以便保留圖像的原始大小。這種方法更簡單的唯一原因是,只需要計算一個“縮放”值,因此可以“內聯”完成。

使用控制點進行扭曲

雖然“SRT”變形方法是通過指定旋轉角度和縮放因子來定義的,但大多數變形是通過移動源圖像上的“點”,並將它們移動到結果圖像中的新位置來定義的。這有點像定義“SRT”平移時“中心”點的移動。這些點稱為控制點,通常通過為每個單獨的控制點提供 4 個浮點值(2 對坐標)來定義。因此,變形通常根據多組 4 個值來定義。例如....
X1,Y1 I1,J1     X2,Y2 I2,J2     X3,Y3 I3,J3     X4,Y4 I4,J4 . . . .
其中,源圖像中的控制點 Xi,Xi(相對於其虛擬畫布)映射到變形後的目標圖像上的 Ii,Ji
但是,由於變形運算符實際上是將目標坐標映射到源坐標(請參閱反向像素映射),因此上述方法的內部使用是將 I,J 坐標映射到 X,Y 坐標。然而,結果應該是一樣的,只是思考方式不同。
在 IM 版本 6.3.6-0 之前,當變形運算符運算符首次引入時,控制點的坐標順序被定義為所有源坐標,然後是所有目標坐標。然而,這使得很難確定哪些源坐標和目標坐標彼此對應,並且不允許簡單地附加更多控制點來進一步細化變形。
這樣定義是為了使每個單獨控制點的移動保持在逗號(或空格)分隔的浮點值列表中。它還允許將來使用外部“控制點文件”。使用控制點的最簡單變形是“仿射”變形,雖然正如您稍後將看到的,它通常根據三個點來定義,但您可以只使用一個或兩個控制點移動。實際上,“SRT”只是一個“仿射”變形的兩點或單點子集。例如,在這裡,我們將無尾熊圖像的“鼻子”從“28,24”移動到新位置“45,40”(如紅色箭頭所示),這會導致圖像位置的簡單“平移”。

  magick koala.gif  -virtual-pixel white \
          -distort Affine '28,24 45,40'   koala_one_point.png
[IM Output] ==> [IM Output]
通過兩個點,“仿射”變形不僅可以平移圖像,還可以縮放和旋轉圖像(“SRT”變形的全部範圍)。例如,在這裡,我將無尾熊的“耳朵”(從“30,11”到“48,29”的紅線)映射到更大的水平位置(從“15,15”到“60,15”的藍線),這需要對圖像進行縮放、旋轉和平移,以便將控制點移動到這個新位置。

  magick koala.gif  -virtual-pixel white \
          -distort Affine '30,11 15,15  48,29 60,15'   koala_two_point.png
當然,“SRT”變形可以重現上述兩點“仿射”變形,只是我們在這裡以不同的方式定義了變形。您應該使用哪種形式取決於您想要達到的目標。

圖像坐標與像素坐標

在一般情況下,控制點的使用非常簡單,但當您需要將扭曲的圖像與另一個圖像或繪製的結構對齊時,就會變得更加困難。原因是,雖然 IM 中的大多數運算符都以「像素位置」來處理坐標(例如在裁剪繪圖等操作時),但扭曲處理的是數學上的「圖像坐標」。您需要記住的是,圖像中的像素不是一個「點」,而實際上是一個大小為 1 個像素單位的「區域」。也就是說,位於10,10的像素定義了一個顏色正方形區域,從向下/向右10個單位到向下/向右11個單位。就圖像坐標而言,「像素」中心實際上位於10.5,10.5。也就是說,當您扭曲圖像以將「像素」的中心移動到特定位置時,需要添加 0.5。因此,要重新定位圖像的角「像素」,您需要根據位於0.5,0,5寬度-0.5,高度-0.5的像素來移動圖像。另一方面,要根據圖像的實際「邊緣」重新定位圖像,您只需使用坐標0.0,0,0寬度,高度。您只需要考慮您實際上想要定位的是什麼,是圖像「像素」的中心還是圖像的「邊緣」。或者,它是否真的對您的特定問題有影響。請記住,如果您想在扭曲的圖像上繪製其他元素,您需要根據「像素位置」給出繪製位置。是的,「-draw」運算符可以使用浮點值繪製線條、圓形和其他形狀。類似地,對象的筆劃寬度和/或半徑也可以作為浮點值給出。
[IM Output] ==> [IM Output]
小於 1.0 的繪製筆劃寬度無法正常工作,(請參閱繪製線條)。此外,區域填充會在填充區域的邊緣添加額外的 0.5(與筆劃寬度添加相匹配)(請參閱繪製填充邊界)。無論使用哪種實際筆劃寬度,都會執行此操作。

有關更多信息,請參閱繪製填充邊界。我認為這是一個錯誤。

使用百分比轉義的控制點

您還可以在扭曲參數中使用百分比轉義。例如,您可以提取一張圖像的圖像屬性,然後使用它們調整另一張圖像的大小以匹配第一張圖像。在這裡,我獲取「rose:」內置圖像的大小,然後使用「仿射」扭曲將較大的「logo:」圖像調整為相同的大小(不保留縱橫比)。

   magick rose: -set option:rw %w -set option:rh %h +delete \
           logo: -alpha set -virtual-pixel transparent \
           +distort Affine '0,0 0,0     %w,0 %[rw],0   0,%h  0,%[rh]' \
           +repage logo_sized_as_rose.png
[IM Output]
請注意,扭曲會在虛擬畫布上生成稍微大一點的「分層圖像」(包括負偏移量),這就是為什麼我需要在上面的示例中包含「+repage」。它也會具有模糊的邊緣,因為扭曲會生成圖像的精確或真實扭曲,而不是經過清理的正交調整大小的圖像。有關使用扭曲運算符調整圖像大小(與調整大小運算符完全相同)的更多進階示例,請參閱扭曲與調整大小,以及下面的扭曲調整大小方法。您還可以根據圖像在當前圖像列表中的位置使用百分比轉義來計算扭曲。有關示例,請參見動畫扭曲

控制點最小二乘擬合

如果您為「仿射」扭曲提供了超過 3 個控制點,或者為「透視」或「雙線性」扭曲提供了超過 4 個點,ImageMagick 將對所有給定點執行最小平方法平均,以找到這些扭曲的「平均」表示。這意味著,如果您嘗試將一個圖像與另一個圖像匹配(一種稱為「圖像配準」的技術),則可以定義超過所需最小數量的點,以便結果是更精確的扭曲。當然,如果這些點中的一個或多個點與其他點「不符」,則結果將因「奇異」點而產生偏差,因為 IM 會嘗試使用所有給定的控制點(包括壞點)來找到最佳擬合。在某些情況下,可能需要進行一些檢查以查找和移除「不良坐標對」。

從文件控制點

扭曲的數字(參數)列表也可以通過使用「@文件名」語法從文件中讀取,就像您可以為「-annotate」和「標籤:」輸入文本一樣(請參閱文本參數中的轉義字符)。例如,您可以像這樣指定扭曲...

  magick input.png  -distort Perspective '@file_of_coords.txt' output.png
文件名可以僅僅是「@-」,表示從標準輸入讀取文件。文件本身將作為字符串讀取,並被視為所涉及扭曲所需的坐標(參數)列表。由於數字可以用逗號或空格分隔,這意味著坐標對可以按文件中每行一對坐標的形式整齊地排序...
   X1   Y1   I1   J1
   X2   Y2   I2   J2
   X3   Y3   I3   J3
   X4   Y4   I4   J4
   ....
結合最小平方法擬合,這使得圖像配準的使用非常實用。由於文件只是一行四個數字的列表,您可以使用其他文本處理腳本工具,例如「cut」、「paste」、「column」,以及更高級的文本處理腳本工具,例如「sed」、「awk」、「perl」等來操作坐標。坐標和扭曲參數文件的使用對於更高級的扭曲(例如「Shepards」扭曲)以及計劃中的「網格」和「網格」扭曲(其中可能涉及數百個坐標對)將變得更加重要。

仿射(三點)扭曲方法

仿射扭曲

上面顯示的「SRT」扭曲以及「仿射」扭曲的一點和兩點形式實際上是「仿射」扭曲的完整三點形式的簡化。事實上,如果您研究任何「SRT」扭曲的「-verbose」輸出(請參閱詳細扭曲設置 的示例),您會發現它在內部實際上是「AffineProjection」扭曲(請參見下文)。上述方法不能完全處理的唯一扭曲效果是類似於剪切運算符提供的「剪切」。為此,您需要使用三點仿射扭曲。您可以將其視為三點扭曲,方法是將第一個坐標映射想像成「原點」,將其他兩個坐標映射想像成從該原點出發的向量。例如,我在這裡繪製一些文本,並覆蓋一條紅色和藍色的「向量」以定義相對於該文本的三個控制點。現在,通過移動這些線的坐標(作為圖像坐標),我們可以平移、旋轉、縮放和剪切該文本圖像,以適應這些線的新位置。

  magick -background lightblue -fill Gray -font Candice \
      -size 100x100 -gravity center label:Affine\! \
      -draw 'fill blue stroke blue path "M 3,60 32,60 M 27,58 27,62 32,60 Z"' \
      -draw 'fill red  stroke red  path "M 3,60  3,30 M  1,35  5,35  3,30 Z"' \
      label_axis.png
  magick label_axis.png \
          -distort Affine ' 3.5,60.5   3.5,60.5
                           32.5,60.5  32.5,60.5
                            3.5,30.5  33.5,20.5' label_axis_distort_shear.png
  magick label_axis.png \
          -distort Affine ' 3.5,60.5   3.5,60.5
                           32.5,60.5  27.5,85.5
                            3.5,30.5  27.5,35.5' label_axis_distort_rotate.png
  magick label_axis.png \
          -distort Affine ' 3.5,60.5  30.5,50.5
                           32.5,60.5  60.5,80.5
                            3.5,30.5  30.5,5.5' label_axis_distort_affine.png
[IM Output] ==> [IM Output] [IM Output] [IM Output]
在第一個範例中,只修改了第三個坐標(垂直紅線),導致圖像被剪切並沿著 Y 軸拉伸。當然,它不限於僅沿 Y 軸。後面的例子對圖像進行了更徹底的更改,包括旋轉和平移。當然,「註釋文字」運算子也可以用同樣的方式扭曲實際文字,但只能改變角度。該運算子不會沿特定方向縮放或放大文字。也就是說,它可以旋轉「向量」,但不能將其拉伸或縮短。有關範例表格,請參閱「註釋參數用法」。仿射扭曲可以對任何圖像進行這種扭曲,而不僅僅是繪製的文字。使用少於或多於三對坐標的仿射 如果只提供 1 或 2 對控制點,IM 將使用更有限制的仿射扭曲形式來匹配這些較少點的移動。例如,如果只有一對坐標,它會將自身限制為圖像的非縮放平移。如果有 2 個點,它將自身限制為「縮放-旋轉-平移」扭曲(無剪切)。有關範例,請參閱先前關於「使用控制點的扭曲」的討論。如果為「仿射」扭曲提供超過 3 個控制點,則 IM 將使用「最小平方法擬合」來找到與給定*所有*坐標對最佳匹配的「3 點」仿射扭曲。這意味著來源影像控制點可能不會完全映射到目標影像控制點,而是給定所有點的最佳擬合「平均值」。例如,如果您有一個文檔的掃描件,您可以找到並映射文檔的所有 4 個角,以進行仿射扭曲,以校正文檔的旋轉和縮放。通過這種方式,您可以根據 4 個點而不是 3 個點獲得更好的「平均」擬合。請注意,雖然更多坐標可以產生更好、更準確的扭曲,但如果一對坐標非常糟糕,則最小平方法擬合可能根本無法產生非常好的擬合。可能需要進行一些檢查以消除「錯誤坐標對」。未來:在 IM 中添加一些程式碼,以報告每個輸入坐標對相對於其他坐標對的「準確度」,以幫助確定用戶應消除哪些「壞點」。

仿射投影扭曲

正如我已經提到的,「SRT」扭曲的各種參數和「仿射」扭曲的控制點,在數學上被轉換為 6 個特殊數字,它們代表「仿射投影」的「係數」。仿射投影中的這些數字是用於將來源影像中的點「正向映射」到目標影像的係數。也就是說,它們是用於將來源影像 x,y 映射到目標影像 i,j 的數學值。6 個浮點參數為(按給定順序)...
sx、rx、ry、sy、tx、ty
這些又形成了扭曲表達式..
Xd sx*Xs + ry*Ys + tx   ,       Yd rx*Xs + sy*Ys + ty
其中「Xs,Ys」是來源影像座標,「Xd,Yd」是目標影像座標。在內部,ImageMagick 的 Distort 會反轉上述方程式,以便進行適當的像素映射,將「Xd,Yd」座標映射到來源影像中「Xs,Ys」處的顏色。有關各種仿射投影矩陣值如何影響影像的詳細資訊,請參閱仿射矩陣變換子頁面。如果您已經預先計算了這些係數(例如,從 distort 的詳細輸出中提取,或者使用其他方法從其他形式的輸入參數中計算得出),那麼您可以直接將它們提供給 IM 以扭曲影像。例如,我在這裡「剪切」影像,但使用角度來計算係數,而不是使用控制點的移動。

   angle=-20
   tan=`magick xc: -format "%[fx:tan( $angle *pi/180)]" info:`
   magick koala.gif -alpha set -virtual-pixel Transparent \
           +distort AffineProjection "1,$tan,0,1,0,0" +repage \
           koala_affine_proj.png
[IM Output]
在 ImageMagick 中進行這種扭曲的舊方法是使用「-affine」和「-transform」運算對。然而,從 IM v6.4.2-8 開始,這只是一個使用「加號」或「最佳擬合」形式的Distort 運算符對「AffineProjection」的簡單調用。有關更多詳細資訊,請參閱仿射矩陣變換子頁面。

仿射扭曲範例

仿射平鋪

到目前為止,我們已經看過的所有三種仿射式扭曲方法,也提供了一些有趣的方法,可以根據扭曲的影像生成各種平鋪圖案。

  magick checks.png    -alpha set    -virtual-pixel tile \
          -distort  ScaleRotateTranslate  '20,20  .5  30' \
          checks_srt_tile.png
  magick checks.png    -alpha set    -virtual-pixel tile \
          -distort  Affine  '0,0 10,10   0,89 10,50   89,0 50,0' \
          checks_affine_tile.png
  magick checks.png    -alpha set    -virtual-pixel tile \
          -distort  AffineProjection  '0.9,0.3,-0.2,0.7,20,15' \
          checks_amatrix_tile.png
[IM Output] ==> [IM Output] [IM Output] [IM Output]
以這種方式使用扭曲映射實際上就是 3D 圖形庫和遊戲中的「紋理映射」的工作原理。唯一的區別是它們將表面的三維座標映射回二維影像。即使是「無操作」扭曲(「-distort SRT 0」),只要使用適當的Distort 視口,就可以提供一種有用的方法來平鋪整個影像序列,例如動畫閃光磚

  magick glitter_blue.gif -virtual-pixel tile \
          -filter point -set option:distort:viewport 100x100 -distort SRT 0 \
          glitter_blue_tiled.gif
[IM Output] ==> [IM Output]
請注意,我還使用了「-filter point」來關閉EWA 重採樣,以便加快操作速度,並確保完美(未採樣)複製來源影像像素。Distort 視口還可以指定偏移量,以便在結果影像上「滾動」平鋪影像。

3D 立方體,使用仿射分層

仿射」扭曲及其控制點非常適合從三個影像生成正交和等距立方體(有關定義,請參閱維基百科上的正交投影等距投影)。您需要做的就是確定目標影像上的四個控制點。由於我們將使用影像分層技術,因此這些點甚至可以具有負值,並且允許 IM 根據生成的扭曲影像調整最終影像大小。在本例中,我將選擇「0,0」作為立方體的中心,並在該中心點周圍等距選擇三個點,分別為「-87,-50」、「87,-50」和「0,100」。然後,我需要做的就是將三個(最好是正方形)影像的適當角點映射到這些控制點。

  magick \
     \( lena_orig.png -alpha set -virtual-pixel transparent \
        +distort Affine '0,512 0,0   0,0 -87,-50  512,512 87,-50' \) \
     \( mandrill_orig.png -alpha set -virtual-pixel transparent \
        +distort Affine '512,0 0,0   0,0 -87,-50  512,512 0,100' \) \
     \( pagoda_sm.jpg -alpha set -virtual-pixel transparent \
        +distort Affine '  0,0 0,0   0,320 0,100    320,0 87,-50' \) \
     \
     -background none -compose plus -layers merge +repage \
     -bordercolor black -compose over -border 5x2     isometric_cube.png
[IM Output]
請注意,我在扭曲影像時使用了影像實際邊緣的 座標。 這意味著在數學上,影像應該完全拼湊在一起。另請注意,我並未簡單地將影像「合成」(使用預設的 Over Alpha 合成)。 如果您這樣做,影像之間會出現略微透明的「間隙」。 正確的方法(如圖所示)是使用 Plus Alpha 合成 來連接「邊緣相連」的部分,這將產生完美的連接,而不會出現透明間隙。 如需更多資訊,請參閱 對齊兩個遮罩影像。 之後,我添加了一個額外的邊框,並刪除了所有透明度。 這不是必需的,您可以輕鬆使用任何背景(或「none」),但這樣做會突出顯示影像中可能存在的任何「間隙」。
[IM 輸出] 右側顯示的是影像中一個此類連接的放大圖,顯示沿連接處没有任何「黑色填充」間隙。 使用錯切的等距立方體 中給出了一種建立等距立方體的替代方法,无需使用「-distort」。 但是,此技術不允許您使用次像素座標(不是我在上面使用的,但我可以使用),而是僅限於使用整像素(整數)座標定位影像。

使用仿射錯切的三維陰影

上面使用的相同分層方法也可以用於生成奇特形狀的酷炫三維陰影。 為任何直立的「平面」形狀添加陰影。 例如,讓我們建立一個底部平坦的形狀,以便它可以直立。

  magick -background None -virtual-pixel Transparent -fill DodgerBlue \
          -pointsize 72 -font Ravie  label:A   -trim +repage \
          -gravity South -chop 0x5  standing_shape.png
[IM Output]
請注意,「形狀」有一個平坦的底部,這也是影像的最後一行。 這一點很重要,因為我們將沿該行扭曲形狀,以便陰影僅沿該行連接到直立的形狀。 以下是從這個「站立形狀」生成三維陰影的命令

  magick standing_shape.png   -flip +distort SRT '0,0 1,-1 0' \
          \( +clone -background Black -shadow 60x5+0+0 \
             -virtual-pixel Transparent \
             +distort Affine '0,0 0,0  100,0 100,0  0,100 100,50' \
          \) +swap -background white -layers merge \
          -fuzz 2% -trim +repage   standing_shadow.jpg
[IM Output]
以上步驟完成了相當多的步驟來實現所示的結果。 然而,最棘手的是第一行。 這會翻轉影像,然後再次進行「扭曲翻轉」。 這樣做的結果是底部行現在位於虛擬畫布上 Y=0 的位置。 也就是說,整個影像被賦予負偏移量以定位它,以便底部行穿過虛擬畫布的原點。 通過執行此「技巧」,我們可以在提取的「陰影」上使用非常簡單的「仿射錯切」來扭曲它。 因此,我們不需要知道形狀影像的大小來扭曲陰影,但仍然設法保持所有内容「對齊」,因為它們都沿著原始影像的底部(Y=0)行保持同步。 您可以通過調整「仿射錯切」的最終座標('100,50')來簡單地調整陰影落下的方向及其長度。 前兩個「座標對」不應修改,因為它們將陰影沿著底部行「鎖定」到原始影像。 但是請注意,直到最後一步,所有影像都將包含負虛擬畫布偏移量,因此如果您計劃查看或保存中間處理影像,請謹慎操作。 這種陰影效果的唯一問題是它是一種「通用模糊」。 也就是說,陰影是不真實的。 實際上,陰影應該在它與「站立形狀」相接的地方清晰,並且隨著陰影越來越遠而變得更加模糊。 然而,這可以使用 可變模糊映射 來完成,例如 距離模糊陰影字體 中使用的。

使用透視壓縮的三維陰影

這是在陰影中加入可變模糊的另一種方法,雖然我並不推薦,但它實現起來相當簡單。這個例子是在 ImageMagick 加入 可變模糊映射 之前開發的。基本上,你首先使用 透視變形(下面會詳細介紹)扭曲初始陰影形狀,以便強烈壓縮陰影的「遠處部分」,使其模糊,然後通過將其變形到我們上面使用的最終「仿射剪切」位置來擴展壓縮。

  magick standing_shape.png   -flip +distort SRT '0,0 1,-1 0' \
          \( +clone   -virtual-pixel Transparent -mattecolor None \
             +distort Perspective \
                '0,0 0,0  100,0 100,0   0,-100 45,-100   100,-100 60,-100' \
             -fuzz 2% -trim   -background Black -shadow 60x3+0+0 \
             +distort Perspective \
                '0,0 0,0  100,0 100,0   45,-100 -100,-50   60,-100 0,-50' \
          \) +swap -background white -layers merge \
          -fuzz 2% -trim +repage     standing_shadow_var.jpg
[IM Output]
這與原始的 3D 陰影示例 幾乎完全相同,但有一些額外的步驟。原始形狀首先被扭曲成梯形,然後修剪任何多餘的空間以加快下一步。然後,我們從扭曲的形狀中提取模糊的陰影。一旦從扭曲的圖像創建了陰影圖像,就會使用相同的控制點來取消扭曲陰影圖像,並將其作為仿射剪切移動到其位置。關鍵是陰影模糊發生在扭曲的圖像上,然後取消扭曲(在這種情況下,同時進行仿射剪切)。結果,模糊也被扭曲和擴展,以便在陰影的頂部周圍更多地模糊,而在基線上的模糊要少得多。由於透視模糊,我們得到一個可變模糊,它應該在距離地面基線約 100 像素處達到峰值。由初始透視模糊控制點定義。

使用扭曲調整圖像大小

事實上,扭曲調整大小 在很多方面都非常相似。它們都是圖像扭曲運算符,並且都使用 反向像素映射 來創建結果圖像。它們也都利用「-filter」設置及其專家控制來確定顏色,儘管它們這樣做的方式非常不同。調整大小 是一種簡化(也是更常見)的圖像扭曲操作,允許您進行許多優化。它是正交對齊的,允許您在調整大小中使用 2 通道正交圖像過濾方法。也就是說,它首先在一个维度上调整大小,然后在另一个维度上调整大小,使用中间临时图像。此外,由於縮放因子在整個目標圖像上是恆定的,邊緣與整個像素(整數)維度對齊,因此算法可以大大簡化其處理以及所用濾波器的緩存要求。所有這些限制允許進行各種優化,使其與扭曲需要做的工作相比非常快。扭曲也可以 調整圖像大小,但它是一次性完成的,直接從原始圖像轉換為結果新圖像。它不需要將邊緣與整數像素位置對齊,並且可以旋轉和縮放每個像素位置。換句話說,它是一個更通用的運算符,要求它為最終結果中的每個像素進行大量額外處理,而優化的地方更少。為了使 扭曲 生成與 調整大小 相同的圖像,它需要遵循完全相同的限制,並使用一些複雜的圖像處理技巧。這在 IM 論壇的 正確調整大小(使用扭曲) 中進行了討論,並產生了一種基於 仿射扭曲方法 的等效扭曲調整大小技術。
生成的「調整大小」扭曲方法已添加到 ImageMagick 6.6.9-2 版本中。此扭曲的命令行界面 (CLI) 版本將接受並處理與 調整大小 完全相同的 幾何參數,包括兩個維度縮放因子的細微差異,使其成為直接調整大小的替代方法。

  magick logo:  -distort Resize 150x  logo_resized.png
[IM Output]
其他使用「Resize」扭曲方法的 API 介面,只接受兩個數字作為參數,它們被視為結果圖像的最終整數大小。目前,它們不接受實際的幾何參數及其各種調整大小控制標誌,這些標誌會修改最終圖像大小。也就是說,百分比、僅放大/縮小,甚至保留長寬比等標誌都不可用。

這些 API 的維護者可以自行添加對這種特殊圖像扭曲方法的支持。
上述 扭曲調整大小 與普通的 調整大小運算符 之間的真正區別在於,扭曲版本使用速度慢得多的單遍 圓柱(橢圓)濾鏡 來確定每個像素的最終顏色。換句話說,它提供了兩遍正交濾鏡(調整大小)與一遍但二維圓柱濾鏡(扭曲調整大小)的直接比較。有關其中一種比較的示例,請參閱 扭曲與調整大小

扭曲調整大小內部結構

以下是上述 扭曲調整大小 在內部執行的等效操作。

  magick logo:  -alpha set -virtual-pixel transparent \
          +distort Affine '0,0 0,0   %w,0 150,0   0,%h 0,113' \
          -alpha off  -crop 150x113+0+0 +repage   distort_resize.png
值「150」和「113」(在兩個地方使用)是最終圖像的所需大小,精確到最接近的整數。計算它們是為了盡可能保留圖像的長寬比,同時保持最終的整數大小限制。它們通常由 ImageMagick 使用單獨的 API 函數從給定的調整大小 幾何參數 計算出來。然後,它會啟用透明度和透明的 虛擬像素,以便外部「虛擬像素」不參與最終像素顏色的計算。當扭曲完成後,透明度將再次被移除(關閉),並使用 圖像裁剪 移除由扭曲添加的「緩衝區」像素。由於使用了透明像素,因此上述命令僅適用於不包含任何透明度的圖像,例如上面示例的「logo:」內建圖像。這是更複雜的版本,需要將 虛擬像素 的效果與圖像中任何可能存在的透明度分開。

  magick logo: -alpha set -virtual-pixel transparent \
          \( +clone -alpha extract -alpha opaque \) \
          +distort Affine '0,0 0,0   %w,0 150,0   0,%h 0,113' \
          -alpha off -crop 150x113+0+0 +repage \
          -compose CopyOpacity -composite      distort_resize_trans.png
這會執行兩次扭曲:首先扭曲圖像,然後分別扭曲 Alpha(透明度)通道,在每種情況下都使用透明度來消除虛擬像素效應。因此,它至少比原始圖像中不存在透明度時慢兩倍。這些技術都在 扭曲調整大小方法 中內部實現。因此,這種「方法」實際上是為用戶提供的方便的「宏」,而不是真正的扭曲方法,後者是一種「仿射」扭曲。

四點扭曲方法

透視扭曲

可能最常被要求的扭曲類型是快速透視扭曲操作。這是一種四點扭曲,因此至少需要 4 組控制點對,或 16 個浮點值。例如,這裡我有一個圖像建築。從這張圖像中,我手動找到了 4 個點的位置(紅色)。我還定義了這些點在最終圖像中變換到的最終位置(藍色),以便「拉直」或「校正」建築物的正面。

  magick building.jpg \
          -draw 'fill none stroke red polygon 7,40 4,124, 85,122, 85,2' \
          building_before.jpg
  magick building.jpg \
          -draw 'fill none stroke blue polygon 4,30 4,123, 100,123, 100,30' \
          building_after.jpg
[IM Output] ==> [IM Output] [IM Output]
要進行實際的圖像扭曲,您只需將這些坐標輸入「-distort」的「perspective」方法中。

  magick building.jpg -alpha set -virtual-pixel transparent \
         -distort Perspective \
              '7,40 4,30   4,124 4,123   85,122 100,123   85,2 100,30' \
          building_pers.png
[IM Output] ==> [IM Output]
請注意右上角的空白區域,扭曲“錯過了”來源圖像中的像素數據。IM 在這種情況下的處理方式由“-virtual-pixel”設定控制(請參閱虛擬像素)。不太明顯的是,原始圖像最左邊緣的一小部分也因為同樣的原因而“丟失”了。有趣的是,我們還可以通過交換每個映射對的坐標來反轉扭曲。這使我們可以看到圖像有多少因扭曲而退化。

  magick building_pers.png  -alpha set -virtual-pixel transparent \
         -distort Perspective \
              '4,30 7,40   4,123 4,124   100,123 85,122   100,30 85,2' \
          building_pers_rev.png
[IM Output] ==> [IM Output] ==> [IM Output]
還不錯。出現了很多“模糊”,但這是無法避免的。請注意,圖像右側的“模糊”更嚴重,因為它被壓縮得最多。所有扭曲都會遇到這種壓縮問題,因此您應該始終嘗試從原始圖像進行扭曲,而不是扭曲已經扭曲的圖像。以下是使用此變換的另一個示例,使用我們上面創建的特殊棋盤格測試圖像,我們對其進行扭曲,然後反轉扭曲。

  magick checks.png        -alpha set    -virtual-pixel transparent \
          -distort Perspective '0,0,0,0  0,90,0,90  90,0,90,25  90,90,90,65' \
          checks_pers.png
  magick checks_pers.png   -alpha set    -virtual-pixel transparent \
          -distort Perspective '0,0,0,0  0,90,0,90  90,25,90,0  90,65,90,90' \
          checks_pers_rev.png
[IM Output] ==> [IM Output] ==> [IM Output]
您可以看到由圖像壓縮引起的輕微模糊,但圖像基本上已恢復。實際發生的情況是 IM 使用給定的所有控制點對來計算“透視投影”的適當係數(見下文)。如果您包含詳細設定,您可以看到係數和 IM 內部用於執行此扭曲的DIY FX 等效項。如果僅提供 3 個或更少的控制點對,IM 將自動回退到更簡單的“仿射”扭曲。而超過 4 個點(用於“*圖像配準*”)將最小二乘擬合以找到適合所有給定控制點的最佳擬合扭曲。*未來:備選方案。四個坐標也可以表示一個三角形和一個中心點。您可以固定三角形並移動中心點,或者固定該中心並移動其他三個坐標,以生成透視圖。*如果您想查看有關扭曲工作原理的更多詳細信息,請查看下面的透視內部結構。您還可以查看 PDF 文件透視校正中介紹的 Postscript 實現,作者是*Gernot Hoffmann*。另請參閱Leptonica 仿射和透視變換

觀看遙遠的地平線

如果您調整坐標以在圖像邊界內產生“消失點”,則可以使用透視扭曲產生一些非常不尋常的效果。

  magick checks.png -mattecolor DodgerBlue \
          -virtual-pixel background -background Green \
          -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          checks_horizon.png
[IM Output]
我們使用「Green」來表示「環繞」原始圖像的虛擬像素,我們使用虛擬像素背景設定來啟用它。但更有趣的是使用「-mattecolor」設定定義的「藍色」外觀。此「藍色」表示由變形產生的像素*無效*的區域,在這些區域中,「-distort」運算子將只輸出「-mattecolor」設定。對於透視變形,最終出現在結果圖像「天空」中的任何像素都將被歸類為無效。它還將「天空」定義為源圖像不會出現的「地平線」一側。「天空」只會出現在透視變形的圖像中,當結果圖像因變形而高度縮短時。如果您不希望最終圖像結果中出現「天空」,那麼最好的方法是將「-background」和「-mattecolor」都設定為使用相同的顏色。當使用一種特殊的無限平鋪虛擬像素設定時,透視變形會變得更加有趣。例如,在這裡我們使用「tile」設定來產生無限平鋪的平面。

  magick checks.png  -virtual-pixel tile -mattecolor DodgerBlue \
          -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          horizon_tile.png
[IM Output]
關於這張圖片的警告。要求無限平鋪的圖像生成起來*非常慢*。圖像越大,速度就越慢。您可以使用「-monitor操作控制設定監控「-distort」(或任何其他緩慢的圖像處理任務)的進度。基本上,對於靠近地平線的單個像素,ImageMagick 需要對原始圖像中的大量像素進行平均,才能確定合適的顏色。這可能需要很長時間。ImageMagick 確實嘗試通過快取資訊和使用對各種虛擬像素設定的一些內建知識來限制處理這些靠近地平線像素所花費的時間,但它仍然可能需要很長時間。有關此方法的更多詳細資訊,請參閱上面的區域重新取樣。另一個無限平鋪的透視圖像可以通過使用隨機虛擬像素設定來產生...

  magick checks.png  -virtual-pixel random -mattecolor DodgerBlue \
          -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          horizon_random.png
[IM Output]
發生的事情是,圍繞圖像的所有虛擬像素只是圖像本身中任何像素的隨機挑選。結果是地面由隨機雜訊組成,當您朝向圖像的地平線看去時,雜訊會變得更加平滑和模糊。它給人一種自然的深度感,而没有任何特定的重複模式。在這裡,我重複了上述操作,但使用的是純黑白源圖像。然而,我對實際變形的圖像不感興趣,只對生成的虛擬像素random」模式感興趣,所以我通過使用特殊的「-set option:distort:viewport」設定來改變我正在查看的「變形圖像空間」部分。此設定會覆蓋正在查看的變形空間區域的正常大小和位置。在本例中,該區域僅包含虛擬像素,而不包含變形圖像。

  magick -size 90x90 pattern:gray50 -alpha set \
       -virtual-pixel random -mattecolor none \
       -set option:distort:viewport 120x120+100-15 \
       -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
       +repage -size 120x50 gradient:dodgerblue-tomato \
       -compose DstOver -composite    sunset_horizon.png
[IM Output]
為了完成圖像,我移除了視口偏移量(使用「+repage」),並將日落顏色的漸層疊底或 DstOver到透明的「天空」中(使用「alpha setmattecolor」設定)。一張非常有趣的圖像,可以用作其他圖像處理工作的背景。您可以調整變形參數來調整地平線的高度和坡度。
這是對平鋪透視變形的更傳統測試。

  magick pattern:checkerboard -scale 120x120 -normalize \
          -virtual-pixel tile  -distort Perspective \
             '0,0 10,61   119,0 60,60   0,119 5,114   119,119 125,110' \
          checkered_plain.gif
[IM Output]
在我的研究中,我發現上述測試具有誤導性,因為它沒有真正表明圖像接近統一比例(前景區域,而不是遠處區域)的區域重採樣技術的質量。那是仔細研究重採樣問題,例如重採樣偽影中描述的問題。最後一張圖像還顯示了靠近地平線的「截止」點,ImageMagick 認為不值得嘗試確定像素的適當顏色(考慮到當前的虛擬像素設置),而是採用捷徑並使用整個圖像的平均顏色。它僅在此圖像中可見,因為圖像中存在大比例的顏色對角線圖案。圖像的平均顏色僅在每次變形操作中計算一次,並且僅在第一次需要時計算。通過使用它,ImageMagick 節省了大量時間來計算靠近地平線的顏色,而通常結果將是圖像的平均顏色。當橢圓變得如此細長以至於超過浮點數限制,或者採樣像素的數量(橢圓的邊界平行四邊形)變得比輸入源圖像大 4 倍時,就會發生這種情況。這目前無法由使用者設置。

3D 盒子、透視分層

+distort」的「加號」形式可確保整個扭曲的圖像保存在正確定位的圖層(或「虛擬畫布」)中,其設計方式是,如果使用相同的「控制點」來扭曲圖像,則這些點將在「虛擬空間」中對齊。這意味著,如果將圖像圖層合併在一起,則這些圖像也將根據控制點對齊。例如,在這裡,我們生成兩個圖像,「正面」圖像和「脊柱」圖像,以便兩個邊緣控制點彼此對齊,形成盒子的脊柱。

  # Generate a Spine Image
  magick -size 200x40 xc:skyblue \
    -pointsize 20 -gravity north -annotate +5+0 'IM Examples' \
    -pointsize 10 -gravity south -annotate +0+0 'ImageMagick' \
    -stroke blue -strokewidth 2 -draw 'line 30,0 30,40' \
    -rotate -90 box_spine.jpg

  # generate the front cover
  magick -size 150x200 xc:skyblue \
    -fill black -pointsize 20 -gravity north -annotate +0+5 'IM Examples' \
    -fill blue -pointsize 15 -gravity northeast -annotate +5+28 'Box Set' \
    -fill black -pointsize 15 -gravity south -annotate +0+5 'ImageMagick' \
    -stroke blue -strokewidth 2 -draw 'line 0,169 150,169' \
    \( logo.gif -resize 100x100 \) \
    -gravity center -compose multiply -composite box_front.jpg

  # Distort both images and merge using common points.
  magick \
    \( box_spine.jpg -alpha set -virtual-pixel transparent \
       +distort Perspective \
           '0,0 -30,20  0,200 -30,179  40,200 0,200  40,0 0,0' \) \
    \( box_front.jpg -alpha set -virtual-pixel transparent \
       +distort Perspective \
           '0,0 0,0  0,200  0,200  150,200 100,156  150,0 100,30' \) \
    \
    -background black -compose plus -layers merge  +repage \
    -bordercolor black -compose over -border 15x2    box_set.jpg
[IM Output] [IM Output] ==> [IM Output]
另請注意使用Alpha 合成加來連接「邊緣連接」的片段。這是防止在兩個圖像之間生成「半透明間隙」所必需的。有關更多信息,請參見上面的3D 立方體示例,以及對齊兩個蒙版圖像。使用這樣的定位意味著幾乎所有「脊柱」圖像實際上都扭曲為負「x」位置。因此,生成的圖像在虛擬畫布上具有負偏移量。使用分層「+distort」版本的運算符時,IM 可以毫無問題地做到這一點。圖層合併運算符還設計用於處理具有負偏移量的分層圖像,將兩個圖像乾淨地「拼接」在一起。在將它們「合併」在一起後,我仍然需要使用最後一個「+repage」來從最終圖像中移除負偏移量。如果我不這樣做,網路瀏覽器等其他程式可能無法理解此類負偏移量,並導致未定義的效果。上面的示例也已放入 shell 腳本「box_set_example」中,以便您可以更方便地下載和使用它。您可以更進一步,添加由其所在表面反射的「盒子」鏡像,儘管您可能還想以某種方式重新著色或調暗該圖像以使其更加逼真。有關此類鏡像技術,請參見反射
在關於在無邊框畫布框架上包裹「照片」的討論中,開發了另一個 PHP 示例。有關更多詳細信息,請參見畫布包裹變換
最後,這裡是 Jean-François Hren 為www.animecoversfan.com製作的一個很棒的示例,該示例在IM 討論區上進行了大量討論。
[Diagram]
這張圖片是透過以下步驟建立的:取得一張動畫影片盒裝封面的藝術圖像,將封面分成三個區塊(「封面」、「書脊」和「背面」),分別扭曲每個區塊成多層圖像,新增第四張「光碟」圖像,最後將它們合併在一起。然後透過新增高光和陰影效果(使用 硬光 圖像合成),以及新增邊框和半透明陰影效果(使用 複製不透明度)完成圖像。更令人驚奇的是,整個過程僅透過單一「magick」指令,從輸入圖像完成。這是 IM 功能的絕佳範例,以及產生複雜指令碼的過程。我建議閱讀 論壇討論,因為它包含許多提示、技巧和一般的除錯技巧。 (歡迎提供更多範例)

透視投影扭曲

就像「仿射」扭曲可以直接處理給定「仿射投影」的數學係數一樣,「透視」也可以透過「透視投影」扭曲的 8 個係數來處理。和之前一樣,這些數字代表用於將來源圖像中的點 正向映射 到目標圖像的係數。也就是說,它們是用於將來源圖像 x,y 映射到目標圖像 i,j 的數學值。8 個浮點數參數依序為...
sx、ry、tx
rx、sy、ty
px、py
這些係數值接著形成以下運算式..
Xd sx*Xs + ry*Ys + tx   ,       Yd rx*Xs + sy*Ys + ty


 px*Xs + py*Ys + 1.0   px*Xs + py*Ys + 1.0 
其中「Xs、Ys」是來源圖像座標,「Xd、Yd」是目標圖像座標。ImageMagick Distort 在內部會反轉上述方程式,以便執行適當的 反向像素映射,將「Xd、Yd」座標映射到來源圖像中的「Xs、Ys」以查詢顏色。「透視投影」的前 6 個值實際上與「仿射投影」的係數相同,只是為了更符合邏輯而稍微重新排序(在「矩陣數學」中,前 6 個元素已進行對角線轉置)。額外的兩個參數 px、py 形成整個扭曲的縮放除數,根據給定的值使圖像在特定方向上看起來更小,從而賦予扭曲圖像透視「距離」效果。如果這兩個值設定為零,「透視投影」扭曲就等同於「仿射投影」。例如...

  magick rose: -alpha set -virtual-pixel transparent \
          -distort Perspective-Projection \
             '1.40, 0.25, 3.0    0.15, 1.30, 0.0    0.007, 0.009' \
          perspective_projection_rose.png
[IM Output]
請記住,您提供的矩陣是正向投影矩陣,它會將來源圖像座標映射到目標圖像座標。ImageMagick 在內部會反轉矩陣,以便將目標圖像座標映射到來源圖像座標。如果您想查看這些值是什麼,請使用 詳細扭曲選項,讓 IM 輸出其內部係數作為 FX 運算子運算式(見下文)。

透視內部

如果您在透視扭曲 IM 之前新增「-verbose」(請參閱上文的 詳細扭曲摘要),它將輸出兩個運算子,它們應該可以替代「-distort」運算子。一種是非常慢的「-fx」版本(請參閱 FX DIY 運算子)。另一個將是正向映射 Perspective_Projection 矩陣。例如...

  magick rose: -alpha set -virtual-pixel transparent -verbose \
          -distort Perspective "0,0,3,0 0,46,10,46 70,0,70,7 70,46,60,40" \
          +verbose perspective_rose.png
[IM Output]
[IM Text]
第一部分的 *透視投影* 可用於將來源座標映射到目標座標。公式如上所示。
  i = ( 1.430099*x +0.246650*y +3 )/( 0.006757*x + 0.009448*y +1 )  
  j = ( 0.147296*x +1.434591*y +0 )/( 0.006757*x + 0.009448*y +1 )  
扭曲圖層影像的位置中的最後一組範例中,顯示了提取和使用這些值的範例。另一方面,第二個等效 FX 區段使用了一組不同的 8 個係數,它執行了影像扭曲實際需要應用的反向像素映射。也就是...
  x = ( 0.711858*i -0.108326*j -2.135575 )/(-0.004119*i -0.005877*j +1 )  
  y = (-0.073090*i +0.699571*j +0.219269 )/(-0.004119*i -0.005877*j +1 )  
請注意,在輸出「等效 FX」公式中,除數係數首先被使用,因為它們在 X 和 Y 坐標方程式中是相同的。請記住,您提供的所有坐標都是影像坐標,而不是像素坐標,詳情請參閱影像坐標與像素坐標。因此,任何像素位置在應用上述公式之前,都需要在輸入像素坐標上加上 0.5,然後從最終坐標中減去 0.5,以將其轉換回像素(繪製)坐標。您可以在上面的「等效 FX」程式碼中看到它的應用。在「等效 FX」中的最後一個測試中,就在來源影像查詢之前,處理了無效的「天空」像素,其中目標無法正確映射到來源影像。但是,它只會用「blue」替換此類像素,而不是「-mattecolor」,並且不提供內部演算法為透視扭曲提供的任何地平線反鋸齒功能。
透視正向映射範例... 這些映射允許您將一張影像中的特定坐標映射到另一張影像中的某個位置(雙向)。例如,來源玫瑰影像中心的一個暗點位於像素坐標「39,20」處。通過加上 ½ 將其映射到影像坐標「39.5,20.5」。現在,我們可以使用 x,y 到 i,j 的方程式將其映射到目標影像坐標「44.2,24.1」。最後,通過減去 ½ 得到最終位置「43.7,23.6」,以獲得「繪製」像素坐標。在這裡,我在輸入和輸出影像上都使用圓圈標記了該坐標。

  magick rose: -fill none -stroke black \
          -draw 'circle 39,20 39,24'    rose_marked.png

  magick perspective_rose.png -fill none -stroke black \
          -draw 'circle 43.7,23.6 43.7,26.6'  perspective_rose_marked.png
[IM Output] ==> [IM Output]
如您所見,透視扭曲影像中的同一點已正確定位在兩張影像中(甚至精確到亞像素級別)!

雙線性扭曲

雙線性」扭曲方法實現了另一種 4 點扭曲。但是,這不像我們上面看到的「透視」扭曲那樣簡單。但正如您將看到的,它是一種非常有用的替代扭曲方法。

正向雙線性扭曲

例如,讓我們以一張特殊的山魈測試影像為例,該影像上疊加了一個網格,並使用透視和雙線性方法對其進行扭曲。

  magick mandrill_grid.jpg -alpha set -virtual-pixel black \
       -distort Perspective \
              '0,0 26,0   128,0 114,23   128,128 128,100   0,128 0,123' \
       mandrill_pers.jpg
  magick mandrill_grid.jpg -alpha set -virtual-pixel black -interpolate Spline \
       -distort BilinearForward \
              '0,0 26,0   128,0 114,23   128,128 128,100   0,128 0,123' \
       mandrill_blin.jpg
[IM Output]
原始影像
==> [IM Output]
透視
[IM Output]
雙線性
首先,您應該注意到這兩種扭曲都正確地將圖像從一組控制點映射到另一組點。 同樣,在兩種扭曲中,源圖像中的所有水平線和垂直線也保持筆直。 然而,相似之處到此為止。 透視會縮小線條之間的間距,以使對角線也保持筆直。 這導致正方形的面積變小,從而使右上角具有逼真的“遠處”外觀。 另一方面,雙線性不會使圖像的一側看起來“更遠”,也不會試圖保持線條筆直。 它試圖做的是保持線條之間的所有間距恆定,但这会导致对角线弯曲。 也就是说,它保留了任何给定线上沿线的距离比。 也就是说,每个线段的相对长度在整条线的长度上保持不变,即使线本身可能整体弯曲、弯曲或缩短。 这意味着在上面的示例中,网格间距在整个图像中保持恒定比例,并且右上角的扭曲正方形仍然与左下角的扭曲正方形大小大致相同。 图像保持“平面外观”,只是扭曲成不同的形状。 请注意,(正向)双线性确实可以确保原始图像中的任何水平线或垂直线在最终图像中保持笔直。 也就是说,它将采用一个正交对齐的矩形并将其转换为指定的四边形,以便原始矩形的每条边在整条线上保持笔直,并具有恒定的缩放比例。 正是扭曲的这方面使“BilinearForward”扭曲在更复杂的“网格”扭曲中很有用。 也就是说,因为两个相邻的“四边形”即使它们可能扭曲得非常不同,但仍然会正确地边缘对齐。 以下是使用内置玫瑰图像的严重扭曲的“透视”和“BilinearForward”之间的另一个比较......


magick rose: -alpha set -virtual-pixel transparent \ -distort Perspective "0,0,3,0 0,46,10,46 70,0,70,7 70,46,60,40" \ perspective_rose.png magick rose: -alpha set -virtual-pixel transparent -interpolate Spline \ -distort BilinearForward "0,0,3,0 0,46,10,46 70,0,70,7 70,46,60,40" \ bilinear_rose.png
[IM Output]
原始影像
==> [IM Output]
透視
[IM Output]
雙線性
为了实现其目标(保留所有直线),透视扭曲似乎将几乎整个图像“吸”到右侧的较小区域,而双线性扭曲将其结果中的居中玫瑰保持在中心。 同樣,它保留了距離比率,使玫瑰在左右邊緣之間等距。 它所做的只是簡單地沿其長度線性地壓縮圖像的高度。 “BilinearForward”扭曲的這一方面使其也被稱為“梯形”扭曲。 也就是说,只需在一个方向上线性压缩图像,而只有一个方向被缩放。 该压缩方向甚至可以是倾斜的,而不是沿着一个轴对齐。
请注意,由于执行“BilinearForward”扭曲所需的逆向像素映射的复杂性,区域重采样当前已关闭。

因此,极端压缩区域(大于 2 倍)可能会显示一些锯齿效应(参见上面示例中的线条边缘。但是,使用 超级采样,或“-interpolate Spline' 可用于提高最终图像的质量。
在 IM v6.5.7-0 之前,“BilinearForward”扭曲仍在开发中,并且在特定的“退化”情况下存在问题,这在特定情况下会导致“黑色”错误图像。

反向双线性扭曲

因为只有水平线和垂直线保持笔直,所以您不能使用“BilinearForward”扭曲来反转扭曲。 由于变换图像中的网格线不再是水平或垂直的,因此它们在生成的图像中将不再保持笔直! 例如,交换坐标对并重新应用“正向”扭曲(例如我们使用上面的“透视”扭曲所做的)将无法恢复原始图像。

  magick mandrill_blin.jpg -alpha set -virtual-pixel black \
       -distort BilinearForward \
              '26,0 0,0   114,23 128,0   128,100 128,128  0,123 0,128' \
       mandrill_blin_back.jpg
[IM Output] ==> [IM Output]
請注意,雖然指定的實際坐標確實正確定位,但圖像失真尚未被逆轉。總之,“BilinearForward”(雙線性正向)失真本身並非其自身的逆轉。要還原圖像,您需要使用略有不同但密切相關的失真。我們已將“幾何變換”的數學逆轉實現為“BilinearReverse”(雙線性反向)失真。例如...

  magick mandrill_blin.jpg -alpha set -virtual-pixel black \
       -distort BilinearReverse \
              '26,0 0,0   114,23 128,0   128,100 128,128  0,123 0,128' \
       mandrill_blin_rev.jpg
[IM Output] ==> [IM Output]
如前所述,由於“BilinearForward”失真的複雜性,區域重新採樣目前處於關閉狀態,這在上述情況下會導致嚴重的鋸齒效應。
BilinearReverse”具有與“BilinearFoward”相同的距離比例保持特性,但會將任何四邊形神奇地變換為正交對齊的矩形,確保四邊形的邊在映射到垂直和水平對齊時保持筆直。如您在上面所見。
在 IM v6.5.1-2 之前,“BilinearReverse”失真僅被實現為“Bilinear”。
一些雙線性失真的實現(包括舊版本的 IM 和Leptonica 庫)僅實現了上述更簡單的(反向)雙線性失真版本。但是,這種失真不太適合對矩形圖像進行“正向映射”。例如,在這裡我嘗試將“BilinearReverse”用於可能應該使用“BilinearForward”失真的失真。

  magick mandrill_grid.jpg -alpha set -virtual-pixel black \
       -distort BilinearReverse \
              '0,0 26,0   128,0 114,23   128,128 128,100   0,128 0,123' \
       mandrill_blin_rev2.jpg
[IM Output] ==> [IM Output]
如您所見,由於目標四邊形不是正交矩形,因此圖像嚴重失真,產生許多向內彎曲的線條。

平鋪雙線性失真

現在,雖然“BilinearReverse”會從矩形圖像生成“彎曲”圖像,但這種效果確實會產生有趣的平鋪圖案,這些圖案似乎會生成彎曲的三維表面。例如,通過應用與上面查看遙遠的地平線相同的變換,我們得到了這個有趣的結果。

  magick checks.png  -virtual-pixel tile  -mattecolor DodgerBlue \
          -distort BilinearReverse \
               '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          bilinear_rev_tile.png
[IM Output]
事實上,“BilinearReverse”永遠不會產生“地平線”(無效像素)。另一方面,使用“BilinearForward”往往會經常產生“天空”或“無效像素”(填充當前“-mattecolor”)。事實上,平鋪圖案往往會變得相當瘋狂...

  magick checks.png  -virtual-pixel tile  -mattecolor DodgerBlue \
          -interpolate Spline  -distort BilinearForward \
               '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          bilinear_fwd_tile.png
[IM Output]
如前所述,由於“BilinearForward”失真的複雜性,區域重新採樣目前處於關閉狀態,這在上述情況下會導致嚴重的鋸齒效應。
因此,我不建議使用“BilinearForward”的平鋪形式。但是,我建議您在使用正向失真時定義適當的“-mattecolor”,以防止出現意外的灰色“天空”色塊。

雙線性內部

使用“正向映射雙線性失真”將源圖像中的坐標映射到目標圖像的實際公式為...
Xd C0*Xs + C1*Ys + C2*Xs*Ys + C3   ,       Yd C4*Xs + C5*Ys + C6*Xs*Ys + C7
但是,由於 IM 使用反向像素映射技術實現失真,因此需要反轉上述公式。這是一個複雜的過程,需要求解二次方程式、平方根和整頁的代數運算。如果您要求 IM詳細輸出等效的 FX,您將看到這種複雜性。例如,使用我們之前創建的檢查圖像...

  magick checks.png -alpha set -virtual-pixel transparent -mattecolor none \
      -interpolate Spline -verbose -distort BilinearForward \
                   '0,0,0,0  0,90,0,90  90,0,60,30  90,90,90,90' \
      +verbose bilinear_checks.png
[IM Output]
[IM Text]
FX 等效項”最後一行的“(rt > 0 ) ? red :”檢查是為了避免無效的負平方根。這是創建先前示例中顯示的“天空”效果的檢查。另一方面,由於反向雙線性失真要簡單得多,因為您可以直接應用更簡單的多項式方程式來反轉先前的失真...

  magick bilinear_checks.png  -virtual-pixel transparent \
      -verbose -distort BilinearReverse \
                   '0,0,0,0  0,90,0,90  60,30,90,0  90,90,90,90' \
      +verbose bilinear_checks_rev.png
[IM Output]
[IM Text]
如您所見,結果方程式非常簡單,因為我們現在將其應用於將目標坐標進行反向像素映射到來源影像坐標。
以上所見的鋸齒效應是由「雙線性正向」造成的,而不是由「雙線性反向」扭曲造成的。這是因為目前由於「正向」映射版本的複雜性,區域重新取樣已關閉。
如需進一步閱讀,請參閱Leptonica 仿射與透視變換

組合雙線性扭曲

施工中
兩種雙線性扭曲方法一起使用,可以讓您直接將任何四邊形扭曲成任何其他四邊形,同時保持四邊形的邊緣筆直。基本上,您可以先將一個四邊形「反向」扭曲成矩形影像,然後再將該矩形「正向」扭曲成最終的四邊形。這種扭曲類型也意味著您可以採用任何矩形坐標網格,並將其扭曲成另一個矩形坐標網格。這稱為「網格」扭曲。這種技術是影像變形的基礎,您可以在兩個影像上定義一個矩形線網格,並使用它們將影像合併成一個中間合成影像,甚至生成一個動畫,從一個影像正確地變形成另一個影像。然而,這還沒有被實現,儘管是一個計劃中的功能。

多項式扭曲(使用多項式擬合進行扭曲)

與大多數先前的扭曲方法一樣,「多項式」扭曲也映射成對的控制點,但使用標準多項式方程式。這表示在給出控制點之前需要一個額外的參數。
階數     X1,Y1 I1,J1     X2,Y2 I2,J2     X3,Y3 I3,J3     X4,Y4 I4,J4 . . . .
階數」參數通常是從「1」開始的整數,但也可以使用特殊值「1.5」。這定義了將應用的二維數學方程式(同時使用「x」和「y」)的「階數」或複雜度。例如,階數為「1」的多項式將擬合以下形式的方程式...
Xd C2x*Xs + C1x*Ys + C0x   ,       Yd C2y*Xs + C1y*Ys + C0y
如果您將其與仿射投影中使用的方程式進行比較,您會發現它們是等效的。由於每個 X 和 Y 公式都需要 3 個常數,因此您還需要至少提供 3 個 X,Y 坐標對。任何更多都將導致方程式通過最小平方法擬合到給定的坐標。「下一個」階數或「1.5」等效於「雙線性反向」(請記住,該方程式用於將目標坐標映射到來源影像)。
Xd C3x*Xs*Ys + C2x*Xs + C1x*Ys + C0x   ,       Yd C3x*Xs*Ys + C2y*Xs + C1y*Ys + C0y
就像「雙線性反向」扭曲一樣,它至少需要 4 個坐標。例如... 基本上,這與階數為「1」的方程式完全相同,只是在多項式方程式中添加了一個額外項。也就是說,由於每個方程式現在每個軸有 4 個項,有 4 個常數,所以您現在至少需要 4 個坐標對,以允許 IM 確定這些常數。

  magick mandrill_grid.jpg -alpha set -virtual-pixel black \
       -distort Polynomial \
              '1.5   0,0 26,0   128,0 114,23   128,128 128,100   0,128 0,123' \
       mandrill_poly_1.5.jpg
[IM Output] ==> [IM Output]
當階數為「2」時,多項式方程式會進一步擴展為完整的二次擬合,至少需要 6 個坐標對。
Xd C5x*Xs2 + C4x*Xs*Ys + C3x*Ys2   + C2x*Xs + C1x*Ys + C0x
Yd C5y*Xs2 + C4y*Xs*Ys + C3y*Ys2   + C2y*Xs + C1y*Ys + C0y
基本上這與順序「1」的方程式完全相同,但在多項式方程式前面加上了 3 個額外的項(2 階 + 1)。也就是說,由於每個方程式現在都有 6 個項和 6 個常數,因此您現在至少需要 6 個座標才能讓 IM 確定這些常數。在此之後的每個連續階數多項式都會在每對方程式中添加另一個「階數」+1 個項。因此,階數為「3」的三次擬合多項式至少需要 10 個座標對才能完全定義,而階數為「4」的五次擬合多項式則需要 15 個座標對。您可以使用詳細失真摘要來查看多項式失真擬合指定座標後得到的方程式。舉一個更大的例子,我有一個網格圖像。我還有一大組座標(存儲在文件「grid16_control_points.txt」中),說明了我想要如何扭曲該網格。然後,我要求 IM 生成一個三次多項式來「最佳擬合」輸入座標。

  # warp image
  magick grid16.png -virtual-pixel gray \
          -distort polynomial "3 $(cat grid16_control_points.txt)" \
          grid16_polynomial.png

  # reverse image coordinate order
  awk '{print $3, $4, $1, $2}' grid16_control_points.txt \
                             > grid16_cp_inverse.txt

  # warp image back again
  magick grid16_polynomial.png -virtual-pixel gray \
          -distort polynomial "3 $(cat grid16_cp_inverse.txt)" \
          grid16_restored.png
[IM Output] ==> [IM Output] ==> [IM Output]
這個小的「awk」腳本會獲取原始的 X、Y 控制點對集並反轉順序,以便我們可以使用新文件來嘗試「撤消」失真。
控制點文件「grid16_control_points.txt」中的座標是圖像座標,表示每個數字都指的是它所指像素的中心。如果沒有額外的 0.5,這些值將是整數「像素座標」。請參閱上面的圖像座標與像素座標

這些值完全是通過使用圖像查看器手動查找確定的,因此實際上並不是很精確。這可能是某些反向失真偽影的來源,儘管多項式方程式的函數「最佳擬合」會減少整體失真效應。

這表明雖然多項式失真有效且效果良好,但它不是一種精確或可逆的失真。基本上,81 個座標被「平均」在一起,以便生成輸入座標的數學「最佳擬合」。由於提供了比所需最小值 (10) 更多的控制點 (81),因此不能保證所有控制點都與請求的座標完全匹配。但是,對於這個特定示例,其中座標接近預期的失真結果,它應該相當接近。多項式函數通常在圖像的邊緣,尤其是在角落處,誤差最大。這不僅會影響像素位置,還會影響邊緣的採樣區域 (EWA)。這是所用近似值的自然結果。可以使用更高階的多項式,但在這種情況下,它並沒有帶來任何顯著的改進。對於這種特殊情況,多項式實際上是在嘗試將自身擬合到非多項式三角函數。由於這些函數的性質,第二次失真將比第一次失真更不準確。這個例子實際上與我們將在下面看到的徑向桶形失真方法非常密切相關。但是請注意,正在映射的座標實際上不需要按網格排列,而可以是任何座標映射集。因此,地理學家經常使用它來對齊(和疊加)航空照片和地球物理地圖,使用方法是使用城鎮、十字路口、山峰和其他地標的已知位置作為控制點。
由於 多項式扭曲 通常是不可逆的,因此 IM 無法針對給定的來源影像計算目標影像視口「最佳擬合」。 因此,運算子的「+distort」形式不起作用,並會回到一般的「-distort」運算。 然而,您仍然可以使用 扭曲視口 選項來定義目標影像的視口。


圓形和徑向扭曲方法

這些扭曲涉及使用徑向向量作為扭曲過程的主要組成部分。

弧形扭曲(將影像彎曲成圓弧)

Arc」扭曲(從 IM v6.3.5-5 開始)是一種更複雜的 極座標扭曲(見下文)的簡單變體。 默認情況下,它會在給定的角度上將給定的影像彎曲成完美的圓弧,並且在沒有其他參數的情況下,它會盡可能地保持影像水平中心線和影像縱橫比的縮放比例。 為此,它最多需要四個參數。
arc_angle   rotate_angle   top_radius   bottom_radius
但是,只需要「arc_angle」,其他參數是可選的,並且可以根據需要按給定順序添加。 例如,在 60 度角上「Arc」影像...

  magick rose: -virtual-pixel White -distort Arc 60  arc_rose.jpg
[IM Output]
請注意,與其他影像扭曲運算子不同,「Arc」扭曲始終會設置結果影像的大小,以便顯示完整的來源影像。 這包括任何反鋸齒邊緣像素。 因此,結果影像的大小將很少與輸入影像的大小相匹配。

只有 視口扭曲選項 允許您更改特定扭曲的結果影像大小。
添加第二個參數「rotate_agle」可以讓您圍繞圓圈旋轉影像。 例如,將其旋轉 90 度。

  magick rose: -virtual-pixel White -distort Arc '60 90'  arc_rose_rot.jpg
[IM Output]
由於沒有提到特定的半徑參數,「Arc」扭曲方法會盡可能地確保保留原始影像的比例。 為此,影像的水平中心線設置為來源影像的寬度和給定「arc_angle」的「理想半徑」。 這意味著,如果您在更大的「arc_angle」上對影像進行弧形扭曲,則使用的中心線半徑也會縮小相同的比例。 因此,中心線的半徑將更小、更緊湊。

  magick rose: -virtual-pixel White -distort Arc 120  arc_rose_3.jpg
[IM Output]
請注意影像現在如何適應更小的圓圈,但影像的底部邊緣仍然是一個更小的圓圈! 如果您設置一個更大的角度來對影像進行弧形扭曲,則底部邊緣將碰到扭曲的中心以及更遠的地方,這會導致來源影像的下部消失在虛空中。

  magick rose: -virtual-pixel White -distort Arc 60   arc_rose_1.jpg
  magick rose: -virtual-pixel White -distort Arc 90   arc_rose_2.jpg
  magick rose: -virtual-pixel White -distort Arc 120  arc_rose_3.jpg
  magick rose: -virtual-pixel White -distort Arc 180  arc_rose_4.jpg
  magick rose: -virtual-pixel White -distort Arc 240  arc_rose_5.jpg
  magick rose: -virtual-pixel White -distort Arc 300  arc_rose_6.jpg
  magick rose: -virtual-pixel White -distort Arc 360  arc_rose_7.jpg
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

弧形到完整圓環

較長的影像在非常大的角度上進行「Arc」扭曲會更好。 例如,您可以將長影像(如簡訊)包裹成環。 為了讓您真正了解這裡發生的事情,我設置了不同的 虛擬像素 背景顏色,以便您可以看到原始影像的邊界。

  magick -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel Background  -background SkyBlue \
          -distort Arc 60     arc_circle_1.jpg
  magick -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel Background  -background SkyBlue \
          -distort Arc 120    arc_circle_2.jpg
  magick -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel Background  -background SkyBlue \
          -distort Arc 180    arc_circle_3.jpg
  magick -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel Background  -background SkyBlue \
          -distort Arc 270    arc_circle_4.jpg
  magick -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel Background  -background SkyBlue \
          -distort Arc 360    arc_circle_5.jpg
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
然後我們將標籤影像「弧形扭曲」成一個完整的圓圈。 如果您仔細觀察完整圓圈影像的連接處,您可能會看到一小行像素,其中連接處並不完全完整。 這是由周圍「SkyBlue虛擬像素 背景的效果引起的,因為我們實際上是在連接影像的兩個邊緣。 生成完整圓圈時,您需要使用一種可以正確「連接」這兩個邊緣的虛擬像素方法。 這通常通過使用平鋪 虛擬像素 方法之一來完成,例如 Tile

  magick -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel Tile -background SkyBlue \
          -distort Arc 360   arc_circle_tile.jpg
[IM Output]
遺憾的是,如您所見,這不僅將圖像正確地拼接在一起,而且還會在主環的內外生成圖像的重複行。這並不好。從 IM v6.4.2-6 開始,一種新的 虛擬像素 方法,水平平鋪,解決了這個問題。此方法僅將圖像橫向平鋪,因此它為我們的圓形圖像創建了一個良好的連接,但使用當前背景顏色填充了圖塊上方和下方的區域,從而產生了一個完美的文本圓圈。

  magick -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel HorizontalTile -background SkyBlue \
          -distort Arc 360   arc_circle.jpg
[IM Output]
如果在對圖像進行“弧形化”之前將輸入圖像上下顛倒,則可以將圖像的原始“頂部”放置在圓的內邊緣。當然,您可能希望之後將結果“旋轉”回直立狀態,但“Arc”扭曲方法已經內建了該功能。

  magick -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel Background -background SkyBlue \
          -rotate 180 -distort Arc '270 180'  arc_flip.jpg
[IM Output]
第三個參數“top_radius”將覆蓋計算出的“理想”中心線半徑,以便圖像的頂部將變成給定半徑的圓。這將創建一個寬度為 100 像素的環,儘管容納圖像的寬度為 102 像素,以便考慮抗鋸齒效果。

  magick -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel HorizontalTile -background SkyBlue \
          -distort Arc '360 0 50'  arc_radius.jpg
[IM Output]
圖像仍然保持相同的縱橫比,因此上面的內容與之前基本相同,只是縮放以適應所請求半徑的圓圈。請記住,半徑可以是浮點數,但圓弧的中心始終與像素“角”對齊,因此生成的圖像寬度仍將是偶數像素。如果您提供第四個“bottom_radius”參數,則可以完全控制環的寬度或其“徑向高度”。

  magick -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel HorizontalTile -background SkyBlue \
          -distort Arc '360 0 45 30'   arc_inner.jpg
[IM Output]
這將扭曲圖像的徑向縮放,並有效地將徑向縮放與結果圖像的“弧寬”或角度分開。換句話說,原始圖像的縱橫比將不再保留。
您甚至可以強制它完全填充圓圈的內部,將輸入圖像的底邊包裹在變形的中心或“極點”。

  magick -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel HorizontalTile -background SkyBlue \
          -distort Arc '360 0 45 0'   arc_fill.jpg
[IM Output]

弧形扭曲範例

您可以使用 弧形變形 生成有趣的效果,例如將長棋盤圖案彎曲成環(使用 虛擬像素 設置“水平平鋪”產生...

  magick -size 210x30 pattern:checkerboard -alpha set \
          -virtual-pixel HorizontalTile -background SkyBlue \
          -distort Arc 360   arc_checks.png
[IM Output]
通過使用“邊緣”的默認 虛擬像素 設置,您可以產生更有趣的效果。

  magick -size 210x30 pattern:checkerboard  -virtual-pixel Edge \
          -distort Arc 360   arc_checks_edge.png
[IM Output]
當然,“平鋪”設置也會產生有趣的“徑向”效果,讓您可以生成圓形棋盤圖案。

  magick -size 210x30 pattern:checkerboard  -virtual-pixel Tile \
          -distort Arc 360   arc_checks_tile.png
[IM Output]
通過控制結果圖像的頂部和底部半徑,可以進一步細化上述內容。以下是一些“弧形”變形示例,但我讓您自行嘗試以了解它們的工作原理。您能想出什麼?

  magick -size 90x1 pattern:gray50 -scale 900x100 -normalize \
          -virtual-pixel Tile  -set option:distort:viewport 100x100-50-50 \
          -distort Arc 360  +repage  arc_radii.gif
[IM Output]

  magick -size 400x100 pattern:hs_diagcross \
          -virtual-pixel Tile  -set option:distort:viewport 100x100-50-50 \
          -distort Arc '360 0 80 0' +repage  arc_cross.gif
[IM Output]

  magick -size 360x80 xc: -draw "fill none stroke black line 0,5 360,80" \
          -virtual-pixel White  -distort Arc '360 0 50 0'  arc_spiral.gif
[IM Output]

  magick tree.gif -set option:distort:viewport 120x60-60-60 \
          -virtual-pixel Dither  +distort Arc '180 0 25 0' \
          +repage arc_rays.gif
[IM Output]
最後一個示例中的“射線”是偽隨機“抖動虛擬像素 設置的副產品,導致原始圖像左上角的“太陽”顏色的奇數像素圖案。相同的抖動效果也會產生圍繞“樹”圖像的圓形“破折號”線。您可以通過對已修改為添加有趣邊緣像素的圖像使用“邊緣”設置來實現此效果的類似且更可控的版本。

弧形中心點放置

預設情況下,「弧形」會完全忽略影像可能具有的任何 虛擬畫布 位移,甚至不會回報影像繞其進行弧形變形的「中心」位置。 然而,知道「中心點」的位置可能非常有用。 如果您使用特殊加號形式「+distort」,而不是使用「-distort」,則影像將被賦予 虛擬畫布,以便中心位於虛擬畫布原點。 換句話說,影像的「0,0」點被設定為弧形的「中心」。 這對於定位角度小於完整圓形的弧形影像特別有用,其中弧形「中心」不是影像的中心。 例如...

  magick logo: -resize x150 -gravity NorthEast -crop 100x100+10+0! \
          \( -background none label:'IM Examples' \
             -virtual-pixel Background +distort Arc '270 50 20' \
             -repage +75+21\! \)  -flatten  arc_overlay.jpg
[IM Output]
在這裡,我建立了一個文字標籤「弧形」,並使用運算子的加號形式「+distort」將其扭曲成一個不完整的圓形。 IM 使用影像虛擬畫布位移仔細保留了弧形的「中心」。 這意味著通過使用帶有「!」標記的「-repage」對位移進行簡單的相對調整,我們可以將生成的文字圓圈定位在我們想要的任何位置! 例如巫師帽的尖端,在上例中位於像素坐標 75,21 處。 不幸的是,由於虛擬位移用於定位影像,因此精確定位僅限於整數像素大小。 如果不進行二次變形,則無法將 弧形變形 定位到子像素定義的位置。 但是,您可以對 極座標變形 執行此操作(請參閱下文)。

極座標變形(全圓變形)

Polar」變形(新增於 IM v6.4.2-6)是上述「弧形」變形的更底層版本。 但它不會自動執行「最佳擬合」,也不會嘗試保留影像的長寬比。 6 個可選的浮點數參數為...
Radius_Max Radius_Min Center_X,Center_Y Start_Angle,End_Angle
所有參數在間隔位置都是可選的。 預設情況下,「CenterX,Y」將預設為輸入影像區域的最中間。 然後將生成一個完整的圓形極座標影像,以便整個頂部邊緣成為中心,而底部邊緣則完全環繞在圓形的外部。 左右邊緣的交匯點將在「-180」到「+180」影像角度的中心點上方交匯。 由於必須指定「Radius_Max」,因此它應該是一些正值。   但是,如果您指定的值為「0」,則它將被設定為中心與最近邊緣之間的距離,因此如果未指定其他值(預設值),則整個輸入影像將被映射到影像中間的圓圈中。 例如,讓我們使用所有預設值將世界地圖變形為極座標視圖。 當然,在生成全圓極座標映射時,您應該指定「水平平鋪」的 虛擬像素 設定...

  magick worldmap_sm.jpg -virtual-pixel HorizontalTile  \
          -background Black   -distort Polar 0   polar_arctic.jpg
[IM Output] ==> [IM Output]
當然,這會嚴重扭曲南半球,將南極洲完全環繞在「盤形世界」的圓周上。
通過旋轉源影像並將其裁剪為僅顯示極地,我們可以生成一張漂亮的南極洲地圖。 我還指定了一個更大的輸出半徑,以便更加清晰可見,並要求 IM 使用 變形運算子 的「加號」形式將輸出影像「擬合」到此大小。

  magick worldmap_md.jpg -rotate 180 -crop 100%x25%+0+0 +repage \
          -virtual-pixel HorizontalTile -background Black \
          +distort Polar 80 +repage  polar_antarctica.jpg
[IM Output]
請注意,以上並非嚴格意義上的地球視圖,因為笛卡爾地圖是球體的表示,而不是極坐標圖像。 如果您使用精確值為“-1”的特殊“Radius_Max”值,則扭曲圖像的半徑將設置為從中心到最遠角落(對角線)的距離。 這是為了為我們接下來要看到的完整圖像“DePolar”扭曲提供理想的“反向”。 (有關使用示例,請參閱下面的(De)Polar 技巧)。
請記住,與“Arc”扭曲不同,“Polar”(也稱為“笛卡爾到極坐標”扭曲)不會嘗試保留源圖像的“理想”縱橫比。 建議謹慎使用。
CenterX,Y”參數在將結果圖像的中心定位在亞像素偏移量時最有用。 也就是說,中心是在像素的邊界(整數)還是在像素的中心(具有 0.5 的偏移量)。 當然,它也決定了虛擬畫布“圖層”的位置。 但是,默認情況下,它被賦予圖像中間的值(對於使用輸入圖像作為視口的“-distort”)或0,0(對於“+distort”圖層圖像)。 接下來的參數“Start_Angle,End_Angle”的使用頻率更低,並且限制了輸入圖像覆蓋的角度,默認為 -180 到 180 度(0 是正下方)。 與“Arc”扭曲一樣,您可以使用它來旋轉生成的極坐標圖像。 但它也可以用於生成“弧”。 例如...

  magick worldmap_sm.jpg -virtual-pixel Black -background Black \
          +distort Polar  '60,20 0,0 -60,60' +repage  polar_arc.jpg
[IM Output] ==> [IM Output]
請注意,目前 IM 不會減小生成的圖層圖像的大小,該圖層圖像已對齊,以便虛擬圖像原點位於坐標0,0處,如 requested 所示。 除了參數樣式之外,這是“Arc”和“Polar”扭曲之間的最大區別。 另請注意,左邊緣(-60 度角)在左側。 當您考慮“Y”軸向下時(與所有圖像旋轉相同),這在數學上是正確的。
當然,像 Arc 一樣,您可以使用虛擬像素平鋪效果來生成重複的圖案。 例如,這與最後一個示例完全相同,只是使用“HorizontalTileEdge”設置...

  magick worldmap_sm.jpg -virtual-pixel HorizontalTile -background Black \
          +distort Polar  '60,20 0,0 -60,60' +repage  polar_arc_tiled.jpg
[IM Output]

DePolar 扭曲(極坐標到笛卡爾坐標)

這本質上是“Polar”扭曲的逆過程,並且具有完全相同的一組可選參數。 6 個可選的浮點參數是...
Radius_Max   Radius_Min   Center_X,Center_Y   Start_Angle,End_Angle
同樣,如果將“Radius_Max”設置為“0”,則使用到最近邊緣的“CenterX,Y”距離,這意味著最大完整圓圈中的任何內容都將被映射以適合與輸入圖像大小相同的圖像。 例如,讓我們將前面的“圓盤世界”反轉回笛卡爾地圖。

  magick polar_arctic.jpg  -distort DePolar 0  world_restored.jpg
[IM Output] ==> [IM Output]
由於輸入圖像大小在整個兩個扭曲過程中都得到了保留,因此上述結果與原始地圖基本相同。 當然,由於圖像在頂部“極點”和半徑處都被壓縮了,因此輸出比您預期的要模糊得多。
實際上,區域重採樣算法 (EWA) 無法對圓弧中的像素進行採樣,因此情況變得更糟。 因此,對於“DePolar”扭曲,區域重採樣被關閉。 建議改用某種形式的超級採樣技術,如下節所示。
如果您允許 IM 使用“最佳擬合”(使用運算符的“+distort”形式),那麼它將調整輸出圖像的大小,以便保持“Radius_Max”處於統一縮放比例,並將寬度設置為“Radius_Max”和“Radius_Min”之間的半徑處的圓周距離。 這本質上是嘗試最佳地保留極坐標圖像的縱橫比,儘管這可能會產生比預期更長更薄的圖像。 例如。

  magick polar_arctic.jpg  +distort DePolar 0  world_restored_2.jpg
[IM Output] ==> [IM Output]

(De)Polar 循環技巧(徑向/角度模糊)

正如我們在上面看到的,當使用“Polar”(*笛卡爾坐標轉極坐標*)扭曲時,使用“0”的“*Radius_Max*”將確保整個圖像映射到一個圓形中,並且相同的設置將通過使用“DePolar”(*極坐標轉笛卡爾坐標*)將該圓形映射回矩形圖像。但是,如果您想“DePolar”一個矩形圖像,然後使用“Polar”再次反轉扭曲,這將不會很好地工作。例如,讓我們拍攝一張花朵圖像,去極化,然後使用“0”的特殊“*Radius_Max*”值(半徑=最近邊緣)恢復它。

  magick flower_sm.jpg -virtual-pixel Black \
          -distort DePolar 0  flower_depolar.jpg
  magick flower_depolar.jpg \
          -virtual-pixel HorizontalTile -background black \
          -distort  Polar  0  flower_circle.jpg
[IM Output] ==> [IM Output] ==> [IM Output]
現在圖像沒有正確恢復,因為它被第一次“DePolar”扭曲剪切掉了。即使如此,這本身也是一種有用的技術,並且可以用於為現有圖像生成完美的圓形蒙版,其大小方式完全獨立於給定的輸入圖像。為了正確執行這種“DePolar”-“Polar”循環技術,我們需要使用從中心到最遠角的距離作為半徑。“-1”的特殊“*Radius_Max*”值將要求 IM 計算並使用距“中心點”最遠的角作為半徑。

  magick flower_sm.jpg  -virtual-pixel Black \
          -distort DePolar -1  flower_depolar-1.jpg
  magick flower_depolar-1.jpg \
          -virtual-pixel HorizontalTile -background black \
          -distort  Polar  -1  flower_restored.jpg
[IM Output] ==> [IM Output] ==> [IM Output]
恢復後的圖像略顯模糊,這是由於在“DePolar”操作期間需要壓縮半徑以保留整個圖像造成的。然而,這可以通過使用適當的超採樣技術來解決(請參閱下一組示例)。但是為什麼要將圖像變成這種形式並再次返回呢?好吧,通過在圖像的中間“DePolar”版本上應用其他扭曲,您可以非常輕鬆地生成一些非常奇特的徑向或角度效果。例如,通過滾動中間圖像,您將旋轉輸出圖像,儘管您可能會看到角落的一些裁剪...

  magick flower_sm.jpg -virtual-pixel Black -distort DePolar -1 \
          -roll +15+0 \
          -virtual-pixel HorizontalTile -background Black \
          -distort  Polar  -1  flower_polar_rotate.jpg
[IM Output]
請注意,旋轉方向與旋轉運算符SRT 扭曲的旋轉方向相反。

去極化-極化循環問題

在上面的圖像旋轉中,您可能已經注意到旋轉圖像邊緣出現了一些“階梯狀”的扭曲。這是一個眾所周知的問題,是由於將圖像的大圓周壓縮到輸入圖像的較小“寬度”中造成的。例如,在這裡我採用棋盤測試圖像,並僅通過正常的去極化-極化循環運行它,而不做任何更改。

  magick checks.png   -virtual-pixel Transparent \
          -distort DePolar -1   checks_depolar.png
  magick checks_depolar.png  -virtual-pixel HorizontalTile -background None \
          -distort  Polar  -1   checks_cycled.png
[IM Output] ==> [IM Output] ==> [IM Output]
您可以清楚地看到由中間圖像點中的圖像壓縮引起的混疊效應。在初始“DePolar”轉換輸入圖像期間沒有使用正常的區域重採樣也加劇了這種情況。解決此問題的最佳方法是使用扭曲輸出縮放來放大中間圖像,然後縮小最終圖像。這將提供超採樣結果,從而消除上面看到的壓縮偽影。例如,這是一個更好的“無操作”去極化-極化循環,都在一個命令中...

  magick checks.png -virtual-pixel Background -background None \
          -set option:distort:scale 4  -distort DePolar -1 \
          -noop \
          -virtual-pixel HorizontalTile -background None \
          -set option:distort:scale .25 -distort  Polar  -1 \
          checks_cycled_ss.png
[IM Output]
如您所見,可怕的混疊效應幾乎消失了。但是請注意,非常高瘦的圖像可能會使問題再次出現。最好的辦法是將其限制為“橫向”或寬幅圖像,並如上所示進行超採樣。您現在需要做的就是用適當的命令替換“-noop”運算符,以生成您正在尋找的徑向和旋轉效果。

去極化-極化效果示例

讓我們再次展示更好的圖像 **極座標旋轉** 效果,這次使用超採樣。但請注意,由於中間圖像的大小是原來的 4 倍,因此 圖像滾動 的量也需要是原來的 4 倍。

  magick flower_sm.jpg   -virtual-pixel Black \
          -set option:distort:scale 4   -distort DePolar -1 \
          -roll +60+0   \
          -virtual-pixel HorizontalTile -background Black \
          -set option:distort:scale .25 -distort Polar -1 \
          flower_polar_rotate_ss.jpg
[IM Output]
如您所見,邊緣的「階梯」效應已被消除,圖像品質得到了顯著提升。
或者,您可以對中間圖像應用簡單的線性模糊處理(例如,通過再次壓縮和放大圖像來實現)。

  magick flower_sm.jpg -virtual-pixel Black \
          -set option:distort:scale 4   -distort DePolar -1 \
          -scale 10%x100%\! -filter Gaussian -resize 1000%x100%\! +filter \
          -virtual-pixel HorizontalTile -background Black \
          -set option:distort:scale .25 -distort Polar -1 \
          flower_angular_blur.jpg
[IM Output]
結果與圖像的「**旋轉模糊**」非常相似。這與被錯誤命名的 徑向模糊運算器 類似,但不完全相同。實際上,結果比那種專門的模糊方法品質更高。請注意,在各種形式的 虛擬像素設定 中使用「black」(黑色)顏色會導致邊緣略微變暗,但在上述情況下並不太明顯。消除「黑色」邊緣效應的一種方法是改用「transparency」(透明)顏色,然後在完成後完全關閉 Alpha 色板,以便僅保留 IM 計算的實際顏色。另一種方法是使用兩種「邊緣」虛擬像素方法(「Edge」和「HorizontalTileEdge」),它們將圖像的邊緣延伸到未定義的虛擬畫布空間中。

  magick flower_sm.jpg -virtual-pixel Edge \
          -set option:distort:scale 4   -distort DePolar -1 \
          -scale 10%x100%\! -filter Gaussian -resize 1000%x100%\! +filter \
          -virtual-pixel HorizontalTileEdge -background Black \
          -set option:distort:scale .25 -distort Polar -1 \
          flower_angular_blur_edge.jpg
[IM Output]
這顯示邊緣附近的結果要好得多。
通過垂直模糊圖像的極座標版本,這次使用 動態模糊運算器 而不是調整大小壓縮,您可以生成從圖像中心向外移動的 **徑向條紋**...

  magick flower_sm.jpg   -virtual-pixel Black \
          -set option:distort:scale 4   -distort DePolar -1 \
          -virtual-pixel Edge   -motion-blur 0x28-90 \
          -virtual-pixel HorizontalTile -background Black \
          -set option:distort:scale .25 -distort Polar -1 \
          flower_radial_blur.jpg
[IM Output]
要使結果僅模糊圖像的高光部分(花瓣),您可以使用 加亮 模式將其與原始圖像合成,這樣只有模糊的較亮顏色保持可見,而深色不會模糊到較亮區域,也不會破壞花朵中間的黃色斑點。

  magick flower_sm.jpg  flower_radial_blur.jpg \
          -compose Lighten -composite   flower_radial_blur_lighten.jpg
[IM Output]
另請參閱 恆星與彗星 以獲取另一個示例,該示例直接生成中間「去極座標」圖像,然後再應用「極座標」扭曲。特別感謝 Fred Weinhaus 對去極座標-極座標循環的特殊使用,以及他堅持要求我確保這些扭曲對於矩形圖像完全可逆。他在他的許多 ImageMagick 腳本 中都很好地應用了這種技術,包括「bump」、「ripples」和「striations」。

桶形失真(校正鏡頭失真)

桶形失真(添加到 IM v6.4.2-4 中)專門用於校正照片中由相機鏡頭引起的球面失真。也就是說,諸如桶形和枕形效應之類的失真,它們實際上是彼此相反的。有關使用此運算器進行鏡頭失真校正的實際應用,請參閱「鏡頭校正」一節。失真基於一組 4 個係數值(稱為 ABCD)實現,如 Helmut Dersch 教授 在一個現已消失的網站中所定義。您可以在 Wayback Machine 上查看該網站的存檔,網址為 校正桶形失真。這些值基本上構成了一個失真方程式,如下所示...
Rsrc = r * ( A*r3 + B*r2 + C*r + D )
其中「r」是目標半徑,「Rsrc」是來源像素,用於取得像素顏色。這些半徑經過標準化,因此對於輸入圖像最小寬度或高度的一半,半徑 = '1.0'。這看起來可能顛倒了,但這是因為使用了反向像素映射技術,以確保完全覆蓋生成的圖像。所有四個係數(ABCD)對於任何特定的相機、鏡頭和變焦組合都是固定的。所有這三個通常都與圖像一起存儲在EXIF 配置文件中。這很重要,因為這意味著一旦您獲得了相機的這些值,就可以使用它們來消除該相機和鏡頭組合拍攝的所有照片中存在的球面透鏡畸變。「Barrel」畸變方法所需的參數。通常您只需提供 3 或 4 個值...
A   B   C   [ D   [ X , Y ] ]
可選的 XY 參數為徑向畸變提供了一個可選的「中心」,否則它默認為給定圖像的精確中心(無論其虛擬偏移量如何)。係數的設計使得如果所有四個 AD 值加起來等於 '1.0',則圖像的最小寬度/高度將不會改變。因此,如果未提供 D(它控制圖像的整體縮放),則將設置它,以便所有四個值加起來等於 '1.0'。使用參數 '0.0 0.0 0.0'(等效於 A=B=C=0.0D=1.0')將不會對輸入圖像產生任何變化,並且是此畸變的「無操作」參數。以下是原始網站上的一個示例,使用了所用相機的提供的係數來拍攝照片。

  magick barrel_distorted.jpg -virtual-pixel black \
          -distort Barrel "0.0 0.0 -0.075 1.1" \
          barrel_distorted_fixed.jpg
[IM Output] ==> [IM Output]
請注意圖像中的畸變是如何被校正的,使建築物的柱子變直。但是,由於 4 個係數加起來的值大於 1.0,因此圖像會縮小一點,從而在中間頂部和底部邊緣產生小的黑色區域(根據給定的虛擬像素設置)。以下是為每個輸入係數添加 0.2 的效果,同樣,這些值加起來大於 1.0,因此生成的畸變圖像將更小。

  magick checks.png -virtual-pixel gray \
          -distort Barrel "0.2 0.0 0.0 1.0"   barrel_checks_A.png
  magick checks.png -virtual-pixel gray \
          -distort Barrel "0.0 0.2 0.0 1.0"   barrel_checks_B.png
  magick checks.png -virtual-pixel gray \
          -distort Barrel "0.0 0.0 0.2 1.0"   barrel_checks_C.png
  magick checks.png -virtual-pixel gray \
          -distort Barrel "0.0 0.0 0.0 1.2"   barrel_checks_D.png
[IM Output] [IM Output] [IM Output] [IM Output]
減去 0.2 會產生相反的效果,儘管我使用更大的「D」值(縮小圖像)來抵消這種效果,以便您可以更好地看到結果。

  magick checks.png -virtual-pixel gray \
          -distort Barrel "-0.2 0.0 0.0 1.3"   barrel_checks-A.png
  magick checks.png -virtual-pixel gray \
          -distort Barrel "0.0 -0.2 0.0 1.3"   barrel_checks-B.png
  magick checks.png -virtual-pixel gray \
          -distort Barrel "0.0 0.0 -0.2 1.3"   barrel_checks-C.png
  magick checks.png -virtual-pixel gray \
          -distort Barrel "0.0 0.0 0.0 1.3"    barrel_checks-D.png
[IM Output] [IM Output] [IM Output] [IM Output]
請注意,A 的值比 B 產生的影響更大,BC 產生的影響更大,而 D 提供結果的整體縮放。這使您可以使用每個係數來調整圖像,以便您可以校正外邊緣周圍的一種畸變和朝向中間的另一種畸變,無論是針墊形畸變還是桶形畸變。非常通用。上述係數(ABCD)設計用於「標準化」半徑,該半徑是圖像最小寬度或高度的一半(例如極坐標畸變的「0」半徑設置)。也就是說,它們與圖像大小無關。因此,您可以對特定相機生成的所有圖像使用相同的這些值,無論其質量大小(相機設置)如何,或者您是否將圖像調整為更小。可以使用適當的乘數/除數調整係數值以使用其他「標準化」半徑值,例如使用最大寬度/高度的一半或使用對角線半徑。
Helmut Dersch 還指出,您應該考慮對照片中的畸變校正使用 LAB 色彩空間,因為它可以產生更好的顏色插值。這實際上可能適用於所有畸變(包括調整大小)。

測試顯示,LAB 色彩空間與 sRGB 一樣具有非線性,但可以避免在極端值被裁剪時出現顏色失真。請參閱人類色彩感知,以及使用色彩空間校正調整大小中的實際範例。

您也可以為 x 軸和 y 軸聲明不同的係數集,從而產生一些不尋常的扭曲。
Ax Bx Cx Dx   Ay By Cy Dy   [ X , Y ]
Fred Weinhaus 在他的 pinbarrel 腳本中嘗試使用了獨立的 X 和 Y 參數,儘管他的參數順序相反,以 D 為首,A 為尾。通過對 'y' 係數集使用適當的 D 值和正 C 值,您可以扭曲圖像,使其在中間垂直凸出。

  magick rose: -alpha set -virtual-pixel transparent \
          -distort Barrel "0.0 0.0 0.0 1.0   0.0 0.0 0.5 0.5" \
          barrel_bulge.png
[IM Output]
同樣,使用負 C 值,您可以在中間“擠壓”圖像。

  magick rose: -alpha set -virtual-pixel transparent \
          -distort Barrel "0.0 0.0 0.0 1.0   0.0 0.0 -0.5 1.9" \
          barrel_pinch.png
[IM Output]
或者,通過為 X 係數添加相反的效果,使其看起來像您在用手指擠壓圖像,使其從側面凸出。

  magick rose: -alpha set -virtual-pixel transparent \
          -distort Barrel "0.0 0.0 0.5 0.5   0.0 0.0 -0.5 1.9" \
          barrel_pinch_2.png
[IM Output]

桶狀反轉失真(替代桶狀失真)

BarrelInverse”失真方法與之前的 桶狀失真 失真方法非常相似,實際上採用相同的參數集。但是,應用的公式略有不同,等式的主要部分除以半徑,即等式已被反轉。
Rsrc = r / ( A*r3 + B*r2 + C*r + D )
此等式不會產生“反轉”的“Barrel”失真。您不能使用它來“撤消”先前的失真。
結果是,您將使用 ABC 的“負”形式,並對 D 進行等效調整,以實現相似但略有不同的結果。一些來源,例如研究論文 鏡頭失真校正方法 (PDF),建議使用這種形式的鏡頭校正失真可以獲得更好的結果。例如,以下是使用這種失真形式的最後一個“擠壓”示例的等效項。

  magick rose: -alpha set -virtual-pixel transparent \
          -distort BarrelInverse "0.0 0.0 -0.5 1.5   0.0 0.0 0.3 0.5" \
          barrel_inv_pinch.png
[IM Output]


投影失真

這些失真是用於將存在於一個表面上的圖像投影或映射到另一個表面上。投影線可以是平行的,也可以從某個特定位置輻射。雖然技術上仿射透視失真也是“投影的”,因為它們將一個平面上的圖像“投影”到另一個平面上(分別使用平行和徑向投影),但它們非常普遍,以至於在上面的示例區域中更詳細地介紹了它們。以下是已實現的更不尋常的“投影失真”,通常是在IM 討論區的幫助下實現的。

圓柱體到平面

Cylinder2Plane”失真是從圓柱體中心的點到與該圓柱體相切的平面的徑向投影失真。
[diagram]
這種排列是稱為 P.90 相機 的特殊針孔相機的典型特徵,其中 90 度弧的照片被拍攝在相機中形成圓柱體的膠片上。以下是來自此類相機的示例照片...
[photo]
這樣做的問題是,由於膠片的物理排列,生成的圖像會失真,因此直線會變成彎曲的弧線。本質上是一個彎曲的表面圍繞“點”投影源(一個針孔)包裹自身。請注意,普通的針孔相機沒有這個問題,因為您是從點光源投影到平面上。“Cylinder2Plane”失真通過將圖像從其圓柱排列投影到平面上來解決這個問題。它採用以下參數...
fov_angle   center_x,y   fov_output   dest_center_x,y
只有第一個參數,即相機視野角度是必需的。對於 P.90 相機,它使用 90 毫米(徑向)焦距和標準 57 毫米寬膠片,這反過來會產生 90 / 57 * 180/pi 或 90.467 度的「視野」。例如,我在這裡將 P90 照片投影到平面上,使圖像看起來更「正常」,並使直線再次變直。

  magick p90_orig.jpg -virtual-pixel Gray \
          +distort Cylinder2Plane 90.467  p90_plane.png
[IM Output]
請注意,圖像的寬度和高度都已更改,因為我們使用的是扭曲的「加號」版本,以便顯示原始圖像中的所有扭曲像素。由於投影,它更寬,而沿垂直中心線的實際圖像高度沒有改變。照片和算法來自 IM 論壇上的討論 校正彎曲膠片平面。討論還延續到另一個關於 針孔相機的算法暈影校正 的討論。
如果給定特殊的「fov_output」,則會縮放生成的輸出圖像,以便輸出圖像的寬度(通常是視口大小)與此角度完全匹配。如果沒有給出視口,則啟用最佳匹配,以最佳地近似圖像的 1:1 縮放,同時仍然將圖像邊緣對齊到整數。失真的中心點參數(輸入的切點和水平點)。最後一個「中心」參數控制視口圖像「圖層」(即亞像素平移)中結果的精確浮點定位。這與「center_x,y」參數允許您從較大的圖像中提取部分。例如,從較大的 360 度全景圖像中提取一個小的 90 度視圖。未來:從 360 度全景中提取更小的平面「觀看」圖像,以及圍繞這些 360 度緩慢平移的動畫。

平面到圓柱體

Plane2Cylinder」扭曲是上述投影的反轉,並採用以下參數...
fov_angle center_x,y
例如,這將撤消之前的 P.90 相機示例。

  magick p90_plane.png -virtual-pixel Black \
          +distort Plane2Cylinder 90.467  p90_restored.png
[IM Output]
結果仍然包含之前添加的額外像素,並且添加了更多像素。這些應該從上述結果中刪除。在這裡,我使用這種扭曲來生成「膠片條」的動畫,並帶有膠片鏈輪邊緣孔。

  magick -size 12x12 xc: -draw 'circle 6,6 6,2' -negate \
          -duplicate 5 +append +duplicate \
          rose: +swap -background black -append \
          -duplicate 3 +append \
          -virtual-pixel HorizontalTile -background SkyBlue \
          -duplicate 19  -distort SRT '%[fx:72*t/n],0 1 0 0,0' \
          -distort Plane2cylinder 115 \
          -bordercolor Skyblue -border 0x3 -set delay 5 \
          film_strip_anim.gif
[IM Output]
說明
  • 首先繪製一個孔圖像,將其複製並附加以製作 6 個孔的序列。然後再次複製。
  • 然後添加一個內置的玫瑰圖像,並將其夾在這些鏈輪孔的兩個副本之間,並附加在一起(填充黑色)以創建最終膠片條的單個幀。
  • 複製它以創建 4 幀的膠片條,這將定義最終圖像的長度。
  • 使用 SRT「平移」扭曲創建一個 20 幀的動畫,請參閱 扭曲動畫
  • 然後使用虛擬像素設置將這 20 個幀中的每一個扭曲到 115 度弧線上的圓柱體上,以生成膠片條的無限水平平鋪。
  • 在這種情況下,角度僅適用於輸入圖像的寬度,最終圖像的寬度超過 180 度,因為我沒有使用扭曲的「加號」版本。因此,雖然扭曲的寬度在寬度方向上縮小,但輸出圖像不會縮小。
  • 添加了最終邊框並應用了動畫設置。


多點和自由形式扭曲

Shepard 的扭曲(太妃糖狀扭曲)

Shepard 演算法(於 IM v6.4.2-4 版本加入)使用給定控制點的移動,根據「局部」效應來扭曲影像。您可以將其想像成一塊代表原始影像的厚「太妃糖」,將大頭針釘入其中,然後移動大頭針。更技術性地說,它是根據 反平方距離插值法 移動點。如果只使用一個控制點,則自然會移動(平移)整個影像,就像對一個點進行「仿射」扭曲一樣。這沒什麼意思。因此,讓我們嘗試移動兩個控制點。例如,讓我們通過拉動無尾熊的耳朵(在「30,11」和「48,29」處)來「折磨」牠…

  magick koala.gif -virtual-pixel Black \
          -distort Shepards '30,11 20,11  48,29 58,29' \
          koala_ear_pull.png
[IM Output] ==> [IM Output]
如您所見,由於控制點的移動,兩個控制點之間的影像部分被拉伸了。然而,影像的所有其他部分幾乎都完好無損,包括靠近控制點本身的影像、影像底部等等。位於控制點之間中間的區域被拉伸,以確保控制點位於您要求的位置。可能不太明顯的是,控制點遠端的區域也被壓縮了,因此隨著您離得越遠,控制點對結果的影響就越小。也就是說,這種扭曲會產生「局部」扭曲。
讓我們放大檢視(使用 扭曲視口),以便我們可以更清楚地看到這一點…

  magick koala.gif -virtual-pixel Black \
          -set option:distort:viewport 115x115-20-20 \
          -distort Shepards '30,11 15,11  48,29 58,29' \
          +repage koala_ear_pull_2.png
[IM Output]
如您所見,影像的形狀也被扭曲,以適應無尾熊被拉伸的「頭部」。
為了避免這種情況,更常見的做法是將影像的角落以及可能的一些邊緣也「固定」,以便它們不會移動。

  magick koala.gif -virtual-pixel Black \
          -set option:distort:viewport 115x115-20-20 \
          -distort Shepards '30,11 15,11  48,29 58,29
              0,0 0,0  0,74 0,74   74,0 74,0  74,74 74,74' \
          +repage koala_ear_pull_3.png
[IM Output]
即使只是移動一個點,同時固定其他點(在本例中僅固定角落),也可能很有用。例如,讓我們將無尾熊的鼻子(位於「28,24」)移動到影像中間。

  magick koala.gif -virtual-pixel Black \
          -distort Shepards '28,24 37,37
              0,0 0,0  0,74 0,74   74,0 74,0  74,74 74,74' \
          +repage koala_move_nose.png
[IM Output]
這個具體示例很特別,因為它是 Fred Weinhaus 用於其單點「動畫變形」腳本「shapemorph」的扭曲。然而,他最初的腳本使用的是速度較慢的 自訂 FX 運算符,因為 Shepards 扭曲 尚未添加到 IM 中。實際上,這個腳本正是 Shepards 扭曲 的靈感來源。

移動影像區域

您甚至可以通過將一組點圍繞該區域一起移動來移動影像的整個部分。例如,讓我們使用頭部周圍的點(紅線)將無尾熊的頭部側向移動,但同時也要固定我們不想移動的影像部分(綠線)。

  magick koala.gif -virtual-pixel Black -distort Shepards \
            '19,8, 29,8   19,27 29,27   26,34 36,34
                 33,37 43,37   36,37 46,37   53,37 63,37   58,25 68,25
             13,20 13,20  17,28 17,28  25,36 25,36
                 35,39 35,39   46,40 46,40   50,43 50,43 ' \
          +repage koala_head_move.png
[IM Output] ==> [IM Output]
請注意,雖然頭部已經移動,但邊緣卻嚴重扭曲。原因是扭曲不會移動區域,而是移動點。如果這些邊緣標記點之間距離太遠,則圖像就會像太妃糖或果凍一樣在這些點之間滴落、滲漏或彎曲。(題外話:實際術語是拉伸“橡膠板”或“氣球”)。此外,如果兩個控制點彼此靠近,但移動方向或移動量不同,則圖像可能會圍繞它們局部旋轉和彎曲。控制點最終仍會位於正確的位置,但周圍的所有其他內容都會嚴重扭曲,以實現該目標。這就是頭部邊緣發生的情況。那麼邊緣標記點應該相距多近?基本上至少是與任何其他移動方向不同的點之間距離的一半。因此,您可以添加更多邊緣點,或者在固定點和移動點之間增加一些額外距離。通過這樣做,您可以更好地定義圖像可以拉伸和壓縮的空間。另請注意,整個圖像通常也會隨著頭部向左移動。只有固定或移動到特定目的地的控制點才能保證放置正確。距離任何控制點較遠的圖像任何部分也將根據所有控制點移動的粗略平均值進行移動。因此,最好在整個圖像中分佈更多“固定”點,甚至在圖像外部一定距離處設置一些負移動點,以抵消一般的平均移動。您還可以複製或加倍控制點(將它們列出兩次),以賦予特定點對該區域變形的更大影響力或“權重”。這是“頭部側移”的另一個版本,但是這次我在移動(紅色)和固定(綠色)點之間增加了一些額外間距。我還添加了更多固定點,以減少扭曲圖像的平均總體移動。

  magick koala.gif -virtual-pixel Black -distort Shepards \
            '15,15, 25,15   19,27 29,27   26,34 36,34
                33,37 43,37   36,37 46,37    53,37 63,37
             10,2 10,2   2,10 2,10   4,55 4,55   14,47 14,47
                25,47 25,47 45,51 45,51   55,45 55,45
                5,70 5,70  15,60 15,60   55,60 55,60   70,70 70,70' \
          +repage koala_head_move_2.png
[IM Output] ==> [IM Output]
上面最後要做的就是簡單地設置一個更好的“-virtual-pixel”設置,以設定上面未定義的黑色區域應該是什麼顏色。

Shepards 和圖像旋轉

這種扭曲的一個方面是它不喜歡任何形式的旋轉!例如,以下是透視雙線性正向以及Shepards 扭曲的重複。


magick mandrill_grid.jpg -alpha set -virtual-pixel black \ -distort Perspective \ '0,0 26,0 128,0 114,23 128,128 128,100 0,128 0,123' \ mandrill_pers.jpg
magick mandrill_grid.jpg -alpha set -virtual-pixel black -interpolate Spline \ -distort BilinearForward \ '0,0 26,0 128,0 114,23 128,128 128,100 0,128 0,123' \ mandrill_blin.jpg magick mandrill_grid.jpg -alpha set -virtual-pixel black -interpolate Spline \ -distort Shepards \ '0,0 26,0 128,0 114,23 128,128 128,100 0,128 0,123' \ mandrill_shep.jpg
[IM Output]
原始影像
==> [IM Output]
透視
[IM Output]
雙線性
[IM Output]
Shepards
請注意,與其他兩種扭曲方法相比,Shepards 扭曲如何產生非常彎曲的圖像。這是因為它試圖在靠近給定控制點的區域中精確保留圖像。這包括圖像的旋轉。由於這種“保留”,網格是彎曲的,因此它在實際控制點處保持“正交”。這有點像控制點上的那些“圖釘”實際上不是圓形圖釘,而是“十字”,迫使“果凍”或“橡膠板”固定圖像也保留圖像的旋轉。這也是這種扭曲可以產生的許多“旋轉”效果的根源。例如,如果我們將圖像中的兩個點取走並將它們相互推動。圖像會旋轉,而不是旋轉。例如,讓我們嘗試將無尾熊的耳朵相互推向而不是分開。

  magick koala.gif -virtual-pixel Black \
          -distort Shepards '30,11 40,11  48,29 38,29' \
          koala_ear_push.png
[IM Output] ==> [IM Output]

Shepard 的冪因子

一般來說,Shepard 反距離加權法 (IWD) 的距離權重遵循平方反比定律 (1/r2),但從 IM v6.8.0-10 開始,您現在可以使用進階的 defineshepards:power」來控制整體權重的「強度」。如果未定義,則其值為 2.0,但透過將其定義為較小的值,您可以針對扭曲影像的整體平均位移,圍繞移動的控制點產生更局部的扭曲。使用較大的值將在控制點周圍產生更大的影響區域。例如,以下重複「拉無尾熊耳朵」的範例,並對扭曲權重套用不同的強度。

  magick koala.gif -virtual-pixel Black -define shepards:power=0.5 \
          -distort Shepards '30,11 20,11  48,29 58,29' \
          koala_ear_pull_pow0.5.png
  magick koala.gif -virtual-pixel Black -define shepards:power=1.0 \
          -distort Shepards '30,11 20,11  48,29 58,29' \
          koala_ear_pull_pow1.png

magick koala.gif -virtual-pixel Black \ -distort Shepards '30,11 20,11 48,29 58,29' \ koala_ear_pull.png magick koala.gif -virtual-pixel Black -define shepards:power=3.0 \ -distort Shepards '30,11 20,11 48,29 58,29' \ koala_ear_pull_pow3.png magick koala.gif -virtual-pixel Black -define shepards:power=8.0 \ -distort Shepards '30,11 20,11 48,29 58,29' \ koala_ear_pull_pow8.png
[IM Output]
原始影像
& action
==> [IM Output]
強度 0.5
[IM Output]
強度 1.0
[IM Output]
強度 2.0
(預設值)
[IM Output]
強度 3.0
[IM Output]
強度 8.0
以上所有影像結果都使用完全相同的控制點移動設定。唯一的差別是這些控制點周圍的影響區域。較小的強度會「將移動局部化到僅限於靠近控制點的區域」,而較大的強度會將更多影像圍繞控制點一起拖曳。在非常大的強度下,這種拉力會傾向於沿著控制點之間的中間線將影像「撕裂」成不同的區域。您甚至可以使用更大的強度,這只會將來源控制點周圍的區域轉換為目標控制點周圍的區域。這些區域將形成「沃羅諾伊區域」的圖案,並且可以包含來源影像的重複副本。例如,在這裡,我將無尾熊鼻子周圍的區域(坐標 28,24)映射到六邊形圖案中的 7 個不同區域,以非常有效的方式產生「昆蟲眼」般的效果。

  magick koala.gif -virtual-pixel Black -define shepards:power=25 \
          -distort Shepards '28,24 35,35 \
                      28,24 20,10   28,24 50,10 \
                      28,24 20,60   28,24 50,60 \
                      28,24 10,35   28,24 60,35'  koala_hexagonal.png
[IM Output]
請記住,Shepards Distortion 實際上等同於使用與 Shepards, Sparse Color Operator 相同的技術生成的位移映射圖(將目標像素映射到來源影像),這也受到相同的強度因子定義的影響。

Shepard's Distortion 總結

Shepards Distortion 是一種非常通用且自由的形式方法,將其扭曲限制在由給定點的移動或非移動標記的區域。其扭曲會根據相鄰控制點之間的距離進行局部化和限制,儘管所有點仍然具有平均的整體影響。只要記住,這種扭曲是由點驅動的,而不是由線條或區域驅動的,因此當移動方式不同的控制點放置得太靠近時,點之間的部分可能會意外地凸出或旋轉。它會在控制點之間旋轉、拉伸和壓縮影像,但它會盡力避免旋轉或縮放控制點附近的影像。最後,它可能會在遠離任何控制點的地方產生影像的整體平均平移。但是,如果可以移動控制點塊並保留其一般的相對位置,它確實提供了一種實現通用且非常簡單的點驅動「影像變形」技術的方法。Fred Weinhaus 的腳本「shapemorph2」使用 Shepards Distortion 來提供一個通用的「動畫影像變形」程式。
在內部,此扭曲等效於使用 Shepards Sparse Color 漸層產生器來建立兩個 相對位移映射圖 來扭曲影像。這也是 Fred Weinhaus 最初的「shapemorph」腳本的作用,並且是扭曲技術的來源。
由於使用 Shepards Distortion 時所需的計算複雜性,因此 IM 不會使用運算子的加號「+distort」形式來提供任何形式的「最佳擬合」目標視口。但是,您仍然可以使用 扭曲視口 選項來定義更大的輸出影像。
基於相同理由,區域重新取樣 被關閉。因此,極度壓縮的區域(超過 2 倍)可能會出現一些鋸齒效應。例如,請參閱最後一個範例中六邊形圖案的邊緣。但是,可以使用 超級採樣 來改善結果的最終影像品質,並減少此類鋸齒效應。