【Excel】高速フーリエ変換(FFT)のマクロ(VBA)

Excelには標準でフーリエ解析の機能を備えていますが、解析用のデータを変更してもフーリエ変換の結果は自動更新してくれないので、少し使い勝手の悪い物になっています。

 

そこで、エクセルのセルの部分にSUMAVERAGE のような関数と同じように動くマクロ(ユーザー定義関数)で作成したフーリエ変換の関数(Fourier)を作成しました。

ユーザー定義関数で作成しているため、解析用のデータを変更すると、フーリエ変換の結果も自動で変更されます。

 

 

ファイルのダウンロードはこちら↓より

fourier_transform_rev3.zip

(Excel2016推奨、それ以前だとファイルを開いた直後はフーリエ変換の値が0になるようです。)

 

使用方法

このファイルはマクロを使用しているため、ファイルを起動するとセキュリティ警告が表示さている場合は、コンテンツの有効化をクリックしてください。

 

まず、フーリエ変換の結果の出力先のセルを縦方向にデータ個数と同じ分だけ選択し、

= Fourier( データのセル)

と入力し、Enterではなく、Ctrl + Shift + Enterキー を入力します。

これで、フーリエ変換の結果が複素数で表示されます。

 

複素数はいらないから、絶対値だけ欲しいという場合にはFourierAbs関数を使って下さい。(使い方は同じです。)

 

フーリエ変換の結果は標準のフーリエ解析の結果と同じになるようにしていますが、10の-15乗ぐらいの誤差が出ています。

 

フーリエ変換の結果の複素数の大きさを計算するには、Excelの標準関数の IMABS関数 で求まります。

 

同様に位相は IMARGUMENT関数 で求まります。

 

このマクロのポイント!

  • 窓関数に対応
    = Fourier( データのセル, “Hamming”)
    のように入力することで、入力データに対して窓関数を通します。
    対応している窓関数の名前は
    ハミング Hamming
    ハニング Hanning
    ブラックマン Blackman

    の3つ。

  • FFT/DFTの自動切換え
    マクロ処理内部で、フーリエ変換するデータ個数が2のN乗個の場合はFFT、それ以外の場合はDFTとなり、データの個数が2のN乗個の制限はありません。

 

逆フーリエ変換を追加

2018.6.19追記

逆フーリエ変換に対応したIFourier関数を追加しました。

逆フーリエ変換の計算は別シートの逆フーリエ変換のシートを参照ください。

 

使用方法については、普通のフーリエ変換の時と同じように

= IFourier( データのセル)

と入力し、Enterではなく、Ctrl + Shift + Enterキー を入力します。

ただし、逆フーリエ変換なので、データのセルの部分は、基本的に複素数となります。

 

逆フーリエ変換の結果はこちら↓です。

 

上の絵を見ても分かるように、虚数成分の10の-15乗程度の誤差が入ってしまっているので、複素数の実部だけを取得するIMREAL関数で実部を取得すると、ほぼフーリエ変換の時に用いたデータに戻っていることが確認できるかと思います。

 

 

フーリエ変換へ戻る

【C#】グローバル変換とローカル変換

画像を拡大縮小表示する場合は、.NET Frameworkのアフィン変換の機能を用いて表示するのが比較的簡単なのですが、そのアフィン変換にもグローバル変換ローカル変換というものがあります。

 

詳細はMSDNのページ

https://msdn.microsoft.com/ja-jp/library/c499ats3(v=vs.110).aspx

 

にも書いてありますが、グローバル変換はGraphicsクラスのTransformプロパティにアフィン変換用の行列のMatrixオブジェクト(名前空間:System.Drawing.Drawing2D)を指定すれば、Grapgicsオブジェクトへ描画する画像や線は、そのMatrixオブジェクトに基づいて拡大縮小、移動表示されるので、個々の画像や線などをアフィン変換する必要がなく、簡単といえば簡単なのですが、画像は拡大したいけど、文字は拡大したくない場合などに不都合があります。

 

下図の左側の画像がフローバル変換を用いて描画した結果ですが、画像を拡大すると、文字は大きくなり、線幅も太くなってしまいます。

(ここでは右側の画像のように拡大しても線幅や文字の大きさが変わらないのが目標)

 

それに対して、ローカル変換は画像や線に対して個々にアフィン変換を行い表示を行うのですが、実際にアフィン変換が出来るのはGraphicsPathのみで、画像に対するアフィン変換が用意されていません。

 

そこで、画像に対してもアフィン変換行列であるMatrixオブジェクトに基づいて、画像の拡大縮小を行うメソッドを作成しました。

private void DrawImageLocal(
    Graphics g, 
    System.Drawing.Drawing2D.Matrix mat,
    Bitmap bmp)
{
    if (bmp == null) return;

    // 描画元の領域
    var srcRect = new RectangleF(-0.5f, -0.5f, bmp.Width, bmp.Height);

    // 描画先の座標(描画元に合わせる、左上、右上、左下の順)
    var points = new PointF[]
    {
        new PointF(srcRect.Left, srcRect.Top),
        new PointF(srcRect.Right, srcRect.Top),
        new PointF(srcRect.Left, srcRect.Bottom),
    };
    // 描画先の座標をアフィン変換で求める(変換後の座標は上書きされる)
    mat.TransformPoints(points);

    // 描画
    g.DrawImage(
        bmp,
        points,
        srcRect,
        GraphicsUnit.Pixel
        );
}

ここでポイントとなるのが、描画元の左上の座標が(-0.5,-0.5)となっているのですが、これは一番左上の画素の中心が(0, 0)で、画素の左上の座標は(-0.5, -0.5)となるためで、詳細は以下のページを参照下さい。

 

【C#】画像の座標系

 

これらを使って作成したサンプルプログラムがこちら↓

 

動作イメージ

 

ダウンロード

Global_Local_Transform.zip

 

関連記事

【C#】画像の座標系

【C#】グローバル変換を使ったアフィン変換

【C#.NET】マイクロソフト仕様のアフィン変換

【C#】GraphicsPathの描画

 

画像処理のためのC#テクニックへ戻る

【Word】数式に使われるフォントは?

教科書など、方程式に使われる英数字のフォントは何か?調べてみました。

 

特徴的なのはxの文字

 

Word2016の数式エディタで使われるフォントは Cambria Math というフォントでした。

 

 

でも、何か違う。。特に Xの文字

昔のワードは私の思い描く X の文字に近かった気がするのは気のせいか??

 

しょうがないので、Wordでフォントを変更しながらプレビューの文字を見ながら探してみたところ、 Times New Roman の斜体が一番近い感じがしました。

 

 

このフォント、斜体でないとあまりそれっぽくありません。

 

 

それでも、最初に示した

みたいなフォントは見つからず。。

 

Word/Excelへ戻る

【C#】アークタンジェントの計算

下図のような角度(θ)を求める際にはアークタンジェントを計算しますが、C#ではSystem.MathクラスにAtanメソッド および Atan2メソッドが用意されています。

public static double Atan(
	double d
)
public static double Atan2(
	double y,
	double x
)

 

AtanとAtan2の違いですが、見てわかるように、メソッドの引数が1つなのと、2つ。それとAtanがメソッドの戻り値が -π / 2 ~ π / 2 なのに対して、Atan2では -π ~ π となります。

 

評価プログラム

 

実行結果

X = 1, Y = 1
Atan:0.785398163397448
Atan2:0.785398163397448

X = 0, Y = 1
Atan:1.5707963267949
Atan2:1.5707963267949

X = 0, Y = -1
Atan:-1.5707963267949
Atan2:-1.5707963267949

X = -1, Y = -1
Atan:0.785398163397448
Atan2:-2.35619449019234

X = 0, Y = 0
Atan:NaN
Atan2:0

 

まとめ

AtanとAtan2はC#に限らずC言語やExcelなどでも用意されているのですが、C#以外の言語では Atan(y / x) としたときに、x = 0 の時に0除算となるため、エラーになる場合が多いのですが、C#は何事も無かったかのうように計算しています。

といっても、Atanでは戻り値が -π / 2 ~ π / 2 に制限されてしまうため、個人的には角度を求める場合は、ほとんどAtan2を使っています。

 

C#へ戻る

【C#】画像ファイルビューア(ソースコード付き)

(2019.09.03追記)本記事の内容を再度、再構成し、下記の記事を作成しました。

【C#】アフィン変換を用いて画像ビューアを作ろう!

 

以下は以前、書いた記事


画像ファイルを開いて、マウスホイールの上下で拡大縮小するソフトは、以前にも作り、旧ブログで公開しているのですが、これはGraphicクラスのTransformプロパティにアフィン変換行列を指定することで、Graphicオブジェクトの描画した画像や線は勝手に拡大縮小表示してくれるという、ワールド変換という機能を使っていました。

 

【C#】マウスホイールで画像の拡大縮小

http://imagingsolution.blog107.fc2.com/blog-entry-287.html

 

しかし、この方法では拡大した画像の上に線を引くと、線も太く表示されるので、少し使いにくい部分がありました。

そこで、今回は描画する元の領域と、描画先の左上、右上、左下の3点の座標を指定し、この3点からなる四角形(平行四辺形も含む)に合わせて画像を表示してくれるメソッド

public void DrawImage(
	Image image,
	PointF[] destPoints,
	RectangleF srcRect,
	GraphicsUnit srcUnit
)

を使って画像ファイルのビューアを作成しました。

 

動作イメージ

 

主な機能

  • ドラッグ&ドロップでファイルを開く
  • マウスホイールの上下による画像の拡大縮小表示
  • マウスのボタンを押しながら画像の移動
  • マウス左ボタンのダブルクリックで画像全体表示
  • マウス右ボタンのダブルクリックで画像等倍表示
  • 画像を開いたあと、矢印キーの左右ボタン(←、→)で同一フォルダ内の画像ファイル切替
  • ウィンドウ左下にマウスポインタ位置の画像上の座標および輝度値の表示
  • ウィンドウ右下に画像の幅x高さxビット数を表示

 

ダウンロード

公開日 バージョン ファイル 備考
2020.07.25 Ver.1.1.0 ImageViewer_V110.zip マウスダブルクリックで発生する例外を修正
2018.02.12 Ver.1.0.0 ImageViewer_V100.zip 初版

 

使用方法

プログラムを実行するだけなら、ファイルを解凍し、exeフォルダ内の ImageViewer.exe をダブルクリックすることで、実行できます。

ソースコード(Visual Studio 2015 C#版)はsourceフォルダに格納しています。

 

画像処理のためのC#テクニックへ戻る

【C#】Bitmapクラスの最大サイズは?

私は仕事でセンサカメラなどを用いる事があるのですが、ラインセンサは横の画素数が8K(8192画素)ぐらいは、割と普通に使われ、1枚の画像として、縦方向の画素数はいくらでも指定できてしまうため、C#プログラムでBitmapクラスはどの程度の大きさ(画素数)まで対応可能なのか?調べてみました。

 

評価環境

OS:Windows10 Pro 64bit

Visual Studio Community 2015

.NET Framework 4.6.2

実装メモリ:32GB

評価プログラム実行時の使用メモリ量:約9GB(残23GB)

 

評価プログラム

private void button1_Click(object sender, EventArgs e)
{
    int width = (int)nudWidth.Value;
    int height = (int)nudHeight.Value;
    // 使用メモリ容量(24bitカラーのとき)
    int size = width * height * 3 / 1024 / 1024;

    try
    {
        using (var bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
        {
            MessageBox.Show(size.ToString("#,0") + "MB 確保");
        }
    } catch 
    {
        MessageBox.Show(size.ToString("#,0") + "MB エラー");
    }
}

(実行画面)

評価方法

プラットフォームを Any CPU(32bit優先)、Any CPU(32bit優先なし)、x64で切り替えて、エラーが出るまでHeightの値を大きくしてみました。

 

32bit優先のあるなしは、プロジェクトのプロパティから、ビルドを選択して 32ビットを優先 の部分のチェックのあるなしで切り替えます。

 

 

Bitmapクラスは以下のように24ビットカラーで確保したので、メモリ的には

Width x Height x 3 バイト

確保されます。

var bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb)

 

結果

プラットフォーム 最大メモリサイズ
Any CPU

(32bit優先)

1GB
Any CPU

(32bit優先なし)

2GB
x64 2GB

 

ということで、Bitmapクラスで確保できる最大のサイズ(メモリ容量)は 2GB のようです。

プロセス的な限界かないか?と思い、下のようにBitmapクラスを2つ確保してみましたが、結果は同じ(bmp1,bmp2とも2GB分、計4GB確保できる)でした。

private void button1_Click(object sender, EventArgs e)
{
    int width = (int)nudWidth.Value;
    int height = (int)nudHeight.Value;
    // 使用メモリ容量(24bitカラーのとき)
    int size = width * height * 3 / 1024 / 1024;

    try
    {
        using (var bmp1 = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
        using (var bmp2 = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
        {
            MessageBox.Show(size.ToString("#,0") + "MB 確保");
        }
    } catch 
    {
        MessageBox.Show(size.ToString("#,0") + "MB エラー");
    }
}

もともと、なぜエラーになるか?

と思ったのですが、エラーが出たときの画面にヒントがあるような。。

 

 

-2,047MB エラー

と表示されいます。

これはメモリのサイズを

int size = width * height * 3 / 1024 / 1024;

と計算していますが、エラーが出るときは

width * height * 3

の値がintの最大値を超えてオバーフローしているためだと思いますが、おそらくBitmapクラス内部でも同じ用なコードがあるのでは?ないでしょうかね。

 

画像処理のためのC#テクニックへ戻る