火曜に、imglのうっちーとあらためてラベリング処理ってどうやんのよという話をしていて、あらためてAS3で書き直した。

ただし、ラベルの衝突処理はまだやっていない。

ラベリング処理について→s.h.log: Proce55ing – 2値化画像を4近傍ラベリング処理してパーツ抜き出し

今まで、ラベルそのものを2次元のint配列で管理してたけど、今回はBitmapDataオブジェクトとして保存する様にしてみた。BitmapDataならx,y座標で要素にアクセスできるし、ピクセルはuint型なので都合がいい。

■できたもの

download => fla, as, swf (FlashDevelop3.0.0 Beta5 + FlashCS3)

年末年始作ったカメラから画像処理のサンプルを元に改造した。

webcamから撮影してBitmapDataにして、1ピクセルずつ走査して真っ白(0x00FFFFFF)のピクセルを検出。

さらにラベリング処理をして、「ピクセルのかたまり」毎に番号をつける。

(0x00FFFFFFは蛍光灯を撮影すると良いです)

labelinglabelinglabeling

今回はノイズを飛ばしたりしていないので、右の本棚の小さな白にも反応してしまって28個とか検出される

labeling

ラベルの衝突時の処理もしていないので、左上が空いた弧の様な形の時に割れてしまう

labeling

この辺はまたの機会に。



■動きます(USBカメラが必要)

■コード

ColorPicker.as

package{

importfl.controls.Button;

importfl.controls.NumericStepper;

importflash.events.*;

importflash.media.*;

importflash.geom.Point;

importflash.utils.*;

importflash.display.*;

importflash.filters.*;

publicclassColorPickerextendsSprite{

privatevarcam:Camera;//カメラ

privatevarvideo:Video;//カメラからの画像を表示

privatevarbmp:Bitmap;//表示

privatevarbmd:BitmapData;//中身のデータ

privatevarlabels:BitmapData;//bmdと同サイズのラベル

privatevarcolor:int=0x00ffffff;//選択する色(白)



privatevar_numericStepperLabelNum:NumericStepper;

privatevar_buttonSnapshot:Button;



/*IDEが生成したオブジェクトを関連づけ*/

publicfunctionlink_ide_obj(){

this._numericStepperLabelNum=numericStepperLabelNum;

this._buttonSnapshot=buttonSnapshot;

}



publicfunctionColorPicker(){

stage.scaleMode=StageScaleMode.EXACT_FIT;//伸縮する

//stage.scaleMode=StageScaleMode.NO_SCALE;//伸縮しない

stage.align=StageAlign.TOP_LEFT;//左上から



link_ide_obj();//IDEが生成したオブジェクトを関連づけ



cam=Camera.getCamera();

cam.setMode(800,600,24,true);//24FPS

cam.setQuality(0,100);



video=newVideo(200,150);//bitmap計算用の小さいビデオ

video.attachCamera(cam);

this.addChild(video);//videoを表示



_buttonSnapshot.addEventListener(MouseEvent.CLICK,snapShot);//撮影の関数登録

bmd=newBitmapData(video.width,video.height);

bmp=newBitmap(bmd);//BitmapDataをBitampに登録

this.addChild(bmp);//Bitmapを表示

bmp.x=video.width+10;



//ラベル番号の選択GUI

_numericStepperLabelNum.enabled=false;

_numericStepperLabelNum.addEventListener(Event.CHANGE,function(){

showSelectedLabel(_numericStepperLabelNum.value);

});

}



/*撮影*/

publicfunctionsnapShot(e:Event){

bmd.draw(video);//カメラから制止画をキャプチャ

labeling();

showSelectedLabel(_numericStepperLabelNum.value);

_numericStepperLabelNum.enabled=true;

}



/*4近傍ラベリング処理*/

publicfunctionlabeling(){

labels=newBitmapData(bmd.width,bmd.height,false,0);//transparent=false

varlabel:int=0;

varx:int,y:int;

bmd.lock();//表示の更新を止める。これやらないとえらい事になる

for(y=0;y
for(x=0;x
if(bmd.getPixel(x,y)==color){//選択した色の時(今回は白)

if(x>0&&labels.getPixel(x-1,y)>0){//左チェック

labels.setPixel(x,y,labels.getPixel(x-1,y));//ラベルをコピー

}

elseif(x>0&&y>0&&labels.getPixel(x-1,y-1)>0){//左上

labels.setPixel(x,y,labels.getPixel(x-1,y-1));

}

elseif(y>0&&labels.getPixel(x,y-1)>0){//上

labels.setPixel(x,y,labels.getPixel(x,y-1));

}

elseif(y>0&&x0){//右上

labels.setPixel(x,y,labels.getPixel(x+1,y-1));

}

else{//4方向いずれも隣接していない時

labels.setPixel(x,y,++label);//新しいラベル

}

}

//else{

//labels.setPixel(x,y,0);//ラベル無し

//}

}

}

bmd.unlock();//表示を更新する



_numericStepperLabelNum.maximum=label;

_numericStepperLabelNum.minimum=1;

_numericStepperLabelNum.value=1;

}



/*選択したラベルの箇所を青く塗る。他は赤くする*/

publicfunctionshowSelectedLabel(labelNum:int){

bmd.lock();

varx:int,y:int;

for(y=0;y
for(x=0;x
varcurrentLabel:int=labels.getPixel(x,y);

if(currentLabel==labelNum){

bmd.setPixel(x,y,0x000000FF);//青

}

elseif(currentLabel>0){

bmd.setPixel(x,y,0x00FF0000);//赤

}

}

}

bmd.unlock();

}

}

}