ImageMagick 範例 --
傅立葉變換

索引
ImageMagick 範例 序言與索引
簡介
傅立葉變換
ImageMagick 中的 FFT/IFT
傅立葉變換的特性
實際應用
進階應用
 
FFT 乘法與除法(低階範例 - 子頁面)

簡介

在圖像處理中,最難理解的概念之一就是傅立葉變換。這有兩個原因。首先,它在數學上比較進階;其次,產生的圖像與原始圖像不相似,難以解釋。儘管如此,利用傅立葉變換可以提供新的方法來進行熟悉的處理,例如增強亮度和對比度、模糊化、銳化和雜訊去除。但它也可以提供在普通圖像域中無法實現的新功能。這些功能包括反捲積(也稱為去模糊化),用於處理典型的相機失真,例如運動模糊和鏡頭失焦,以及使用歸一化互相關進行圖像匹配。本頁面的目標是嘗試解釋傅立葉變換的背景和簡化後的數學原理,並通過範例說明使用傅立葉變換可以進行的處理。如果您覺得這太難了,您可以跳過它,直接從 ImageMagick 中的 FFT/IFT 開始,重點關注其特性和範例。對於感興趣的人,可以在 傅立葉理論的直觀解釋 中找到另一個很好的簡單討論,包括與光學的類比。范德比爾特大學工程學院的講義對於更傾向於數學的人來說也非常有用:《一維和二維傅立葉變換》和《頻率濾波》。其他數學參考資料包括維基百科上的《傅立葉變換》、《離散傅立葉變換》和《快速傅立葉變換》以及《複數》。*感謝 Sean Burke 對原始演示代碼的貢獻,以及 ImageMagick 的創建者將其整合到 ImageMagick 中。這兩者都是英勇的努力。* 許多範例都使用了 HDRI 版本的 ImageMagick,這是為了保持變換後圖像的準確性。如果您想充分利用這些技術,建議您編譯一個個人 HDRI 版本。

傅立葉變換

一張圖片通常由一個「像素」陣列組成,每個像素由一組值定義:紅、綠、藍,有時還有透明度。但在這裡,我們將忽略透明度。因此,紅色、綠色和藍色「通道」中的每一個都包含一組「強度」或「灰階」值。這被稱為「空間域」中的點陣圖像。這只是一種說法,即圖像由其在每個「位置」或「空間位置」上的「強度值」定義。但圖像也可以用另一種方式表示,稱為圖像的「頻域」。在這個域中,每個圖像通道都用正弦波表示。在這樣的「頻域」中,每個通道都有「振幅」值,這些值存儲在基於 X、Y「頻率」而不是 X、Y「空間」坐標的位置。由於這是一種數位表示,因此頻率是「最小」或單位頻率的倍數,而像素坐標表示該單位頻率的索引或整數倍數。這遵循「任何表現良好的函數都可以由正弦波的疊加(組合或總和)表示」的原理。換句話說,「頻域」表示只是存儲和複製「空間域」圖像的另一種方式。但是如何將圖像表示為「波」呢?

圖像即波

好吧,如果我們從任何圖像中取一行或一列像素,並將其繪製出來(使用腳本「im_profile」使用「gnuplot」生成),你會發現它看起來很像一個波。

  magick holocaust_tn.gif -colorspace gray miff:- |\
    im_profile -s - image_profile.gif
[IM Output] ==> [IM Output]
如果波動在間距和振幅上更規則,你會得到更像波形的東西,例如...

  magick -size 20x150 gradient: -rotate 90 \
          -function sinusoid 3.5,0,.4   wave.gif
  im_profile -s wave.gif wave_profile.gif
[IM Output] ==> [IM Output]
然而,雖然這種規則的波形與上面顯示的圖像輪廓有點相似,但它太規則了。但是,如果你將更多的波加在一起,你可以製作出更接近圖像的圖案。

  magick -size 1x150 gradient: -rotate 90 \
          -function sinusoid 3.5,0,.25,.25     wave_1.png
  magick -size 1x150 gradient: -rotate 90 \
          -function sinusoid 1.5,-90,.13,.15   wave_2.png
  magick -size 1x150 gradient: -rotate 90 \
          -function sinusoid 0.6,-90,.07,.1    wave_3.png

  magick wave_1.png wave_2.png wave_3.png \
          -evaluate-sequence add added_waves.png
[IM Output]  + [IM Output]  + [IM Output] ==> [IM Output]
另請參閱 添加偏置漸變 以獲取上述內容的替代示例。這種「波疊加」(波的加法)更接近,但仍然與圖像圖案不完全匹配。但是,你可以繼續以這種方式添加更多波並調整它們,以便生成的合成波越來越接近原始圖像的實際輪廓。最終,通過添加足夠的波,你可以精確地複製圖像的原始輪廓。這是數學家 約瑟夫·傅立葉 的發現。現代的解釋是「任何表現良好的函數都可以由正弦波的疊加來表示」。換句話說,通過將足夠數量的具有正確頻率和振幅的正弦波加在一起,你可以複製任何波動圖案。因此,「頻域」表示只是存儲和複製「空間域」圖像的另一種方式。「傅立葉變換」是計算圖像由哪些「波」組成的過程,就像在上面的例子中所做的那樣。

圖像中的二維波

上面顯示了一個如何使用多個正弦波逼近圖像單行的輪廓的示例。但是圖像是二維的,因此用於在「頻域」中表示圖像的波也必須是二維的。以下是一個這樣的二維波示例。該波具有多個組成部分。 圖像示例

在 ImageMagick 中使用 FFT/IFT

實現注意事項

ImageMagick 使用了 FFTW 離散傅立葉變換函式庫,它需要將影像轉換為浮點數值(複數)並從中轉換回來,此功能最早是在 IM 版本 6.5.4-3 中實現的。為了讓它按照人們對影像的普遍預期運作,任何非正方形或維度為奇數的影像都會被填充(使用 虛擬像素)為以影像最大寬度或高度為邊長的正方形。為了讓「FFT 原點」能正確置中於影像中央,它也會被強制調整為偶數(2 的倍數)維度。這樣做的結果是,在套用反向傅立葉變換後,需要將影像裁剪回其原始維度以移除填充的部分。由於傅立葉變換是由「複數」組成的,因此變換的結果無法直接視覺化。所以,複數變換會以兩種形式之一分離成兩個分量影像。
[Diagram]
複數
實部/虛部

實部和虛部

複數」的一般數學和數值表示法是由「實部」(a) 和「虛部」(b) 組成的浮點數值對。遺憾的是,這兩個數字可能包含負值,因此無法形成可視的影像。因此,這種表示法無法在一般版本的 ImageMagick 中使用,因為它會裁剪此類影像(請參閱下方範例中產生的效果)。但是,當使用 HDRI 版本的 ImageMagick 時,您仍然可以產生、使用,甚至儲存這種傅立葉變換影像的表示法。它們本身可能沒有用處,甚至無法作為影像觀看,但您仍然可以對它們套用許多數學運算。為了產生這種表示法,我們使用運算子的「加號」形式,「+fft」和「+ift」,並將在下方 以實部-虛部表示 FFT 中詳細討論。
[Diagram]
複數極座標形式
強度/相位

強度和相位

直接以數值表示「複數」的方式對影像處理來說不是很有用。但是藉由將這些值繪製在二維平面上,您可以將其轉換為由「強度」(r) 和「相位」(θ) 組成的極座標表示法。這種形式在影像處理中非常有用,特別是強度分量,它基本上指定了構成影像的所有頻率。「強度」分量只包含正值,並且直接映射到影像值。它沒有固定的值範圍,但除了 DC 或零頻率顏色外,這些值通常非常小。因此,強度影像通常看起來非常暗(幾乎是黑色的)。通常需要調整強度並對其強度值應用對數轉換,才能顯示出任何視覺細節。得到的「對數轉換」強度影像稱為影像的「頻譜」。但是請記住,應用於反向轉換的是「強度」影像,而不是「頻譜」影像。出現在影像中心「原點」的 DC(「直流電」的縮寫)或「零頻率」顏色,將是整個影像的平均顏色值。同樣,由於輸入影像不包含「虛部」,因此 DC 相位值也始終為零相位,產生純灰色。「相位」分量的範圍從 -π 到 +π。這首先會偏置到 0 到 2π 的範圍,然後縮放到從 0 到 QuantumRange 的實際影像值(由編譯時記憶體品質決定)。因此,零相位將具有純灰色值(適用於每個通道),而負相位將是純黑色('0')值。請注意,純白色('QuantumRange')幾乎但並不完全相同。使用正常的 FFT 運算符「+fft」和「+ift」可以產生影像的強度和相位 FFT 表示。這將首先在生成 FFT 影像及其反轉中討論。

生成 FFT 影像及其反轉
(強度和相位)

現在,讓我們簡單地對 Lena 影像嘗試傅立葉變換往返。也就是說,我們只需執行正向轉換,然後立即應用反向轉換即可獲得原始影像。然後我們將比較結果以查看產生的品質水準。

  time magick lena.png -fft -ift lena_roundtrip.png


echo -n "RMSE = "
magick compare -metric RMSE lena.png lena_roundtrip.png null:
echo -n "PAE = "
magick compare -metric PAE lena.png lena_roundtrip.png null:
[IM Output] ==> [IM Output]
[IM Text]
上面的「compare」程式返回兩個影像差異程度的度量。在這種情況下,您可以看到總體差異非常小,約為 0.22%。至少一個像素中的峰值差異約為(「PAE」,峰值絕對誤差)僅約為 1%。您可以使用HDRI版本的 ImageMagick 來改進這一點。(請參閱下面的使用 HDRI 進行 FFT)。讓我們仔細看看在上述往返過程中生成的 FFT 影像。

  magick lena.png -fft    +depth +adjoin lena_fft_%d.png
[IM Output]
原始影像
==> [IM Output]
強度
[IM Output]
相位
如同 約翰·M·布雷耶 對傅立葉變換所說... 我們通常不會顯示「相位」圖像,因為大多數看到它們的人不久後就會沉迷於迷幻藥,或者最終在西藏寺院中結束一生。請注意,「-fft」運算符生成了兩張圖像,第一張圖像是「幅度」分量(是的,它幾乎是黑色的,中間只有一個彩色點),而第二張看起來幾乎是隨機的圖像,則包含了「相位」分量。PNG 圖像每個文件只能存儲一張圖像,因此實際上不需要輸出文件名中的「+adjoin」或「%d」,因為 IM 會處理這個問題。但是,為了完整性,我在上面包含了這些選項,以便明確說明我正在生成兩個獨立的圖像文件,而不是一個。有關更多詳細信息,請參閱編寫多圖像序列。由於生成了兩張圖像,因此幅度圖像(第零張圖像)會保存到「lena_fft_0.png」中,而相位圖像(第二張圖像)則會保存到「lena_fft_1.png」中。
為了防止因儲存 FFT 圖像而造成任何失真的可能性,最好根本不要將它們儲存到磁碟,而是在處理圖像時將它們保存在記憶體中。

如果您必須儲存,那麼最好使用 Magick 文件格式「MIFF」,以便以最高品質(位元深度)保留圖像。這種格式還可以在一個文件中儲存多個圖像。對於腳本工作,您也可以使用詳細的「TXT」列舉像素格式。

不要使用「JPEG」或「GIF」圖像格式儲存它們。

如果您必須將這些圖像儲存到文件中以供實際觀看,例如用於網路瀏覽器,請使用圖像格式「PNG」,並將「+depth」重置為內部預設值(就像我們在這些範例中所做的那樣)。但是,它每個文件只能存儲一張圖像。

TIFF」文件格式也可以使用,但網路瀏覽器並不像 PNG 那樣廣泛接受,不過它允許每個文件包含多個圖像。

將中間圖像儲存到單個文件的最佳方法是使用「MIFF」文件格式...

  magick lena.png -fft  +depth lena_fft.miff
或者,您可以使用「-write」將它們儲存到完全不同的文件名中(請參閱寫入圖像)...

  magick lena.png -fft  +depth \
          \( -clone 0 -write lena_magnitude.png +delete \) \
          \( -clone 1 -write lena_phase.png +delete \) \
          null:
請注意,在上面的示例中,我使用了特殊的「NULL:」圖像格式來丟棄兩張仍然保存在記憶體中以供進一步處理的圖像。最後,我們再次讀取這兩張圖像,以便將其轉換回正常的「空間」圖像...

  magick lena_magnitude.png lena_phase.png -ift lena_restored.png
[IM Output] [IM Output] ==> [IM Output]
FFT 過程中生成的兩張圖像都對修改非常敏感,即使是很小的更改也可能導致結果嚴重失真。因此,切勿將它們儲存為任何可能會扭曲這些值的圖像格式。重要的是要記住,從頻域恢復圖像時,需要同時使用這兩張圖像。因此,如果您打算將它們用於圖像重建,那麼儲存一張圖像並丟棄另一張圖像是沒有用的。

僅顯示強度或相位的圖像

最後,讓我們嘗試僅從幅度分量或僅從相位分量重建圖像。

  magick lena_fft_0.png  -size 128x128 xc:'gray(50%)' \
                                                  -ift lena_magitude_only.png

  magick -size 128x128 xc:gray1  lena_fft_1.png  -ift lena_phase_only.png
[IM Output]
僅限幅度
[IM Output]
僅限相位
由此可知,實際上是相位圖像包含了圖像大部分的位置信息,而幅度圖像則包含了大部分的顏色信息。 這並不完全絕對,因為信息之間存在一些重疊,但通常情況下是這樣的。 “僅幅度” 圖像的角落始終是白色的,因為使用了恆定的 50% 相位圖像。 您可以使用隨機相位圖像來移除這些白色斑塊。 但是,請確保中心像素的相位是完美的 50% 灰色,否則整個圖像會變暗。 “僅相位” 圖像使用恆定的 1% 灰色(幾乎是純黑色)幅度圖像進行轉換。 即使幅度恆定,它仍然會產生非常強烈的像素斑塊,尤其是在邊緣處。 您只需記住,需要這兩張圖像才能重建原始圖像。

頻譜圖像

您會注意到幅度圖像(第一張或第零張圖像)看起來幾乎完全是黑色的。 它實際上不是,但對我們的眼睛來說,所有值都非常非常小。 這樣的圖像研究起來並不有趣,所以讓我們使用對數變換來增強結果,以生成“頻譜”圖像。 這是通過將強對數變換評估應用於歸一化“幅度”圖像來完成的。

  magick lena_fft_0.png -auto-level -evaluate log 10000 \
          lena_spectrum.png
[IM Output] ==> [IM Output]
現在我們可以看到幅度圖像頻譜版本的細節。 您甚至可能會在頻譜圖像中看到一些特定的顏色,但通常這些顏色在頻譜圖像中並不重要。 更重要的是每個頻率的整體強度及其產生的模式。 因此,您可能還希望在增強後對頻譜圖像進行灰度化。 您需要使用多少對數增強取決於圖像,因此您應該調整它,直到獲得足夠的細節以清楚地看到圖像頻譜的模式。
或者,您可以使用以下小型 shell 腳本來計算用於特定幅度圖像的對數縮放因子

  scale=`magick lena_fft_0.png -auto-level \
          -format "%[fx:exp(log(mean)/log(0.5))]" info:`
  magick lena_fft_0.png -auto-level \
          -evaluate log $scale    lena_spectrum_auto.png
[IM Output]
但是請記住,您不能將頻譜圖像用於反向“-ift”變換,因為它會產生過亮的圖像。

  magick lena_spectrum.png lena_fft_1.png -ift lena_roundtrip_fail.png
基本上,當您增強“幅度”圖像時,您也以相同的方式增強了生成的圖像,從而產生了顯示的嚴重“裁剪”結果。
[IM Output]

HDRI FFT 圖像

當我們將傅立葉變換的結果映射到圖像表示時,我們將值從浮點“複數”縮放並轉換為整數圖像值。 這自然會產生捨入誤差和其他“量子”效應,尤其是在較小的低頻幅度中。 如果準確性在您的圖像處理中很重要,那麼您將需要使用位元深度(例如 ImageMagick 的 Q32 或 Q64 位元版本),或者最好使用HDRI 版本 ImageMagick,以便將值存儲為浮點數。 當將 IM 的 HDRI 版本與傅立葉變換的幅度和相位表示一起使用時,幅度分量仍然都是正值,因此仍然可以如上所示使用,只是更加精確。 但是,相位分量仍將如前所示進行偏差和縮放。 換句話說,HDRI 中的幅度和相位表示完全相同,只是更加準確。
例如,在這裡我使用HDRI 版本 ImageMagick來生成圖像的另一個“往返”轉換。

  # HDRI version of IM used
  time magick lena.png -fft -ift lena_roundtrip_hdri.png


echo -n "RMSE = "
magick compare -metric RMSE lena.png lena_roundtrip_hdri.png null:
echo -n "PAE = "
magick compare -metric PAE lena.png lena_roundtrip_hdri.png null:
[IM Output]
[IM Text]
如果您將上面的結果與之前的非 HDRI 比較進行比較...
[IM Text]
您會看到 HDRI 版本的 IM 生成的結果更精確,速度與之前大致相同(速度可能會因您的電腦而異)。雖然它會比普通的 Q16 IM 需要更多記憶體(請參閱編譯時品質)。然而,此類影像雖然更精確地表示影像 FFT 的頻率分量,但可能包含負值和小數值,只能使用能夠處理浮點值的特殊HDRI 相容檔案格式來儲存。
與浮點數相容的檔案格式包括「MIFF」、「TIFF」、「PFM」和 HDRI 專用的「EXR」檔案格式。但是您可能需要設定「-define quantum:format=floating-point」才能使其運作。
在後面的範例中,處理影像的 FFT 將需要這樣的精度才能產生良好的結果。因此,隨著我們繼續使用快速傅立葉變換,HDRI 版本的 ImageMagick將成為必要條件。

FFT 作為實部和虛部

到目前為止,我們只看到了傅立葉變換影像的「幅度」和「相位」表示。但是,如果您已經編譯了HDRI 版本的 IM,則也可以使用浮點「實數」和「虛數」分量來處理影像。這是透過使用選項「+fft」和「+ift」的「加號」版本來完成的。例如,這裡我使用HDRI 版本的 IM來執行影像的「往返」FFT,但這次會產生實數/虛數影像。

  # HDRI version of IM used
  time magick lena.png   +fft +ift   lena_roundtrip_ri.png


echo -n "RMSE = "
magick compare -metric RMSE lena.png lena_roundtrip_ri.png null:
echo -n "PAE = "
magick compare -metric PAE lena.png lena_roundtrip_ri.png null:
[IM Output]
[IM Text]
當您使用加號形式產生實數/虛數 FFT 影像時,必須使用 HDRI 版本。如果您不這樣做,大約有一半的值會是零,導致影像看起來「髒髒的」。例如...

  # non-HDRI Q16 version of IM used  -- THIS IS BAD
  magick lena.png   +fft +ift   lena_roundtrip_ri_bad.png
[IM Output]
要記住的另一件事是,您產生的任何形式的 FFT 影像也會影響您想要套用至 FFT 影像的所有影像處理操作。它們是非常不同的影像,因此必須以非常不同的方式,使用不同的數學運算來處理它們。同樣地,和以前一樣,您必須同時擁有實數和虛數分量影像才能還原最終影像。例如,以下說明了如果我們用「黑色」影像替換其中一個分量會發生什麼情況。

  # HDRI version of IM used
  magick lena.png +fft -delete 1 \
          -size 128x128 xc:black +ift lena_real_only.png
  magick lena.png +fft -delete 0 \
          -size 128x128 xc:black +ift lena_imaginary_only.png
[IM Output]
僅限實數
[IM Output]
僅限虛數
從這裡您可以看到,實數/虛數 FFT 影像都相當平均地包含了原始影像的重要資訊。兩者之間最大的區別在於特殊的 DC 或「平均顏色」沒有虛數分量,因此只存在於幅度影像中。您在兩個影像中看到的對角鏡像(實際上是 180 度旋轉)效應是由於另一個分量中包含的「符號」資訊遺失所造成的。如果沒有另一個分量,則可以將波形視為相位相差 180 度,並產生這種奇怪的外觀。這種資訊損失在兩種影像類型之間是相等的。

傅立葉變換的性質

常數圖像的 FFT

讓我們示範其中的一些性質。首先,讓我們簡單地取一個恆定顏色的影像並取得其幅度。

  magick -size 128x128 xc:gold constant.png
  magick constant.png -fft +delete constant_magnitude.png
[IM Output] ==> [IM Output]
請注意,在這種情況下,幅度影像實際上是純黑色的,除了影像正中央、像素位置寬度/2、高度/2 處的一個彩色像素。這個像素是影像的零頻率或 DC(「直流電」)值,並且是不表示正弦波的一個像素。換句話說,這個值就是 FFT 常數分量!
為了更清楚地看到這個像素,讓我們放大影像的該區域...

  magick constant_magnitude.png -gravity center -extent 5x5 \
           -scale 2000% constant_dc_zoom.gif
[IM Output]
請注意,DC 點的顏色與原始圖像相同。實際上,請務必牢記您所看到的是三個值。也就是說,生成的圖像實際上是三個獨立的快速傅立葉變換。紅色、綠色和藍色圖像通道各有一個 FFT。FFT 本身並不真正了解顏色,只了解顏色值或「灰度」。事實上,FFT 變換可以應用於幾乎任何色彩空間,因為實際上... 它不在乎!對於傅立葉變換來說,圖像只是一個值陣列,僅此而已。
雖然 DC 值的「相位」並不重要,但它應該始終是「零」角度(相位顏色值為 50% 灰色)。如果未設定為 50% 灰色,則 DC 值將具有「非實數」分量,並且其值會根據給定的角度進行調製。

直流顏色的影響

在更典型的非恆定圖像中,DC 值是圖像的平均顏色。如果您將圖像完全模糊、平均或縮小到單個像素或顏色,通常應該獲得的顏色。例如,讓我們從「Lena」圖像的 FFT 中提取 DC 像素。


magick lena.png -fft +delete lena_magnitude.png magick lena_magnitude.png -gravity center -extent 1x1 \ -scale 60x60 lena_dc_zoom.gif
[IM Output] ==> [IM Output] ==> [IM Output]
如您所見,圖像的平均顏色是一種「深粉色」。對這個特殊像素的另一種理解方式是,它代表中心「偏差」級別,所有其他正弦波圍繞該級別修改圖像顏色。
例如,讓我們將「深粉色」DC 像素替換為其他顏色,例如更橙色的「番茄色」...

  magick lena.png -fft \
          \( -clone 0  -draw "fill tomato  color 64,64 point" \) \
          -swap 0 +delete -ift lena_dc_replace.png
[IM Output]
實際發生的是,通過更改 FFT 圖像中的 DC 值,您正在以相同的方式更改整個圖像。實際上,DC 值的任何變化(差異)都將加到(或減去)結果圖像中的每個像素。這就好像我們真的在原始圖像中的每個像素上添加了一些常數。因此,重建圖像中的最終像素顏色也可能被最大值(白色)或最小值(黑色)限制所裁剪。因此,這不是一種推薦的圖像顏色著色方法。這比修改整個圖像中的每個像素更簡單,儘管 FFT 來回行程將使其成為一種整體上更慢的顏色著色技術。

正弦波圖像的頻譜

接下來,讓我們看一下具有 4 個週期的單個正弦(或餘弦)波圖像的光譜

  magick -size 128x129 gradient: -chop 0x1 -rotate 90 -evaluate sine 4 \
          sine4.png
  magick sine4.png -fft +delete \
          -auto-level -evaluate log 100  sine4_spectrum.png
[IM Output] ==> [IM Output]
以上漸變圖像的特殊創建方式是必要的,以確保生成的正弦波圖像在整個圖像中完美平鋪。

普通的「漸變:」圖像無法完美平鋪,因此由其生成的正弦波也無法完美平鋪。這種不完美平鋪的 FFT 變換將導致一系列不希望有的諧波,而不是傅立葉變換光譜中的單個「點」。

有關此問題的更多詳細信息,請參閱生成完美漸變

在上面的頻譜圖像(增強後的強度圖像)中,我們可以看到它有 3 個點。中間的點像以前一樣是平均直流值。另外兩個點代表傅立葉運算符在圖像中找到的完美正弦波。由於圖像寬度上的頻率恰好是 4 個週期,因此兩個頻率像素恰好距離中心直流值 4 個像素。但為什麼是兩個像素?這是因為正弦單波可以用兩種完全不同的方式來描述(一種具有負方向和相位)。這兩種描述在數學上都是正確的,並且傅立葉變換無法區分它們。如果我們用一個 16 個週期的正弦波重複這個過程,我們會再次看到它有 3 個點,但這些點相距更遠。在這種情況下,側點在中心點的左側和右側間隔 16 個像素。

  magick -size 128x129 gradient: -chop 0x1 -rotate 90 -evaluate sine 16 \
          -write sine16.png -fft -delete 1 \
          -auto-level -evaluate log 100 sine16_spectrum.png
[IM Output] ==> [IM Output]
由此可見,完美的正弦波在頻譜圖像中僅用兩個點表示在適當的位置。這個位置與中心直流值的距離決定了正弦波的頻率。波長越小,頻率越高,因此這些點離直流值越遠。事實上,通過將圖像的大小除以頻率(點到中心的距離),就可以得到波的波長(波峰之間的距離)。在上述情況下:128 個像素除以 16 個週期,得到每個“波段”之間的波長為 8 個像素。這是 FFT 變換最重要的區別特徵之一。原始圖像上的小特徵圖案需要小的波長,因此需要大的頻率。這導致頻域中的大規模效應。類似地,大的特徵使用較小的頻率,因此會產生小規模的圖案,尤其是在靠近中心的區域。在傅立葉變換中...
小變大,大變小。
這是處理傅立葉變換時要記住的最重要的方面之一,因為它是從圖像中去除噪聲(小特徵)的關鍵,同時保留圖像的整體較大方面。
讓我們通過繪製它們的原始幅度(不是對數譜)來仔細觀察這三個“頻率”。

  magick sine16.png -fft -delete 1  miff:- |\
     im_profile - sine16_magnitude_pf.png
[IM Output]
請注意,直流值(圖像的平均值或偏差)的值為 1/2,這是預期的(圖像的平均值是完美的 50% 灰色),但傅立葉變換發現的兩個 16 週期正弦波的實際幅度僅為最大值的 1/4。原始正弦波的幅度實際上是 1/2,但傅立葉變換將該幅度分為兩部分,在兩個繪製的頻率波之間共享結果,因此兩個分量中的每一個的幅度僅為 1/4。那是傅立葉變換的正常部分。[IM 輸出] FFT 圖像中正負頻率的這種二元性解釋了為什麼所有 FFT 圖像頻譜(例如重複左側的 Lena 頻譜)始終關於中心對稱。對於圖像一側上的每個點,您始終會在圖像中心旋轉鏡像得到一個相似的“點”。同樣的事情也發生在 FFT 圖像對的“相位”分量上,但值也發生了 180 度的偏移(負相位)。這意味著每個圖像的一半實際上是另一半的複製品,但您需要兩個圖像才能重新創建原始圖像。換句話說,這兩個圖像仍然包含完全相同的信息量,一半在一個圖像中,一半在另一個圖像中。它們一起產生一個整體。
在生成過程中,FFT 算法僅生成圖像的左半部分。另一半是通過旋轉和複製生成的數據生成的。

將頻域圖像轉換回空間域圖像時,算法再次只查看圖像的左半部分。右半部分完全被忽略,因為它只是一個副本。

因此,當您(在後面的範例中)對 FFT 幅度圖像進行「陷波濾波」時,您只需要過濾幅度圖像的左側。您也可以忽略右半邊來節省一些工作量。但是為了清楚起見,我將「陷波」兩半。

直接產生 FFT 圖像

現在我們可以使用上述信息來實際生成正弦波的圖像。您需要做的就是創建一對黑色和 50% 灰度的圖像對,並添加具有適當幅度和相位的「點」。例如...

  magick -size 128x128  xc:black \
          -draw 'fill gray(50%)  color 64,64 point' \
          -draw 'fill gray(50%)  color 50,68 point' \
          -draw 'fill gray(25%)  color 78,60 point' \
          generated_magnitude.png
  magick generated_magnitude.png \
          -auto-level -evaluate log 3  generated_spectrum.png
  magick -size 128x128  xc:gray50  generated_phase.png
  magick generated_magnitude.png generated_phase.png \
          -ift  generated_wave.png
[IM Output] [IM Output] ==> [IM Output]
然後,一個完美的角度(和可平鋪)正弦波就出現了。當然,您只能在特定頻率下生成完美的正弦波,並且只能在方形圖像中平鋪(除非以後調整大小)。不幸的是,所有頻率在任何水平或垂直方向上也將是 2 的冪,這是此技術的主要限制。
實際上,只需要第一個(最左側)「gray25」點來生成正弦波,因為 IFT 變換完全忽略了圖像的右半部分,因為這應該只是左半部分的旋轉鏡像。
DC 值的相位必須具有「零角度」(50% 灰色)。如果您不確保這種情況,則 DC 色彩值將通過其非零相位進行調製,從而產生更暗、可能「裁剪」的圖像。
相位中的其他像素可以是您喜歡的任何灰度級別,並且將有效地「滾動」圖像上的正弦波。同樣,只有最左側點的相位才真正重要。右側完全被忽略。只需確保中心 DC 相位像素保持 50% 灰色。

未來:使用 FFT 的 Perlin 雜訊產生器

垂直線的光譜

顯示細線和粗線的 FFT 光譜 演示圖像的 FFT 中小特徵如何變「大」,大特徵如何變「小」。將其鏈接到可以被視為具有單一諧波的「線」的正弦波。 旋轉線

矩形圖案圖像的光譜

接下來,讓我們看看黑色背景中寬度為 8 高度為 16 的白色矩形的光譜。

  magick -size 8x16 xc:white -gravity center \
          -gravity center -background black -extent 128x128 rectangle.png
  magick rectangle.png -fft +delete \
          -auto-level -evaluate log 100 rect_spectrum.png
[IM Output] ==> [IM Output]
如您所見,生成的圖像具有非常特殊的圖案,具有許多諧波頻率。您還可以發現矩形似乎旋轉了 90 度。這是錯誤的,您所看到的是我們之前提到的相同規則.. 大特徵變小,小特徵變大。因此,矩形的較小維度變大,而較大維度變小。現在,讓我們將矩形旋轉 45 度。我們發現光譜也沿相同方向旋轉了 45 度。

  magick rectangle.png -rotate 45 -gravity center -extent 128x128 \
          -write rect_rot45.png -fft -delete 1 \
          -auto-level -evaluate log 100 rect_rot45_spectrum.png
[IM Output] ==> [IM Output]
如您所見,頻域中的旋轉相同。也就是說,某些旋轉對象的效果也將在其傅立葉變換中旋轉。但是,如果我們現在移動矩形...

  magick rectangle.png -rotate 45  -geometry +30+20 -extent 128x128 \
          -write rect_rot45off.png -fft -delete 1 \
          -auto-level -evaluate log 100 rect_rot45off_spectrum.png
[IM Output] ==> [IM Output]
頻率圖案沒有移動。那是因為所有定位信息都包含在相位圖像中。頻率圖案(幅度或其光譜)不會因其移動而改變。這種位置分離是傅立葉變換使其如此重要的關鍵特性之一。它將允許您在較大的圖像中搜索特定的圖像模式,而無需考慮產生該傅立葉光譜圖案的對象的位置。

平面圓形圖案圖像的頻譜

接下來,讓我們看一下具有白色平面圓形圖案的圖像的光譜,一種情況下直徑為 12(半徑為 6),另一種情況下直徑為 24(半徑為 12)。

  magick -size 128x128 xc:black -fill white  \
          -draw "circle 64,64 64,70" -write circle6.png -fft -delete 1 \
          -auto-level -evaluate log 100 circle6_spectrum.png

  magick -size 128x128 xc:black -fill white  \
          -draw "circle 64,64 64,76" -write circle12.png -fft -delete 1 \
          -auto-level -evaluate log 100 circle12_spectrum.png
[IM Output] ==> [IM Output]
[IM Output] ==> [IM Output]
請注意,第一張影像與我們在上面 sinc 範例中生成的影像非常接近。 然而,它有點破碎。這些偽影是由於圓圈尺寸小而發生的。由於它是以數位方式表示的,因此它的周長不是完美的圓形。我們再次看到,小的細節在變換後的頻域中變得很大。較大圓圈的變換效果更好,因為它的周長更接近於真實的圓圈。因此,我們得出結論,平面圓形的變換確實是一個 sinc 函數,並且包含較小直徑圓形的影像會產生更加分散和更寬的變換特徵。 根據傅立葉變換的數學性質,從中心到頻譜中第一個暗環中間的距離將是 1.22*N/d。當圓的直徑為 d=12 時,我們得到的距離為 1.22*128/12=13。同樣,當圓的直徑為 d=24 時,我們得到的距離為 1.22*128/24=6.5。

高斯圖案影像的光譜

接下來,讓我們看看兩張影像的光譜,每張影像都有一個白色高斯圓形圖案,sigma 分別為 8 和 16

  magick -size 128x128 xc:black -fill white \
          -draw "point 64,64" -gaussian-blur 0x8 -auto-level \
          -write gaus8.png -fft -delete 1 \
          -auto-level -evaluate log 1000 gaus8_spectrum.png

  im_profile -s gaus8.png gaus8_pf.gif
  im_profile -s gaus8_spectrum.png gaus8_spectrum_pf.gif
[IM Output] ==> [IM Output]
[IM Output] ==> [IM Output]

  magick -size 128x128 xc:black -fill white \
          -draw "point 64,64" -gaussian-blur 0x16 -auto-level \
          -write gaus16.png -fft -delete 1 \
          -auto-level -evaluate log 1000 gaus16_spectrum.png

  im_profile -s gaus16.png gaus16_pf.gif
  im_profile -s gaus16_spectrum.png gaus16_spectrum_pf.gif
[IM Output] ==> [IM Output]
[IM Output] ==> [IM Output]
除了圖案矩形陣列產生的雜訊外,結果是高斯圖案產生了幾乎相同的高斯頻率圖案。更重要的是,該圖案在外观上非常乾淨。當然,大小也有所不同,同樣遵循相同的規則,大變小,小變大。根據數學性質,頻譜中的 sigma 將僅為 N/(2*sigma),其中 sigma 來自原始影像。因此,對於大小為 N=128 且 sigma=8 的影像,頻譜中的 sigma 將為 128/16=8。類似地,如果影像的 sigma 為 16,則頻譜中的 sigma 將為 128/32=4。這是“大變小,反之亦然”規則的數學關係,了解它會很有用。

網格圖案圖像的頻譜

接下來,讓我們變換一張僅包含一組間隔 16x8 像素的網格線的影像。

  magick -size 16x8 xc:white -fill black \
          -draw "line 0,0 15,0" -draw "line 0,0 0,7" \
          -write mpr:tile +delete \
          -size 128x128 tile:mpr:tile \
          -write grid16x8.png -fft -delete 1 \
          -auto-level -evaluate log 100000 grid16x8_spectrum.png
[IM Output] ==> [IM Output]
產生的光譜只是一個點陣列,其中間距較小的網格線產生的點間距較大,反之亦然。根據上面的性質,由於網格線間隔 16x8 像素,因此點的間距應為 N/a=128/16=8 和 M/b=128/8=16,這正是此影像中測量的結果。這種圖案特別重要,因為它可以讓您了解傅立葉變換與影像中規則平鋪圖案的關係。這種平鋪圖案在其傅立葉變換中會產生非常強的非中心網格圖案。這裡的關鍵是形狀信息位於中心,而平鋪信息位於遠離其傅立葉變換中心的網格狀陣列中。

更多光譜信息

如果您想了解更多有關光譜影像及其特性的信息,請訪問以下鏈接。

實際應用

好的,既然我們已經介绍了基礎知識,那麼使用傅立葉變換的實際應用有哪些?可以完成的事情包括:1) 增加或減少影像的對比度,2) 模糊,3) 銳化,4) 邊緣檢測和 5) 雜訊去除。

改變圖像的對比度 - 係數開根號

可以通過執行正向傅立葉變換、將幅度影像提高到冪,然後將其與反向傅立葉變換中的相位一起使用來調整影像的對比度。要增加對比度,可以使用略小於 1 的指數;要降低對比度,可以使用略大於 1 的指數。因此,讓我們首先使用 0.9 的指數增加 Lena 影像的對比度,然後使用 1.1 的指數降低對比度。

  magick lena.png -fft \
          \( -clone 0 -evaluate pow 0.9 \) -delete 0 \
          +swap -ift lena_plus_contrast.png

  magick lena.png -fft \
          \( -clone 0 -evaluate pow 1.1 \) -delete 0 \
          +swap -ift lena_minus_contrast.png
[IM Output] ==> [IM Output]
[IM Output] ==> [IM Output]
但是,對原始圖像執行此操作與對原始圖像執行此操作的效果相同。也就是說,對強度進行全局修改與對原始圖像進行全局修改的效果相同。

模糊圖像 - 低通濾波

傅立葉變換最重要的特性之一是空間域中的卷積等效於頻域中的簡單乘法。在空間域中,可以使用小的、方形的、簡單的卷積濾波器(內核)通過 -convole 選項對圖像進行模糊處理。這稱為低通濾波器。最簡單的濾波器只是一個等加權的方形陣列。也就是說,所有值都是 1,在應用卷積之前通過除以它們的總和進行歸一化。這相當於局部或鄰域平均值。另一個低通濾波器是由 -gaussian-blur-blur 提供的高斯加權圓形濾波器。在頻域中,一種低通模糊濾波器只是一個被黑色包圍的恆定強度的白色圓圈。這類似於空間域中的圓形平均卷積濾波器。但是,由於空間域中的卷積等效於頻域中的乘法,因此我們只需要執行正向傅立葉變換,然後將濾波器與強度圖像相乘,最後執行反向傅立葉變換。我們注意到,小型卷積濾波器將對應於頻域中的大圓圈。乘法是通過 -composite-compose 乘法設置來執行的。因此,讓我們嘗試使用兩種尺寸的圓形濾波器來做到這一點,一種直徑為 40(半徑為 20),另一種直徑為 28(半徑為 14)。

  magick -size 128x128 xc:black -fill white \
          -draw "circle 64,64 44,64" circle_r20.png
  magick lena.png -fft \
       \( -clone 0 circle_r20.png -compose multiply -composite \) \
       \( +clone -evaluate log 10000 -write lena_blur_r20_spec.png +delete \) \
       -swap 0 +delete -ift lena_blur_r20.png

  magick -size 128x128 xc:black -fill white \
          -draw "circle 64,64 50,64" circle_r14.png
  magick lena.png -fft \
       \( -clone 0 circle_r14.png -compose multiply -composite \) \
       \( +clone -evaluate log 10000 -write lena_blur_r14_spec.png +delete \) \
       -swap 0 +delete -ift lena_blur_r14.png
[IM Output] ==> [IM Output] x [IM Output] ==> [IM Output] ==> [IM Output]
[IM Output] ==> [IM Output] ==> [IM Output]
因此,我們可以看到使用較小直徑濾波器的圖像產生了更多的模糊。我們還注意到結果圖像中邊緣附近的“振鈴”或“波紋”效應。發生這種情況是因為圓的傅立葉變換,正如我們之前看到的,是一個 Jinc 函數,它隨著從中心向外移動而振盪減小。然而,這裡的 Jinc 函數和振盪是在空間域而不是頻域中,正如我們之前在上面演示的那樣。那麼我們該怎麼辦呢?最簡單的方法是使用各種 加窗函數 來縮減圓形的邊緣。或者,可以使用已經根據定義縮減的高斯形狀等濾波器。因此,讓我們執行後者,並使用兩個高斯模糊圓圈來消除大多數嚴重的“振鈴”效應。

  magick circle_r20.png -blur 0x4 -auto-level gaussian_r20.png
  magick lena.png -fft \
       \( -clone 0 gaussian_r20.png -compose multiply -composite \) \
       \( +clone -evaluate log 10000 -write lena_gblur_r20_spec.png +delete \) \
       -swap 0 +delete -ift lena_gblur_r20.png

  magick circle_r14.png -blur 0x4 -auto-level gaussian_r14.png
  magick lena.png -fft \
       \( -clone 0 gaussian_r14.png -compose multiply -composite \) \
       \( +clone -evaluate log 10000 -write lena_gblur_r14_spec.png +delete \) \
       -swap 0 +delete -ift lena_gblur_r14.png
[IM Output] ==> [IM Output] x [IM Output] ==> [IM Output] ==> [IM Output]
[IM Output] ==> [IM Output] ==> [IM Output]
這當然好多了。理想的低通濾波器根本不是模糊圓圈,而是實際使用 sigma 的適當高斯曲線而不是 radius。當然,在這個例子中,我們最終進行了模糊處理,以進行模糊處理!但是,用於乘以 FFT 強度圖像的模糊模式是固定的,實際上可以從預先生成的緩存中檢索。此外,乘法圖像不需要與原始圖像的大小相同,您可以使用較小的圖像。因此,對於大型圖像以及處理大量圖像的情況,上述操作可能會快很多。更重要的一點是,對於較大的強模糊,頻域圖像很小,並且只進行一次乘法,而不必像原始圖像中的每個像素那樣對大量像素求平均值。對於小尺寸的模糊,直接使用卷積模糊可能會更好。

偵測圖像中的邊緣 - 高通濾波

在空間域中,從圖像中提取邊緣的高通濾波器通常以帶有正負權重的卷積實現,使得它們的總和為零。在頻域中,事情就簡單多了。這裡的高通濾波器只是低通濾波器的反轉版本。也就是說,低通濾波器亮的地方,高通濾波器就暗,反之亦然。所以在 ImageMagick 中,我們只需要 反轉 低通濾波器圖像即可。讓我們使用圓形圖像對 Lena 圖像應用高通濾波器。然後再使用純高斯曲線。

  magick circle_r14.png -negate circle_r14i.png
  magick lena.png -fft \
       \( -clone 0 circle_r14i.png -compose multiply -composite \) \
       \( +clone -evaluate log 10000 -write lena_edge_r14_spec.png +delete \) \
       -delete 0 +swap -ift -normalize lena_edge_r14.png

  magick -size 128x128 xc: -draw "point 64,64" -blur 0x14 \
          -auto-level   gaussian_s14i.png
  magick lena.png -fft \
       \( -clone 0 gaussian_s14i.png -compose multiply -composite \) \
       \( +clone -evaluate log 10000 -write lena_edge_s14_spec.png +delete \) \
       -delete 0 +swap -ift -normalize lena_edge_s14.png
[IM Output] ==> [IM Output] x [IM Output] ==> [IM Output] ==> [IM Output]
[IM Output] ==> [IM Output] ==> [IM Output]
仔細觀察這兩個結果,我們會發現簡單的圓形不如高斯曲線好,因為它有「振鈴」偽影,而且不夠銳利。

銳化圖像 - 高增益濾波

銳化圖像最簡單的方法是對其進行高通濾波(不進行歸一化拉伸),然後將其與原始圖像混合。

  magick lena.png -fft \
       \( -size 128x128 xc: -draw "point 64,64" -blur 0x14 -auto-level \
          -clone 0 -compose multiply -composite \) \
       -delete 0 +swap -ift \
       lena.png -compose blend -set option:compose:args 100x100 -composite \
       lena_sharp14.png
[IM Output] ==> [IM Output]
這裡在頻域中完成高通濾波,並將結果轉換回空間域,在空間域中將其與原始圖像混合,以增強圖像的邊緣。

雜訊去除 - 陷波濾波

許多噪聲圖像都包含某種模式的噪聲。這種噪聲在頻域中很容易去除,因為模式顯示為幾個點或線的模式。回想一下,簡單的正弦波是一種重複的模式,在頻譜中僅顯示為 3 個點。為了消除這種噪聲,人們只需要(但遺憾的是)在幅度圖像中手動遮罩(或切除)點或線。我們通過轉換到頻域、創建頻譜的灰度版本、遮罩點或線、對其進行閾值處理、將二進制遮罩圖像與幅度圖像相乘,然後轉換回空間域來做到這一點。讓我們在 小丑圖像 上嘗試一下,該圖像包含對角條紋狀的抖動模式。首先,我們對小丑圖像進行變換,以創建其幅度和相位圖像。

  magick clown_orig.jpg -fft \
          \( +clone  -write clown_phase.png +delete \) +delete \
          -write clown_magnitude.png  -colorspace gray \
          -auto-level -evaluate log 100000  clown_spectrum.png
[IM Output]
原始影像
==> [IM Output]
頻譜
[IM Output]
相位
我們可以看到頻譜包含四個明亮的星形點,每個象限中一個。這些不尋常的點代表了我們想要去除的圖像中的模式。圖像中間的亮點和線無關緊要,因為它們代表直流電(平均圖像顏色)以及圖像邊緣的影響,不應修改。請注意,在生成頻譜圖像時,我強制生成的圖像是純灰度圖像。這樣我就可以將圖像加載到編輯器中,並使用任何非灰色(例如紅色)遮罩掉這 4 個星形圖案的區域。完成編輯後,我可以通過提取與未編輯版本的差異圖像來提取我著色的區域。像這樣...

  magick clown_spectrum_edited.png clown_spectrum.png \
          -compose difference -composite \
          -threshold 0 -negate clown_spectrum_mask.png
[IM Output] ==> [IM Output]
現在我們只需將遮罩與幅度相乘,並使用結果與原始相位圖像一起轉換回空間域。我們將原始圖像顯示在它旁邊以進行比較。

  magick clown_magnitude.png clown_spectrum_mask.png \
          -compose multiply -composite \
          clown_phase.png -ift clown_filtered.png
[IM Output] ==> [IM Output]
結果非常好。但我們可以做得更好。正如您在前面的示例中所見,簡單的“圓形”對 FFT 圖像不是特別友好,所以讓我們稍微模糊一下遮罩...

  magick clown_spectrum_mask.png \
          -blur 0x5 -level 50x100%  clown_mask_blurred.png
[IM Output]
並過濾小丑,這次在內存中重新生成 FFT 圖像。

  magick clown_orig.jpg -fft \
          \( -clone 0 clown_mask_blurred.png -compose multiply -composite \) \
          -swap 0 +delete -ift clown_filtered_2.png
[IM Output]
結果簡直太神奇了!通過調整遮罩以更好地擬合“星形”形狀,結果可能會進一步改善。
我們甚至可以取原始圖像和結果圖像之間的差異,以創建一個顯示已去除噪聲區域的圖像。

  magick clown_orig.jpg clown_filtered_2.png -compose difference \
          -composite -normalize clown_noise.png
[IM Output]
讓我們在另一個例子上試試這個。這次是在 RoboRealm 網站上找到的“樹枝”圖像上,該圖像包含水平和垂直條紋的不規則圖案。我們再次提取灰度頻譜圖像,就像我們之前做的那樣。

  magick twigs.jpg -fft +delete -colorspace gray \
          -auto-level -evaluate log 100000 twigs_spectrum.png
[IM Output] ==> [IM Output]
在這種情況下,由於圖像中的雜訊是水平和垂直方向的,因此會顯示為沿中心線的粗水平和垂直條帶,但不會顯示在圖像的實際中心。我們再次使用圖像編輯器遮罩掉這些部分,這次使用“藍色”(實際上使用哪種顏色並不重要)……

  magick twigs_spectrum_edited.png twigs_spectrum.png \
          -compose difference -composite \
          -threshold 0 -negate twigs_spectrum_mask.png
[IM Output] ==> [IM Output]
現在我們再次將遮罩與 FFT 幅度圖像相乘,然後重建圖像。

  magick twigs.jpg -fft \
          \( -clone 0 twigs_spectrum_mask.png -compose multiply -composite \) \
          -swap 0 +delete  -ift twigs_filtered.png
[IM Output] ==> [IM Output]
我們可以取原始圖像和結果圖像之間的差異,以創建一個顯示已去除雜訊區域的圖像。

  magick twigs.jpg twigs_filtered.png -compose difference -composite \
          -normalize twigs_noise.png
[IM Output]
對遮罩添加一點模糊可以進一步改善結果。作為練習,嘗試從圖像中移除字符串。提示:請記住真實圖像中線條的效果在 FFT 中旋轉了 90 度。如果您弄錯了,您可能會移除樹枝。

進階應用

使用傅立葉變換的其他一些更進階的應用包括:1) 對運動模糊和散焦圖像進行反捲積(去模糊)和 2) 歸一化互相關以找到小圖像在較大圖像中的最佳匹配位置。FFT 乘法和除法(反捲積)的示例已移至 子目錄,因為它正在等待更正式定義的圖像處理運算符。