Visual Basic とOpenCVを用い、画像に対する離散フーリエ変換、および逆変換を行う例を紹介します。
逆離散フーリエ変換
先の例を拡張し、DFT したデータをIDFT して元の画像に戻ることを確認します。画像に対してDFT を実施した結果を可視化し、その結果をIDFT して元の画像に戻ることを示します。これらを3 つのフォームで表示します。
Form1.vb
ユーザーインターフェースは少し変わります。以降にソースリスト一部を示します。
: Public Class Form1 Private ReadOnly ttl As String = "sample" Private ReadOnly mFormDft As Form2 = Nothing Private ReadOnly mFormIdft As Form2 = Nothing Private ccvfunc As CCvFunc = Nothing Public Sub New() MyBase.New InitializeComponent() : mFormDft = New Form2 With {.Text = "DFT"} mFormIdft = New Form2 With {.Text = "IDFT"} ccvfunc = New CCvFunc() End Sub : Private Sub ToolMenuEffect_Click(sender As Object, e As EventArgs) _ Handles ToolMenuEffect.Click Try If PBox.Image Is Nothing Then Return ' 読み込んでいるか Cursor = Cursors.WaitCursor Dim result = ccvfunc.DoCvFunction() mFormDft.DoCvShow(ccvfunc, result.Item1) mFormIdft.DoCvShow(ccvfunc, result.Item2) Catch ex As Exception MessageBox.Show(ex.Message) Finally Cursor = Cursors.Default End Try End Sub :
本プログラムは、フォームが3つ必要です。Form1は、これまでと同じです。Form2をフーリエ変換(パワースペクトル、DFT)と逆フーリエ変換(IDFT)の表示に用います。このため、2つのForm2インスタンスを生成し、かつタイトルの表示を変更します。そして、DoCvFunctionメソッドは、2つのBitmapオブジェクトを返しますので、それぞれを生成した2つのフォームに表示します。
CCvFunc.vb
以降に、実際にIDFT を行うCCv の派生クラスCCvFunc を示します。
: Public Function DoCvFunction() As (Bitmap, Bitmap) Dim dft As Mat = mat2Dft(mSrc) ' image to DFT Dim dft8u As Mat = dft2dispMat(dft) ' DFT to display image Dim dispDft As Mat = swapDft(dft8u) ' swap: 1 <-> 4, 2 <-> 3 Dim dispIdft As Mat = dft2idft8u(dft, mSrc) Return (OpenCvSharp.Extensions.BitmapConverter.ToBitmap(dispDft), OpenCvSharp.Extensions.BitmapConverter.ToBitmap(dispIdft)) End Function Private Function mat2Dft(src As Mat) As Mat : Private Function dft2dispMat(complex As Mat) As Mat : Private Function swapDft(src As Mat) As Mat : Private Function dft2idft8u(dft As Mat, src As Mat) As Mat Dim temp As New Mat() Cv2.Idft(dft, temp) ' IDFT ' 複素画像の実部と虚部を2枚の画像に分離する。 Dim readImage = New Mat(1) {} Cv2.Split(temp, readImage) ' (0)-> Real, (1)->imaginary ' 実部について正規化を行う。入力画像のサイズはDFT用に ' 拡大されているので、原画像の同サイズにROIを設定して縮小する。 Dim idftRoi As Mat = New Mat(readImage(0), New Rect(0, 0, src.Cols, src.Rows)) Dim idft As New Mat() Cv2.Normalize(idftRoi, idft, 0, 1, NormTypes.MinMax) idft.ConvertTo(idft, MatType.CV_8UC1, 255.0, 0) Return idft End Function
mat2Dft メソッドで入力画像をDFT するのは前のプログラムと同じです。
DoCvFunctionメソッドは、DFTとIDFTを行い、2つのBitmapオブジェクトをタプルで戻します。
dft2idft8u メソッドは、入力画像をDFT したMat オブジェクトへIDFT 処理を行い、その結果のMat オブジェクトを返します。引数にDFT したMat オブジェクト(dft)と入力画像を格納したMat オブジェクト(src)を受け取ります。
Cv2.Idft メソッドでIDFT 処理を行います。次に、Cv2.Split メソッドでIDFT の結果をMat 配列であるreadImage へ分離します。この配列の (0) に実数部が、(1) に虚数部が格納されます。
一般的にDFT したMat オブジェクトのみでIDFT は可能と思うでしょうが、本プログラムはDFT を行う際に高速に処理できるようにMat オブジェクトのサイズを調整します。このため、何も考えずにIDFT を行うと、入力画像と異なったサイズのMat オブジェクトを返してしまいます。これを避けるために、入力画像も引数で受け取ります。この入力画像はサイズしか使用しません。このため、Mat オブジェクトではなくサイズを受け取っても良いでしょう。このサイズを利用し、IDFT 処理後の実数部にROI を設定し、これをidftRoi とします。
次に、Cv2.Normalize メソッドで0.0 ~ 1.0 へ正規化します。最後に、この正規化したMat オブジェクトをCV_8U へ変更します。その際に0.0 ~ 1.0 を0 ~ 255 へスケーリングします。このMat オブジェクトを呼び出し元へ戻します。
実行
以降に実行例を示します。左から原画像、DFT で得られたパワースペクトル、そしてIDFTで戻した画像を示します。
次に、この現画像にノイズを乗せ、オリジナル画像に比べ高周波成分を付加したものを示します。
ノイズも正確に元に戻っています。
ノイズを乗せたため、高周波成分が増えているのも観察できます。