以前書いた位相限定相関のコードなんですが、ピクセルデータを一次元(Number)で扱いたくて
1 2 3 4 5 6 7 8 |
// グレースケールのデータ private function serializeData(data:Vector.<Number>, img:BitmapData):void { for(var y:int=0; y<h; y++) { for(var x:int=0; x<w; x++) { data[x + y*w] = img.getPixel(x, y) & 0xff; } } } |
こんな風に書いていました。
ナイトビジョンエフェクトのコードは最初はByteArrayで書いてて、その後でVectorに書き換えています。
get/setVector() vs get/setPixels()
で、コードの整理ついでに位相限定相関のコードもVector版で書き換えようとしたんですが、
位相限定相関法はフーリエ変換してからいろいろ計算する必要があります。
でも、getVector() の戻り値が Vector.<uint> なのでこのままでは使えません。
ということで、
1 2 |
// reはVector.<Number>, imgDataはBitmapData re = Vector.<Number>(imgData.getVector(imgData.rect)); |
と書いて実際これで上手く動いたのですが、これって新しいVectorをさらにもう一つ生成してることになるの?
ちなみに速度的には前述の getPixel() での一次元化とほとんど変わりませんでした。
(計算量的にはこの部分がボトルネックになってるわけではないのですが;)
メリットはコードが少しだけ短くなることですかね。
参考:トップレベルの定数と関数 – ActionScript 3.0 言語およびコンポーネントリファレンス
・ソースコード
FFT演算用クラスはこれまで利用してきたものと同じものです → FFT.as
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
package { import __AS3__.vec.Vector; import flash.display.*; import flash.geom.Point; import flash.utils.getTimer; [SWF(width = "514", height = "300", backgroundColor = "#000000", frameRate = "12")] public class POC extends Sprite { [Embed(source = './assets/lennagray1.jpg')] private var EmbedImage:Class; [Embed(source = './assets/lennagray2.jpg')] private var EmbedImage2:Class; private var srcBmp:Bitmap; private var srcBmp2:Bitmap; private var imgData:BitmapData; private var imgData2:BitmapData; private var re:Vector.<Number>; private var im:Vector.<Number>; private var re2:Vector.<Number>; private var im2:Vector.<Number>; private var rePOC:Vector.<Number>; private var imPOC:Vector.<Number>; private var w:int = 0; private var h:int = 0; public function POC() { srcBmp = new EmbedImage() as Bitmap; imgData = srcBmp.bitmapData.clone(); srcBmp2 = new EmbedImage2() as Bitmap; imgData2 = srcBmp2.bitmapData.clone(); w = imgData.width; h = imgData.height; var ts:int = getTimer(); // 画像データの直列化 re = Vector.<Number>(imgData.getVector(imgData.rect)); re2 = Vector.<Number>(imgData2.getVector(imgData2.rect)); im = new Vector.<Number>(w*h, true); im2 = im.concat(); rePOC = im.concat(); imPOC = im.concat(); // 位相限定相関 phaseOnlyCorrelation(re, im, re2, im2, rePOC, imPOC); var te:int = getTimer(); trace("time: " + (te - ts) + " ms"); // ピーク値と座標の探索 var peak:Number = 0.0, spectrum:Number = 0.0; var pos:Point = new Point(); for(var y:int=0; y<h; y++) { for(var x:int=0; x<w; x++) { //spectrum = Math.sqrt(rePOC[x + y*w]*rePOC[x + y*w] + imPOC[x + y*w]*imPOC[x + y*w]); spectrum = rePOC[x + y*w] + Math.abs(imPOC[x + y*w]); if(spectrum > peak){ peak = spectrum; pos.x = x; pos.y = y; } } } trace("peak: " + peak + ", position: " + pos); addChild(srcBmp); addChild(srcBmp2).x += w + 2; } // 位相限定相関 private function phaseOnlyCorrelation(srcRe1:Vector.<Number>, srcIm1:Vector.<Number>, srcRe2:Vector.<Number>, srcIm2:Vector.<Number>, dstRe:Vector.<Number>, dstIm:Vector.<Number>):void { var fft:FFT = new FFT(w); var spectrum:Number = 0.0; // 2D-FFT fft.fft2d(srcRe1, srcIm1); fft.fft2d(srcRe2, srcIm2); for(var i:int=0; i<w*h; i++) { // 位相を算出 (振幅で正規化) spectrum = Math.sqrt(srcRe1[i]*srcRe1[i] + srcIm1[i]*srcIm1[i]); srcRe1[i] /= spectrum; srcIm1[i] /= spectrum; spectrum = Math.sqrt(srcRe2[i]*srcRe2[i] + srcIm2[i]*srcIm2[i]); srcRe2[i] /= spectrum; srcIm2[i] /= spectrum; // 相互相関 dstRe[i] = srcRe1[i]*srcRe2[i]; dstIm[i] = srcIm1[i]*(-srcIm2[i]); } // 2D-IFFT fft.fft2d(dstRe, dstIm, true); } } } |
・出力結果
time: 1542 ms
peak: 0.44900903245107504, position: (x=86, y=45)