package { import flash.display.BitmapData; import flash.geom.Point; import Shadow; public class Extractor { public var threshold:int; public var bmd:BitmapData; public var silhouette:Shadow; public var point:Point; public function Extractor() { trace("Construct: Extractor"); silhouette = new Shadow(); point = new Point(0,0); threshold = 1; bmd = new BitmapData(silhouette.width,silhouette.height); } public function extract():void{ if(bmd == null) return; // マウス位置を中心に2値化 img2shadow(silhouette, bmd, bmd.getPixel(point.x, point.y), threshold); // ラベリング処理 var labels:Array = shadow2label(silhouette); var label:int = labels[point.x+point.y*silhouette.width]; for(var y:int = 0; y < silhouette.height; y++){ for(var x:int = 0; x < silhouette.width; x++){ var i:int = x+y*silhouette.width; if(labels[i] == label) silhouette.setPixel(x,y,true); else silhouette.setPixel(x,y,false); } } silhouette.updateBitmapData(); // 表示に反映 } public function colorCmp(a:int, b:int , threshold:int):Boolean { var a_red:int = a>>16&0xFF; var b_red:int = b>>16&0xFF; var a_green:int = a>>8&0xFF; var b_green:int = b>>8&0xFF; var a_blue:int = a&0xFF; var b_blue:int = b&0xFF; if ( ( (a_red > b_red && a_red-b_red > threshold) || (a_red < b_red && b_red-a_red > threshold) ) && ( (a_green > b_green && a_green-b_green > threshold) || (a_green < b_green && b_green-a_green > threshold) ) && ( (a_blue > b_blue && a_blue-b_blue > threshold) || (a_blue < b_blue && b_blue-a_blue > threshold) ) ) { return false; // 色に差がある時 } else { return true; // 色に差が無い時 } } // 画像から2値化データを作る public function img2shadow(shadow:Shadow, bmd:BitmapData, cmpPixel:uint, threshold:uint):void{ for(var y:int = 0; y < bmd.height; y++){ for(var x:int = 0; x < bmd.width; x++){ shadow.setPixel(x, y, colorCmp(bmd.getPixel(x, y), cmpPixel, threshold) ); } } } // 2値化画像を4近傍ラベリング処理する public function shadow2label(shadow:Shadow):Array{ var label:int = 1; var labels:Array = new Array(shadow.width*shadow.height); if(shadow.getPixel(0,0)) labels[0] = label; // まず1番上の列だけを処理 var i:int; for(i = 1; i < shadow.width; i++){ if(shadow.getPixel(i, 0)){ // 黒の時 if(!shadow.getPixel(i-1,0)){ labels[i] = ++label; // 新しいラベルを付ける } else{ labels[i] = labels[i-1]; // ラベルのコピー } } } // 2列目以降を処理 var replaceHash:Array = new Array(); for(var y:int = 1; y < shadow.height; y++){ for(var x:int = 0; x < shadow.width; x++){ i = x+y*shadow.width; if(shadow.getPixel(x, y)){ // 黒の時 // 左上、上、右上、左が空白の時、新しいラベルを作成 if( (x == 0 || !shadow.getPixel(x-1, y)) && // 左 !shadow.getPixel(x, y-1) && // 上 (x == shadow.width-1 || !shadow.getPixel(x+1,y-1)) && // 右上 (x == 0 || !shadow.getPixel(x-1,y-1)) ){ // 左上 labels[i] = ++label; } else{ // どこかで隣接している時 var label_buf:Array = new Array(4); // 隣接しあっているラベルのオフセット var connect_count:int = 0; // 左上、上、右上、左のラベルをチェック&コピー if(x > 0 && shadow.getPixel(x-1, y-1)){ // 左上 label_buf[connect_count++] = labels[i] = labels[i-shadow.width-1]; } if(shadow.getPixel(x,y-1)){ // 上 label_buf[connect_count++] = labels[i] = labels[i-shadow.width]; } if(x < shadow.width-1 && shadow.getPixel(x+1,y-1)){ // 右上 label_buf[connect_count++] = labels[i] = labels[i-shadow.width+1]; } if(x > 0 && shadow.getPixel(x-1, y)){ // 左 label_buf[connect_count++] = labels[i] = labels[i-1]; } if(connect_count>1){ for(var j:int = 0; j < connect_count-1; j++){ label_replace(labels, i, label_buf[j], label_buf[j+1]); } } } } } } return labels; } /// label1をlabel2に置き換える private function label_replace(labels:Array, limit:int, label1:int, label2:int):void{ if(label1 == label2) return; for(var i :int = 0; i < limit; i++){ if(labels[i] == label1) labels[i] = label2; } } } }