ImageMagick 範例 --
影像映射效果

索引
ImageMagick 範例 前言和索引
影像映射簡介
使用影像映射扭曲影像
絕對扭曲查找表
相對位移查找表
可變模糊映射
使用某種輔助「映射」影像來扭曲或修改影像,該影像控制著處理過程。無論是替換顏色、可變地模糊影像,還是透過絕對或相對地指定來源坐標來扭曲影像。

簡介

正如您在前面關於合成簡單扭曲扭曲的章節中所見,您可以透過許多不同的方式修改影像。然而,它們都受限於 ImageMagick 內建的特定方法。您甚至可以使用「FX」DIY 運算子「自訂」影像扭曲,或使用評估函數等運算子直接修改影像的值,甚至可以使用各種色階運算子。然而,扭曲需要大量的計算(和時間)才能完成任務,如果您打算對多個影像執行相同的任務,讓 IM 重複所有這些計算可能會非常浪費時間。另一個方面是,很難以自由形式的方式限制扭曲的效果。您無法簡單地編輯或修改您想要應用的扭曲。您的控制權有限。影像映射則不同。您可以使用額外的「映射」影像來控制要修改影像的哪些部分,以及修改的程度或方式。它不需要修改整個影像,也不必以某些預先定義或預先程式化的方式修改影像。您可以建立一個「映射」,以任何可能的方式修改影像,而沒有限制。您也可以編輯或進一步修改映射,以調整或限制其效果,使其更複雜,方法是將不同的映射合併在一起,或僅平滑或模糊效果。最後,您可以儲存映射,以便稍後再次使用。結果由「映射」影像控制。由於修改是由「映射」控制的,因此 ImageMagick 通常只需要執行很少的計算,因此「影像映射」通常非常快。它也是可重複的,因為您可以將同一個非常複雜的映射應用於任何數量的影像,以獲得完全相同的修改。也就是說,您可以非常快速地將其應用於整個影像目錄。簡而言之,影像映射的作用是將特定效果的緩慢而複雜的數學運算從特定影像轉移到更通用的「映射」影像。一旦產生了該「映射」,就可以非常快速地將其應用於許多實際影像。

什麼是影像映射

映射圖像基本上是「查找表」或 LUT,它們定義了如何將特定效果應用於逐個像素的圖像。也就是說,是否應用效果以及應用程度完全由圖像映射控制。本質上,圖像是一個值數組,這些值的含義取決於正在應用的映射過程。它們可以指示...
  • 直接替換值(顏色查找),
  • 顏色應該來自哪個圖像(圖像遮罩),
  • 像素應該變亮或變暗多少(高光),
  • 指定源坐標(扭曲),
  • 或相對於當前位置的位置(位移)。
  • 在這個位置模糊像素的程度
其中許多我們已經在《圖像合成》中看過,從某種意義上說,圖像映射只是將多個圖像合併在一起的另一種方式。事實上,許多圖像映射技術僅僅是作為專門的合成方法來實現的!請記住,真正的圖像合成實際上只是以各種方式疊加兩個真實彩色圖像(特別是 Duff-Porter Alpha 合成方法)。更籠統地說,圖像映射涉及使用以特殊方式修改一個圖像的專用圖像。圖像映射最困難的部分是為特定效果生成特定的“映射”。這就是本頁上介紹的許多工作、努力和技術的重點。但是,一旦你有了地圖,你就可以在許多不同的圖像上多次使用它,速度非常快。

使用圖像映射扭曲圖像

雖然 IM 示例的前幾節中描述了各種扭曲運算符(例如 簡單圖像扭曲一般圖像扭曲),但您僅限於使用 IM 圖形庫中已編程的各種扭曲類型,這些扭曲類型通常使用特定的數學方程式和公式。但是,有時您希望以更自由和更少數學的方式設計自己的失真。例如,要生成更複雜的扭曲,例如將圖像映射到特定形狀,或使用特定的複雜鏡頭效果,這比用數學方式定義更容易繪製。有時您只想能夠在大量圖像上重複您的扭曲,並避免一遍又一遍地重新計算扭曲。解決方案是預先計算您的扭曲,並將其保存為灰度圖像形式的特殊查找表 (LUT)。也就是說,對於每個輸出像素,我們查找 LUT,然後使用該值從源圖像中查找顏色。也就是說,需要三個步驟。
  1. 在 LUT 中查找每個目標像素
  2. 將 LUT 值映射到源圖像位置(兩種方法)
  3. 從源圖像中查找顏色
由於圖像用於扭曲的“查找表”,因此您可以使用圖像編輯器(例如“Gimp”或“PhotoShop”)創建或修改扭曲貼圖,讓您可以自由地進行一些非常花哨和複雜的扭曲。但是,您必須記住,就像我們見過的所有其他扭曲方法一樣,查找是作為 反向像素映射 應用的。也就是說,對於目標圖像中的每個像素,我們使用正在應用的扭曲方法從源圖像中查找像素的顏色。在這種情況下,該方法是從提供的查找表圖像中查找源坐標。
現在,有兩種方法可以使用影像映射來決定在來源影像中的哪個位置查找顏色...絕對相對。使用絕對座標查找時,變形映射會將 LUT 顏色值直接轉換為來源影像中的座標,以便查找要使用的顏色。LUT 中的顏色位置並不重要,因為每種顏色都表示要使用的精確查找點。變形 LUT 影像將具有顏色漸層,但是當應用映射時,該漸層的任何扭曲或變形都會產生相同的效果。使用相對座標查找時,位移映射會使用顏色值來偏移當前座標,以找出來源影像中要查找顏色的位置。這表示會使用純灰色 LUT 影像,其中較亮和較暗的區域定義了像素如何被映射偏移或位移,而與它們在映射中的位置無關。正如您將看到的,這兩種方法都有其優缺點。

絕對變形查找映射

建立絕對變形 LUT 映射是兩種方法中更容易理解、建立變形 LUT 映射以及應用的方法。但是,正如您將看到的,它有一個非常嚴重的缺點,使其不如相對位移映射實用。'變形映射' 中任何特定點的顏色都直接指向來源影像中的位置。也就是說,'映射' 上的灰階漸層定義了要放置在該位置的'紋理'。現在考慮到映射影像實際上是一個複雜物件(例如 T 恤)的影像,具有複雜的摺痕和波紋。如果那件襯衫上有漸層,則可以將任何平面影像映射到該襯衫上。也就是說,絕對變形映射的強大之處。LUT 影像中的任何'黑色'像素(顏色值 0)都將被視為最左邊的像素或來源影像的'0' X 座標,而 LUT 中的任何'白色'(值 1)都被視為最右邊的像素(來源影像的寬度)。請注意,此 LUT 將僅查找來源影像中顏色的 X 或水平位置。它不會更改顏色的高度或 Y 位置。因此,讓我們嘗試使用簡單的純粹灰階水平漸層作為 LUT。

  magick koala.gif \( -size 75x75 gradient: -rotate 90 \) \
          -fx 'p{v*w,j}'      distort_noop.gif
[IM Output]  + [IM Output] ==> [IM Output]
請注意,這並未對將來源影像映射到目標影像進行任何實際更改。也就是說,因為我們從變形映射中查找的 X 座標與我們查找顏色時的位置相同。只需翻轉漸層,像素的查找也會翻轉,從而建立鏡像。也就是說,白色在左側,'黑色'在右側,並且圖像上有水平漸層。

    magick koala.gif \( -size 75x75 gradient: -rotate -90 \) \
          -fx 'p{v*w,j}'      distort_mirror_x.gif
[IM Output]  + [IM Output] ==> [IM Output]
如果我們採用原始漸層並使用對比增強運算符對其進行壓縮,則可以獲得更有用的變形。

  magick -size 75x75 gradient: -rotate 90 \
          -sigmoidal-contrast 8,50%      map_compress.gif
  magick koala.gif  map_compress.gif -fx 'p{v*w,j}'  distort_compress.gif
[IM Output]  + [IM Output] ==> [IM Output]
請注意,變形的側面被拉伸,而中心被壓縮。我們可以通過使用 2 個變形映射將其擴展到兩個維度,一個用於調整 X 座標,另一個用於調整 Y 座標。

  magick map_compress.gif -rotate 90 map_compress_y.gif
  magick koala.gif  map_compress.gif map_compress_y.gif \
          -fx 'p{u[1]*w,u[2]*h}'   distort_compress_2D.gif
[IM Output]  + [IM Output] [IM Output] ==> [IM Output]
如您所見,以上操作重新創建了內爆方法的變體,但僅通過沿 X 軸和 Y 軸(同時)壓縮影像,而不是像內爆運算符那樣徑向壓縮影像。這裡的關鍵是,無論您對絕對變形映射做什麼,您都會對正在應用它的任何影像的最終影像做同樣的事情。也就是說,變形映射的強大之處。

複合'變形'方法

到目前為止,我們一直使用FX,通用 DIY 運算子來應用絕對變形映射。這提供了一種方法來精確地調整和修改您正在做的事情,但速度非常慢。合成運算子Distort」編碼了一個與我們上面一直使用的公式非常相似的公式。雖然它的實現方式使其與我們稍後將在相對位移映射中看到的「Displace」合成運算子更加相容。

那麼讓我們使用「Distort」合成重複最後一個「向內爆炸」的例子。


  magick koala.gif  map_compress.gif map_compress_y.gif \
          -compose Distort  -define compose:args=37.5x37.5 -composite \
          distort_compose.gif
[IM Output]  + [IM Output] [IM Output] ==> [IM Output]
請注意上面使用了定義設置compose:args」。這個值是針對所使用的 LUT 漸變(以完美的灰色為中心)的乘數。在這裡使用的值「37.5」是圖像寬度和高度的一半(75 像素)。您可以更改該乘數以擴展或收縮變形的整體比例。如果未定義「compose:args」值,它將默認為正確的值。如果該值設置為零,則在該方向上不會應用變形。如果您想自動設置合成參數,則可以使用以下等效的設置「選項:」方法來計算它...

  magick koala.gif  map_compress.gif map_compress_y.gif \
          -set option:compose:args '%[fx:w/2]x%[fx:h/2]' \
          -compose Distort  -composite \
          distort_compose_set.gif
[IM Output]
或者取消定義它,以便讓 IM 計算正確的值(對於 2D 變形)...

  magick koala.gif  map_compress.gif map_compress_y.gif \
          -compose Distort -define compose:args='' -composite \
          distort_compose_default.gif
[IM Output]

無操作變形映射

在我們繼續之前,我想先退後一步,再看一下上面的「無操作」示例。這實際上會稍微模糊圖像,因為我概述的公式實際上並不完全正確。獲取原始圖像的「無操作」副本是測試您的變形數學是否正確的一個很好的方法。

也就是說,當給定完美的漸變時,您可以將源圖像中的每個像素映射到目標圖像。也就是說,LUT「白色」(或 1.0)值將精確映射到目標圖像中最右側(或最底部)的像素。

為了測試無操作變形,我們使用「像素檢查圖像」(例如:「pattern:gray50」),因為它會顯示任何變形,從而顯示所用數學中的任何問題。那麼讓我們嘗試將無操作變形應用於我們目前使用的方法...

  magick -size 75x75 pattern:gray50 \
          \( gradient: -rotate 90 \) \( gradient: -flip \) \
          -fx 'p{u[1]*w,u[2]*h}'    distort_fx_check.gif
[IM Output]

  magick -size 75x75 pattern:gray50 \
          \( gradient: -rotate 90 \) \( gradient: -flip \) \
          -set option:compose:args '%[fx:w/2] x %[fx:h/2]' \
          -compose Distort  -composite  distort_compose_check.gif
[IM Output]
如您所見,這兩種方法都無法重現「像素檢查」圖像。儘管由於坐標的計算方式不同,它們的表現方式略有不同。發生的事情是,從顏色查找到着色坐標的縮放因子偏離了 1 個像素。有關發生這種情況的原因的詳細信息,請參閱變形,圖像坐標與像素坐標
FX 變形以右上角(像素位置 0,0)為中心,並沿底部和右邊緣生成重複的虛擬像素。這是因為它沒有嘗試改變縮放的中心,從查找顏色到着色坐標用於實際查找。因此,即使縮放錯誤,黑色像素仍然以像素 0,0 為中心。

合成「Distort」運算子在應用縮放之前會平移坐標,因此零位於圖像的中心。它將此作為「位移映射」縮放的一部分(請參閱後文)。因此,不准確的縮放會沿每個邊緣向內拉動圖像邊緣 1/2 個像素,同時保持圖像中心正確。
以下是絕對變形映射的校正後「完美無操作」版本,它在計算顏色和坐標之間的縮放因子時,本質上使用了圖像坐標(寬度和高度減少了 1)。

  magick -size 75x75 pattern:gray50 \
          \( gradient: -rotate 90 \) \( gradient: -flip \) \
          -fx 'p{u[1]*(w-1),u[2]*(h-1)}'    distort_fx_check_correct.gif
[IM Output]

  magick -size 75x75 pattern:gray50 \
          \( gradient: -rotate 90 \) \( gradient: -flip \) \
          -set option:compose:args '%[fx:(w-1)/2] x %[fx:(h-1)/2]' \
          -compose Distort  -composite  distort_compose_check_correct.gif
[IM Output]
實際上,「compose:args」的默認值(如果未定義)使用的是正確的縮放值。

  magick -size 75x75 pattern:gray50 \
          \( gradient: -rotate 90 \) \( gradient: -flip \) \
          -compose Distort -define compose:args='' -composite \
          distort_compose_default_check.gif
[IM Output]
但是應該指出,這些輕微的不準確性在使用變形時通常並不重要,因此通常會忽略任何細微的差異。只要記住這一點,以便在真正重要的時候知道它。

扭曲映射的問題

讓我們繼續對圖像進行扭曲,嘗試旋轉它。生成旋轉後的映射可能有點棘手,但還是可以做到的...

  magick -size 75x75 gradient: -background black -rotate 45 \
          -gravity center -crop 75x75+0+0 +repage  map_rot45_x.png
  magick map_rot45_x.png  -rotate 90              map_rot45_y.png
  magick koala.gif  map_rot45_x.png   map_rot45_y.png \
          -compose Distort  -composite    distort_rot45.gif
[IM Output]  + [IM Output]  + [IM Output] ==> [IM Output]
現在我們有了另一種旋轉任何圖像的方法。這個技巧最大的問題是,通過使用旋轉創建扭曲映射,我們在對角線邊緣的兩側引入了一些顏色奇怪的像素。在上一個例子中,這導致在圖像右下角沿著一條線添加了一些隨機像素。這些“隨機”顏色是旋轉引入的反鋸齒值,用於生成“更好”的圖像。然而,對於扭曲映射來說,反鋸齒邊緣像素會導致真正的問題。現在我們可以嘗試更好地定義旋轉後的 LUT 圖像邊緣的顏色。在這種情況下,我們可以生成一個更大的漸變圖像,然後將旋轉裁剪到正確的大小。

  magick -size 100x20 xc:white xc:black -size 115x75 gradient: \
          +swap -append   -rotate 45 \
          -gravity center -crop 75x75+0+0 +repage   map_rot45b_x.png
  magick map_rot45b_x.png  -rotate 90              map_rot45b_y.png
  magick koala.gif  map_rot45b_x.png   map_rot45b_y.png \
          -compose Distort  -composite     distort_rot45_better.png
[IM Output]  + [IM Output]  + [IM Output] ==> [IM Output]
通過這種方式,LUT 中的所有像素現在都得到了正確的定義,沒有任何鋸齒。這現在顯示了一個稍微不同的問題。最終圖像中的所有像素都得到了正確的定義,但有些像素不應該成為最終圖像的一部分。它們在結果圖像中沒有任何實際意義。這表示使用 LUT 指定從源圖像獲取絕對坐標的最大問題。您無法指定 IM 在這些未定義區域應該做什麼。

使用遮罩設定未定義像素

解決“未定義像素”問題的更通用的方法是定義一個映射,說明哪些像素實際上是扭曲中有效的定義結果。換句話說,就是一個遮罩圖像。例如...

  magick -size 75x75 xc:white -background black -rotate 45 \
          -gravity center -crop 75x75+0+0 +repage  map_rot45b_m.png
  magick distort_rot45_better.png map_rot45b_m.png \
          -alpha off -compose CopyOpacity -composite   distort_rot45_masked.png
[IM Output]  + [IM Output] ==> [IM Output]
現在我們有三個圖像與扭曲映射相關聯,結果確實變得複雜了。當然,在典型的情況下,您可能不需要做到這一點,但對於一般情況,您需要這樣做。

統一扭曲影像

然而,您可能已經注意到,所有三個映射都是灰度圖像。這意味著將所有映射合併到單個扭曲映射圖像中是相當合理的。例如,讓我們將“X 扭曲映射”映射到“紅色”通道,“Y 映射”映射到“綠色”,遮罩映射到“alpha”或透明度通道,這樣更容易處理。

  magick map_rot45b_x.png map_rot45b_y.png \( map_rot45b_m.png -negate \) \
          -alpha off -channel RGA -background black -combine  map_rot45u.png
[IM Output] [IM Output] [IM Output] ==> [IM Output]
組合通道圖像中的“藍色”通道未定義,因此採用當前“-background”顏色的值,我在上面將其預設為“黑色”或值為零。
現在讓我們將這個統一的扭曲映射應用於我們的考拉圖像。遺憾的是,這需要兩個圖像處理步驟,一個是扭曲圖像,另一個是遮罩結果。

  magick koala.gif -alpha set   map_rot45u.png \
          \( -clone 0,1  -fx 'p{v.r*w,v.g*h}' \
             +clone -compose Dst_In -composite \) -delete 0,1 \
          distort_rot45_unified.png
[IM Output] [IM Output] ==> [IM Output]
您也可以直接使用統一的扭曲映射圖像使用“扭曲”合成方法...

  magick koala.gif -alpha set   map_rot45u.png \
          -compose Distort -define compose:args='' -composite \
          distort_rot45_compose.gif
[IM Output]
在“統一扭曲映射”圖像中仍然有一個未使用的通道(藍色)。它的一個合理用途是用作向扭曲圖像添加高光和陰影的方法。(請參閱疊加高光)。您可以在下面的球面扭曲映射示例中看到這種技術的進一步應用。

沙漏扭曲映射

現在我想要一個一維扭曲映射,它根據每一行的行高不同地縮放圖像的每一行。有點像製作一個真正的嘉年華哈哈鏡扭曲,讓胖子看起來很瘦。換句話說,就是一種沙漏扭曲。這是一個相當複雜的 LUT 圖像,經過一番摸索,我想出了以下表達式來生成高度變量,但水平線性漸變映射。

  magick -size 100x100 xc:  -channel G \
          -fx 'sc=.15; (i/w-.5)/(1+sc*cos(j*pi*2/h)-sc)+.5' \
          -separate  map_hourglass.png
[IM Output]
生成灰度漸變時,您可以使 -fx 運算符的速度提高 3 倍,只需要求它僅生成一個顏色通道,例如上面示例中的“G”或綠色通道。然後可以分離此通道以形成所需的灰度圖像。這可以表示速度的大幅提升,尤其是在使用非常複雜的“-fx”公式時。
sc」是沙漏的縮放因子(值範圍從 0 到 0.5),允許您調整扭曲的幅度。現在讓我們將此映射應用於內建的「rose:」圖像。請注意,100x100 像素的映射與 70x46 像素的圖像不符。這讓事情變得複雜,因為我們需要將來源圖像中的當前像素縮放適當的量,以匹配我們給定的扭曲映射,以便查找該像素顏色的位置。

  magick rose:  map_hourglass.png \
          -fx 'p{ v.p{i*v.w/w,j*v.h/h}*w,  j}'  distort_hourglass.png
[IM Output]
如果您仔細觀察,像素 X 坐標「i」乘以扭曲映射圖像的寬度「v.w」,再除以原始圖像的寬度「w」,得到「i*v.w/w」。像素 Y 坐標也會發生同樣的事情,「j*v.h/h」。這會重新縮放目標圖像中的像素坐標,以匹配扭曲 LUT 圖像。然後,將查找的坐標乘以 LUT 值與來源圖像寬度,以成為顏色查找的 X 坐標。如果您同時具有 X 和 Y 扭曲映射,則必須對 Y 映射重複縮放查找。當然,我們遇到了之前看到的相同「邊緣」扭曲,因此讓我們將虛擬像素設定更改為透明。

  magick rose: -alpha set  -virtual-pixel transparent -channel RGBA \
          map_hourglass.png  -fx 'p{ v.p{i*v.w/w,j*v.h/h}.g*w, j}' \
          distort_hourglass2.png
[IM Output]
請注意使用「-channel」設定,以確保「-fx」將與來源圖像一起使用並返回 Alpha 色板(透明)值。特別是透明虛擬像素。另請注意,在查找扭曲映射時,我們僅從綠色通道查找(使用「v.p{}.g」)。如果未完成此操作,則將使用與來源圖像中正在處理的通道相同的通道,並且對於映射,「Alpha」未定義。通過使用非線性漸層,可以使此扭曲映射變得更好,因此圖像保持矩形,邊緣的扭曲比中間更多,使其具有更「圓形」或「圓柱形」的外觀。 *有人想試試看嗎?寫信給我*

球形扭曲映射

在之前的沙漏扭曲映射範例中,我產生了一個水平縮放為餘弦曲線的漸層。只需多加一點功夫,您就可以產生一個球形...

  magick -size 100x100 xc:  -channel R \
          -fx 'yy=(j+.5)/h-.5; (i/w-.5)/(sqrt(1-4*yy^2))+.5' \
          -separate  +channel     sphere_lut.png
[IM Output]
但是請注意,以上內容並非完全準確。壓縮漸層仍然是線性漸層,只是壓縮以適應圓形。更準確的表示可能需要建立非線性漸層。在絕對位置方面,這將是「arccos()」函數。現在,此映射還具有一些將被歸類為無效的大區域,因此需要某種類型的遮罩來定義最終圖像中的哪些像素有效和無效。在這種情況下,一個簡單的圓圈就足夠了。

  magick -size 100x100 xc:black -fill white \
          -draw 'circle 49.5,49.5 49.5,0'    sphere_mask.png
[IM Output]
為了完成,我們還需要一個陰影高光,例如在疊加高光中開發的,供疊加強光合成使用...

  magick sphere_mask.png \
          \( +clone -blur 0x20 -shade 110x21.7 -contrast-stretch 0% \
             +sigmoidal-contrast 6x50% -fill grey50 -colorize 10%  \) \
          -composite sphere_overlay.png
[IM Output]
請記住,上述陰影僅在球體對象的邊界內才有意義,因此陰影溢出這些邊界並不重要。實際上,如果您想嘗試想出一個更好的球形陰影,產生一個更好的球形圖像,我很樂意看到它。因此,讓我們將所有三種圖像(X 坐標 LUT、疊加陰影和透明遮罩)應用於實際尺寸的圖像(為簡單起見)。

  magick lena_orig.png -resize 100x100   sphere_lut.png   -fx 'p{ v*w, j }' \
          sphere_overlay.png   -compose HardLight  -composite \
          sphere_mask.png -alpha off -compose CopyOpacity -composite \
          sphere_lena.png
[IM Output] ==> [IM Output]
這個特殊的例子展現了絕對扭曲映射最強大的面向。您可以在任何自由形狀的物件上定義漸層(不一定是數學上的),以便將任何圖像映射到該物件上,無論是曲線、皺紋、褶皺等。簡而言之,一旦您完成了物件映射,就可以將任何圖像映射到其表面上。然後,為了使其看起來更逼真,您可以覆蓋第二個映射,以添加高光、陰影、邊緣和其他特徵。當然,由於所有三張圖像都是灰度的,您可以將它們組合成單個統一扭曲映射圖像,以便於存儲。在這種情況下,我將通過對 Y 坐標也重複使用 X 坐標扭曲 LUT 來使其成為更球形的扭曲。

  magick sphere_lut.png   \( +clone -transpose \) \
          sphere_overlay.png   \( sphere_mask.png -negate \) \
          -channel RGBA  -combine    spherical_unified.png
[IM Output]
這是一個相當漂亮的映射。但如果嘗試解讀它,請記住:『紅色』和『綠色』通道是 X 和 Y 坐標 LUT,『藍色』是高光和陰影效果的疊加,透明度通道則保存最終圖像的無效像素遮罩。因此,讓我們使用「扭曲」合成方法來應用它。

  magick mandrill_grid_sm.jpg   spherical_unified.png  \
          \( -clone 0,1 -alpha set -compose Distort -composite \) \
          \( -clone 1   -channel B -separate +channel \) \
          \( -clone 2,3 -compose HardLight -composite \) \
          \( -clone 4,1 -compose DstIn -composite \) \
          -delete 0--2  spherical_mandrill.png
[IM Output] ==> [IM Output]
按順序...
  • 我們應用扭曲映射(包括遮罩)
  • 從統一圖像映射中提取陰影映射
  • 將陰影映射應用於扭曲的圖像
  • 恢復陰影操作中丟失的遮罩
  • 刪除除最終圖像以外的所有內容並保存
這種複雜性純粹是由於需要提取陰影遮罩,並恢復陰影移除的 Alpha 遮罩所致。

圓弧扭曲映射

為了展示使用位置扭曲映射真正可以實現的效果,這裡有一個絕對扭曲 LUT,類似於上面「弧形」扭曲方法提供的 LUT。基本上,我們不是計算每個要扭曲的圖像中每個像素的坐標映射,而是將這些計算出的坐標保存到兩個 X 和 Y 坐標灰度 LUT 映射中。也就是說,我們將整個扭曲預先計算到一個更簡單的查找表圖像中,允許它一遍又一遍地應用,而不需要進一步的平方根或三角函數。

  magick -pointsize 30 -font Candice label:Anthony -trim +repage \
          -gravity center -resize 95x95 -crop 100x100+0+0\! \
          -flatten text_image.jpg
  magick -size 100x100 xc: -channel G  -fx 'atan(j/(i+.5))*2/pi' \
          -separate   -flip -flop       map_p_angle.png
  magick -size 100x100 xc: -channel G  -fx '1-hypot(i,j)/(w*1.6)' \
          -separate   -transverse       map_p_radius.png
  magick text_image.jpg   map_p_angle.png map_p_radius.png \
              -fx 'p{u[1]*w,u[2]*h}'    distort_p_curved.jpg
[IM Output]
顏色來源
 +
 
[IM Output]
角度 - X 映射
 +
 
[IM Output]
半徑 - Y 映射
==>
 
[IM Output]
彎曲文本
當然,生成該扭曲映射很困難,但是一旦完成一次,使用您喜歡的任何方法(甚至使用像「Gimp」這樣的圖像編輯器以藝術方式進行),您就可以在大量圖像上重複使用它。

極座標扭曲映射

有時,您可能需要由扭曲映射(而不是源圖像)定義目標圖像,以便使事情正常工作。例如,如果我們想將一些文本映射到一個圓圈中(也稱為極坐標變換),您實際上需要能夠使用長度約為高度 3 到 4 倍的圖像(高縱橫比),否則結果將不會很清晰。為此,我們將扭曲映射圖像放置在顏色源圖像之前,以便使用第一個(X 映射)圖像來設置最終結果的大小,而不是輸入源圖像。

  magick -size 100x100 xc:  -channel G \
          -fx 'atan2(i-w/2,h/2-j)/pi/2 + .5' \
          -separate  map_p_angular.png
  magick -size 100x100 xc:  -channel G \
          -fx 'rr=hypot(i-w/2,j-h/2); (.5-rr/70)*1.2+.5' \
          -separate  map_p_radial.png
  magick -font Candice -gravity center -size 200x50 \
                                label:'Around  the  World'    text.jpg
  magick map_p_angular.png map_p_radial.png text.jpg \
                 -fx 'u[2].p{ u*u[2].w, v*u[2].h }' distort_p_circle.jpg
[IM Output]
角度 - X 映射
 +
 
[IM Output]
徑向 - Y 映射
 +
 
[IM Output]
顏色來源
==>
 
[IM Output]
環形文本
本質上,顏色源圖像現在可以是任何大小或縱橫比,並且事情都將得到正確處理,但是您可能需要調整扭曲映射的生成以正確處理源圖像的縱橫比。在生成上述映射時,值『70』控制圓圈的最終大小,中線沿著該圓圈放置。另一方面,『1.2』值控制圖像到圓圈的垂直縮放,允許您調整扭曲文本的高度。
請記住,這個「-fx」表達式需要先給出失真映射圖,然後將顏色來源作為第三個(索引 2)圖像給出。但是,這也意味著存儲在來源圖像中的任何元數據也將丟失。
這個失真映射圖的問題是,在「X 映射圖」中有一個非常尖銳的顏色斷層(由數學中的漸近線引起)。當您進行任何顏色查找或調整映射圖大小以生成更大的圖像時,這條線必須保持清晰。也就是說,您需要確保對該映射圖的任何調整大小或插值查找都不會沿該漸近線產生灰色查找顏色。

如果您確實沿此線生成灰色查找,則最終結果中將獲得一行彩色像素(從圖像中間查找)。

因此,建議您始終以最終圖像所需的尺寸生成此失真映射圖,並且不要使用之前顯示的任何縮放技術。
您也可以將其用於其他效果,例如圓形棋盤格...

  magick map_p_angular.png map_p_radial.png \
          -size 150x90 pattern:checkerboard \
          -fx 'u[2].p{ u*u[2].w, v*u[2].h }'   distort_check_circle.gif
[IM Output]
嘗試將上面提到的 IM 提供的其他一些內建圖案 與上述內容一起使用,以獲得其他有趣的效果。
上面清楚地顯示了使用「-fx」進行圖像變形的限制。在圖像中心附近,徑向線變得鋸齒狀,因為沒有將大面積的像素合併到單個像素中。另一方面,圖像的邊緣,特別是角落,顯示出適當的徑向線模糊。

原因是「-fx」(以及大多數較舊的失真方法)僅對來源圖像中的顏色進行簡單的未縮放插值查找。這意味著隨著圖像縮小,來源圖像像素不會合併在一起以生成目標像素的正確顏色。

這對於放大區域(如角落)來說不是問題,僅對於極度壓縮(中心)來說是問題。因此,一種解決方案是使用超級採樣,但这只会将问题推迟到更高的压缩级别。
失真映射圖(圖像中心到底部)中的相同漸近線(突然變化)也會在上述示例中沿該線產生急劇的顏色變化。將該線與其他徑向線(如從中心到圖像頂部的線)進行比較,這些線由於前面提到的插值查找而在接近圖像邊緣時變得非常模糊。

使用可平鋪圖像(如上所示)生成圓形圖案時,這可能是一個問題,並且可能需要一些特殊處理以避免該圖像部分出現可見差異。

為了避免这种情况,最好将图像的上半部分和下半部分分别扭曲,以避开渐近区域。

行洗牌

在本例中,我們做了一些更不尋常的事情... 隨機打亂圖像的行。首先,我們創建一個映射圖,其中 X 軸(紅色通道)具有漸變,Y 軸(綠色通道)具有隨機雜訊圖像。

  magick rose: \
          \( -size 46x70 gradient: -rotate -90 \) \
          \( -size 1x46 gradient: -spread 23 -scale 70x46\! \) \
          -compose Distort -define compose:args='' -composite \
          rose_row_shuffle.png
[IM Output] ==> [IM Output]
不幸的是,「-spread」似乎在其選擇要交換的像素時包含了虛擬像素,這意味著某些行變成了重複項,而另一些行則完全丟失。換句話說,「洗牌」圖像映射圖不太正確。*您是否有更好的像素洗牌解決方案?*

相對查找位移映射圖

如你所見,建立絕對扭曲地圖相當容易。 然而,當扭曲具有「未定義」區域,或扭曲超出來源影像正常邊界範圍的區域時,它就會出現嚴重的問題。 更嚴重的問題是,你始終在處理定義顏色查找絕對坐標的漸層。 映射影像的任何部分都不簡單、不乾淨,也不容易手動修改或編輯。 在創建和使用過程中,需要特殊的技術和數學方法。 這通常意味著「藝術性」發展的空間非常小。 但是,還有另一種使用查找表的方法,用於指定獲取最終顏色的坐標。 通過使用相對位移地圖。 它不是定義從來源影像查找每個像素顏色的確切坐標的「地圖」,而是定義相對於當前位置的偏移或位移。 現在,偏移量可以是正值或負值,負值需要一些技巧才能編碼成顏色值。 所以他們所做的就是定義「純灰色」作為坐標的 0 位移(無變化)。 然後,他們將「黑色」定義為最大負位移,將「白色」定義為最大正位移。 這可能很難描述,所以讓我們看一個例子。 首先,我們創建一個測試影像來「位移」。

  magick -font Candice -gravity center -size 150x50 \
                                           label:'Anthony'    label.jpg
[IM Output]
現在,我將使用一些「魔法」來創建一個帶有「純白色」和「純黑色」區域的「純灰色」影像。

  echo "P2 5 1 255\n 127 0 127 255 127" |\
                magick - -scale 150x50\! -alpha off   displace_map.jpg
[IM Output]
現在要將此影像用作「位移地圖」,我們從位移地圖中獲取「灰度值」,並將其添加到 X 或 Y 坐標(或兩者都添加)。 也就是說,我們根據位移地圖的「灰度」將查找從當前位置相對位移一定量。 「值」的處理方式很特別,「純灰色」表示查找點的零位移(在本例中僅指 Y 坐標),但「最大位移」用於「白色」(正)或「黑色」(負)值。 例如,讓我們將位移地圖應用於我們的「標籤」影像。

  magick label.jpg  displace_map.jpg  -virtual-pixel Gray \
          -fx 'dy=10*(2*v-1); p{i,j+dy}'   displaced.jpg
[IM Output]
如您所見,圖像的各個部分看起來像是根據置換圖的顏色“移動”了。“白色”區域會將給定的“置換值”添加到查找點,因此在該區域中,每個像素都會查找“向南”(正 Y 方向)“10”個像素的來源圖像。結果,看起來來源圖像向上移動了。請記住,被置換的是查找,而不是實際圖像本身,這就是為什麼它看起來向上移動或白色表示負方向的原因。對於具有“黑色”置換的區域,也會看到類似的效果。來源圖像看起來向下移動,因為查找置換是在負方向上完成的。仔細想想。您還會注意到,“置換查找”實際上可以查看正常的圖像邊界之外,允許您使用虛擬像素設置來控制這些超出邊界的像素。在上面,我只是要求返回灰色像素。上面例子中的“最大置換”值“10”非常重要,它是來源圖像的任何部分看起來移動的最大相對距離,用於映射圖像中的“純白色”或“純黑色”置換值。您不能置換查找,因此輸入圖像不能超過此值。最大白色或黑色值與中心無置換 50% 灰色值之間的其他灰色陰影將按適當的量置換查找。因此,25% 的灰色值將在負方向上將查找置換 1/2 的置換值,而 75% 的灰色將在正方向上將其置換 1/2 的置換值。該值是絕對扭曲圖相對置換圖之間的關鍵區別。您可以增加或減少相對置換,使圖像或多或少失真,只需更改置換值,而無需更改置換圖。此外,由於“零置換”圖只是純色 50% 或純灰色,而不是複雜的漸變,因此您可以從簡單的灰色圖像開始,並通過藝術方式變亮或變暗區域以生成所需的置換。您可以通過繪製形狀或區域來做到這一點,而不需要複雜而精確的數學公式。最後,由於所有置換都是相對的,因此邊緣效應產生的狂野值不會產生狂野或隨機的像素顏色。事實上,正如您將看到的,平滑或模糊置換圖實際上是一件好事,因為它消除了您在上面的例子中可以看到的不連續或不連續的“切割”效果。總之置換圖更易於控制和藝術化,提供局部置換而不需要複雜而精確的數學,並且對錯誤、邊緣效應甚至置換圖模糊非常寬容。它非常適合簡單的“置換”類型的失真,例如在產生水、波浪、扭曲的鏡子、光的彎曲、透鏡狀效果或磨砂或氣泡玻璃效果等效果時。另一方面,高度數學化的失真,例如“極坐標”、“旋轉”和“透視”失真,或其他真實世界的 3D 類型映射,並不容易實現。也就是說,並不是說不可能,因為稍後我們將證明您實際上可以在兩種風格的地圖之間進行轉換,只是更加困難。

複合置換方法

我們使用了DIY FX 運算符來進行置換映射,因此您可以看到實際執行的操作。但這是一種緩慢的技術。但是,有一個等效的內置合成運算符,“Displace”。以下是您如何使用它...

    magick {image} {displacement_map} \
            -compose Displace   -define compose:args={X}x{Y} \
            -composite   {result+}

    magick {image} {displacement_map} \
            -compose Displace   -set option:compose:args {X}x{Y} \
            -composite   {result+}

    magick composite {displacement_map} {image} \
              -displace {X}x{Y}    {result+}

請注意順序,尤其是在“magick composite”命令中。

使用「-set」而非 define 也允許您在參數中使用百分號跳脫字元。『X』和『Y』值定義用於給定置換映射中「白色」和「黑色」顏色的方向和「最大位移」。您可以定義其中一個或兩個值,以便您朝任何特定方向進行置換。也就是說,置換映射通常會在某個隨機方向上提供線性置換,其最大強度由『X』和『Y』值控制。然後,「映射圖像」會設定從負最大值(黑色)到正最大值(白色)應用多少最大值,完美的灰色表示該像素的查找沒有位移。例如,以下是我們上面提到的相同 Y 位移範例…

  magick label.jpg  displace_map.jpg  -virtual-pixel Gray \
          -compose Displace -define compose:args=0x10 -composite \
          displaced_y.jpg
[IM Output]
您也可以使用其他設定,例如「-geometry」和「-gravity」設定,來調整置換映射覆蓋在圖像上的區域。從置換映射產生的像素查找仍然可以參考圖像覆蓋部分之外的區域,將它們複製到覆蓋區域中。

簡單位移範例

沒有任何平滑過渡的原始顏色區域的置換映射通常會在結果圖像的不同區域之間產生不連續的置換,就像您在上面看到的那樣。事實上,您可以使用這種技術製作一個「斷裂」的置換映射,就好像您正在透過一面破裂的鏡子觀看一樣。例如,請參閱下面的碎裂鏡子。如果顏色從一個區域平滑地流向另一個區域,您可以產生更好、更平滑的結果。例如,透過模糊置換映射,您可以在置換區域之間產生波浪狀的過渡…

  magick displace_map.jpg  -blur 0x10   dismap_wave.jpg
  magick label.jpg  dismap_wave.jpg  -virtual-pixel Gray \
          -compose Displace -define compose:args=0x10 -composite \
          displaced_wave_y.jpg
[IM Output]
[IM Output]
您也可以使用映射沿 X 方向置換圖像,而不是沿 Y 方向置換圖像,從而產生一種壓縮波。

  magick label.jpg  dismap_wave.jpg  -virtual-pixel Gray \
          -compose Displace -define compose:args=10x0 -composite \
          displaced_wave_x.jpg
[IM Output]
透過對 X 和 Y 方向使用相同的置換映射,我們可以同時添加壓縮波和振幅波。

  magick label.jpg  dismap_wave.jpg  -virtual-pixel Gray \
          -compose Displace -define compose:args=10x10 -composite \
          displaced_wave_xy.jpg
[IM Output]
請注意,圖像仍然沿單一線性方向置換,導致上圖在下坡上被拉伸,在上坡上被擠壓在一起。也就是說,扭曲是以一個角度或「向量」執行的,同時具有水平和垂直分量。您可以看到這種效果非常像在水下,圖像被水面上的漣漪扭曲。然而,扭曲映射可以包含原始圖像的多個副本,就像您在反射或折射圖像中可以做到的那樣…

  echo "P2 3 1 255\n 255 127 0 " | magick - -scale 150x50\! dismap_copy.jpg
  magick label.jpg  dismap_copy.jpg \
          -compose Displace -define compose:args=66x0 -composite \
          displaced_copy.jpg
[IM Output]
[IM Output]
您也可以使用漸變來建立圖像部分的鏡像翻轉或翻轉。例如,在這裡您可以使用線性置換映射,將像素從圖像的一側複製到另一側。

  magick -size 50x150 gradient: -rotate -90  -alpha off  dismap_mirror.png
  magick label.jpg  dismap_mirror.png \
          -compose Displace -define compose:args=150x0 -composite \
          displaced_mirror.jpg
[IM Output]
[IM Output]
你能弄清楚這個置換映射是如何工作的嗎?   作為提示,請找出最左側和最右側邊緣有什麼位移,然後看看圖像的其餘部分是如何融入其中的。然而,當您再次使用漸變圖像時,您會失去置換映射的簡單性。因此,鏡像最好使用圖像上的直接翻轉操作或使用絕對扭曲映射來完成。請注意,透過翻轉漸變,您可以縮小圖像。

  magick -size 50x150 gradient: -rotate 90  -alpha off  dismap_shrink.png
  magick label.jpg  dismap_shrink.png \
          -compose Displace -define compose:args=150x0 -composite \
          displaced_shrink.jpg
[IM Output]
[IM Output]
以上也展示了置換地圖的一個特殊問題。當圖像的一個區域(或全部)被壓縮超過 50% 時,就會開始產生 鋸齒偽影。這在階梯狀的「鋸齒」邊緣中尤為明顯。如前所述,解決此問題的一種方法是對生成每個輸出像素所使用的像素數量進行 超採樣。為此,我們放大圖像和置換地圖,然後將生成的圖像調整回其正常大小。這將允許更多像素參與設置結果中的特定像素,從而產生更好的圖像。例如...

  magick label.jpg  dismap_shrink.png  -resize 200% \
          -compose Displace -define compose:args=400x0 -composite \
          -resize 50%    displaced_resize.jpg
[IM Output]
一個更好、更平滑的結果,雖然可能也有點模糊。 繪製梯度圖 從上面的例子中直接產生的一個想法是,通過使用簡單線條的 Y 位移,您可以生成置換地圖的顏色圖。例如,我在這裡生成一個數學 sinc() 函數(定義為 'sin(x)/x'),並通過將其用作置換地圖來繪製該梯度圖...

  magick -size 121x100 xc: -fx 'sin(i*24/w-12)/(i*24/w-12)/1.3+.2' \
                                                      gradient_sinc.gif
  magick -size 121x100 xc: -draw 'line 0,50 120,50'     graph_source.gif
  magick graph_source.gif gradient_sinc.gif \
          -compose Displace -define compose:args=0x49 -composite \
          displace_graph.gif
[IM Output]  + [IM Output] ==> [IM Output]
如您所見,它有效,儘管我不喜歡將其用於數學繪圖。最好使用專門的繪圖軟體。然而,這種技術作為一種繪製圖像中一行或一列像素強度的粗略方法很有用。它的作用是顯示位移的巨大差異如何輕鬆產生不連續性或不平滑的結果。基本上,由於「圖形源」中的每個單個像素都只被查看一次,沒有平均,因此從一個像素到下一個像素的位移查找值的巨大差異會導致結果中出現較大的顏色變化。結論是,置換不僅適用於平滑的置換地圖,也適用於包含大面積或色調的圖像。它不適用於銳利的細線。當然,您可以通過再次 超採樣 變形地圖來改善效果...

  magick graph_source.gif gradient_sinc.gif  -resize 400% \
          -compose Displace -define compose:args=0x196 -composite \
          -resize 25%   displace_graph_2.gif
[IM Output]
結果好多了,雖然不如使用繪圖軟體所能達到的效果好。仍然只使用了 ImageMagick 來創建它。這是同一張圖表的另一個版本,但這次使用的是純色,它比置換細線的效果要好得多。

  magick -size 121x50 xc:white xc:black -append \
          gradient_sinc.gif  -resize 400% \
          -compose Displace -define compose:args=0x196 -composite \
          -resize 25%   displace_graph_3.gif
[IM Output]

區域置換(線性)

讓我們嘗試一個更合乎邏輯的置換問題。將圖像的一個區域沿直線從一個位置移動到另一個位置。正如我們所見,「純灰色」圖像不會導致任何置換,而「白色」會導致從源圖像中查找正向置換。例如,讓我們創建這樣一個圖像....

  magick -size 75x75 xc:gray50 -fill white \
          -draw 'circle 37,37 37,20'  dismap_spot.jpg
[IM Output]
現在,當我們應用此圖像時,標記區域的內容應具有給定位移值方向上出現的任何內容的副本。那麼讓我們嘗試一個 X+10 和 Y+10 或 '10x10' 的位移值...

  magick koala.gif dismap_spot.jpg \
          -compose Displace -define compose:args=10x10 -composite \
          displace_spot.png
[IM Output]  + [IM Output] ==> [IM Output]
如您所見,標記區域的內容現在包含了位於東南方向 +10,+10 像素處的圖像副本。基本上是無尾熊「尾巴」的圖像。換句話說,在圓圈內,圖像向東北方向或 -10,-10 像素移動。請記住,置換是查找的,因此源圖像由於 反向像素映射 而移動了負值。圖像向相反方向移動!另請注意,移動的是標記區域內的圖像。您沒有置換標記的圖像,而是將圖像置換到標記的區域中。最後請注意圓圈邊緣的尖銳不連續性。標記區域內的區域被移動,而外部區域保持原樣。這些都是事實,因此值得重複。
置換使圖像朝與值相反的方向移動。
只有標記為非灰色的區域才會被置換。
急劇的顏色變化會產生急劇的圖像不連續性。
讓我們嘗試一些更實用的東西。讓我們將無尾熊鼻子和眼睛之間的中心點,位於 '32,22',移動到我們的白色(完全正位移)圓圈的中心點 '37,37'。這需要一個 '-5,-15' 的位移值(記住這是一個反向方向)...

  magick koala.gif dismap_spot.jpg \
          -compose Displace -define compose:args=-5x-15 -composite \
          displace_head.png
[IM Output]
這樣我們就得到了無尾熊頭部中心部分的一個很好地居中的副本。但圖像仍然是「不連續」的,而且使用負值也不是很好。解決方案是改用一個黑點,同時也要模糊該點的邊緣。我們還要把它放大,以包含更多無尾熊的頭部。這就是我們的「正向移動點」圖像...

  magick -size 75x75 xc:gray50 -fill black \
          -draw 'circle 37,37 37,17'  -blur 0x5  dismap_area.jpg
[IM Output]
您不希望將圖像模糊太多,否則斑點的中心將不再是平坦的黑色。或者,您可以歸一化反向調整色階圖像,以確保繪製區域為黑色,周圍部分為完美的灰色。您將在後面的示例中經常看到這種做法。現在,讓我們使用我們的黑色「模糊點」位移圖重複最後的「頭部」位移。

  magick koala.gif dismap_area.jpg \
          -compose Displace -define compose:args=5x15 -composite \
          displace_area.png
[IM Output]
如您所見,我們將圖像移動了 +5,+15 到「模糊」區域,但這次該區域的邊界更加平滑,並與圖像的其餘部分相連。當然,圓圈邊緣的耳朵被模糊的邊緣扭曲了,無尾熊的身體也被壓縮了,但它仍然比我們之前的要好得多。為了防止在尾隨邊緣出現圖像「撕裂」或留下位移部分的副本,您需要擴展該點,或製作更複雜的漸變類型的位移圖像。例如,假設您想將無尾熊的頭部從其起始位置 '32,22' 移動到圖像的中心 '37,37',或移動 +5,+15 像素,但您想調整整個圖像以適應這種變化,以產生更平滑的效果。為此,您需要在 '37,37' 處具有黑色的最大位移(正圖像位移),並位移 +5,+15 的值。但您還希望通過將角落「固定」在 50% 灰色來確保圖像的其餘部分保持完整。也就是說,非常適合Shepard 的稀疏梯度插值

  magick -size 75x75 xc:  -sparse-color  Shepards \
          '37,37 black   0,0 gray50  74,74 gray50  0,74 gray50  74,0 gray50' \
          dismap_move.jpg
  magick koala.gif dismap_move.jpg \
          -compose Displace -define compose:args=5x15 -composite \
          displace_move.png
[IM Output]  + [IM Output] ==> [IM Output]
如您所見,您會看到更大的位移區域擴散到整個圖像上。結果是比之前使用的更緊湊的「點」方法更平滑地改變圖像。這實際上與Shepard 的變形完全相同,但僅適用於一個移動的控制點。這也與 Fred Weinhaus 的腳本 'shapemorph' 中使用的方法完全相同,但帶有一些動畫。總之:對於小的局部位移,可以使用「模糊點」位移。但對於較大距離上的較大位移,應使用較大的平滑漸變位移圖,以防止撕裂或複製源圖像。
施工中

簡單位移變形

Modifying the Size of Displacement Vectors
Two Image Morphing
Random 1D Displacements

漣漪水面反射

如前所述,位移圖對於生成水和玻璃般的扭曲特別有用。[IM 輸出] 在這個例子中,我通過裁剪一張花朵圖像來生成一個小圖像。現在我想讓它看起來像是在一些波紋的水面上。為了生成漣漪,我需要一個相同大小的正弦波漸變,我可以使用評估正弦函數來生成它。數字 '8' 表示將添加到漸變中的「波浪」的數量。

  magick -size 150x80 gradient:  -evaluate sin 8  wave_gradient.png
[IM Output]
現在,讓我們使用斜向置換向量(不僅僅是簡單的垂直或水平變形)來扭曲該圖像,以便給予它更多強調。

  magick composite wave_gradient.png  flower.jpg -displace 5x5 flower_waves.png
[IM Output]
現在看起來還不太有趣,但是如果您翻轉該圖像、垂直壓縮並將其附加到原始圖像上,會發生什麼情況呢?

  magick flower_waves.png -flip \
          flower.jpg  +swap -append  flower_waves_2.png
[IM Output]
不幸的是,它看起來仍然很不自然。原因是反射在圖像的頂部和底部看起來都一樣。它沒有「深度」感。反射與原始圖像的亮度也相同,而實際情況很少如此。為了使其更加逼真,您需要使用強度不同的漣漪圖案。以下內容使用了一些花哨的漸變數學來「衰減」我們上面使用的波浪漸變。也就是說,我們使波浪圖案從上到下線性變小。這種技巧確保了波浪在圖像底部的純灰色或「無位移」顏色處結束(稍後會翻轉)。

  magick -size 150x80 gradient: \
          \( wave_gradient.png \
             +clone -compose multiply -composite \) \
          \( -clone 0 -negate -evaluate divide 2 \
             -clone 1 -compose plus -composite \) \
          -delete 0-1      waves_decreasing.png
[IM Output]
因此,讓我們應用此漸變來形成花朵的新反射。我還稍微調暗了反射圖像,以表示一些光線散失到水中,使其看起來更像水的反射。

  magick flower.jpg  waves_decreasing.png  \
          -compose Displace -define compose:args=8x8 -composite \
          -flip   +level 0,80% \
          flower.jpg  +swap -append   flower_in_water.png
[IM Output]
請注意,由於扭曲的圖像被翻轉以形成反射。此外,與底部相比,圖像在「水面」頂部(最靠近與原始圖像連接處)的「漣漪」會更少。這賦予了失真一種距離感。您可以通過稍微旋轉、弧形或僅使用「隨機」位移來扭曲波浪位移貼圖,使其更加逼真。這將使波浪看起來更自然。儘管最好在「衰減」之前就這樣做,以便之後添加「深度」。嘗試一下,實驗一下,然後告訴我您的成果。
Future Animated Ripples -
  Using -function Sinusoid with phase changing

二維位移映射

到目前為止,所有相對位移貼圖都只沿一個方向位移圖像。儘管可以通過設置適當的「XxY」位移值或「向量」來將該方向設置為任何所需的角​​度。但是,您可以通過使用兩個獨立的位移來產生更複雜的位移,其中圖像可以在任何方向上位移任何量。為此,我們需要創建兩個位移貼圖,分別用於 X 和 Y 方向。以下是您可以使用的命令...

magick {image} {X displacement} {Y displacement} \
        -compose Displace   -define compose:args={X}x{Y} \
        -composite   {result+}

magick {image} {X displacement} {Y displacement} \
        -compose Displace   -set option:compose:args {X}x{Y} \
        -composite   {result+}

composite {X displacement} {image} {Y displacement} \
          -displace {X}x{Y}    {result+}
請注意「magick composite」命令中的輸入圖像順序。奇怪的順序是由於需要濫用「magick composite」選項處理以及歷史原因造成的。您必須正確理解這一點。因此,我建議您使用「magick」命令,而不是「magick composite」。
在 IM v6.4.4 之前,對單獨的 X 和 Y 位移使用 2 個單獨的位移貼圖是碰巧的事。它有時有效,有時無效。不建議嘗試在比此版本舊的 IM 上使用它。
此外,就像統一失真貼圖一樣,您可以使用單個「統一位移貼圖」。如果只提供了一個位移圖像,則將從「紅色」通道查找 X 位移,從「綠色」通道查找 Y 位移,並且任何 Alpha 遮罩也將從位移貼圖傳輸到最終圖像。「藍色」通道將被忽略。
在內部,「magick」和「magick composite」實際上都會合併兩個圖像(如果提供),以便生成「統一位移貼圖」,然後再將其傳遞給內部 API。

這不會影響我們之前查看的先前「線性位移」,因為給定的位移貼圖是灰度圖像,因此「紅色」和「綠色」通道是相同的。

圓柱位移

在 IM 論壇上出現過多次的一個問題是如何將圖像映射到圓柱體上,例如將其覆蓋在咖啡杯或汽水瓶上。這就是解決方案…

  magick rose: -background black -gravity south -splice 0x8 \
          \( +clone -sparse-color barycentric '0,0 black 69,0 white' \) \
          \( -clone 1 -function arcsin 0.5 \) \
          \( -clone 1 -level 25%,75% \
                 -function polynomial -4,4,0 -gamma 2 \
                 +level 50%,0 \) \
          -delete 1 \
          -virtual-pixel black  -define compose:args=17x7 \
          -compose Displace  -composite   rose_cylinder.png
[IM Output]
以上非常複雜,但本質上是同時使用兩個獨立的位移。X 方向上的 arcsin() 壓縮,以及 Y 方向上的圓弧位移。以下是指令的功能…
  • 載入「玫瑰」圖像並為垂直位移添加一些空間
  • 為以後的數學函數建立水平數學漸變
  • 使用 magick 複製漸變以產生壓縮位移貼圖
  • 使用 magick 將另一個副本複製到垂直橢圓弧位移
  • 移除線性漸變
  • 準備並執行位移
結果… 一朵玫瑰被正確地包裹成圓柱體的 30 度等距視圖。 將上述指令分開以儲存和檢視各個位移貼圖。要記住的關鍵是,兩個貼圖位移都會執行 X 和 Y 值的查找,以確定應該在查找位置顯示哪個像素。請記住,位移實際上不是源圖像的位移,而是查找在源圖像中的位移。這種位移扭曲方法已內建到 Fred Wienhaus 的「cylinderize」腳本中。

破碎鏡像

您可以通過生成 X 和 Y 位移的隨機區域來為圖像建立「破碎鏡像」外觀。

  magick dragon_sm.gif -sparse-color voronoi '  \
                  %[fx:rand()*w],%[fx:rand()*h]  red
                  %[fx:rand()*w],%[fx:rand()*h]  lime
                  %[fx:rand()*w],%[fx:rand()*h]  black
                  %[fx:rand()*w],%[fx:rand()*h]  yellow
               ' -interpolate integer -implode 1     mirror_areas.gif
  magick  mirror_areas.gif -channel R  -separate   mirror_dismap_x.gif
  magick  mirror_areas.gif -channel G  -separate   mirror_dismap_y.gif

  magick composite mirror_dismap_x.gif  dragon_sm.gif  mirror_dismap_y.gif -alpha off \
            -background white -virtual-pixel background -displace 7 \
                                                        mirror_displaced.gif

  magick  mirror_areas.gif -edge 1 -threshold 20% \
            -evaluate multiply .7 -negate               mirror_cracks.gif
  magick composite mirror_displaced.gif  mirror_cracks.gif -compose multiply \
                                                        mirror_cracked.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] ==>  
  [IM Output] [IM Output] ==> [IM Output]
使用隨機化的 Voronoi 稀疏顏色 圖像生成四個隨機位移區域。然後對其進行 內爆失真,以將這些區域扭曲到圖像的中心。由於四個彩色區域中的每一個都保持純色,因此每個區域都將包含原始圖像的未失真但已位移的副本。但是,每個區域都會以不同的方式位移圖像,就像破碎鏡子的每個碎片一樣。為了完成鏡像效果,使用 邊緣偵測 來勾勒區域的邊緣,從而呈現出最終圖像的破碎性質。也就是說,裂縫也被顯示出來。
從技術上講,我不必分離生成的彩色隨機位移貼圖中的「紅色」和「綠色」通道。我可以直接使用它們,因為 X 位移是從「紅色」通道查找的,而 Y 位移是從「綠色」通道查找的。也就是說,我可以直接使用「mirror_areas.gif」圖像作為「統一位移貼圖」。
施工中

Shepards 位移

隨機位移

鏡頭效果

毛玻璃效果

色散效果(旋轉位移)

具有隨機位移的色散效果

未來:其他可能的扭曲/位移映射示例
  • 將漸變光線追踪到 3D 物件上,以便稍後可以將任何圖像映射到這些物件上。
    • X 和 Y 漸變映射圖像
    • 用於顏色、高光和陰影的純灰色圖像

可變模糊映射

在 ImageMagick 6.5.4-0 版中添加的「-compose」方法「Blur」為您提供了一種方法,可以根據映射圖像將每個像素替換為相鄰像素的橢圓高斯平均值(模糊)。

    magick composite -blur {Xscale}[x{Yscale}[+{angle}]]          blur_map  image   result

    magick image  blur_map \
        -define compose:args='{Xscale}[x{Yscale}[+{angle}]]' \
        -compose blur -composite   result

    magick image  blur_map \
        -set option:compose:args '{Xscale}[x{Yscale}[+{angle}]]' \
        -compose blur  -composite   result

請注意,這種 圖像合成 需要使用運算元參數,該參數可以通過多種方式設定。有關更多詳細資訊,請參閱 全局定義的工件。通過使用可變貼圖來控制模糊,您可以模糊圖像的一部分,同時完全保留另一部分,或者您可以產生諸如 移軸效果 之類的效果,其中真實世界圖像被製作成看起來更像一個小型的人造模型。

例如,在這裡我模糊了無尾熊圖像的一半,而另一半完全沒有模糊…

  magick -size 37x75 xc:black -size 38x75 xc:white +append  blur_map_bool.gif
  magick koala.gif blur_map_bool.gif \
          -compose blur -define compose:args=3 -composite \
          blur_koala_bool.gif
[IM Output]  + [IM Output] ==> [IM Output]
如您所見,在「模糊映射」圖像中,「白色」像素會使用給定的最大「sigma」值進行模糊處理,而「黑色」像素則完全不會模糊。 換句話說,您有一個非常簡單的遮罩模糊。 當然,這可以用許多其他方法來實現,但这並不能說明模糊映射的強大之處。 使這種模糊映射具有多功能性的是它在整個圖像中是可變的。 也就是說,如果模糊映射顏色為灰色,則使用較小的「鄰域」,您將獲得相應的較小模糊結果。 但是,黑色不會模糊,而白色則根據給定的值進行最大程度的模糊。 需要注意的一件事是,只有模糊的區域才會花費額外的時間。 未模糊的像素不需要這種額外的處理。 這使得上述速度比使用 遮罩合成 快得多,後者等同於模糊整個圖像並合併結果。 在處理圖像中非常小區域的大模糊時,這種時間節約甚至更為重要。 例如,讓我們讓無尾熊的腳漸漸變得更加模糊...

  magick -size 75x75 gradient:black-white blur_map_gradient.gif
  magick koala.gif blur_map_gradient.gif \
          -compose blur -define compose:args=3 -composite \
          blur_koala_gradient.gif
[IM Output]  + [IM Output] ==> [IM Output]
這裡又是相同的模糊,但顯示了模糊如何隨著高度而變化。

  magick blur_map_bool.gif blur_map_gradient.gif \
          -compose blur -define compose:args=15 -composite \
         blur_edge_gradient.gif
[IM Output]  + [IM Output] ==> [IM Output]
有關可變映射模糊的實際示例,請查看 照片移軸效果距離模糊陰影字體。 請注意,用於生成該像素的「模糊顏色」的是每個單個像素周圍的鄰域。 這意味著即使您可能指定圖像的某些部分不模糊,但來自該未模糊區域的顏色也可能會被用作周圍像素模糊的一部分。 也就是說,僅僅因為一個區域沒有模糊並不意味著來自該區域的顏色不會被用作其他模糊像素結果的一部分。 也就是說,來自未模糊區域的顏色可能會「洩漏」到周圍的模糊區域中。 要在不包含前景像素的情況下模糊背景,您需要使用 讀取遮罩技術 來防止它們被讀取為模糊操作的一部分。

橢圓模糊

模糊」合成設置使用與普通 模糊或高斯模糊運算符 不同的技術,因為它是通過使用高斯 橢圓區域重新採樣 算法實現的,該算法是作為 廣義失真運算符 的一部分為縮放圖像重新採樣而開發的。 用於鄰域重新採樣的橢圓區域也使得這種模糊方法比「-blur」和「-gaussian-blur」運算符提供的普通均勻「圓形」模糊更加多樣化。 橢圓本身由模糊區域的 sigma 的「寬度」、「高度」定義。 橢圓也可以通過給定的「角度」(順時針)從正交對齊旋轉。 例如,在下圖中,我們展示了單個像素的模糊顏色如何根據給定的 sigma 值從旋轉的橢圓區域獲得其顏色。 然後,根據 高斯濾波器(使用橢圓距離公式)對該區域中的像素進行加權平均,以產生模糊的顏色。

  magick koala.gif -compose blur -define compose:args=5x1-30 -composite \) \
             elliptical_blur.gif
  # ... other commands to create diagram of blur effect ...
[IM Output]
如前所述,這與廣義失真運算器用於為其失真圖像生成顏色的顏色查找方法完全相同,因為它允許將源圖像區域縮放(和過濾)合併到一個像素中,尤其是在極端失真中,例如觀看遙遠的地平線中的示例。有關此過程的更多詳細信息,請參閱區域重新採樣重新採樣濾鏡

作為可變模糊映射的橢圓控制的示例,讓我們使用與之前相同的漸變模糊映射來使用黑點。但這次我們將縮放一個細長的水平橢圓「30x0」,而不是一個圓形。「x0」可能看起來很奇怪,但基本上意味著不應該看到垂直模糊,只需要一個最小高度的橢圓即可產生良好的效果。


  magick -size 75x75 xc: -draw 'circle 36,36 36,8'  black_circle.gif
  magick black_circle.gif blur_map_gradient.gif \
          -compose blur -define compose:args=15x0 -composite \
          blur_horizontal.gif
[IM Output]  + [IM Output] ==> [IM Output]
如您所見,模糊量仍然隨提供的映射圖像而變化,在圖像頂部產生非常小的模糊,而在底部產生大量模糊。但也要注意,底部邊緣在水平方向上向兩個方向的模糊程度相同,但在垂直方向上沒有模糊,從而在垂直方向上產生清晰的截止。通過給出第三個「角度」參數來旋轉細長的橢圓,或者直接定義一個垂直橢圓,您可以僅在垂直方向上模糊圖像...

  magick black_circle.gif blur_map_gradient.gif \
          -compose blur -define compose:args=0x15 -composite \
          blur_vertical.gif
[IM Output]
但請注意,模糊的應用並不均勻!上半部分看起來比下半部分模糊程度低,因為這就是「映射圖像」告訴它要做的。這反過來又扭曲了圖像,使其看起來有點被模糊效果截斷。最後,讓我們再做一次,但使用旋轉了固定 45 度角的水平橢圓。

  magick black_circle.gif blur_map_gradient.gif \
          -compose blur -define compose:args=15x0+45 -composite \
          blur_angle.gif
[IM Output]
圖像可能看起來很奇怪,但這是因為可變模糊映射是垂直的,而模糊本身是傾斜的,由於橢圓角度和模糊映射的角度不一致,因此產生了奇怪的外觀效果。
請注意,使用這樣的細長橢圓實際上比使用單個大圓要快得多。事實上,「-blur」運算器通過使用兩個獨立的水平和垂直模糊來提高速度,而「-gaussian」模糊運算器以一種更簡單的方式執行完整的二維卷積,就像剛剛描述的「模糊」合成方法一樣。

可變長寬比模糊

到目前為止,我們已經使用「模糊映射」改變了用於模糊的橢圓區域的大小。然而,雖然橢圓的大小甚至角度都可以旋轉,但其形狀和角度保持不變。現在,「模糊映射」是由三個顏色通道組成的圖像:紅色、綠色和藍色。由於我們使用灰度圖像,因此所有三個顏色通道都具有相同的值。然而,在內部,橢圓的寬度僅由紅色通道值縮放,而高度由綠色通道值縮放。藍色通道值的任何影響通常都被忽略,除非在我們稍後將查看的特殊情況下。這意味著橢圓形狀或其「縱橫比」可以通過對紅色和綠色通道使用不同的映射來改變。與普通的模糊映射一樣,零值(或僅在該通道中為「黑色」)將導致最小寬度或高度,而最大值(或「白色」)將導致給定的模糊量。例如,在這裡,我可以分割圖像,以便圖像的四分之二水平模糊(紅色通道最大),而使其他區域垂直模糊(綠色通道最大)。對於此示例,我在組合它們到單個且現在是彩色的「模糊映射」之前,分別生成了寬度和高度映射。在正常實踐中,您可以以任何您喜歡的方式創建映射,甚至可以使用預先準備好的映射來獲得特定的模糊效果。

  magick -size 2x2 pattern:gray50 -sample 75x75! blur_map_r.gif
  magick blur_map_r.gif -negate blur_map_g.gif
  magick blur_map_r.gif blur_map_g.gif -background black \
          -channel RG -combine blur_map_aspect.gif
  magick black_circle.gif blur_map_aspect.gif \
          -compose blur -define compose:args=10x10 -composite \
          blur_aspect.gif
[IM Output]  + [IM Output] ==> [IM Output]
[IM Output]  + [IM Output] ==> [IM Output]
當然,您仍然可以為橢圓設置固定角度。

  magick black_circle.gif blur_map_aspect.gif \
          -compose blur -define compose:args=15x15+45 -composite \
          blur_aspect_angle.gif
[IM Output]
在 IM 6.5.8-8 版本之前,發現在處理傾斜垂直橢圓模糊時出現錯誤。

可變角度模糊

到目前為止,用於模糊圖像的橢圓角度在整個圖像中一直是固定角度。也就是說,用於模糊的橢圓始終處於相同的角度,即使可以通過修改模糊映射的紅色和綠色通道來改變橢圓的縱橫比。從 IM v6.5.8-8 開始,您可以使用模糊映射圖像的藍色通道為模糊提供可變角度。這是通過為模糊參數提供兩個角度來完成的。第一個角度參數用於定義藍色通道中零值('0' 或 '黑色')的角度,而給定的第二個角度用於定義藍色通道的最大值('QuantumRange' 或 '白色')。如果只給定一個角度值,則該角度用於設置零和最大「藍色」通道值的 ​​角度,這基本上意味著角度變為固定,而不管「模糊映射」圖像的藍色通道中存在什麼值。這就是為什麼在之前的示例中,角度一直是恆定的。例如,這裡我使用水平模糊橢圓,然後使用藍色通道在圖像中心周圍從 '+0' 到 '+360' 的角度範圍內改變橢圓的角度。地圖生成使用極坐標漸變,其詳細信息可以在扭曲漸變中找到。請注意,將該漸變放入藍色通道時,我如何使用「-background」顏色設置和組合運算符來確保紅色和綠色通道都設置為最大值('白色'),因此它不會縮放有角度的橢圓。當然,這意味著在最終的映射圖像中,白色表示使用最大角度,而黃色(或零藍色通道值)表示最小角度。

  magick -size 100x300 gradient: -rotate 90 \
          +distort Polar '36.5,0,.5,.5' +repage -flop gradient_polar.jpg
  magick gradient_polar.jpg -background white \
          -channel B -combine blur_map_angle.jpg
  magick koala.gif blur_map_angle.jpg \
          -compose blur -define compose:args=5x0+0+360 -composite \
          blur_rotated.jpg
[IM Output] ==> [IM Output]
[IM Output]  + [IM Output] ==> [IM Output]
結果如您所見,圖像旋轉模糊。將結果與使用的模糊映射進行比較。在圖像頂部,角度,漸變為白色或黑色,根據使用的參數,這意味著橢圓的角度為 0 或 360,因此橢圓保持水平。在底部,漸變為純灰色,因此使用了給定角度範圍之間的中間角度,即 180 度。這意味著橢圓再次水平。但在圖像大小處,漸變為 25% 或 75% 灰色。因此角度為 90 或 270 度,使橢圓垂直旋轉。所有其他角度都遵循,導致橢圓圍繞圖像平滑旋轉。但是,生成的圖像中心模糊得很奇怪!這是因為橢圓尺寸保持不變,並且不會朝向圖像中間適當變小。解決方案是同時使用紅色和綠色通道設置橢圓大小。例如。

  magick -size 106x106 radial-gradient: -negate \
          -gravity center -crop 75x75+0+0 +repage gradient_radial.jpg
  magick gradient_radial.jpg gradient_radial.jpg gradient_polar.jpg \
          -channel RGB -combine blur_map_polar.jpg
  magick koala.gif blur_map_polar.jpg \
          -compose blur -define compose:args=10x0+0+360 -composite \
          blur_polar.jpg
[IM Output]  + [IM Output]  + [IM Output] ==> [IM Output]
[IM Output]  + [IM Output] ==> [IM Output]
更好的結果。但是請注意,雖然結果看起來不錯,但模糊橢圓並未像真正的旋轉模糊圖像那樣沿弧線正確彎曲。因此,以上只是對真正旋轉模糊的近似。但對於小的模糊距離(等於模糊角度),它非常好。進行旋轉模糊的更好方法是使用特殊的極坐標去極化扭曲技術,或當前名稱錯誤的徑向模糊運算符。通過更改用於橢圓角度(藍色通道)的角度範圍,您可以輕鬆地將上述內容變成徑向模糊,隨著距離中心的距離越遠,模糊程度越高。

  magick koala.gif blur_map_polar.jpg \
          -compose blur -define compose:args=5x0+90+450 -composite \
          blur_radial.jpg
[IM Output]
除了這些徑向/旋轉模糊之外,您還可以執行更多操作,因為您可以在整個圖像中的任何位置以任何數量旋轉和縮放模糊。您可以完全控制。例如,您可以使用不同的角度範圍來混合兩者,使模糊橢圓的角度與圖像中心周圍的角度不匹配。

  magick koala.gif blur_map_polar.jpg \
          -compose blur -define compose:args=10x0+0+180 -composite \
          blur_weird.jpg
[IM Output]
基本上,您現在可以完全控制圖像的哪些部分將如何模糊。通過使用範本,您可以創建一個完整的模糊效果庫。