FlashPlayer 10ではBitmapDataクラスのメソッドとして get/setVector() が追加されています。
これらのメソッドを使えばピクセルデータを一次元のVectorで扱えますが、
getPixels()/setPixels() も同じようなメソッドだよな、、と思ってリファレンスで見比べてみると、
getPixels(rect:Rectangle):ByteArray
ピクセルデータの矩形領域からバイト配列を生成します。getVector(rect:Rectangle):Vector.<uint>
ピクセルデータの矩形領域からベクター配列を生成します。
バイト配列かベクター配列かということのようです。
とりあえず昨日のナイトビジョンエフェクトのコードを get/setVector() を使って書き換えてみます。
エフェクトをかけるメソッドだけ以下に載せます。
他の処理は前回と同じコードを使い、imageDataだけByteArrayからVectorに変更しました。
・ソースコード
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 |
private function excute(e:Event):void { output.bitmapData.draw(video); // imageDataは今回はByteArrayではなくVector imageData = output.bitmapData.getVector(output.bitmapData.rect); filterNightVision(imageData, 4, 30, 6); output.bitmapData.setVector(output.bitmapData.rect, imageData); noiseData.noise(Math.random()*0xff, 0, 255, BitmapDataChannel.GREEN, false); output.bitmapData.merge(noiseData, noiseData.rect, pt, 0, 32, 0, 0); } // Vector版 private function filterNightVision(img:Vector.<uint>, thick:int, contrast:int, ghost:int):void { var w:int = video.width, h:int = video.height; var g:uint = 0, pos:uint = 0, f:uint = 0; for (var y:int=0; y<h; y++) { f = y%thick<<1; for(var x:int=0; x<w; x++) { pos = w*y + x; if (x + ghost<w) g = ((img[pos]>>8 & 0xff) + (img[pos + ghost]>>8 & 0xff))>>1; if(f<thick) { g += contrast; if(g>255) g = 255; } // tbl はガンマ補正用変換テーブル,赤・青チャンネルのみ補正する img[pos] = tbl[img[pos]>>16 & 0xff]<<16 | g<<8 | tbl[img[pos] & 0xff] ; } } } // 比較のため、ByteArray版も載せておきます private function filterNightVision(img:ByteArray, thick:int, contrast:int, ghost:int):void { var w:int = video.width, h:int = video.height; var g:uint = 0, pos:uint = 0, f:uint = 0; for (var y:int = 0; y<h; y++) { f = y%thick<<1; for(var x:int=0; x<w; x++) { pos = (w*y<<2) + (x<<2) + 2; g = img[pos] + img[pos + (ghost<<2)]>>1; if(f<thick) { g += contrast; if(g>255) g = 255; } img[pos - 1] = tbl[img[pos - 1] >>= 1]; img[pos] = g; img[pos + 1] = tbl[img[pos + 1] >>= 1]; } } } |
currentFPSプロパティを見る限り0.5~1.5fpsほどVector版の方が速かったですが、誤差の範囲かなと思います。
環境によっては結果が逆転したりするかもしれません。
ただ、Vector版はインデックスの範囲チェックをしているので処理量自体は増えています。
(チェックしないと img[pos + ghost] の部分で RangeError が発生する)
getVector()で得たVectorにインデックスアクセスした場合はピクセルデータ(32bit)を取り出すことができ、
getPixels()で得たByteArrayにインデックスアクセスした場合はチャンネルデータ(8bit)が取り出せるということになります。
このエフェクトの場合はチャンネルデータに直アクセスできるByteArrayの方が有利だと考えられますが、
処理時間に(ほとんど)違いがないということは、Vectorで処理した方が一般的には良いと言えるかもしれません。
これまではピクセルデータを取得するには getPixel() or getPixel32() を使う必要がありましたが、
getVector() で得たVectorならインデックスアクセスするだけでピクセルデータが取り出せるからです。
なので、Vectorでデータ操作した後に setVector() でBitmapDataに戻す方が効率的かと思います。
ただ、getVector() で得られるVectorの要素が32ビット整数になっているということは、
浮動小数点演算が必要な画像の周波数解析などには利用できないので注意。