Simple Binary Square Pattern - Demo Magnitude And Phase Of FFT |
original image |
|
FFT to produce tiff stack of frames:
path-to-imfft/trunk/demo f square30.png
Then create magnitude and phase (below):
|
convert square30_F_Q16.tiff[0] square30_F_Q16.tiff[2] \
square30_F_Q16.tiff[4] square30_mag.png
|
convert square30_F_Q16.tiff[1] square30_F_Q16.tiff[3] \
square30_F_Q16.tiff[5] square30_phase.png
|
|
|
Linearly Stretch Magnitude: min->0%, max->100%
convert square30_F_Q16_mag.png -contrast-stretch 0% square30_F_Q16_mag_cs0.png
|
|
Generate Spectrum From Magnitude (scale=100):
convert square30_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(99*u+1)/log(100)" -fill "rgb(1,1,1)" \
-opaque black square30_F_Q16_spec100.png
|
Generate Spectrum From Magnitude (scale=1000):
convert square30_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(999*u+1)/log(1000)" -fill "rgb(1,1,1)" \
-opaque black square30_F_Q16_spec1000.png
|
|
|
Generate Nearly Equivalent Spectrum, But Faster:
convert square30_F_Q16_mag.png -contrast-stretch 0% \
-gamma 2.5 -fill "rgb(1,1,1)" -opaque black \
square30_F_Q16_spec_g2p5.png
|
Generate Nearly Equivalent Spectrum, But Faster:
convert square30_F_Q16_mag.png -contrast-stretch 0% \
-gamma 3.5 -fill "rgb(1,1,1)" -opaque black \
square30_F_Q16_spec_g3p5.png
|
|
|
Simple Patterns - Demo Of Spectra Concepts |
- High frequencies in the FFT (corresponding to rapidly varying intensities in the original image)
lie near the outer parts of the spectrum.
- Low frequencies in the FFT (corresponding to slowly varying intensities in the original image)
lie near the center of the spectrum.
- The zero frequency (DC) point in the spectrum for an NxM original image lies at coordiniage
N/2-1,M/2 in the spectrum image.
- The intensity value in the magnitude image at the DC point is equal the average graylevel
in the original image.
- Edges in an image give rise to transform components lying along lines
perpedicular to the edges.
- Smaller objects have more spread-out transforms; Larger objects have more
compressed transform.
- The transform of uniform object lies along a line perpendicular to the
dimension of the object.
- Gratings (evenly repeated grid lines) produce an array of dots perpendicular
to the grating lines.
- The transform of a constant rectangle of dimension x=a,y=b in image an size NxM is a sinc function:
sinc(pi*a/N)*sinc(pi*b/M), where sinc(x)=sin(x)/(x). The spacing between the troughs in the
spectrum will be Dx=N/a and Dy=M/b.
- The transform of a constant circle of diameter d in an image size NxN is a jinc function: jinc(pi*d/N),
where jinc(x)=J1(r)/(r) and J1(r) is the Bessel function of the first kind of order one.
The spacing from the center to the first trough in the spectrum will be Dr=1.22*N/d.
- The transform of a Gaussian (Normal) function of sigma=d in an image size NxN is a Gaussian
function. The sigma of the Gaussian function in the spectrum will be sigma=N/d.
- The transform of a set of grid lines of spacing x=a,y=b in image size NxM is an array of dots:
The spacing of the dots in the spectrum will be Dx=N/a and Dy=M/b.
|
Square
|
Generate Spectrum From Magnitude (scale=1000):
convert square30_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(999*u+1)/log(1000)" -fill "rgb(1,1,1)" \
-opaque black square30_F_Q16_spec1000.png
|
|
|
Rectangle 16x32
|
Generate Spectrum From Magnitude (scale=1000):
convert rect16x32_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(999*u+1)/log(10000)" -fill "rgb(1,1,1)" \
-opaque black rect16x32_F_Q16_spec1000.png
|
|
|
Circle Diameter 16
|
Generate Spectrum From Magnitude (scale=5000):
convert circle16_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(4999*u+1)/log(5000)" -fill "rgb(1,1,1)" \
-opaque black circle16_F_Q16_spec5000.png
|
|
|
Circle Diameter 30
|
Generate Spectrum From Magnitude (scale=5000):
convert circle30_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(4999*u+1)/log(5000)" -fill "rgb(1,1,1)" \
-opaque black circle30_F_Q16_spec5000.png
|
|
|
Circle Diameter 60
|
Generate Spectrum From Magnitude (scale=100000):
convert circle60_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(99999*u+1)/log(5000)" -fill "rgb(1,1,1)" \
-opaque black circle60_F_Q16_spec100000.png
|
|
|
Gaussian Sigma=16
|
Generate Spectrum From Magnitude (scale=100000):
convert gaussian_128_sigma16_clut_F_Q16_mag.png \
-contrast-stretch 0% -fx "log(99999*u+1)/log(100000)" \
-fill "rgb(1,1,1)" -opaque black \
gaussian_128_sigma16_clut_F_Q16_mag_spec100000.png
|
|
|
Profile Of Gauss Sigma 16
|
Profile Of Magnitude Of Gauss Sigma 16
|
|
|
Gaussian Sigma=8
|
Generate Spectrum From Magnitude (scale=100000):
convert gaussian_128_sigma8_clut_F_Q16_mag.png \
-contrast-stretch 0% -fx "log(99999*u+1)/log(100000)" \
-fill "rgb(1,1,1)" -opaque black \
gaussian_128_sigma16_clut_F_Q16_mag_spec100000.png
|
|
|
Profile Of Gauss Sigma 8
|
Profile Of Magnitude Of Gauss Sigma 8
|
|
|
Grid 8x16
|
Generate Spectrum From Magnitude (scale=100000):
convert grid8x16_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(99999*u+1)/log(5000)" -fill "rgb(1,1,1)" \
-opaque black grid8x16_F_Q16_spec100000.png
|
|
|
Reconstruction From Magnitude Or Phase Only |
FFT to produce tiff stack of frames:
path-to-imfft/trunk/demo f lena.png
Generate Magnitude and Phase Images:
|
convert lena_F_Q16.tiff[0] lena_F_Q16.tiff[2] \
lena_F_Q16.tiff[4] lena_mag.png
|
convert lena_F_Q16.tiff[1] lena_F_Q16.tiff[3] \
lena_F_Q16.tiff[5] square30_phase.png
|
Generate Spectrum From Magnitude (scale=100000):
convert lena_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(99999*u+1)/log(5000)" -fill "rgb(1,1,1)" \
-opaque black lena_F_Q16_spec100000.png
|
phase |
|
|
Combine Magnitude With Flat Gray Image:
convert -size 256x256 xc:gray gray.png
convert \( lena_F_Q16_mag.png -channel R -separate \) \
\( gray.png -channel R -separate \) \
\( lena_F_Q16_mag.png -channel G -separate \) \
\( gray.png -channel G -separate \) \
\( lena_F_Q16_mag.png -channel B -separate \) \
\( gray.png -channel B -separate \) \
lena_mag_gray.tiff
IFT of tiff stack to regenerate image:
path-to-imfft/trunk/demo i lena_mag_gray_F_Q16.tiff
|
Combine Flat Gray Image With Phase:
convert -size 256x256 xc:gray gray.png
convert \( gray.png -channel R -separate \) \
\( lena_F_Q16_phase.png -channel R -separate \) \
\( gray.png -channel G -separate \) \
\( lena_F_Q16_phase.png -channel G -separate \) \
\( gray.png -channel B -separate \) \
\( lena_F_Q16_phase.png -channel B -separate \) \
lena_gray_phase.tiff
IFT of tiff stack to regenerate image:
path-to-imfft/trunk/demo i lena_gray_phase_F_Q16.tiff
|
magnitude only reconstruction |
phase only reconstruction |
|
|
Dynamic Range Change By Coefficient Rooting: (Raising Magnitude To A Power) |
original |
|
FFT to produce tiff stack of frames:
path-to-imfft/trunk/demo f lena.png
Generate Magnitude and Phase Images:
|
convert lena_F_Q16.tiff[0] lena_F_Q16.tiff[2] \
lena_F_Q16.tiff[4] lena_mag.png
|
convert lena_F_Q16.tiff[1] lena_F_Q16.tiff[3] \
lena_F_Q16.tiff[5] square30_phase.png
|
Generate Spectrum From Magnitude (scale=100000):
convert lena_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(99999*u+1)/log(5000)" -fill "rgb(1,1,1)" \
-opaque black lena_F_Q16_spec100000.png
|
phase |
|
|
Increase Dynamic Range:
Raise Magnitude To Power Less Than 1.0
convert lena_F_Q16_mag.png -fx "pow(u,0.9)" \
lena_F_Q16_mag_powp9.png
|
Decrease Dynamic Range:
Raise Magnitude To Power Greater Than 1.0
convert lena_F_Q16_mag.png -fx "pow(u,1.1)" \
lena_F_Q16_mag_pow1p1.png
|
Combine Modified Magnitude With Phase:
convert \( lena_F_Q16_mag_powp9.png -channel R -separate \) \
\( lena_F_Q16_phase.png -channel R -separate \) \
\( lena_F_Q16_mag_powp9.png -channel G -separate \) \
\( lena_F_Q16_phase.png -channel G -separate \) \
\( lena_F_Q16_mag_powp9.png -channel B -separate \) \
\( lena_F_Q16_phase.png -channel B -separate \) \
lena_mag_powp9_phase.tiff
IFT of tiff stack to regenerate image:
path-to-imfft/trunk/demo i lena_mag_powp9_phase_F_Q16.tiff
|
Combine Modified Magnitude With Phase:
convert \( lena_F_Q16_mag_pow1p1.png -channel R -separate \) \
\( lena_F_Q16_phase.png -channel R -separate \) \
\( lena_F_Q16_mag_powp1p1.png -channel G -separate \) \
\( lena_F_Q16_phase.png -channel G -separate \) \
\( lena_F_Q16_mag_powp1p1.png -channel B -separate \) \
\( lena_F_Q16_phase.png -channel B -separate \) \
lena_mag_pow1p1_phase.tiff
IFT of tiff stack to regenerate image:
path-to-imfft/trunk/demo i lena_mag_pow1p1_phase_F_Q16.tiff
|
increased dynamic range |
decreased dynamic range |
|
|
original |
|
Image With "Noise" Pattern - Demo Pattern Filtering By Notch Masking FFT |
original noisy image
(image from http://www.roborealm.com/help/FFT.php)
|
|
Perform FFT to produce tiff stack of frames:
path-to-imfft/trunk/demo f FFT_src.png
Then create magnitude and phase (below):
|
convert FFT_src_F_Q16.tiff[0] FFT_src_F_Q16.tiff[2] \
FFT_src_F_Q16.tiff[4] FFT_src_F_Q16_mag.png
|
convert FFT_src_F_Q16.tiff[1] FFT_src_F_Q16.tiff[3] \
FFT_src_F_Q16.tiff[5] FFT_src_F_Q16_phase.png
|
Generate Spectrum From Magnitude (scale=100000):
convert FFT_src_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(99999*u+1)/log(100000)" -fill "rgb(1,1,1)" \
-opaque black FFT_src_F_Q16_spec100000.png
|
Phase
|
|
|
Mask Spectrum in GIMP or Photoshop
|
Threshhold To Create Binary Notch Mask
From Masked Spectrum
convert FFT_src_F_Q16_spec100000_masked.jpg \
-threshold 1 FFT_scr_F_Q16_mask.jpg
|
|
|
Apply Notch Mask To FFT Stack:
convert \( FFT_src_F_Q16.tiff -coalesce \) null: \
FFT_scr_F_Q16_mask.png -compose multiply \
-layers Composite FFT_src_F_Q16_filtfft.tiff
|
Then Perform IFT On Masked FFT Stack:
path-to-imfft/trunk/demo i FFT_src_F_Q16_filtfft.tiff
|
Original Noisy Image
|
|
|
Create Difference Image And Normalize To See Noise Pattern That Was Removed:
|
convert FFT_src.png FFT_src_F_Q16_filtfft_rt_Q16.tiff \
-compose difference -composite -normalize FFT_src_F_Q16_fft_diff_norm.png
|
|
Image With A Second "Noise" Pattern - Demo Pattern Filtering By Notch Masking FFT |
original noisy image
(image from http://www.mediacy.com/index.aspx?page=AH_FFTExample)
|
|
Perform FFT to produce tiff stack of frames:
path-to-imfft/trunk/demo f clown.png
Then create magnitude and phase (below):
|
convert clown_F_Q16.tiff[0] clown_F_Q16.tiff[2] \
clown_F_Q16.tiff[4] clown_F_Q16_mag.png
|
convert clown_F_Q16.tiff[1] clown_F_Q16.tiff[3] \
clown_F_Q16.tiff[5] clown_F_Q16_phase.png
|
Generate Spectrum From Magnitude (scale=100000):
convert clown_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(99999*u+1)/log(100000)" -fill "rgb(1,1,1)" \
-opaque black clown_F_Q16_spec100000.png
|
Phase
|
|
|
Mask Spectrum in GIMP or Photoshop
|
Threshhold To Create Binary Notch Mask
From Masked Spectrum
convert clown_F_Q16_spec100000_masked.jpg \
-threshold 1 clown_F_Q16_mask.jpg
|
|
|
Apply Notch Mask To FFT Stack:
convert \( clown_F_Q16.tiff -coalesce \) null: \
clown_F_Q16_mask.png -compose multiply \
-layers Composite clown_F_Q16_filtfft.tiff
|
Then Perform IFT On Masked FFT Stack:
path-to-imfft/trunk/demo i clown_F_Q16_filtfft.tiff
|
Original Noisy Image
|
|
|
Create Difference Image And Normalize To See Noise Pattern That Was Removed:
|
convert clown.png clown_F_Q16_filtfft_rt_Q16.tiff \
-compose difference -composite -normalize clown_F_Q16_fft_diff_norm.png
|
|
Image With Grid Pattern - Demo Pattern Filtering By Notch Masking FFT |
original image
|
|
Perform FFT to produce tiff stack of frames:
path-to-imfft/trunk/demo f lena_grid16.png
Then create magnitude and phase (below):
|
convert lena_grid16_F_Q16.tiff[0] lena_grid16_F_Q16.tiff[2] \
lena_grid16_F_Q16.tiff[4] lena_grid16_F_Q16_mag.png
|
convert lena_grid16_F_Q16.tiff[1] lena_grid16_F_Q16.tiff[3] \
lena_grid16_F_Q16.tiff[5] lena_grid16_F_Q16_phase.png
|
Generate Spectrum From Magnitude (scale=100000):
convert lena_grid16_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(99999*u+1)/log(100000)" -fill "rgb(1,1,1)" \
-opaque black lena_grid16_F_Q16_spec100000.png
|
Phase
|
|
|
Mask Spectrum in GIMP or Photoshop
|
Threshhold To Create Binary Notch Mask
From Masked Spectrum
convert lena_grid16_F_Q16_spec100000_masked.jpg \
-threshold 1 lena_grid16_F_Q16_mask.jpg
|
|
|
Apply Notch Mask To FFT Stack:
convert \( lena_grid16_F_Q16.tiff -coalesce \) null: \
lena_grid16_F_Q16_mask.png -compose multiply \
-layers Composite lena_grid16_F_Q16_masked.tiff
|
Then Perform IFT On Masked FFT Stack:
path-to-imfft/trunk/demo i lena_grid16_F_Q16_masked.tiff
|
Original Noisy Image
|
|
|
Low Pass Filtering: Blurring
(Larger Masks Generate Less Blurring And Smaller Masks Generate More Blurring)
|
original image
|
|
Perform FFT to produce tiff stack of frames:
path-to-imfft/trunk/demo f lena.png
|
Create Simple Circular Low Pass Filter Mask:
(Diameter 92)
convert -size 256x256 xc:black -fill white -stroke white \
-draw "circle 127,128 173,128" circle92.png
|
Apply Mask To Image And Do IFT:
convert \( lena_F_Q16.tiff -coalesce \) null: \
circle92.png -compose multiply -layers Composite \
lena_mask_circle92_F_Q16_filtfft.tiff
path-to-imfft/trunk/demo i lena_mask_circle92_F_Q16_filtfft.tiff
|
|
|
Create Simple Circular Low Pass Filter Mask:
(Diameter 64)
convert -size 256x256 xc:black -fill white -stroke white \
-draw "circle 127,128 159,128" circle64.png
|
Apply Mask To Image And Do IFT:
convert \( lena_F_Q16.tiff -coalesce \) null: \
circle64.png -compose multiply -layers Composite \
lena_mask_circle64_F_Q16_filtfft.tiff
path-to-imfft/trunk/demo i lena_mask_circle64_F_Q16_filtfft.tiff
|
|
|
Create Gaussian Low Pass Filter Mask:
(Sigma 48)
convert -size 256x256 xc: -fx \
"xx=i-w/2; yy=j-h/2; rr=hypot(xx,yy)/(sqrt(2)*256); exp(-(rr*rr)/(pow(48/256,2)))" \
gauss48.png
|
Apply Mask To Image And Do IFT:
convert \( lena_F_Q16.tiff -coalesce \) null: \
gauss48.png -compose multiply -layers Composite \
lena_mask_gauss48_F_Q16_filtfft.tiff
path-to-imfft/trunk/demo i lena_mask_gauss48_F_Q16_filtfft.tiff
|
|
|
Create Gaussian Low Pass Filter Mask:
(Sigma 32)
convert -size 256x256 xc: -fx \
"xx=i-w/2; yy=j-h/2; rr=hypot(xx,yy)/(sqrt(2)*256); exp(-(rr*rr)/(pow(32/256,2)))" \
gauss32.png
|
Apply Mask To Image And Do IFT:
convert \( lena_F_Q16.tiff -coalesce \) null: \
gauss32.png -compose multiply -layers Composite \
lena_mask_gauss32_F_Q16_filtfft.tiff
path-to-imfft/trunk/demo i lena_mask_gauss32_F_Q16_filtfft.tiff
|
|
|
High Pass Filtering: Edge Extraction And Sharpening
|
original image
|
|
Perform FFT to produce tiff stack of frames:
path-to-imfft/trunk/demo f lena.png
|
Create Simple Circular Low Pass Filter Mask And Negate:
(Diameter 32)
convert -size 256x256 xc:black -fill white -stroke white \
-draw "circle 127,128 143,128" -negate circle32neg.png
|
Apply Mask To Image And Do IFT:
convert \( lena_F_Q16.tiff -coalesce \) null: \
circle32neg.png -compose multiply -layers Composite \
lena_mask_circle32neg_F_Q16_filtfft.tiff
path-to-imfft/trunk/demo i lena_mask_circle32neg_F_Q16_filtfft.tiff
|
Simple High Pass Filter Mask
|
Normalize Filtered Image To Enhance Edges:
convert lena_mask_circle32neg_F_Q16_filtfft.tiff \
-normalize lena_mask_circle32neg_F_Q16_filtfft_norm.tiff
|
|
|
Create Gaussian Low Pass Filter Mask And Negate:
(Sigma 48)
convert -size 256x256 xc: -fx \
"xx=i-w/2; yy=j-h/2; rr=hypot(xx,yy)/(sqrt(2)*256); exp(-(rr*rr)/(pow(16/256,2)))" \
-negate gauss16neg.png
|
Apply Mask To Image And Do IFT:
convert \( lena_F_Q16.tiff -coalesce \) null: \
gauss16neg.png -compose multiply -layers Composite \
lena_mask_gauss16neg_F_Q16_filtfft.tiff
path-to-imfft/trunk/demo i lena_mask_gauss16neg_F_Q16_filtfft.tiff
|
Gaussian High Pass Filter Mask
|
Normalize Filtered Image To Enhance Edges:
convert lena_mask_gauss16neg_F_Q16_filtfft.tiff \
-normalize lena_mask_gauss16neg_F_Q16_filtfft_norm.tiff
|
|
|
Blend Image With Gaussian High Pass Edge Image To Sharpen:
composite -blend 100x100 lena.png \
lena_mask_gauss16neg_F_Q16_filtfft_rt_Q16.tiff \
lena_sharp16_blend100x100.png
|
Original Image
|
|
|
Image With A Third "Noise" Pattern - Demo Pattern Filtering By Notch and Low Pass Masking FFT |
original noisy image
(image from http://home.planet.nl/~ber03728/4N6site/improc/fftplugin/howto.htm)
|
|
Perform FFT to produce tiff stack of frames:
path-to-imfft/trunk/demo f fingerprint.png
Then create magnitude and phase (below):
|
convert fingerprint_F_Q16.tiff[0] fingerprint_F_Q16.tiff[2] \
fingerprint_F_Q16.tiff[4] fingerprint_F_Q16_mag.png
|
convert fingerprint_F_Q16.tiff[1] fingerprint_F_Q16.tiff[3] \
fingerprint_F_Q16.tiff[5] fingerprint_F_Q16_phase.png
|
Generate Spectrum From Magnitude (scale=100000):
convert fingerprint_F_Q16_mag.png -contrast-stretch 0% \
-fx "log(99999*u+1)/log(100000)" -fill "rgb(1,1,1)" \
-opaque black fingerprint_F_Q16_spec100000.png
|
Phase
|
|
|
Mask Spectrum in GIMP or Photoshop
To Remove Low Frequency Stripes
|
Threshhold To Create Binary Notch Mask
From Masked Spectrum
convert fingerprint_F_Q16_spec100000_masked1.png \
-threshold 1 fingerprint_F_Q16_mask1.png
|
|
|
Apply Mask To FFT Stack To Remove Stripes:
convert \( fingerprint_F_Q16.tiff -coalesce \) null: \
fingerprint_F_Q16_mask1.png -compose multiply \
-layers Composite fingerprint_F_Q16_masked1.tiff
|
Then Perform IFT On Masked FFT Stack:
path-to-imfft/trunk/demo i fingerprint_F_Q16_masked1.tiff
|
Original Noisy Image
|
|
|
Apply Low Pass Filter To Remove Dotted Noise:
convert -size 400x400 xc:black -fill white -stroke white \
-draw "circle 199,200 279,200" circle80.png
convert fingerprint_F_Q16_spec100000_masked1.png \
circle80.png -compose multiply -composite \
fingerprint_F_Q16_spec100000_masked2.png
|
Threshhold To Create Binary Low Pass And
Notch Mask From Masked Spectrum
convert fingerprint_F_Q16_spec100000_masked2.png \
-threshold 1 fingerprint_F_Q16_mask2.png
|
|
|
Apply Mask To FFT Stack To Remove Dotted Noise:
convert \( fingerprint_F_Q16.tiff -coalesce \) null: \
fingerprint_F_Q16_mask2.png -compose multiply \
-layers Composite fingerprint_F_Q16_masked2.tiff
|
Then Perform IFT On Masked FFT Stack:
path-to-imfft/trunk/demo i fingerprint_F_Q16_masked1.tiff
|
Original Noisy Image
|
|
|