BitmapData#threshold 高速化
前回は BitmapData#peletteMap の高速化を見ましたが、今回は BitmapData#threshold の高速化についてです。
この検証については「入力元と出力先が異なる」という条件を設定しています。
条件部分を抜き出すと以下のような感じ。
var target:BitmapData = new BitmapData(source.width, source.height, transparent, color); target.threshold(source, rect, ZERO_POINT, ">=", _threshold << 8, 0xffffffff, 0x0000ff00, false);
結果は以下のとおり。
- source の transparent は false よりも true の方が速い
- source の transparent が同じなら、target の transparent には、あまり大きく左右されない
以下に列挙する数値から考えると、こんな感じでしょうか
- source、target の transparent はともに true にする
- 少なくとも target の transparent は true にしておく
1,000回ループで、各々10回実行した結果は以下のとおり。
source.transparent = true かつ target.transparent = true のとき
第1回:3976 msec.
第2回:3885 msec.
第3回:4056 msec.
第4回:4351 msec.
第5回:3950 msec.
第6回:3892 msec.
第7回:3971 msec.
第8回:4400 msec.
第9回:4045 msec.
第10回:3986 msec.
平均:4051.2 msec.
source.transparent = true かつ target.transparent = false のとき
第1回:3883 msec.
第2回:4092 msec.
第3回:4116 msec.
第4回:4530 msec.
第5回:4049 msec.
第6回:3951 msec.
第7回:4082 msec.
第8回:4132 msec.
第9回:4054 msec.
第10回:3996 msec.
平均:4088.5 msec.
source.transparent = false かつ target.transparent = true のとき
第1回:4733 msec.
第2回:4737 msec.
第3回:4864 msec.
第4回:4907 msec.
第5回:4881 msec.
第6回:4667 msec.
第7回:4764 msec.
第8回:5052 msec.
第9回:4931 msec.
第10回:4865 msec.
平均:4840.1 msec.
source.transparent = false かつ target.transparent = false のとき
第1回:4875 msec.
第2回:4784 msec.
第3回:4906 msec.
第4回:5048 msec.
第5回:5096 msec.
第6回:4729 msec.
第7回:4712 msec.
第8回:4792 msec.
第9回:4748 msec.
第10回:4816 msec.
平均:4850.6 msec.
Main.as(ドキュメント・ファイル)
package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.GradientType; import flash.display.Graphics; import flash.display.Shape; import flash.display.Sprite; import flash.geom.Matrix; import flash.geom.Point; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import flash.utils.getTimer; [SWF(width = "500", height = "500", frameRate = "30", backgroundColor = "#ffffff")] public class Main extends Sprite { public function Main() { // ソースイメージ var trueBmd:BitmapData = createSrcBmd(true); var falseBmd:BitmapData = createSrcBmd(false); //addChild(new Bitmap(trueBmd)); //addChild(new Bitmap(falseBmd)); //return; // 結果表示 var display:TextField = new TextField(); display.autoSize = TextFieldAutoSize.LEFT; display.defaultTextFormat = new TextFormat("_typewriter", 12, 0x000000); addChild(display); display.text = "BitmapData#threshold\n"; // 処理回数 const LOOP:int = 1000; // 二値化フィルター var threshold:uint = 128; var filter:Binarize = new Binarize(); filter.threshold = threshold; // 二値閾値 display.appendText("binarize threshold : " + String(threshold) + "\n"); var i:int = 0; var buf:BitmapData; var dstTransparent:Boolean; var started:int; // transparent = false dstTransparent = false; display.appendText("src trasnparent = " + String(falseBmd.transparent) + ".\n"); display.appendText("dst trasnparent = " + String(dstTransparent) + ".\n"); started = getTimer(); for (i = 0; i < LOOP; i++) { falseBmd.lock(); buf = falseBmd.clone(); buf.lock(); filter.applyEffect(buf, true); falseBmd.unlock(); buf.unlock(); buf.dispose(); } display.appendText(" loop : " + String(LOOP) + " times, required : " + String(getTimer() - started) + " msec.\n"); dstTransparent = true; display.appendText("src trasnparent = " + String(falseBmd.transparent) + ".\n"); display.appendText("dst trasnparent = " + String(dstTransparent) + ".\n"); started = getTimer(); for (i = 0; i < LOOP; i++) { falseBmd.lock(); buf = falseBmd.clone(); buf.lock(); filter.applyEffect(buf, true); falseBmd.unlock(); buf.unlock(); buf.dispose(); } display.appendText(" loop : " + String(LOOP) + " times, required : " + String(getTimer() - started) + " msec.\n"); // transparent = true dstTransparent = false; display.appendText("src trasnparent = " + String(trueBmd.transparent) + ".\n"); display.appendText("dst trasnparent = " + String(dstTransparent) + ".\n"); started = getTimer(); for (i = 0; i < LOOP; i++) { trueBmd.lock(); buf = trueBmd.clone(); buf.lock(); filter.applyEffect(buf, dstTransparent); trueBmd.unlock(); buf.unlock(); buf.dispose(); } display.appendText(" loop : " + String(LOOP) + " times, required : " + String(getTimer() - started) + " msec.\n"); dstTransparent = true; display.appendText("src trasnparent = " + String(trueBmd.transparent) + ".\n"); display.appendText("dst trasnparent = " + String(dstTransparent) + ".\n"); started = getTimer(); for (i = 0; i < LOOP; i++) { trueBmd.lock(); buf = trueBmd.clone(); buf.lock(); filter.applyEffect(buf, dstTransparent); trueBmd.unlock(); buf.unlock(); buf.dispose(); } display.appendText(" loop : " + String(LOOP) + " times, required : " + String(getTimer() - started) + " msec.\n"); } // ソースイメージ生成 private function createSrcBmd(sw:Boolean):BitmapData { const IMAGE_WIDTH:int = 500; const IMAGE_HEIGHT:int = 500; var shape:Shape = new Shape(); var matrix:Matrix = new Matrix(); matrix.createGradientBox(IMAGE_WIDTH, IMAGE_HEIGHT); var g:Graphics = shape.graphics; g.beginGradientFill(GradientType.LINEAR, [0xff0000, 0x00ff00, 0x0000ff], [1, 1, 1], [0, 128, 255], matrix); g.drawRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT); g.endFill(); var bmd:BitmapData = new BitmapData(IMAGE_WIDTH, IMAGE_HEIGHT, sw); bmd.draw(shape); return bmd; } } }
Binarize(二値化フィルター)
package { import flash.display.BitmapData; import flash.geom.Point; import flash.geom.Rectangle; /** * 二値化 * ピクセル値が閾値より大きい場合は白、小さい場合は黒に置き換える * 判別分析法による自動閾値計算モードあり * @author YOSHIDA, Akio */ final public class Binarize { /** * 閾値 */ public function get threshold():uint { return _threshold; } public function set threshold(value:uint):void { // value の有効範囲は 0 ~ 256 if (value < 0) value = 0; if (value > 256) value = 256; _threshold = value; } private var _threshold:uint = 128; // 閾値:0 ~ 256 private static const ZERO_POINT:Point = new Point(); /* * 効果適用 * @param value 効果対象 BitmapData */ public function applyEffect(value:BitmapData, transparent:Boolean):void { // 画像処理 value.lock(); var rect:Rectangle = value.rect; var color:uint = transparent ? 0xff000000 : 0x000000; var buffer:BitmapData = new BitmapData(value.width, value.height, transparent, color); buffer.lock(); if (_threshold != 256) buffer.threshold(value, rect, ZERO_POINT, ">=", _threshold << 8, 0xffffffff, 0x0000ff00, false); value.copyPixels(buffer, rect, ZERO_POINT); value.unlock(); buffer.unlock(); buffer.dispose(); } } }
Comments
Tell me what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!