Archive
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
以前、Octaveで求めていた位相画像をC#とOpenCVSharpにて実装してみたいと思います。



ソース

以下がソースコードになります。
Form1_Paint()内にてフーリエ変換などを行っていますが、 途中まではOpenCVのサンプルをまねしています。

離散変換 - http://opencv.jp/sample/discrete_transforms.html

また、
DFT - http://opencv.jp/opencv-1.0.0/document/opencvref_cxcore_discrete.htmlにて記載されているように離散フーリエ変換であるcvDFT(Cv.DFT)の変換・逆変換は3つ目の引数であるflagsにより決まります。

つまり、以下のようになります。
CV_DXT_FORWARD(DFTFlag.Forward)
→フーリエ変換
CV_DXT_INVERSE(DFTFlag.Inverse)
→フーリエ逆変換


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OpenCvSharp;

namespace PhaseImage
{
    public partial class Form1 : Form
    {
        Bitmap bitmap;
        String filename = "Lenna.bmp";

        public Form1()
        {
            InitializeComponent();
            bitmap = new Bitmap(filename);

            //左側のpictureBoxの設定
            pictureBox1.Height = bitmap.Height;
            pictureBox1.Width = bitmap.Width;
            pictureBox1.Left = 0;
            pictureBox1.Top = 0;
            pictureBox1.Image = bitmap;

            //右側のpictureBoxの設定
            pictureBox2.Height = bitmap.Height;
            pictureBox2.Width = bitmap.Width;
            pictureBox2.Left = pictureBox1.Width;
            pictureBox2.Top = 0;

            this.ClientSize = new Size(pictureBox1.Width + pictureBox2.Width, pictureBox1.Height);
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            IplImage img = new IplImage(filename, LoadMode.GrayScale);
            IplImage phase;
            using (IplImage reimg = Cv.CreateImage(img.Size, BitDepth.F64, 1))
            using (IplImage imimg = Cv.CreateImage(img.Size, BitDepth.F64, 1))
            using (IplImage cmpimg = Cv.CreateImage(img.Size, BitDepth.F64, 2))
            {
                // (1)入力画像を実数配列にコピーし,虚数配列とマージして複素数平面を構成
                Cv.Scale(img, reimg, 1.0, 0.0);
                Cv.Zero(imimg);
                Cv.Merge(reimg, imimg, null, null, cmpimg);

                // (2)DFT用の最適サイズを計算し,そのサイズで行列を確保する
                int dft_M = Cv.GetOptimalDFTSize(img.Height - 1);
                int dft_N = Cv.GetOptimalDFTSize(img.Width - 1);

                using (CvMat dft_A = Cv.CreateMat(dft_M, dft_N, MatrixType.F64C2))
                using (IplImage image_Re = Cv.CreateImage(new CvSize(dft_N, dft_M), BitDepth.F64, 1))
                using (IplImage image_Im = Cv.CreateImage(new CvSize(dft_N, dft_M), BitDepth.F64, 1))
                using (IplImage image_Re_Norm = Cv.CreateImage(new CvSize(dft_N, dft_M), BitDepth.F64, 1))
                using (IplImage image_Im_Norm = Cv.CreateImage(new CvSize(dft_N, dft_M), BitDepth.F64, 1))
                {
                    // (3)複素数平面をdft_Aにコピーし,残りの行列右側部分を0で埋める
                    CvMat tmp;
                    Cv.GetSubRect(dft_A, out tmp, new CvRect(0, 0, img.Width, img.Height));
                    Cv.Copy(cmpimg, tmp, null);
                    if (dft_A.Cols > img.Width)
                    {
                        Cv.GetSubRect(dft_A, out tmp, new CvRect(img.Width, 0, dft_A.Cols - img.Width, img.Height));
                        Cv.Zero(tmp);
                    }

                    // (4)離散フーリエ変換を行い,その結果を実数部分と虚数部分に分解
                    Cv.DFT(dft_A, dft_A, DFTFlag.Forward, cmpimg.Height);
                    Cv.Split(dft_A, image_Re, image_Im, null, null);

                    // 正規化用に複素数の値を保持しておく
                    Cv.Split(dft_A, image_Re_Norm, image_Im_Norm, null, null);

                    // (5)スペクトルの振幅を計算 Mag = sqrt(Re^2 + Im^2)
                    Cv.Pow(image_Re, image_Re, 2.0);
                    Cv.Pow(image_Im, image_Im, 2.0);
                    Cv.Add(image_Re, image_Im, image_Re, null);
                    Cv.Pow(image_Re, image_Re, 0.5);

                    // 正規化する
                    for (int j = 0; j < image_Re.Height; j++)
                    {
                        for (int i = 0; i < image_Re.Width; i++)
                        {
                            image_Re_Norm[j, i] = image_Re_Norm[j, i] / image_Re[j, i];
                            image_Im_Norm[j, i] = image_Im_Norm[j, i] / image_Re[j, i];
                        }
                    }
                    // 正規化した複素数平面をdft_Aにコピーする
                    Cv.Merge(image_Re_Norm, image_Im_Norm, null, null, dft_A);
                    Cv.DFT(dft_A, dft_A, DFTFlag.Inverse, cmpimg.Height);
                    
                    // 逆変換した画像を表示用の変数に格納
                    Cv.Split(dft_A, image_Re, image_Im, null, null);
                    phase = image_Re.Clone();
                }
            }

            //描画
            pictureBox1.Image = bitmap;
            pictureBox2.Image = phase.ToBitmap();
        }
    }
}

結果

左が元画像、右が位相画像です。





どうやらうまくいっているようです(;´Д`)=3

スポンサーサイト
FC2カウンター
プロフィール

詠み人知らず

Author:詠み人知らず
プログラム好きな名もなき凡人がお送りしています。(得意とは言っていない
最近の興味はPython、C#、Matlab(Octave)、画像処理、AR(拡張現実)、統計などなど・・・

気分で思いついたことを書くため話題に一貫性がないかもしれません。

カレンダー
09 | 2012/10 | 11
- 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 - - -
最新記事
タグクラウドとサーチ

カテゴリ
最新コメント
最新トラックバック
月別アーカイブ
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。