前回の続き。
今回はフーリエ変換で得られた周波数スペクトルにハイパスフィルタ(HPF)/ローパスフィルタ(LPF)をかけます。
Flashだとサウンド関連でよく耳にするフィルタかもしれませんが、画像でも基本は同じです。
前回作ったクラスにフィルタ処理等を追加します。
・1D/2D-FFT + HPF/LPF
(追記 2008 12/19) バンドパスフィルタ(BPF)の処理を追加。
(追記 2009 2/20) 空間周波数フィルタのメソッドを少し修正。処理内容は変わってません。
[as]
package {
import __AS3__.vec.Vector;
/*
* Fast Fourier Transform implementation in pure AS3
*/
public class FFT {
private var n:int;
private var bitrev:Vector.
private var cstb:Vector.
public static const HPF:String = “high”;
public static const LPF:String = “low”;
public static const BPF:String = “band”
public function FFT(n:int) {
if(n != 0 && (n & (n-1)) == 0) {
this.n = n;
this.cstb = new Vector.
this.bitrev = new Vector.
makeCstb();
makeBitrev();
}
}
// 1D-FFT
public function fft(re:Vector.
if(!inv) {
fftCore(re, im, 1);
}else {
fftCore(re, im, -1);
for(var i:int=0; i
var tre:Vector.
var tim:Vector.
var i:uint;
if(inv) swapQuadrant(re, im);
// x-axis
for(var y:int=0; y
var r:int = 0; // radius
var n2:int = n>>1;
var i:int, ptr:int;
for(var y:int=-n2; y
(type == BPF && (r < rad || r > (rad + bandWidth)))) {
re[ptr] = im[ptr] = 0;
}
}
}
}
// Fast Fourier Transform core operation.
private function fftCore(re:Vector.
var h:int, d:int, wr:Number, wi:Number, ik:int, xr:Number, xi:Number, m:int, tmp:Number;
// bit reversal
for(var l:int=0; l
wi = sign*cstb[h];
for(var i:int=j; i
var tmp:Number, xn:int, yn:int, i:int, j:int, k:int, l:int;
var len:int = n>>1;
for(var y:int=0; y
var t:Number = Math.sin(Math.PI/n);
var dc:Number = 2*t*t;
var ds:Number = Math.sqrt(dc*(2 – dc));
var c:Number = cstb[n4] = 1;
var s:Number = cstb[0] = 0;
t = 2*dc;
for(var i:int=1; i
while(k<=j) {
j -= k;
k >>= 1;
}
j += k;
bitrev[i] = j;
}
}
}
}
[/as]
・ハイパス/ローパスフィルタのテスト
[as]
package {
import __AS3__.vec.Vector;
import flash.display.*;
import flash.text.*;
import flash.utils.getTimer;
[SWF(width = “768”, height = “300”, backgroundColor = “#000000”, frameRate = “12”)]
public class FFTImg extends Sprite {
[Embed(source = ‘./assets/lenagray.jpg’)]
private var EmbedImage:Class;
private var srcBmp:Bitmap;
private var fftBmp:Bitmap;
private var dstBmp:Bitmap;
private var imgData:BitmapData;
private var fftTest:FFT;
private var re:Vector.
private var im:Vector.
private var retmp:Vector.
private var max:Number = 0.0;
private var data:Number = 0.0;
private var w:int = 0;
private var h:int = 0;
private var tf:TypingTextField;
private var fmt:TextFormat;
public function FFTImg() {
srcBmp = new EmbedImage() as Bitmap;
imgData = srcBmp.bitmapData.clone();
w = imgData.width;
h = imgData.height;
fftTest = new FFT(w);
re = new Vector.
im = re.concat();
retmp = re.concat();
// 画像データの直列化
for(var y:int=0; y
}
// 8ビットに正規化 (表示用)
for(var i:int=0; i
if(data<0) data = 0;
var color:uint = data<<16 | data<<8 | data;
imgData.setPixel(x, y, color);
}
}
fftBmp = new Bitmap(imgData.clone());
// 逆2D-FFT
fftTest.fft2d(re, im, true);
// 8ビットに正規化 (表示用)
max = 0.0;
for(var i:int=0; i
}
for(var i:int=0; i
if(data<0) data = 0;
color = data<<16 | data<<8 | data;
imgData.setPixel(x, y, color);
}
}
dstBmp = new Bitmap(imgData);
addChild(srcBmp);
addChild(fftBmp);
addChild(dstBmp);
fftBmp.x += w;
dstBmp.x += w*2;
}
}
}
[/as]
・出力結果 (クリックで拡大)
ハイパスフィルタは高域の周波数成分のみ通過させます。
これによって緩やかな変動成分は除去され、エッジ部分だけが残る画像が得られます。
一方、ローパスフィルタは低域の周波数成分のみ通過させます。
こちらは緩やかな変動成分だけが残り、全体的にボケた画像が得られます。
フィルタ適用後のスペクトル画像を見れば視覚的にもわかりやすいかと。
画像の周波数成分が扱えるとできることがさらに広がります。
・関連記事
二次元離散フーリエ変換 – AS3.0
離散フーリエ変換 – AS3.0