/**
* Copyright wrotenodoc ( http://wonderfl.net/user/wrotenodoc )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/Yd32
*/
package {
import flash.display.Sprite
import flash.display.Bitmap
import flash.display.BitmapData
import com.actionscriptbible.Example
public class FFTTest extends Example {
public function FFTTest() {
// write as3 code here..
var bd:BitmapData = new BitmapData(64, 64, true, 0x0)
bd.perlinNoise(32, 32, 4, 0, false, true, 7, true)
var bmp:Bitmap = new Bitmap(bd)
bmp.y = 20
bmp.scaleX = bmp.scaleY = 3
addChild(bmp)
// cut frequencies < 100
var fft:FFTResult = FFT(bd2ary(bd), 100)
var fftBD:Vector.<BitmapData> = fft2bd(fft)
with(addChild(new Bitmap(fftBD[0]))){
x = 64 * 3
y = 20
scaleX = scaleY = 3
}
with(addChild(new Bitmap(fftBD[1]))){
x = 64 * 3
y = bmp.y + bmp.height
scaleX = scaleY = 3
}
var ifft:Array = IFFT(fft)
var bd2:BitmapData = bd.clone()
var col:uint
for(var i:int=0; i<bd.width; i++){
for(var j:int=0; j<bd.height; j++){
col = ifft[j][i]
col = col<<16 | col<<8 | col
bd2.setPixel(i, j, col)
}
}
with(addChild(new Bitmap(bd2))){
scaleX = scaleY = 3
y = bmp.y + bmp.height
}
}
private function bd2ary(bd:BitmapData):Array {
var ary:Array = []
for(var y:int=0; y<bd.height; y++){
ary[y] = []
for(var x:int=0; x<bd.width; x++){
ary[y][x] = bd.getPixel(x, y) & 0xFF
}
}
return ary
}
private function fft2bd(fft:FFTResult):Vector.<BitmapData> {
var bd:BitmapData = new BitmapData(fft.width, fft.height, false, 0x0)
var bd2:BitmapData = new BitmapData(fft.width, fft.height, false, 0x0)
for(var y:int=0; y<fft.height; y++){
for(var x:int=0; x<fft.width; x++){
var color:uint = uint(Math.log(1 + (fft.mag[y][x] - fft.magMin)/(fft.magMax - fft.magMin)) * 255 * 255)
bd.setPixel(x, y, color<<16 | color<<8 | color)
color = uint(fft.phase[y][x]/pi2 * 255)
bd2.setPixel(x, y, color<<16 | color<<8 | color)
}
}
return Vector.<BitmapData>([bd, bd2]) // magnitude image, phase image
}
// image: 2D array (row-major)
private const pi2:Number = Number.PI * 2
private function FFT(image:Array, freqCut:Number):FFTResult {
var N:int = image.length // height
var M:int = image[0].length // width
var result:FFTResult = new FFTResult(M, N)
var i:int, j:int
for(i=0; i<N; i++){
for(j=0; j<N; j++){
result.data[i][j] = sum(i, j)
result.mag[i][j] = result.data[i][j].magnitude
result.phase[i][j] = result.data[i][j].phase
if(result.phase[i][j] < 0) result.phase[i][j] += pi2
}
}
result.magMin = result.realMin = result.imgMin = Infinity
result.magMax = result.realMax = result.imgMax = -Infinity
var r:Number, im:Number, mag:Number
for(i=0; i<N; i++){
for(j=0; j<N; j++){
r = result.data[i][j].real
im = result.data[i][j].img
mag = result.mag[i][j]
if(mag < freqCut) result.data[i][j].real = result.data[i][j].img = 0 // cut low frequencies
if(r > result.realMax) result.realMax = r
if(r < result.realMin) result.realMin = r
if(im > result.imgMax) result.imgMax = im
if(im < result.imgMin) result.imgMin = im
if(mag > result.magMax) result.magMax = mag
if(mag < result.magMin) result.magMin = mag
}
}
return result
function sum(i:int, j:int):Component {
var real:Number = 0, img:Number = 0
for(var y:int=0; y<N; y++){
for(var x:int=0; x<M; x++){
real += image[y][x] * Math.cos(pi2 * (x*j/M + y*i/N))
img -= image[y][x] * Math.sin(pi2 * (x*j/M + y*i/N))
}
}
return new Component(real, img)
}
}
private function IFFT(fft:FFTResult):Array {
var ary:Array = []
var i:int, j:int
var N:int = fft.height, M:int = fft.width
var MN:int = M * N
for(i=0; i<N; i++) ary[i] = []
for(i=0; i<N; i++){
for(j=0; j<M; j++){
ary[i][j] = sum(i, j)
}
}
return ary
function sum(i:int, j:int):Number {
var real:Number = 0, img:Number = 0
var s:Number, c:Number, r:Number, im:Number
for(var y:int=0; y<N; y++){
for(var x:int=0; x<M; x++){
c = Math.cos(pi2 * (x*j/M + y*i/N))
s = Math.sin(pi2 * (x*j/M + y*i/N))
r = fft.data[y][x].real
im = fft.data[y][x].img
real += r * c - im * s
img += im * c + r * s
}
}
// original signal had only real part, so as a result of summation, img is 0
return real / MN
}
}
}
}
class FFTResult {
public var data:Array, mag:Array, phase:Array
public var realMax:Number, realMin:Number
public var imgMax:Number, imgMin:Number
public var magMax:Number, magMin:Number
public var width:int, height:int
public function FFTResult(width:int, height:int) {
data = []
for(var i:int=0; i<height; i++) data[i] = []
mag = []
for(i=0; i<height; i++) mag[i] = []
phase = []
for(i=0; i<height; i++) phase[i] = []
this.width = width
this.height = height
}
}
class Component {
public var real:Number
public var img:Number
public function Component(r:Number, i:Number) {
real = r
img = i
}
public function get magnitude():Number {
return Math.sqrt(real*real + img*img)
}
public function get phase():Number {
return Math.atan2(real, img)
}
}