ImageMagick 範例 --
傅立葉乘法/除法

索引
ImageMagick 範例前言與索引
傅立葉變換
DIY FFT 數學簡介
FFT 乘法
FFT 除法


DIY FFT 數學簡介

以下是以兩種不同樣式的快速傅立葉變換影像進行乘法和除法的幾種技術範例。

基本上有兩種方法可以進行數學運算。使用 FX 數學和使用合成數學...
FX 數學
使用 FX, DIY 運算子 直接套用公式。但由於它是被解譯的,所以速度非常慢。然而,公式會在單一表達式中全部套用,避免了對中間影像的需求。對於非 HDRI 版本的 IM,這將減少量子化效應。

合成數學
這使用影像合成來執行數學運算,這比「FX 數學」快得多。但是,您一次只能執行一個數學運算,這表示每次運算後都必須將影像儲存到另一個記憶體影像中。對於非 HDRI 版本,這將在運算之間產生額外的「捨入效應」。

上面提到的另一個方面是 HDRI 的使用。

HDRI 版本的 ImageMagick 將色彩值儲存為浮點數,而不是 QuantumRange 調整後的整數(請參閱 品質)。因此,在產生 FFT 影像或將中間結果儲存到新影像時,不會造成「捨入效應」,尤其是在涉及小數值時(FFT 影像中很常見)。

此外,由於實部/虛部 FFT 影像對需要使用負數,因此在處理這些類型的 FFT 影像時,您必須使用 HDRI 版本的 ImageMagick。

然而,負數對於幅度/相位 FFT 影像來說不是問題,因此您可以不使用 HDRI 處理此類影像,但您在每個影像處理步驟之間仍會遇到強烈的「捨入效應」。

因此,無論您使用哪種 FFT 影像類型,快速傅立葉變換都最適合用於 HDRI 版本的 ImageMagick。

將中間 HDRI 影像儲存到磁碟檔案時,您需要使用極少數的浮點影像檔案格式之一。這些格式包括 NetPBM PFM 檔案格式、TIFF 或具有特殊設定 "-define quantum:format=floating-point" 的 MIFF 檔案格式。


以下是我們將使用的捲積核影像...

  # motion blur kernel
  #magick -size 128x128 xc:black -fill white -draw 'line 60,64 68,64' \
  #        -alpha off convolve_kernel.png

  # disk blur kernel (Fred Wienhaus's version)
  magick -size 128x128 xc:black -fill white -draw 'circle 64,64 54,64' \
          -alpha off convolve_kernel.png

[IM Output]

必須捲動捲積核,以便像素 0,0 包含捲積的中心。在這種情況下,讀取核心影像後,需要立即套用 "-roll -64-64"。

核心影像也需要除以其平均值,以便保留與其進行 FFT 乘法或除法的影像的強度。這是 FFT 乘法和除法的一個主要複雜因素。

由於非 HDRI 影像無法以這種方式正規化,因此通常在套用 FFT 轉換之後和乘法之前完成此操作。

對於 HDRI 版本的 IM,您可以在任何時候執行此操作。


FFT 乘法  ( )

使用 IM Q16 的幅度/相位影像的 FFT 乘法

    R = A  B       ( FFT Multiply )

    Rm = Am × Bm
    Rp = mod( Ap + Bp +0.5, 1.0)

    mean = the DC value (center pixel) of the magnitude image
使用 FX 數學,
(注意值 v.p{64x64} 是捲積核的 DC 或平均值)

  # non-HDRI
  magick convolve_kernel.png -roll -64-64 -fft \
          \( cameraman_sm.png -fft \) \
          \
          \( -clone 0,2 -fx 'u*v / p{64,64} ' \) \
          \( -clone 1,3 -fx 'mod(u + v + 0.5, 1.0)' \) \
          \
          -delete 0-3 -ift  cameraman_convolve_1.png
[IM Output] [IM Output] ==> [IM Output]

使用合成數學...

  # non-HDRI
  magick convolve_kernel.png -roll -64-64 -fft \
          \( -clone 0 -crop 1x1+64+64 +repage -scale 128x128 \
             -clone 0 -compose divide -composite \) -swap 0 +delete \
          \( cameraman_sm.png -fft \) \
          \
          \( -clone 0,2 -compose multiply -composite \) \
          \( -clone 1,3 -compose add -background gray50 -flatten \) \
           -delete 0-3 -ift  cameraman_convolve_2.png
[IM Output] [IM Output] ==> [IM Output]

請注意,「加法」是一種模數加法合成,它用於將值加上 50% 的偏置值,以產生 50% 的偏置值。

替代方案
用原始影像的平均值除

  # non-HDRI
  magick convolve_kernel.png \( -clone 0 -roll -64-64 -fft \) \
          \( -clone 0 -scale 1x1 -scale 128x128 \
             -clone 1 -compose divide -composite \) \
          -delete 0,1 +swap \
          \( cameraman_sm.png -fft \) \
          \
          \( -clone 0,2 -compose multiply -composite \) \
          \( -clone 1,3 -compose add -background gray50 -flatten \) \
           -delete 0-3 -ift  cameraman_convolve_2b.png
[IM Output] [IM Output] ==> [IM Output]

替代方案...
請注意,直流值除以直流值 ==> 1.0

由於直流值是幅度譜中的最大值,為何不直接歸一化!例如:-auto-level"

這只能對幅度影像進行,而不能對實部/虛部對進行,因為它們必須被相同程度地拉伸。


  # non-HDRI
  magick convolve_kernel.png -roll -64-64 -fft \
          \( -clone 0 -auto-level \) -swap 0 +delete \
          \( cameraman_sm.png -fft \) \
          \
          \( -clone 0,2 -compose multiply -composite \) \
          \( -clone 1,3 -compose add -background gray50 -flatten \) \
          \
          -delete 0-3 -ift  cameraman_convolve_2c.png
[IM Output] [IM Output] ==> [IM Output]

實部/虛部影像的 FFT 相乘,使用 IM HDRI

    R = A  B       ( FFT Multiply )

    Rr = Ar×Br - Ai×Bi
    Ri = Ar×Bi + Ai×Br

    mean = the DC value (center pixel) of the real image
使用 FX...
涉及 5 張影像,第 5 張是縮放後的平均值 - FX 進行除法

  # HDRI
  magick convolve_kernel.png -roll -64-64 \( +clone +fft \) \
          \( cameraman_sm.png +fft \) +matte \
          \( -clone 0 -scale 1x1 \) -delete 0 \
          \
          \( -clone 0-4 -fx '( u[0]*u[2] - u[1]*u[3] ) / u[4].p{0,0}' \) \
          \( -clone 0-4 -fx '( u[0]*u[3] + u[1]*u[2] ) / u[4].p{0,0}' \) \
          -delete 0-4 +ift  cameraman_convolve_3.png
[IM Output] [IM Output] ==> [IM Output]

使用 FX...
使用直流值作為平均值(沒有第 5 張影像)

  # HDRI
  magick convolve_kernel.png -roll -64-64 +fft \
          \( cameraman_sm.png +fft \) \
          \
          \( -clone 0-3 -fx '( u[0]*u[2] - u[1]*u[3] ) / u[0].p{64,64}' \) \
          \( -clone 0-3 -fx '( u[0]*u[3] + u[1]*u[2] ) / u[0].p{64,64}' \) \
          -delete 0-3 +ift  cameraman_convolve_3b.png
[IM Output] [IM Output] ==> [IM Output]

使用合成數學...
使用縮放影像的平均值!

  # HDRI
  magick convolve_kernel.png -roll -64-64 \
          \( -clone 0 -scale 1x1 -scale 128x128 \) \
          \( -clone 0 +fft \) \
          \( -clone 1,2 -compose divide -composite \) \
          \( -clone 1,3 -compose divide -composite \) \
          -delete 0--3 \
          \
          \( cameraman_sm.png  +fft \) \
          \
          \( -clone 0,2 -compose multiply -composite \) \
          \( -clone 1,3 -compose multiply -composite \) \
          \( -clone 0,3 -compose multiply -composite \) \
          \( -clone 1,2 -compose multiply -composite \) \
          \
          \( -clone 4,5 +swap +matte -compose minus -composite \) \
          \( -clone 6,7 -compose plus -composite \) \
          \
          -delete 0--3 +ift  cameraman_convolve_4.png
[IM Output] [IM Output] ==> [IM Output]

優化的合成數學...
從影像縮放得到的平均值

  # HDRI
  magick convolve_kernel.png -roll -64-64 \
          \( -clone 0 -scale 1x1 -scale 128x128 \) \
          \( -clone 0 +fft    null: +insert    -clone 1 +insert \
             -compose divide -layers composite \) -delete 0,1  \
          \
          \( cameraman_sm.png +fft \) \
          \
          \( -clone 0,1,0,1 null: -clone 2,3,3,2 \
                -compose multiply -layers composite \) \
          \( -clone 4,5 +swap +matte -compose minus -composite \) \
          \( -clone 6,7 -compose plus -composite \) \
          \
          -delete 0--3 +ift  cameraman_convolve_4b.png
[IM Output] [IM Output] ==> [IM Output]

替代方案...
使用直流值作為平均值...

  # HDRI
  magick convolve_kernel.png -roll -64-64 +fft \
          \( -clone 0 -crop 1x1+64+64 +repage -scale 128x128 \) \
          null: +insert +insert   -compose divide -layers composite \
          \
          \( cameraman_sm.png +fft \) \
          \
          \( -clone 0,1,0,1 null: -clone 2,3,3,2 \
                -compose multiply -layers composite \) \
          \( -clone 4,5 +swap +matte -compose minus -composite \) \
          \( -clone 6,7 -compose plus -composite \) \
          \
          -delete 0--3 +ift  cameraman_convolve_4c.png
[IM Output] [IM Output] ==> [IM Output]

替代方案...
在 FFT 相乘之後應用直流值平均值...

  # HDRI
  magick convolve_kernel.png -roll -64-64 +fft \
          \( cameraman_sm.png  +fft \) \
          \
          \( -clone 0,1,0,1 null: -clone 2,3,3,2 \
                -compose multiply -layers composite \) \
          \( -clone 4,5 +swap -compose minus -composite \) \
          \( -clone 6,7 -compose plus -composite \) \
          \
          \( -clone 0 -crop 1x1+64+64 +repage -scale 128x128 \
             null: -clone -2,-1  -compose divide -layers composite \) \
          \
          -delete 0--3 +ift  cameraman_convolve_4d.png
[IM Output] [IM Output] ==> [IM Output]


FFT 除法  ( )

這裡我們使用除法來移除或反卷積(姑且這樣稱呼)添加到上述影像的模糊。它基本上完全相同,只是將「歸一化」的卷積核從主影像中去除。

每個範例都使用使用上述相同技術生成的影像。

幅度/相位的 FFT 除法,使用 IM Q16

    R = B ø A       ( FFT Divide )

    Rm = Bm / Am
    Rp = mod( -Ap + Bp +1.5, 1.0)

    mean = the DC value (center pixel) of the magnitude image
注意:分母中添加了最小量子尺度,以避免被零完美除法。這在稍後也會用於從影像中去除雜訊。

使用 FX 數學...

  # non-HDRI
  noise=QuantumScale
  magick convolve_kernel.png -roll -64-64 -fft \
          \( cameraman_convolve_1.png -fft \) \
          \
          \( -clone 0,2 -fx "v/(u/p{64,64}+$noise)" \) \
          \( -clone 1,3 -fx 'mod( -u + v + 1.5, 1.0)' \) \
          \
          -delete 0--3 -ift cameraman_deconvolve_1.png
[IM Output] [IM Output] ==> [IM Output]

  echo -n "Peak = "
  magick compare -metric PAE cameraman_sm.png cameraman_deconvolve_1.png null:
  echo -n "Avg = "
  magick compare -metric RMSE cameraman_sm.png cameraman_deconvolve_1.png null:
[IM Text]

使用 IM 的 HDRI 版本進行往返 MP 卷積 FFT(FX 數學)
[IM Output] ==> [IM Output] ==> [IM Output]
[IM Text]

使用合成數學...

  # non-HDRI
  noise=1
  magick convolve_kernel.png -roll -64-64 -fft \
           \( -clone 0 -crop 1x1+64+64 +repage -scale 128x128 \
              -clone 0 -compose divide -composite \) -swap 0 +delete \
          \( cameraman_convolve_2.png -fft \) \
          \
          \( -clone  0  -evaluate add $noise \
             -clone  2  -compose divide -composite \) \
          \( -clone 1,3 -compose subtract -background gray50 -flatten \) \
          \
          -delete 0--3 -ift cameraman_deconvolve_2.png
[IM Output] [IM Output] ==> [IM Output]

  echo -n "Peak = "
  magick compare -metric PAE cameraman_sm.png cameraman_deconvolve_2.png null:
  echo -n "Avg = "
  magick compare -metric RMSE cameraman_sm.png cameraman_deconvolve_2.png null:
[IM Text]

使用 IM 的 HDRI 版本進行往返 MP 卷積 FFT(合成數學)
[IM Output] ==> [IM Output] ==> [IM Output]
[IM Text]

實部/虛部的 FFT 除法,使用 IM 的 HDRI 版本

    R = B ø A       ( FFT Divide )

    Denom = Ar×Ar + Ai×Ai + noise
    Rr = ( Ar×Br + Ai×Bi ) / Denom
    Ri = ( Ar×Bi - Ai×Br ) / Denom

    mean = the DC value (center pixel) of the real image
使用 FX...

  # HDRI
  #noise=QuantumScale
  noise=Epsilon
  magick convolve_kernel.png -roll -64-64 +fft \
          \( -clone 0 -fx "u/p{64,64}" \) \( -clone 0,1 -fx "v/u.p{64,64}" \) \
          -delete 0,1 \
          \( cameraman_convolve_3.png +fft \) \
          \
          \( -clone 0-3 -fx "u[0]*u[0] + u[1]*u[1] + $noise" \) \
          \( -clone 0-3 -fx 'u[0]*u[2] + u[1]*u[3]' \) \
          \( -clone 0-3 -fx 'u[0]*u[3] - u[1]*u[2]' \) \
          \( -clone 4,5 -fx 'u==0?0:v/u' \) \
          \( -clone 4,6 -fx 'u==0?0:v/u' \) \
          \
          -delete 0--3 +ift cameraman_deconvolve_3.png
[IM Output] [IM Output] ==> [IM Output]

  echo -n "Peak = "
  magick compare -metric PAE cameraman_sm.png cameraman_deconvolve_3.png null:
  echo -n "Avg = "
  magick compare -metric RMSE cameraman_sm.png cameraman_deconvolve_3.png null:
[IM Text]

我上面使用的 -fx 除法不如合成除法好。大概是與額外的 FX 縮放有關。

  # HDRI
  #noise=QuantumScale
  noise=Epsilon
  magick convolve_kernel.png -roll -64-64 +fft \
          \( -clone 0 -fx "u/p{64,64}" \) \( -clone 0,1 -fx "v/u.p{64,64}" \) \
          -delete 0,1 \
          \( cameraman_convolve_3.png +fft \) \
          \
          \( -clone 0-3 -fx "u[0]*u[0] + u[1]*u[1] + $noise" \) \
          \( -clone 0-3 -fx 'u[0]*u[2] + u[1]*u[3]' \) \
          \( -clone 0-3 -fx 'u[0]*u[3] - u[1]*u[2]' \) \
          \( -clone 4,5 -compose divide -composite \) \
          \( -clone 4,6 -compose divide -composite \) \
          \
          -delete 0--3 +ift cameraman_deconvolve_3b.png
[IM Output] [IM Output] ==> [IM Output]

  echo -n "Peak = "
  magick compare -metric PAE cameraman_sm.png cameraman_deconvolve_3b.png null:
  echo -n "Avg = "
  magick compare -metric RMSE cameraman_sm.png cameraman_deconvolve_3b.png null:
[IM Text]

使用合成數學(詳細)...

  # HDRI
  noise=0.00000001  # Epsilon
  magick \( convolve_kernel.png -roll -64-64 +fft \
             \( -clone 0 -crop 1x1+64+64 +repage -scale 128x128 \) \
             \( -clone 2,0 -compose divide -composite \) \
             \( -clone 2,1 -compose divide -composite \) \
             -delete 0-2 \) \
          \( cameraman_convolve_4.png +fft \) \
          \
          \( -clone 0,0 -compose multiply -composite \) \
          \( -clone 1,1 -compose multiply -composite \) \
          \( -clone 0,2 -compose multiply -composite \) \
          \( -clone 1,3 -compose multiply -composite \) \
          \( -clone 0,3 -compose multiply -composite \) \
          \( -clone 1,2 -compose multiply -composite \) \
          \
          \( -clone 4,5 -compose plus  -composite -evaluate add $noise \) \
          \( -clone 6,7 -compose plus -composite \) \
          \( -clone 8,9 +swap -compose minus -composite \) \
          \
          \( -clone 10,11 -compose divide -composite \) \
          \( -clone 10,12 -compose divide -composite \) \
          \
          -delete 0--3 +ift cameraman_deconvolve_4.png
[IM Output] [IM Output] ==> [IM Output]


  echo -n "Peak = "
  magick compare -metric PAE cameraman_sm.png cameraman_deconvolve_4.png null:
  echo -n "Avg = "
  magick compare -metric RMSE cameraman_sm.png cameraman_deconvolve_4.png null:
[IM Text]

優化的合成數學...

  # HDRI
  noise=0.00000001  # Epsilon
  magick \( convolve_kernel.png -roll -64-64 +fft \
             \( -clone 0 -gravity center -extent 1x1 -scale 128x128 \) \
             null: +insert +insert -compose divide -layers composite \) \
          \( cameraman_convolve_4.png +fft \) \
          \
          \( -clone 0,1,0,1,0,1 null: -clone 0,1,2,3,3,2 \
                -compose multiply -layers composite \) \
          \( -clone 4,5 -compose plus  -composite -evaluate add $noise \) \
          \( -clone 6,7 -compose plus  -composite \) \
          \( -clone 9,8 -compose minus -composite \) \
          \( -clone 10 null: -clone 11,12 \
                -compose divide -layers composite \) \
          \
          -delete 0--3 +ift cameraman_deconvolve_4b.png
[IM Output] [IM Output] ==> [IM Output]

  echo -n "Peak = "
  magick compare -metric PAE cameraman_sm.png cameraman_deconvolve_4b.png null:
  echo -n "Avg = "
  magick compare -metric RMSE cameraman_sm.png cameraman_deconvolve_4b.png null:
[IM Text]


更新: 上述內容中使用的顏色「gray50」應改為「gray(50%)」,以產生更準確的 50% 灰色值。前一種「命名」顏色實際上只是一種 8 位元顏色,因此不太準確。

此外,對於新的色彩空間處理,gray50 位於 sRGB 色彩空間中,而 gray(50%) 位於線性色彩空間中,這是在上述計算中應該使用的。

還需要檢查範例是否使用了線性灰階色彩空間。