- 2008-07-28 (月)
- Action Script 3.0
ふとした理由により、画像の色の平均値を調べたくなった。
いろいろ方法を模索してみたのだが、大きく2つの方法がある感じ。
1つは、ビットマップデータを取得し1×1ピクセルの大きさまで縮小。その色を取得するという方法。
1つは、同じくビットマップデータを取得し、各ピクセルの色をRGB別に計算し平均を求めるという方法。
もちろん、後者の方が処理負荷がかかることは言ううまでもない。640x480の画像の場合、約3万回以上のループ処理が必要になるし…(汗
上記2つの方法の結果も知りたかったし処理速度の計測も気になったので、ついでに比較検証できるようなサンプルを作成してみた。
サンプル
Flash Player Plug-in はこちらからダウンロードする事が出来ます(無料)。
- 処理1
- ビットマップデータを縮小して平均を求める処理
- 処理2
- 各ピクセルの色をRGB別に計算して平均を求める処理
上の2つの四角の色が「処理1」の結果。2つあるのは、色の結果を表示させたものと縮小したビットマップデータを addChild したものなので、それほど気にしなくてもOK。で、下の四角の色が「処理2」の結果。
結果的には若干ではあるが異なる色の結果となった。
ただ、思ったよりも処理速度に大差がない。
環境によって処理時間が異なると思うが、僕のPCで閲覧したところ、左から順に
処理1:32ミリ秒|処理1:24ミリ秒|処理1:27ミリ秒
処理2:56ミリ秒|処理2:61ミリ秒|処理2:62ミリ秒
1:2 という感じか。3万ループを3回ほど行っているんだけども、さすが AS3 の処理能力。内部的な計算はすさまじく早い。実際に試したことないんであまり自信がないけども、AS2 だとココまでは早くないと思われる(多分…)。
まぁ、色の平均をどういう意図で利用するかによるのだけど、それほど厳密でなくて良い場合であれば、ビットマップデータを縮小して求めた方が、コードもすっきり処理も快適、という感じになるのかな。
ソースはこちら
一応、ドキュメントクラスにて記述しているが、サンプルのため、画像はFlashのステージに予め A~C のインスタンス名で配置してテストを行ってます。下記のソースを試す場合は、適当な画像を用意して試してみてください(汗
package {
/*============================================================
クラス読み込み
============================================================*/
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.display.Sprite;
import flash.display.MovieClip;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.utils.getTimer;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.events.MouseEvent;
import flash.geom.Matrix;
public class averageColor extends Sprite {
//コンストラクタ
public function averageColor() {
//ステージサイズ設定
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
//色の平均を求める
getAveColor1(A);
getAveColor2(A);
getAveColor1(B);
getAveColor2(B);
getAveColor1(C);
getAveColor2(C);
}
//処理1(ビットマップを縮小して平均色を取得)
public function getAveColor1(MC:MovieClip):String {
var old_time:uint = getTimer();//処理時間計測
var BMD:BitmapData = new BitmapData(1, 1, false);
var MTX:Matrix = new Matrix();
MTX.scale(1/(MC.width/MC.scaleX), 1/(MC.height/MC.scaleY));
BMD.draw(MC, MTX);
//色の平均を取得
var aveColor:uint = BMD.getPixel(0,0);
//=====色を配置(確認用)
var SP:Sprite = new Sprite();
SP.graphics.beginFill(aveColor);
SP.graphics.drawRect(0, 0, 20, 20);
SP.graphics.endFill();
SP.x = MC.x;
SP.y = MC.y+MC.height+5;
addChild(SP);
var BMP:Bitmap = new Bitmap(BMD);
BMP.scaleX = 20;
BMP.scaleY = 20;
BMP.x = MC.x+25;
BMP.y = MC.y+MC.height+5;
addChild(BMP);
var txtMC:TextField = new TextField();
txtMC.autoSize = TextFieldAutoSize.LEFT;
txtMC.x = MC.x+25+25;
txtMC.y = MC.y+MC.height+5;
addChild(txtMC);
//=====
//確認用
var time:uint = getTimer()-old_time;
trace("経過時間:"+time);
txtMC.text = "処理1:"+time+"ミリ秒";
//色の平均を返す
trace("色の平均:"+aveColor.toString(16));
return aveColor.toString(16);
}
//処理2(各ピクセルの色の平均を計算して平均色を取得)
public function getAveColor2(MC:MovieClip):String {
var old_time:uint = getTimer();//処理時間計測
var r:Array = [];
var g:Array = [];
var b:Array = [];
var rAll:uint = 0;
var gAll:uint = 0;
var bAll:uint = 0;
//ビットマップを取得
var BMD:BitmapData = new BitmapData(MC.width/MC.scaleX, MC.height/MC.scaleY, false);
BMD.draw(MC);
//各ピクセルの色の合計
var count:uint = 0;
for (var i:uint=0; i> 16;
var gC:uint = (CLR & 0x00FF00) >> 8;
var bC:uint = (CLR & 0x0000FF);
//trace(rC,gC,bC)
rAll += rC;
gAll += gC;
bAll += bC;
count++;
}
}
//RGBを16進数に変換
var rN:String = Math.floor(rAll/count).toString(16);
var gN:String = Math.floor(gAll/count).toString(16);
var bN:String = Math.floor(bAll/count).toString(16);
//16以下なら前に0を加える
//※parseInt()はストリングを整数に変換。第2引数で元の数が何進数なのかを指定可能。
if (parseInt(rN,16) <= 16 ) {
rN = "0"+rN;
}
if (parseInt(gN,16) <= 16 ) {
gN = "0"+gN;
}
if (parseInt(bN,16) <= 16 ) {
bN = "0"+bN;
}
//色の平均を取得
var aveColor = uint("0x"+rN+gN+bN);
//=====色を配置(確認用)
var SP:Sprite = new Sprite();
SP.graphics.beginFill(aveColor);
SP.graphics.drawRect(0, 0, 20, 20);
SP.graphics.endFill();
SP.x = MC.x;
SP.y = MC.y+MC.height+30;
addChild(SP);
var txtMC:TextField = new TextField();
txtMC.autoSize = TextFieldAutoSize.LEFT;
txtMC.x = MC.x+25+25;
txtMC.y = MC.y+MC.height+30;
addChild(txtMC);
//=====
//処理時間
var time:uint = getTimer()-old_time;
trace("経過時間:"+time);
txtMC.text = "処理2:"+time+"ミリ秒";
//色の平均を返す
trace("色の平均:"+aveColor.toString(16));
return aveColor.toString(16);
}
}
}
うーん…。適当感がアリアリの美しくないソースだ…(汗
コメント:0
トラックバック:0
- この記事のトラックバックURL
- http://god.xsrv.jp/__mt/mt-tb.cgi/1313
- トラックバックを受ける記事
- ビットマップの色の平均を2つの方法で求めて比較してみる from 1ka2ka.com