Contoh penggunaan ImageMagick -- transformasi Fourier
- Gambar adalah gelombang
- Gambar hanya magnitudo atau hanya fase
- Gambar spektrum FFT
- Gambar FFT HDRI
- Efek warna DC
- Spektrum gambar gelombang sinus
- Membuat gambar FFT secara langsung
- Spektrum gambar pola persegi panjang
- Spektrum gambar pola lingkaran datar
- Spektrum gambar pola lingkaran Gaussian
- Mengaburkan gambar - penyaringan lolos-rendah
- Mendeteksi tepi dalam gambar - penyaringan lolos-tinggi
- Menajamkan gambar - penyaringan high boost
-
Menghilangkan noise - penyaringan notch
Perkalian dan pembagian FFT (contoh tingkat rendah - subhalaman)
Pengantar
Salah satu konsep yang paling sulit dipahami dalam pemrosesan gambar adalah transformasi Fourier. Ada dua alasannya. Pertama, tingkat matematikanya tinggi, dan kedua, gambar yang dihasilkan tidak menyerupai gambar aslinya sehingga sulit ditafsirkan. Meski begitu, transformasi Fourier membuka cara baru untuk melakukan pemrosesan yang sudah kita kenal, seperti memperkuat kecerlangan dan kontras, mengaburkan, menajamkan, serta menghilangkan noise. Namun transformasi ini juga memberi kemampuan baru yang tidak dapat dilakukan pada domain gambar biasa. Termasuk di dalamnya dekonvolusi (dikenal juga sebagai deblurring) atas distorsi kamera yang lazim seperti motion blur dan lensa yang tidak fokus, serta pencocokan gambar memakai korelasi silang ternormalisasi. Tujuan halaman ini adalah menjelaskan latar belakang dan matematika sederhana dari transformasi Fourier, sekaligus memberi contoh pemrosesan yang bisa dilakukan dengannya. Kalau ini terasa terlalu berat, lewati saja dan langsung fokus ke sifat-sifat dan contohnya, mulai dari FFT/IFT di ImageMagick Bagi yang tertarik, pembahasan sederhana lain yang bagus, lengkap dengan analogi ke optika, ada di An Intuitive Explanation of Fourier Theory. Catatan kuliah dari Vanderbilt University School Of Engineering juga sangat informatif bagi yang lebih condong ke matematika: 1 & 2 Dimensional Fourier Transforms dan Frequency Filtering. Rujukan matematis lainnya mencakup halaman Wikipedia tentang Fourier Transform, Discrete Fourier Transform dan Fast Fourier Transform serta Complex Numbers. Terima kasih saya kepada Sean Burke yang menulis kode demo aslinya dan kepada pencipta ImageMagick yang mengintegrasikannya ke dalam ImageMagick. Keduanya adalah kerja yang luar biasa. Banyak contoh di sini memakai versi HDRI ImageMagick yang diperlukan untuk menjaga akurasi gambar hasil transformasi. Disarankan untuk mengompilasi versi HDRI sendiri jika Anda ingin memanfaatkan teknik-teknik ini semaksimal mungkin.
Transformasi Fourier
Gambar biasanya terdiri atas larik 'piksel' yang masing-masing ditentukan oleh sekumpulan nilai: merah, hijau, biru, dan kadang transparansi juga. Namun untuk keperluan di sini transparansi kita abaikan. Jadi masing-masing 'kanal' merah, hijau, dan biru berisi sekumpulan nilai 'intensitas' atau 'grayscale'. Inilah yang disebut gambar raster 'dalam domain spasial '. Ini sekadar cara keren untuk mengatakan bahwa gambar ditentukan oleh 'nilai intensitas' yang dimilikinya pada tiap 'lokasi' atau 'posisi dalam ruang'. Tetapi sebuah gambar dapat pula disajikan dengan cara lain, yang dikenal sebagai 'domain frekuensi ' gambar tersebut. Dalam domain ini, tiap kanal gambar disajikan dalam bentuk gelombang sinusoidal. Dalam 'domain frekuensi ' semacam itu, tiap kanal memiliki nilai 'amplitudo' yang disimpan pada lokasi yang tidak didasarkan pada koordinat 'spasial' X,Y, melainkan pada 'frekuensi' X,Y. Karena ini representasi digital, frekuensinya merupakan kelipatan dari frekuensi 'terkecil' atau frekuensi satuan, dan koordinat pikselnya mewakili indeks atau kelipatan bulat dari frekuensi satuan itu. Hal ini mengikuti prinsip bahwa "setiap fungsi yang berperilaku baik dapat disajikan oleh superposisi (gabungan atau jumlah) gelombang sinusoidal". Dengan kata lain, representasi 'domain frekuensi' hanyalah cara lain untuk menyimpan dan menghasilkan kembali gambar 'domain spasial'. Tapi bagaimana mungkin sebuah gambar disajikan sebagai 'gelombang'?
Gambar adalah gelombang
Nah, kalau kita ambil satu baris atau satu kolom piksel dari sembarang gambar lalu kita gambarkan grafiknya (dibuat dengan "gnuplot" memakai skrip "im_profile"), hasilnya ternyata cukup mirip gelombang.
magick holocaust_tn.gif -colorspace gray miff:- |\
im_profile -s - image_profile.gif
Seandainya fluktuasinya lebih teratur dalam jarak dan amplitudo, hasilnya akan lebih menyerupai pola gelombang, seperti ini...
magick -size 20x150 gradient: -rotate 90 \
-function sinusoid 3.5,0,.4 wave.gif
im_profile -s wave.gif wave_profile.gif
Namun meski pola gelombang teratur ini samar-samar mirip dengan profil gambar di atas, polanya terlalu teratur. Dengan menjumlahkan lebih banyak gelombang, dapat dibuat pola yang lebih dekat lagi ke pola dari gambar tadi.
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
Lihat juga Menambahkan gradien berbias untuk contoh alternatif dari yang di atas. 'Superposisi gelombang ' (penjumlahan gelombang) ini jauh lebih dekat, tetapi masih belum persis sama dengan pola gambarnya. Cara ini bisa diteruskan, menambah lebih banyak gelombang dan menyetelnya, sehingga gelombang gabungan yang dihasilkan makin lama makin dekat ke profil sebenarnya dari gambar asli. Pada akhirnya, dengan menambahkan cukup banyak gelombang, profil asli gambar dapat direproduksi secara persis. Inilah penemuan matematikawan Joseph Fourier. Tafsiran modernnya menyatakan bahwa "setiap fungsi yang berperilaku baik dapat disajikan oleh superposisi gelombang sinusoidal". Dengan kata lain, dengan menjumlahkan gelombang sinus dalam jumlah yang memadai pada frekuensi dan amplitudo yang tepat, pola berfluktuasi apa pun dapat direproduksi. Karena itu, representasi 'domain frekuensi' hanyalah cara lain untuk menyimpan dan menghasilkan kembali gambar 'domain spasial'. 'Transformasi Fourier ' dengan demikian adalah proses mencari tahu 'gelombang' apa saja yang menyusun sebuah gambar, persis seperti yang dilakukan pada contoh di atas.
Gelombang 2 dimensi dalam gambar
Di atas ditunjukkan satu contoh bagaimana profil satu baris gambar dapat dihampiri dengan beberapa gelombang sinus. Tetapi gambar itu 2 dimensi, sehingga gelombang yang dipakai untuk menyajikan gambar dalam 'domain frekuensi' juga harus dua dimensi. Berikut contoh salah satu gelombang 2 dimensi semacam itu. Gelombang ini punya sejumlah komponen. Contoh gambar
Menggunakan FFT/IFT di ImageMagick
Catatan implementasi
ImageMagick memanfaatkan FFTW, pustaka transformasi Fourier diskret yang mengharuskan gambar dikonversi ke dan dari nilai floating point (bilangan kompleks), dan pertama kali diimplementasikan pada IM versi 6.5.4-3. Agar bekerja sebagaimana umumnya orang harapkan untuk gambar, gambar yang tidak persegi atau yang salah satu dimensinya ganjil akan diberi padding (memakai Piksel virtual sehingga menjadi persegi seukuran lebar atau tinggi terbesar gambar itu. Supaya 'titik asal FFT' dapat ditempatkan tepat di tengah gambar, dimensinya juga dipaksa menjadi genap (kelipatan 2). Akibatnya, setelah transformasi Fourier balik diterapkan, gambar perlu dipangkas (crop) kembali ke dimensi aslinya untuk membuang padding tadi. Karena transformasi Fourier tersusun dari "bilangan kompleks", hasil transformasinya tidak dapat divisualisasikan secara langsung. Karena itu, transformasi kompleks tersebut dipisahkan menjadi dua gambar komponen dalam salah satu dari dua bentuk. ![[Diagram]](../static/img/img_diagrams/complex_number.jpg)
Bilangan kompleks
Real/Imajiner
Real dan imajiner
Representasi matematis dan numerik yang lazim untuk "bilangan kompleks" adalah sepasang nilai floating point yang terdiri atas komponen 'Real' (a) dan 'Imajiner' (b). Sayangnya kedua bilangan ini bisa memuat nilai negatif sehingga tidak membentuk gambar yang dapat ditampilkan. Karena itu representasi ini tidak dapat dipakai pada versi ImageMagick biasa, yang akan memotong (clip) gambar semacam itu (lihat contoh efeknya di bawah. Namun dengan versi HDRI ImageMagick representasi gambar hasil transformasi Fourier ini tetap dapat dibuat, dipakai, bahkan disimpan. Sebagai gambar tersendiri mungkin representasi itu tidak berguna atau bahkan tidak dapat dilihat, tetapi banyak operasi matematis masih dapat diterapkan padanya. Untuk menghasilkan representasi ini kita memakai bentuk 'plus' dari operator, yaitu "+fft" dan "+ift", dan hal ini akan dibahas lebih rinci di bawah pada FFT sebagai komponen real-imajiner. ![[Diagram]](../static/img/img_diagrams/polar_number.jpg)
Polar kompleks
Magnitudo/Fase
Magnitudo dan fase
Representasi numerik langsung dari "bilangan kompleks" tidak terlalu berguna untuk pekerjaan gambar. Tetapi dengan memplot nilai-nilainya ke bidang 2 dimensi, nilai itu dapat diubah menjadi representasi polar yang terdiri atas komponen 'Magnitudo' (r) dan 'Fase' (θ). Bentuk ini sangat berguna dalam pemrosesan gambar, terutama komponen magnitudonya, yang pada dasarnya menyebutkan semua frekuensi penyusun gambar. Komponen 'Magnitudo' hanya memuat nilai positif, dan langsung dipetakan menjadi nilai gambar. Rentang nilainya tidak tetap, meski kecuali untuk warna DC atau frekuensi nol, nilainya umumnya cukup kecil. Akibatnya gambar magnitudo umumnya tampak sangat gelap (praktis hitam). Biasanya diperlukan penskalaan magnitudo dan penerapan transformasi log atas nilai intensitasnya untuk memunculkan detail visualnya. Gambar magnitudo hasil 'transformasi log' itu dikenal sebagai 'spektrum' gambar. Namun ingat bahwa yang harus dipakai untuk transformasi balik adalah gambar 'magnitudo', bukan gambar 'spektrum'. Warna DC (singkatan dari "Direct Current") atau "Frekuensi Nol", yang muncul di 'titik asal' tengah gambar, adalah nilai warna rata-rata seluruh gambar. Selain itu, karena gambar masukan tidak memuat komponen 'imajiner', nilai fase DC juga selalu berfase nol sehingga menghasilkan warna abu-abu murni. Komponen 'Fase' sebaliknya berkisar dari -π sampai +π. Nilai ini mula-mula dibias ke rentang 0 sampai 2π, lalu diskalakan menjadi nilai gambar sebenarnya yang berkisar dari 0 sampai QuantumRange (sebagaimana ditentukan oleh Kualitas memori saat kompilasi). Akibatnya, fase nol akan bernilai abu-abu murni (sesuai untuk tiap kanal), sedangkan fase yang dinegasikan akan bernilai hitam murni ('0'). Perhatikan bahwa putih murni ('_QuantumRange_') hampir sama, tetapi tidak persis sama. Representasi FFT magnitudo dan fase sebuah gambar dihasilkan memakai operator FFT biasa, "+fft" dan "+ift". Hal ini akan dibahas lebih dulu di Membuat gambar FFT dan inversnya.
Membuat gambar FFT dan inversnya (magnitudo dan fase)
Sekarang mari kita coba saja transformasi Fourier bolak-balik pada gambar Lena. Artinya, kita lakukan transformasi maju lalu langsung menerapkan transformasi balik untuk mendapatkan kembali gambar aslinya. Kemudian hasilnya kita bandingkan untuk melihat tingkat kualitas yang dihasilkan.
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:
Program "compare" di atas mengembalikan ukuran seberapa berbeda kedua gambar itu. Dalam hal ini terlihat bahwa perbedaan umumnya sangat kecil, sekitar 0.22%. Dengan selisih nilai puncak pada setidaknya satu piksel ("PAE", Peak Absolute Error) hanya sekitar 1%. Hasil ini dapat diperbaiki dengan memakai versi HDRI ImageMagick. (Lihat FFT dengan HDRI di bawah). Mari kita cermati lebih rinci gambar FFT yang dihasilkan pada perjalanan bolak-balik di atas.
magick lena.png -fft +depth +adjoin lena_fft_%d.png
Seperti kata John M. Brayer tentang transformasi Fourier... Kami umumnya tidak menampilkan gambar FASE karena kebanyakan orang yang melihatnya tak lama kemudian terjerumus ke halusinogen atau berakhir di biara Tibet. Perhatikan bahwa operator "-fft" menghasilkan dua gambar: gambar pertama adalah komponen 'magnitudo' (ya, sebagian besar hitam dengan satu titik berwarna di tengah), sedangkan gambar kedua, yang tampak nyaris acak, memuat komponen 'fase'. Gambar PNG hanya dapat menyimpan satu gambar per file, jadi sebenarnya "+adjoin" maupun '%d' pada nama file keluaran tidak diperlukan karena IM akan menanganinya sendiri. Namun saya menyertakan opsi itu di atas demi kelengkapan, supaya jelas bahwa saya menghasilkan dua file gambar terpisah, bukan satu. Lihat Menulis rangkaian multi-gambar untuk detailnya. Karena dua gambar dihasilkan, gambar magnitudo (gambar pertama atau ke-nol) disimpan ke "lena_fft_0.png" dan gambar fase (gambar kedua) ke "lena_fft_1.png". | _Untuk mencegah segala kemungkinan distorsi akibat penyimpanan gambar FFT, sebaiknya gambar itu tidak disimpan ke disk sama sekali, melainkan ditahan di memori selama gambarnya diproses.
Kalau memang harus disimpan, sebaiknya pakai Magick File Format "MIFF" agar gambar terjaga pada kualitas (kedalaman bit) tertingginya. Format ini juga dapat menyimpan beberapa gambar dalam satu file. Untuk pekerjaan skrip, dapat dipakai pula format piksel terenumerasi "TXT" yang verbose.
JANGAN menyimpannya memakai format gambar "JPEG" atau "GIF".
Kalau gambar-gambar ini memang harus disimpan ke file untuk benar-benar dilihat, misalnya lewat peramban web, gunakan format gambar "PNG" dengan "+depth" yang dikembalikan ke bawaan internal (seperti yang kita lakukan pada contoh-contoh ini). Namun format ini hanya bisa menyimpan satu gambar per file.
Format file "TIFF" juga dapat dipakai meski kurang cocok untuk peramban web, walaupun format ini memang mengizinkan beberapa gambar per file.
_
Cara terbaik menyimpan gambar antara ke dalam satu file adalah memakai format file "MIFF"...
magick lena.png -fft +depth lena_fft.miff
Atau gambar itu dapat disimpan ke nama file yang sepenuhnya terpisah memakai "-write" (lihat Menulis gambar)...
magick lena.png -fft +depth \
\( -clone 0 -write lena_magnitude.png +delete \) \
\( -clone 1 -write lena_phase.png +delete \) \
null:
Perhatikan bahwa di atas saya memakai format gambar khusus "NULL:" untuk membuang kedua gambar yang tetap tersimpan di memori untuk diproses lebih lanjut. Dan akhirnya kedua gambar itu kita baca lagi, untuk mengonversinya kembali menjadi gambar 'spasial' biasa...
magick lena_magnitude.png lena_phase.png -ift lena_restored.png
Kedua gambar yang dihasilkan proses FFT sangat peka terhadap perubahan, sampai-sampai perubahan kecil pun dapat memberi hasil yang sangat terdistorsi. Karena itu penting untuk tidak pernah menyimpannya dalam format gambar apa pun yang bisa mendistorsi nilai-nilai tersebut. Penting diingat bahwa kedua gambar itu dibutuhkan saat memulihkan gambar dari domain frekuensi. Jadi percuma menyimpan satu gambar dan membuang yang lain kalau keduanya hendak dipakai untuk merekonstruksi gambar.
Gambar hanya magnitudo atau hanya fase
Terakhir, mari kita coba merekonstruksi gambar hanya dari komponen magnitudonya saja atau hanya dari komponen fasenya saja.
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
Dari sini terlihat bahwa justru gambar fase yang memuat sebagian besar informasi posisi gambar, sedangkan magnitudonya memegang banyak informasi warna. Ini tidak persis demikian karena informasinya sedikit tumpang tindih, tetapi secara umum begitulah keadaannya. Gambar 'Hanya magnitudo' akan selalu memiliki sudut-sudut putih karena yang dipakai adalah gambar fase konstan 50%. Bercak putih itu dapat dihilangkan dengan memakai gambar fase yang diacak. Namun pastikan fase piksel tengahnya benar-benar abu-abu 50%, kalau tidak seluruh gambar akan meredup. Gambar 'Hanya fase' memakai gambar magnitudo konstan abu-abu 1% (nyaris hitam murni) untuk konversinya. Bahkan dengan magnitudo konstan itu pun tetap muncul bercak piksel yang sangat intens, terutama di sepanjang tepi. Yang perlu diingat, kedua gambar itu dibutuhkan untuk merekonstruksi gambar aslinya.
Gambar spektrum frekuensi
Anda pasti sudah memperhatikan bahwa gambar magnitudo (gambar pertama atau ke-nol) tampak hampir seluruhnya hitam. Sebenarnya tidak, hanya saja bagi mata kita semua nilainya sangat sangat kecil. Gambar seperti itu tidak menarik untuk diamati, jadi mari kita perkuat hasilnya dengan transformasi log untuk menghasilkan gambar 'spektrum frekuensi '. Caranya dengan menerapkan transformasi log Evaluate yang kuat pada gambar 'magnitudo' yang sudah dinormalisasi.
magick lena_fft_0.png -auto-level -evaluate log 10000 \
lena_spectrum.png
Sekarang detail pada versi spektrum dari gambar magnitudo sudah terlihat. Mungkin tampak pula beberapa warna tertentu pada gambar spektrum, tetapi umumnya warna semacam itu tidak penting dalam gambar spektrum. Yang jauh lebih penting adalah intensitas keseluruhan tiap frekuensi dan pola yang dibentuknya. Karena itu gambar spektrum boleh saja dijadikan grayscale setelah diperkuat. Seberapa kuat penguatan log yang diperlukan bergantung pada gambarnya, jadi setel terus sampai diperoleh detail yang cukup untuk melihat jelas pola spektrum frekuensi gambar tersebut. Sebagai alternatif, skrip shell kecil berikut dapat dipakai untuk menghitung faktor penskalaan log bagi gambar magnitudo tertentu. |
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]](../static/img/fourier/lena_spectrum_auto.png)
Namun ingat, gambar spektrum tidak dapat dipakai untuk transformasi balik "-ift" karena akan menghasilkan gambar yang terlalu terang. |
magick lena_spectrum.png lena_fft_1.png -ift lena_roundtrip_fail.png
Pada dasarnya, karena gambar 'magnitudo' sudah diperkuat, gambar hasilnya pun ikut diperkuat dengan cara yang sama, sehingga muncul hasil 'terpotong' yang parah seperti terlihat. ![[IM Output]](../static/img/fourier/lena_roundtrip_fail.png)
Gambar FFT HDRI
Ketika hasil transformasi Fourier dipetakan menjadi representasi gambar, nilainya kita skalakan dan konversi dari "bilangan kompleks" floating point menjadi nilai gambar bilangan bulat. Wajar saja hal ini memunculkan error pembulatan dan efek "kuantum" lainnya, terutama pada magnitudo frekuensi rendah yang kecil. Jika akurasi penting dalam pemrosesan gambar Anda, gunakan kualitas bit yang lebih tinggi (misalnya ImageMagick versi Q32 atau Q64), atau lebih baik lagi gunakan versi HDRI ImageMagick supaya nilainya disimpan sebagai bilangan floating point. Saat memakai versi HDRI dari IM dengan representasi magnitudo dan fase dari transformasi Fourier, komponen magnitudo tetap seluruhnya bernilai positif sehingga tetap dapat dipakai seperti ditunjukkan di atas, hanya saja jauh lebih tepat. Komponen fase tetap akan dibias dan diskalakan, seperti yang sudah ditunjukkan sebelumnya. Dengan kata lain, representasi magnitudo dan fase pada HDRI persis sama, hanya jauh lebih akurat.
Sebagai contoh, di sini saya memakai versi HDRI ImageMagick untuk melakukan lagi konversi 'bolak-balik' sebuah gambar. |
# 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:
Kalau hasil di atas dibandingkan dengan perbandingan non-HDRI sebelumnya...
| Terlihat bahwa versi HDRI dari IM memberi hasil yang jauh lebih akurat, pada kecepatan yang kira-kira sama seperti sebelumnya (kecepatan dapat berbeda tergantung komputer Anda). Meski memorinya jauh lebih boros dibanding IM Q16 biasa (lihat Kualitas saat kompilasi). Namun gambar semacam itu, walau menyajikan komponen frekuensi FFT gambar dengan lebih tepat, dapat memuat nilai negatif dan pecahan sehingga hanya bisa disimpan memakai format file berkemampuan HDRI khusus yang sanggup menangani nilai floating point. | Format file yang kompatibel dengan floating point antara lain "MIFF", "TIFF", "PFM" dan format file "EXR" yang khusus HDRI. Namun mungkin perlu menyetel "-define quantum:format=floating-point" agar berfungsi. |
|---|---|
| Pada contoh-contoh berikutnya, pemrosesan FFT sebuah gambar akan menuntut akurasi semacam itu untuk memberi hasil yang bagus. Karena itu, seiring kita melanjutkan penggunaan Fast Fourier Transform, versi HDRI ImageMagick menjadi keharusan. |
FFT sebagai komponen real-imajiner
Sejauh ini kita baru melihat representasi 'Magnitudo' dan 'Fase' dari gambar hasil transformasi Fourier. Tetapi kalau Anda sudah mengompilasi versi HDRI dari IM, gambar juga dapat diproses memakai komponen 'Real' dan 'Imajiner' floating point. Caranya dengan memakai versi 'plus' dari opsi "+fft" dan "+ift". Sebagai contoh, di sini saya memakai versi HDRI dari IM untuk melakukan FFT 'bolak-balik' sebuah gambar juga, tetapi kali ini menghasilkan gambar Real/Imajiner. |
# 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:
Versi HDRI wajib dipakai bila bentuk plus dipakai untuk menghasilkan gambar FFT Real/Imajiner. Kalau tidak, sekitar 1/2 nilainya akan menjadi nol sehingga gambarnya tampak 'kotor'. Sebagai contoh... |
# non-HDRI Q16 version of IM used -- THIS IS BAD
magick lena.png +fft +ift lena_roundtrip_ri_bad.png
![[IM Output]](../static/img/fourier/lena_roundtrip_ri_bad.png)
Hal lain yang perlu diingat, bentuk gambar FFT mana pun yang dihasilkan akan memengaruhi SEMUA operasi pemrosesan gambar yang hendak diterapkan pada gambar FFT itu. Keduanya gambar yang sangat berbeda, sehingga harus diproses dengan cara yang sangat berbeda pula, dengan operasi matematis yang berbeda. Seperti sebelumnya, gambar komponen Real dan Imajiner keduanya harus ada untuk memulihkan gambar akhir. Sebagai contoh, inilah yang terjadi kalau salah satu komponennya kita ganti dengan gambar 'hitam'.
# 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
Dari sini terlihat bahwa kedua gambar FFT Real/Imajiner sama-sama memuat informasi penting tentang gambar aslinya dalam porsi yang kurang lebih setara. Perbedaan terbesarnya, DC khusus atau 'warna rata-rata' tidak punya komponen imajiner sehingga hanya hadir pada gambar magnitudo. Efek pencerminan diagonal (sebenarnya rotasi 180 derajat) yang terlihat pada kedua gambar disebabkan hilangnya informasi 'tanda' yang tersimpan pada komponen satunya. Tanpa komponen satunya, gelombang itu bisa dianggap berbeda fase 180 derajat sehingga memunculkan tampilan aneh ini. Kehilangan informasi ini setara di antara kedua jenis gambar tersebut.
Sifat-sifat transformasi Fourier
FFT dari gambar konstan
Mari kita tunjukkan beberapa sifat itu. Pertama, ambil saja gambar berwarna konstan lalu dapatkan magnitudonya.
magick -size 128x128 xc:gold constant.png
magick constant.png -fft +delete constant_magnitude.png
Perhatikan bahwa gambar magnitudo dalam kasus ini benar-benar hitam murni, kecuali satu piksel berwarna tepat di tengah gambar, pada lokasi piksel width/2, height/2. Piksel ini adalah nilai frekuensi nol atau DC ('Direct Current ') dari gambar itu, dan merupakan satu-satunya piksel yang tidak mewakili gelombang sinus. Dengan kata lain nilai ini tak lain adalah komponen konstan FFT! Supaya piksel tunggal ini terlihat lebih jelas, mari kita perbesar juga area gambar itu... |
magick constant_magnitude.png -gravity center -extent 5x5 \
-scale 2000% constant_dc_zoom.gif
![[IM Output]](../static/img/fourier/constant_dc_zoom.gif)
Perhatikan bahwa warna titik DC sama dengan gambar aslinya. Sebenarnya ada baiknya diingat bahwa yang terlihat itu tiga nilai. Artinya, gambar yang dihasilkan sesungguhnya tiga Fast Fourier transform terpisah: satu FFT untuk masing-masing kanal gambar merah, hijau, dan biru. FFT sendiri sama sekali tidak paham soal warna, hanya nilai warna atau 'tingkat abu-abu '. Bahkan transformasi FFT dapat diterapkan pada hampir semua ruang warna, sebab sesungguhnya... ia tidak peduli! Bagi transformasi Fourier, gambar hanyalah larik nilai, dan hanya itu. | Meskipun 'fase' nilai DC tidak penting, fase itu semestinya selalu bersudut 'nol' (nilai warna fase abu-abu 50%). Kalau tidak disetel ke abu-abu 50%, nilai DC akan punya komponen 'tak-real' dan nilainya termodulasi oleh sudut yang diberikan.
Efek warna DC
Pada gambar tak konstan yang lebih lazim, nilai DC adalah warna rata-rata gambar itu: warna yang umumnya diperoleh kalau gambar dikaburkan total, dirata-ratakan, atau diubah ukurannya menjadi satu piksel atau satu warna saja. Sebagai contoh, mari kita ambil piksel DC dari FFT gambar "Lena".
magick lena.png -fft +delete lena_magnitude.png
magick lena_magnitude.png -gravity center -extent 1x1 \
-scale 60x60 lena_dc_zoom.gif
Seperti terlihat, warna rata-rata gambar ini semacam 'merah muda gelap'. Cara lain memandang piksel istimewa ini adalah sebagai tingkat 'bias' tengah, yang di sekitarnya semua gelombang sinus lain mengubah warna gambar. Sebagai contoh, mari kita ganti piksel DC 'merah muda gelap' itu dengan warna lain, misalnya warna yang lebih oranye, 'tomato'... |
magick lena.png -fft \
\( -clone 0 -draw "fill tomato color 64,64 point" \) \
-swap 0 +delete -ift lena_dc_replace.png
![[IM Output]](../static/img/fourier/lena_dc_replace.png)
Yang sebenarnya terjadi adalah, dengan mengubah nilai DC pada gambar FFT, seluruh gambar ikut berubah dengan cara yang sama. Sebenarnya setiap perubahan nilai DC (selisihnya) akan ditambahkan (atau dikurangkan) pada tiap-tiap piksel gambar hasilnya. Persis seolah-olah kita memang menambahkan suatu konstanta ke tiap piksel gambar aslinya. Karena itu warna piksel akhir pada gambar hasil rekonstruksi juga bisa terpotong oleh batas maksimum (putih) atau minimum (hitam). Jadi ini bukan metode yang disarankan untuk mewarnai gambar. Cara ini lebih sederhana diterapkan daripada mengubah tiap piksel di seluruh gambar, meski perjalanan bolak-balik FFT membuatnya secara keseluruhan menjadi teknik pewarnaan yang jauh lebih lambat.
Spektrum gambar gelombang sinus
Berikutnya, mari kita lihat spektrum dari gambar satu gelombang sinus (atau kosinus) dengan 4 siklus melintasi gambar
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
| _Pembuatan gambar gradien yang tidak biasa di atas diperlukan untuk memastikan gambar gelombang sinus yang dihasilkan dapat di-tile secara sempurna melintasi gambar.
Gambar "gradient:" biasa tidak dapat di-tile secara sempurna, begitu pula gelombang sinus yang dibuat darinya. Transformasi FFT atas tile yang tidak sempurna semacam itu akan menghasilkan larik harmonik yang tak diinginkan, alih-alih 'titik' tunggal pada spektrum transformasi Fourier.
Lihat Membuat gradien yang sempurna untuk detail lebih lanjut tentang masalah ini.
_
Pada gambar spektrum (gambar magnitudo yang diperkuat) di atas, terlihat ada 3 titik. Titik tengahnya, seperti sebelumnya, adalah nilai DC rata-rata. Dua titik lainnya mewakili gelombang sinus sempurna yang ditemukan operator Fourier di dalam gambar. Karena frekuensinya sepanjang lebar gambar tepat 4 siklus, dua piksel frekuensi itu berjarak tepat 4 piksel dari nilai DC di tengah. Tapi kenapa dua piksel? Sebabnya, satu gelombang sinus dapat dijabarkan dengan dua cara yang sepenuhnya berbeda (salah satunya dengan arah dan fase negatif). Kedua penjabaran itu benar secara matematis, dan transformasi Fourier tidak membedakan keduanya. Kalau ini diulangi dengan gelombang sinus 16 siklus, sekali lagi terlihat ada 3 titik, tetapi titik-titiknya lebih berjauhan. Dalam hal ini titik-titik sampingnya berjarak 16 piksel di sisi kiri dan kanan titik tengah.
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
Dari sini terlihat bahwa gelombang sinus sempurna cukup diwakili oleh dua titik pada posisi yang sesuai. Jarak posisi itu dari nilai DC di tengah menentukan frekuensi gelombang sinusnya. Makin pendek panjang gelombangnya, makin tinggi frekuensinya, sehingga titik-titiknya makin jauh dari nilai DC. Bahkan dengan membagi ukuran gambar dengan frekuensinya (jarak titik dari pusat) diperoleh panjang gelombang (jarak antarpuncak) gelombang tersebut. Pada kasus di atas: 128 piksel dibagi 16 siklus memberi panjang gelombang 8 piksel di antara tiap 'pita'. Inilah salah satu ciri pembeda terpenting dari transformasi FFT. Pola berupa fitur-fitur kecil pada gambar asli menuntut panjang gelombang yang pendek, jadi frekuensi yang besar. Hasilnya efek berskala besar di domain frekuensi. Sebaliknya fitur besar memakai frekuensi yang lebih kecil sehingga menghasilkan pola berskala kecil, terutama dekat ke arah pusat. Dalam transformasi Fourier...
Yang kecil menjadi besar dan yang besar menjadi kecil.
Ini salah satu aspek paling penting untuk diingat saat berurusan dengan transformasi Fourier, sebab inilah kunci untuk menghilangkan noise (fitur-fitur kecil) dari gambar sambil mempertahankan aspek gambar yang lebih besar secara keseluruhan. Mari kita cermati lebih rinci ketiga 'frekuensi' ini dengan memplot magnitudo aslinya (bukan spektrum logaritmiknya). |
magick sine16.png -fft -delete 1 miff:- |\
im_profile - sine16_magnitude_pf.png
![[IM Output]](../static/img/fourier/sine16_magnitude_pf.png)
Perhatikan bahwa nilai DC (rata-rata atau bias gambar) bernilai 1/2, sebagaimana diharapkan (nilai rata-rata gambarnya tepat abu-abu 50%), tetapi magnitudo sebenarnya dari kedua gelombang sinus 16 siklus yang ditemukan transformasi Fourier hanya 1/4 dari nilai maksimum. Magnitudo gelombang sinus aslinya sebenarnya 1/2, tetapi transformasi Fourier membagi magnitudo itu menjadi dua, membagikan hasilnya ke kedua gelombang frekuensi yang diplot, sehingga masing-masing dari kedua komponen itu hanya bermagnitudo 1/4. Itu bagian yang normal dari transformasi Fourier.
Dualitas frekuensi positif dan negatif pada gambar FFT inilah yang menjelaskan mengapa semua spektrum gambar FFT (seperti spektrum Lena yang diulang di sebelah kiri) selalu simetris terhadap pusatnya. Untuk tiap titik di satu sisi gambar, selalu ada 'titik' serupa yang tercermin secara rotasional melintasi pusat gambar. Hal yang sama terjadi pada komponen 'fase' dari pasangan gambar FFT, tetapi disertai pergeseran nilai 180 derajat (fase negatif) juga. Artinya separuh masing-masing gambar sebenarnya duplikat dari separuh lainnya, tetapi KEDUA gambar itu dibutuhkan untuk membuat ulang gambar aslinya. Dengan kata lain, kedua gambar tetap memuat jumlah informasi yang persis sama, separuh di satu gambar dan separuh di gambar lainnya. Bersama-sama keduanya membentuk satu keutuhan. | _Saat pembuatan, algoritma FFT hanya menghasilkan separuh kiri gambar. Separuh sisanya dihasilkan lewat rotasi dan penggandaan data yang sudah dibuat.
Saat mengonversi gambar domain frekuensi kembali menjadi gambar domain spasial, algoritmanya sekali lagi hanya melihat separuh kiri gambar. Separuh kanannya sepenuhnya diabaikan karena hanya duplikat.
Karena itu, ketika (pada contoh-contoh berikutnya) sebuah gambar magnitudo FFT di-'notch filter', sebenarnya cukup sisi kiri gambar magnitudo itu saja yang disaring. Sebagian pekerjaan dapat dihemat dengan mengabaikan separuh kanannya. Namun demi kejelasan, saya akan me-'notch' kedua separuhnya.
Membuat gambar FFT secara langsung
Sekarang informasi di atas dapat kita pakai untuk benar-benar membuat gambar sebuah gelombang sinus. Yang perlu dilakukan hanyalah membuat sepasang gambar hitam dan abu-abu 50%, lalu menambahkan 'titik' dengan magnitudo dan fase yang sesuai. Sebagai contoh...
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
| Dan simsalabim, jadilah gelombang sinus miring yang sempurna (dan dapat di-tile). Tentu saja gelombang sinus sempurna hanya bisa dibuat pada frekuensi tertentu, dan hanya dapat di-tile pada gambar persegi (kecuali kalau ukurannya diubah kemudian). Sayangnya semua frekuensinya juga akan berupa pangkat dua pada arah horizontal maupun vertikal, dan itulah keterbatasan utama teknik ini. | Sebenarnya hanya titik 'gray25' pertama (paling kiri) yang diperlukan untuk membuat gelombang sinus itu, karena transformasi IFT sepenuhnya mengabaikan separuh kanan gambar yang semestinya sekadar cerminan rotasional dari separuh kiri. |
|---|---|
| Fase nilai DC harus bersudut 'nol' (warna abu-abu 50%). Kalau hal itu tidak dipastikan, nilai warna DC akan termodulasi oleh fasenya yang bukan nol sehingga menghasilkan gambar yang lebih gelap dan mungkin 'terpotong'. | |
| --- | --- |
| _Piksel-piksel lain pada fase boleh bertingkat abu-abu berapa pun sesuai selera, dan efeknya akan 'menggulirkan' gelombang sinus melintasi gambar. Sekali lagi, yang benar-benar berpengaruh hanyalah fase titik paling kiri. Sisi kanannya sepenuhnya diabaikan. Cukup pastikan piksel fase DC di tengah tetap abu-abu 50%. |
_
FUTURE: Perlin Noise Generator using FFT
Spektrum garis vertikal
Tunjukkan spektrum FFT dari garis tipis dan garis tebal Peragakan bagaimana fitur kecil menjadi 'besar' dan fitur besar menjadi 'kecil' pada FFT gambar itu. Kaitkan hal itu kembali ke gelombang sinus yang dapat dianggap sebagai 'garis' dengan satu harmonik. Putar garisnya
Spektrum gambar pola persegi panjang
Berikutnya, mari kita lihat spektrum dari persegi panjang putih selebar 8 dan setinggi 16 di dalam latar belakang hitam.
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
Seperti terlihat, gambar hasilnya memiliki pola yang sangat khas dengan banyak frekuensi harmonik. Terlihat pula bahwa persegi panjangnya seolah-olah diputar 90 derajat. Anggapan itu keliru; yang terlihat adalah aturan yang sama yang tadi kita sebut.. fitur besar menjadi kecil dan fitur kecil menjadi besar. Karena itu dimensi persegi panjang yang lebih kecil menjadi lebih besar dan dimensi yang lebih besar menjadi lebih kecil. Sekarang mari kita putar persegi panjang itu 45 derajat. Ternyata spektrumnya ikut berputar 45 derajat ke arah yang sama.
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
Seperti terlihat, rotasi yang sama muncul di domain frekuensi. Artinya, efek suatu objek yang diputar juga akan ikut berputar pada transformasi Fouriernya. Tetapi kalau sekarang persegi panjang itu kita geser...
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
Pola frekuensinya tidak bergeser. Sebabnya, semua informasi posisi termuat pada gambar fase. Pola frekuensinya (magnitudo atau spektrumnya tidak berubah karena pergeseran itu). Pemisahan posisi inilah salah satu ciri kunci transformasi Fourier yang membuatnya begitu penting. Ciri ini memungkinkan pencarian pola gambar tertentu di dalam gambar yang lebih besar, tak peduli di mana letak objek yang menghasilkan pola spektrum Fourier tersebut.
Spektrum gambar pola lingkaran datar
Berikutnya, mari kita lihat spektrum dari gambar berpola lingkaran datar berwarna putih, yang satu berdiameter 12 (jari-jari 6) dan yang lain berdiameter 24 (jari-jari 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
Perhatikan bahwa gambar pertama sangat mendekati apa yang kita hasilkan untuk contoh jinc jauh di atas. Hanya saja gambar itu agak terpecah-pecah. Artefak ini muncul karena ukuran lingkarannya yang kecil. Karena disajikan secara digital, kelilingnya tidak benar-benar melingkar sempurna. Sekali lagi terlihat bahwa detail kecil menjadi besar di ruang frekuensi hasil transformasi. Transformasi lingkaran yang lebih besar hasilnya lebih baik karena kelilingnya lebih mendekati lingkaran sejati. Karena itu kita simpulkan bahwa transformasi bentuk lingkaran datar memang berupa fungsi jinc, dan gambar dengan lingkaran berdiameter lebih kecil menghasilkan fitur transformasi yang lebih menyebar dan lebih lebar. Menurut sifat matematis transformasi Fourier, jarak dari pusat ke tengah cincin gelap pertama pada spektrum adalah 1.22N/d. Bila diameter lingkarannya d=12, jaraknya menjadi 1.22128/12=13. Begitu pula bila diameter lingkarannya d=24, jaraknya menjadi 1.22*128/24=6.5.
Spektrum gambar pola Gaussian
Berikutnya, mari kita lihat spektrum dari dua gambar, masing-masing berpola lingkaran Gaussian putih dengan sigma 8 dan 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
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
Selain noise yang ditimbulkan oleh larik persegi dari polanya, hasilnya, pola Gaussian menghasilkan pola frekuensi Gaussian yang nyaris identik. Yang lebih penting, tampilan pola itu cukup bersih. Tentu saja ada perbedaan ukuran, lagi-lagi mengikuti aturan yang sama: yang besar menjadi kecil dan yang kecil menjadi besar. Dari sifat matematisnya, sigma pada spektrum adalah N/(2*sigma), dengan sigma diambil dari gambar aslinya. Jadi untuk gambar berukuran N=128 dan sigma=8, sigma pada spektrumnya menjadi 128/16=8. Begitu pula kalau sigma gambarnya 16, sigma pada spektrumnya menjadi 128/32=4. Inilah hubungan matematis dari aturan "yang besar menjadi kecil dan sebaliknya", dan hubungan ini berguna untuk diketahui.
Spektrum gambar pola grid
Berikutnya, mari kita transformasikan sebuah gambar yang isinya hanya sekumpulan garis grid berjarak 16x8 piksel.
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
Spektrum yang dihasilkan tak lain adalah larik titik: garis grid yang jaraknya lebih rapat menghasilkan titik yang lebih berjauhan, dan sebaliknya. Menurut sifat-sifat di atas, karena garis gridnya berjarak 16x8 piksel, titik-titiknya semestinya berjarak N/a=128/16=8 dan M/b=128/8=16, dan itulah yang terukur pada gambar ini. Pola ini penting secara khusus karena memperlihatkan hubungan antara transformasi Fourier dan pola tile yang teratur di dalam gambar. Pola tile semacam itu menghasilkan pola grid non-pusat yang sangat kuat pada transformasi Fouriernya. Inti pentingnya, informasi bentuk berada di pusat, sedangkan informasi tile berada pada larik mirip grid yang menjauh dari pusat transformasi Fouriernya.
Informasi spektrum lainnya
Berikut beberapa tautan bagi yang ingin tahu lebih banyak tentang gambar spektrum dan sifat-sifatnya.
- Wikipedia: Fourier Transform
- Fred Weinhaus, Properities of a Fourier Transform
- Wolfram MathWorld: Fourier Transform
Penerapan praktis
Baik, sekarang setelah dasar-dasarnya kita bahas, apa saja penerapan praktis dari transformasi Fourier? Beberapa hal yang bisa dilakukan antara lain: 1) menaikkan atau menurunkan kontras gambar, 2) mengaburkan, 3) menajamkan, 4) mendeteksi tepi, dan 5) menghilangkan noise.
Mengubah kontras gambar - coefficient rooting
Kontras sebuah gambar dapat disetel dengan melakukan transformasi Fourier maju, memangkatkan gambar magnitudonya, lalu memakai hasil itu bersama fasenya pada transformasi Fourier balik. Untuk menaikkan kontras dipakai eksponen yang sedikit kurang dari satu, dan untuk menurunkan kontras dipakai eksponen yang sedikit lebih dari satu. Jadi mari kita naikkan dulu kontras gambar Lena memakai eksponen 0.9, lalu turunkan kontrasnya memakai eksponen 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
Namun melakukan hal ini pada gambar aslinya akan memberi efek yang sama saja. Artinya, modifikasi magnitudo secara global memberi efek yang sama seperti kalau modifikasi global itu dilakukan pada gambar aslinya.
Mengaburkan gambar - penyaringan lolos-rendah
Salah satu sifat terpenting transformasi Fourier adalah bahwa konvolusi di domain spasial setara dengan perkalian sederhana di domain frekuensi. Di domain spasial, filter konvolusi (kernel) sederhana berukuran kecil dan persegi dipakai untuk mengaburkan gambar dengan opsi -convolve. Filter ini disebut filter lolos-rendah. Filter yang paling sederhana hanyalah larik persegi berbobot sama rata. Artinya, semua nilainya satu, lalu dinormalisasi dengan membaginya dengan jumlah totalnya sebelum konvolusi diterapkan. Ini setara dengan rata-rata lokal atau rata-rata ketetanggaan. Filter lolos-rendah lainnya adalah filter berbentuk lingkaran berbobot Gaussian yang disediakan oleh -gaussian-blur atau -blur. Di domain frekuensi, salah satu jenis filter pengabur lolos-rendah cukup berupa lingkaran putih berintensitas konstan yang dikelilingi warna hitam. Filter ini mirip dengan filter konvolusi perata berbentuk lingkaran di domain spasial. Namun karena konvolusi di domain spasial setara dengan perkalian di domain frekuensi, yang perlu kita lakukan hanyalah melakukan transformasi Fourier maju, lalu mengalikan filter itu dengan gambar magnitudonya, dan terakhir melakukan transformasi Fourier balik. Perlu dicatat, filter konvolusi berukuran kecil akan bersesuaian dengan lingkaran besar di domain frekuensi. Perkalian dilakukan lewat -composite dengan pengaturan (setting) -compose multiply. Jadi mari kita coba dengan dua ukuran filter lingkaran, yang satu berdiameter 40 (jari-jari 20) dan yang lain berdiameter 28 (jari-jari 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
Jadi terlihat bahwa gambar yang memakai filter berdiameter lebih kecil menghasilkan pengaburan yang lebih kuat. Terlihat pula efek 'ringing' atau 'riak' di dekat tepi pada gambar-gambar hasilnya. Ini terjadi karena transformasi Fourier sebuah lingkaran, seperti yang kita lihat tadi, adalah fungsi jinc, yang osilasinya mengecil seiring menjauh dari pusat. Namun di sini fungsi jinc dan osilasinya berada di domain spasial, bukan di domain frekuensi seperti yang diperagakan sebelumnya di atas. Lalu apa yang bisa dilakukan? Cara paling sederhana adalah melandaikan tepi lingkarannya memakai berbagai fungsi jendela. Cara lain, pakai filter berbentuk Gaussian yang menurut definisinya sudah landai. Jadi mari kita tempuh cara kedua dan memakai dua lingkaran yang di-blur secara Gaussian untuk menghilangkan sebagian besar efek 'ringing' yang parah.
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
Hasil ini tentu jauh lebih baik. Filter lolos-rendah yang ideal sebenarnya bukan dengan mengaburkan lingkaran sama sekali, melainkan memakai kurva Gaussian yang sesungguhnya dengan sigma alih-alih radius. Tentu saja pada contoh ini kita malah melakukan blur untuk melakukan blur! Namun pola blur yang dikalikan terhadap gambar magnitudo FFT itu tetap, dan sebenarnya bisa diambil dari cache yang sudah dibuat sebelumnya. Selain itu gambar pengalinya tidak harus seukuran penuh gambar aslinya; gambar yang lebih kecil pun bisa dipakai. Karena itu cara di atas bisa jauh lebih cepat untuk gambar besar, dan juga saat menangani banyak gambar sekaligus. Yang lebih penting, untuk blur yang besar dan kuat, gambar domain frekuensinya kecil dan hanya melakukan satu perkalian, alih-alih harus merata-ratakan banyak piksel untuk tiap-tiap piksel gambar aslinya. Untuk blur berukuran kecil, blur konvolusi yang lebih langsung mungkin lebih menguntungkan.
Mendeteksi tepi dalam gambar - penyaringan lolos-tinggi
Di domain spasial, filter lolos-tinggi yang mengekstrak tepi dari gambar sering diimplementasikan sebagai konvolusi dengan bobot positif dan negatif yang jumlahnya nol. Di domain frekuensi urusannya jauh lebih sederhana. Di sini filter lolos-tinggi tak lain adalah versi ternegasi dari filter lolos-rendah. Artinya, di tempat filter lolos-rendah terang, filter lolos-tinggi gelap, dan sebaliknya. Jadi di ImageMagick yang perlu kita lakukan hanyalah me--negate gambar filter lolos-rendah tadi. Mari kita terapkan filter lolos-tinggi pada gambar Lena memakai gambar lingkaran. Lalu ulangi memakai kurva Gaussian murni.
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
Kalau kedua hasil ini diamati dengan saksama, terlihat bahwa lingkaran sederhana itu tidak sebaik yang Gaussian, karena punya artefak 'ringing' dan kurang tajam.
Menajamkan gambar - penyaringan high boost
Cara paling sederhana untuk menajamkan gambar adalah menyaringnya dengan filter lolos-tinggi (tanpa peregangan normalisasi) lalu memadukannya dengan gambar asli.
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
Di sini filter lolos-tinggi dikerjakan di domain frekuensi lalu hasilnya ditransformasikan kembali ke domain spasial untuk dipadukan dengan gambar asli, sehingga tepi gambarnya menguat.
Menghilangkan noise - penyaringan notch
Banyak gambar ber-noise memuat noise yang berpola. Noise semacam ini mudah dihilangkan di domain frekuensi karena polanya muncul sebagai pola beberapa titik atau garis saja. Ingat kembali bahwa gelombang sinus sederhana adalah pola berulang dan hanya muncul sebagai 3 titik pada spektrumnya. Untuk menghilangkan noise ini, sayangnya titik atau garis pada gambar magnitudo harus di-mask (atau di-notch) secara manual. Caranya dengan mentransformasikan gambar ke domain frekuensi, membuat versi grayscale dari spektrumnya, me-mask titik atau garisnya, menerapkan ambang batas (threshold), mengalikan gambar mask biner itu dengan gambar magnitudo, lalu mentransformasikannya kembali ke domain spasial. Mari kita coba pada gambar badut yang memuat pola bergaris diagonal mirip dithering. Pertama kita transformasikan gambar badut itu untuk membuat gambar magnitudo dan fasenya.
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
Terlihat bahwa spektrumnya memuat empat titik terang mirip bintang, satu di tiap kuadran. Titik-titik tak biasa itu mewakili pola dalam gambar yang ingin kita singkirkan. Titik dan garis terang di tengah gambar tidak perlu dirisaukan karena mewakili DC (warna rata-rata gambar) dan efek tepi gambar, jadi jangan diubah. Perhatikan bahwa saat membuat gambar spektrum saya memaksa gambar hasilnya menjadi gambar grayscale murni. Dengan begitu gambar itu bisa saya muat ke sebuah editor lalu, memakai warna apa pun selain abu-abu (misalnya merah), saya mask area keempat pola mirip bintang tadi. Setelah selesai menyunting, area yang saya warnai dapat diekstrak dengan mengambil gambar selisih terhadap versi yang belum disunting. Seperti ini...
magick clown_spectrum_edited.png clown_spectrum.png \
-compose difference -composite \
-threshold 0 -negate clown_spectrum_mask.png
Sekarang kita tinggal mengalikan mask itu dengan magnitudonya lalu memakai hasilnya bersama gambar fase asli untuk mentransformasikannya kembali ke domain spasial. Gambar aslinya kita tampilkan di sebelahnya sebagai pembanding
magick clown_magnitude.png clown_spectrum_mask.png \
-compose multiply -composite \
clown_phase.png -ift clown_filtered.png
Hasil yang sangat bagus. Tapi kita masih bisa lebih baik lagi. Seperti terlihat pada contoh-contoh sebelumnya, 'lingkaran' sederhana kurang bersahabat dengan gambar FFT, jadi mari kita kaburkan sedikit mask-nya... |
magick clown_spectrum_mask.png \
-blur 0x5 -level 50x100% clown_mask_blurred.png
![[IM Output]](../static/img/fourier/clown_mask_blurred.png)
Lalu saring gambar badutnya, kali ini dengan membuat ulang gambar FFT-nya di memori. |
magick clown_orig.jpg -fft \
\( -clone 0 clown_mask_blurred.png -compose multiply -composite \) \
-swap 0 +delete -ift clown_filtered_2.png
![[IM Output]](../static/img/fourier/clown_filtered_2.png)
Hasil yang sungguh menakjubkan! Dan hasil itu mungkin masih bisa diperbaiki lagi dengan menyetel mask tadi supaya lebih pas dengan bentuk 'bintang'-nya. Kita bahkan bisa mengambil selisih antara gambar asli dan hasilnya untuk membuat gambar area tempat noise dihilangkan. |
magick clown_orig.jpg clown_filtered_2.png -compose difference \
-composite -normalize clown_noise.png
![[IM Output]](../static/img/fourier/clown_noise.png)
Mari kita coba pada contoh lain. Kali ini pada gambar "Twigs" yang ada di situs RoboRealm, yang memuat pola garis horizontal dan vertikal yang tak beraturan. Sekali lagi kita ekstrak gambar spektrum grayscale, persis seperti tadi.
magick twigs.jpg -fft +delete -colorspace gray \
-auto-level -evaluate log 100000 twigs_spectrum.png
Dalam kasus ini, karena noise pada gambar berorientasi horizontal dan vertikal, hal itu muncul sebagai pita horizontal dan vertikal yang tebal di sepanjang garis tengah, tetapi tidak di titik pusat gambarnya. Sekali lagi kita mask bagian-bagian itu memakai editor gambar, kali ini dengan warna 'biru' (warna apa yang dipakai sebenarnya tidak penting)...
magick twigs_spectrum_edited.png twigs_spectrum.png \
-compose difference -composite \
-threshold 0 -negate twigs_spectrum_mask.png
Sekarang kita kalikan lagi mask itu dengan gambar magnitudo FFT, lalu rekonstruksi gambarnya.
magick twigs.jpg -fft \
\( -clone 0 twigs_spectrum_mask.png -compose multiply -composite \) \
-swap 0 +delete -ift twigs_filtered.png
Dan kita bisa mengambil selisih antara gambar asli dan hasilnya untuk membuat gambar area tempat noise dihilangkan.
magick twigs.jpg twigs_filtered.png -compose difference -composite \
-normalize twigs_noise.png
Menambahkan sedikit blur pada mask-nya sekali lagi dapat memperbaiki hasilnya lebih jauh. Sebagai latihan, coba hilangkan talinya dari gambar itu. Sebagai petunjuk, ingatlah bagaimana efek sebuah garis pada gambar nyata berputar 90 derajat pada FFT. Kalau salah, yang hilang malah rantingnya.
Penerapan lanjutan
Beberapa penerapan transformasi Fourier lain yang lebih lanjut antara lain: 1) dekonvolusi (deblurring) gambar yang terkena motion blur dan gambar yang tidak fokus, serta 2) korelasi silang ternormalisasi untuk menemukan di bagian mana sebuah gambar kecil paling cocok di dalam gambar yang lebih besar. Contoh perkalian dan pembagian FFT (dekonvolusi) sudah dipindahkan ke subdirektori karena masih menunggu operator pemrosesan gambar yang didefinisikan lebih formal.
![[IM Output]](../static/img/img_photos/holocaust_tn.gif)
![[IM Output]](../static/img/fourier/image_profile.gif)
![[IM Output]](../static/img/fourier/wave.gif)
![[IM Output]](../static/img/fourier/wave_profile.gif)
![[IM Output]](../static/img/fourier/wave_1_pf.gif)
![[IM Output]](../static/img/fourier/wave_2_pf.gif)
![[IM Output]](../static/img/fourier/wave_3_pf.gif)
![[IM Output]](../static/img/fourier/added_waves_pf.gif)
![[IM Output]](../static/img/img_photos/lena.png)
![[IM Output]](../static/img/fourier/lena_roundtrip.png)
![[IM Text]](../static/img/fourier/lena_roundtrip_cmp.txt.gif)
![[IM Output]](../static/img/fourier/lena_fft_0.png)
![[IM Output]](../static/img/fourier/lena_fft_1.png)
![[IM Output]](../static/img/fourier/lena_magnitude.png)
![[IM Output]](../static/img/fourier/lena_phase.png)
![[IM Output]](../static/img/fourier/lena_restored.png)
![[IM Output]](../static/img/fourier/lena_magitude_only.png)
![[IM Output]](../static/img/fourier/lena_phase_only.png)
![[IM Output]](../static/img/fourier/lena_roundtrip_hdri.png)
![[IM Text]](../static/img/fourier/lena_roundtrip_hdri_cmp.txt.gif)
![[IM Output]](../static/img/fourier/lena_roundtrip_ri.png)
![[IM Text]](../static/img/fourier/lena_roundtrip_ri_cmp.txt.gif)
![[IM Output]](../static/img/fourier/lena_real_only.png)
![[IM Output]](../static/img/fourier/lena_imaginary_only.png)
![[IM Output]](../static/img/fourier/constant.png)
![[IM Output]](../static/img/fourier/constant_magnitude.png)
![[IM Output]](../static/img/fourier/lena_dc_zoom.gif)
![[IM Output]](../static/img/fourier/sine4.png)
![[IM Output]](../static/img/fourier/sine4_spectrum.png)
![[IM Output]](../static/img/fourier/sine16.png)
![[IM Output]](../static/img/fourier/sine16_spectrum.png)
![[IM Output]](../static/img/fourier/generated_spectrum.png)
![[IM Output]](../static/img/fourier/generated_phase.png)
![[IM Output]](../static/img/fourier/generated_wave.png)
![[IM Output]](../static/img/fourier/rectangle.png)
![[IM Output]](../static/img/fourier/rect_spectrum.png)
![[IM Output]](../static/img/fourier/rect_rot45.png)
![[IM Output]](../static/img/fourier/rect_rot45_spectrum.png)
![[IM Output]](../static/img/fourier/rect_rot45off.png)
![[IM Output]](../static/img/fourier/rect_rot45off_spectrum.png)
![[IM Output]](../static/img/fourier/circle6.png)
![[IM Output]](../static/img/fourier/circle6_spectrum.png)
![[IM Output]](../static/img/fourier/circle12.png)
![[IM Output]](../static/img/fourier/circle12_spectrum.png)
![[IM Output]](../static/img/fourier/gaus8.png)
![[IM Output]](../static/img/fourier/gaus8_spectrum.png)
![[IM Output]](../static/img/fourier/gaus8_pf.gif)
![[IM Output]](../static/img/fourier/gaus8_spectrum_pf.gif)
![[IM Output]](../static/img/fourier/gaus16.png)
![[IM Output]](../static/img/fourier/gaus16_spectrum.png)
![[IM Output]](../static/img/fourier/gaus16_pf.gif)
![[IM Output]](../static/img/fourier/gaus16_spectrum_pf.gif)
![[IM Output]](../static/img/fourier/grid16x8.png)
![[IM Output]](../static/img/fourier/grid16x8_spectrum.png)
![[IM Output]](../static/img/fourier/lena_plus_contrast.png)
![[IM Output]](../static/img/fourier/lena_minus_contrast.png)
![[IM Output]](../static/img/fourier/circle_r20.png)
![[IM Output]](../static/img/fourier/lena_blur_r20_spec.png)
![[IM Output]](../static/img/fourier/lena_blur_r20.png)
![[IM Output]](../static/img/fourier/circle_r14.png)
![[IM Output]](../static/img/fourier/lena_blur_r14_spec.png)
![[IM Output]](../static/img/fourier/lena_blur_r14.png)
![[IM Output]](../static/img/fourier/gaussian_r20.png)
![[IM Output]](../static/img/fourier/lena_gblur_r20_spec.png)
![[IM Output]](../static/img/fourier/lena_gblur_r20.png)
![[IM Output]](../static/img/fourier/gaussian_r14.png)
![[IM Output]](../static/img/fourier/lena_gblur_r14_spec.png)
![[IM Output]](../static/img/fourier/lena_gblur_r14.png)
![[IM Output]](../static/img/fourier/circle_r14i.png)
![[IM Output]](../static/img/fourier/lena_edge_r14_spec.png)
![[IM Output]](../static/img/fourier/lena_edge_r14.png)
![[IM Output]](../static/img/fourier/gaussian_s14i.png)
![[IM Output]](../static/img/fourier/lena_edge_s14_spec.png)
![[IM Output]](../static/img/fourier/lena_edge_s14.png)
![[IM Output]](../static/img/fourier/lena_sharp14.png)
![[IM Output]](../static/img/fourier/clown_orig.jpg)
![[IM Output]](../static/img/fourier/clown_spectrum.png)
![[IM Output]](../static/img/fourier/clown_phase.png)
![[IM Output]](../static/img/fourier/clown_spectrum_edited.png)
![[IM Output]](../static/img/img_photos/clown_spectrum_mask.png)
![[IM Output]](../static/img/fourier/clown_filtered.png)
![[IM Output]](../static/img/fourier/twigs.jpg)
![[IM Output]](../static/img/fourier/twigs_spectrum.png)
![[IM Output]](../static/img/fourier/twigs_spectrum_edited.png)
![[IM Output]](../static/img/img_photos/twigs_spectrum_mask.png)
![[IM Output]](../static/img/fourier/twigs_filtered.png)
![[IM Output]](../static/img/fourier/twigs_noise.png)