BitmapData#threshold 高速化

2013 / 10 / 11 by
Filed under: AS 
Bookmark this on Delicious
[`livedoor` not found]
[`yahoo` not found]

前回は 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);

結果は以下のとおり。

  1. source の transparent は false よりも true の方が速い
  2. source の transparent が同じなら、target の transparent には、あまり大きく左右されない

以下に列挙する数値から考えると、こんな感じでしょうか

  1. source、target の transparent はともに true にする
  2. 少なくとも 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!





WP-SpamFree by Pole Position Marketing