ふと目が覚めたのでbuilt with processing。

ラベリング処理をやってみた。

画像を読み込んで2値化し、2値化画像のマウスクリックしたパーツだけを抜き出して一番右に表示する。

■処理結果

頭の部分だけ抜き出し

labeling with Processing

二値化の閾知を変えて、頭の部分だけ抜き出し

labeling with Processing

■4近傍ラベリング処理

ラベリング処理は、2値化(白黒化)した画像のピクセルを走査して、ピクセルの塊り毎にラベル(番号)を付けてやる処理のこと。

視覚センサを用いた自律移動ロボットの行動決定(pdf)という論文がとてもわかりやすかった。

今回使った4近傍の他にも、ラインブロックを使ったラベリング処理やヒストグラムを用いた連結成分検出が解説・ベンチマークされている。

左上から右へ、一番右までたどり着いたら1段下の左端に戻る。

そして、毎ピクセル毎に左、左上、上、右上の4近傍ピクセルをチェックする(図の赤と青の部分)

labeling algorithm

(画像は視覚センサを用いた自律移動ロボットの行動決定より)

今回俺は未実装だが、この方法でやると「ラベルの衝突」が起こる。図では1と2のピクセル塊が実は右下の部分でつながっていた、という事。遡って書き換えてやる必要がある。

collision of labeling

(画像は視覚センサを用いた自律移動ロボットの行動決定より)

衝突処理をしていないので、目の部分を選択しても頭とつながって認識されない。

labeling with Processing

■ソースコード

Source Code(Processing Beta 0124) and Image File

PImageimg,img_bin,img_result;

booleanbins[];

intlabels[];

floatr_ratio=0.299;//RGB比合計して1

floatg_ratio=0.587;

floatb_ratio=0.114;

intthreshold=128;//2値化の閾値

voidsetup(){

img=loadImage(“shokai.jpg”);

size(img.width*3,img.height);

image(img,0,0);

binarize();

}

voiddraw(){

}

voidbinarize(){

img_bin=newPImage(img.width,img.height);

bins=newboolean[img.width*img.height];

//2値化

floatlevel;

for(inti=0;i colorpix=img.pixels[i];

floatmed=(int)(r_ratio*red(pix)+g_ratio*green(pix)+b_ratio*blue(pix));

//floatmed=(int)(red(pix)+green(pix)+blue(pix));//RGB比を考慮しない

if(med>threshold){

bins[i]=false;//白

img_bin.pixels[i]=color(255);

}

else{

bins[i]=true;//黒

img_bin.pixels[i]=color(0);

}

}

image(img_bin,img.width,0);//2値化画像を表示



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

intlabel=0;

labels=newint[img.width*img.height];

if(bins[0])labels[0]=label;//左上



for(inti=1;i if(bins[i]){//黒の時

if(!bins[i-1]){

labels[i]=++label;//新しいラベルを付ける

}

else{

labels[i]=labels[i-1];//ラベルのコピー

}

}

}



for(inty=1;y for(intx=1;x inti=x+y*img.width;

if(bins[i]){//黒の時

if(!bins[i-1]&&!bins[i-img.width]&&!bins[i-img.width+1]&&!bins[i-img.width-1]){

labels[i]=++label;//新しいラベル

}

else{

if(bins[i-1])labels[i]=labels[i-1];//左

elseif(bins[i-img.width])labels[i]=labels[i-img.width];//上

elseif(bins[i-img.width+1])labels[i]=labels[i-img.width+1];//右上

elseif(bins[i-img.width-1])labels[i]=labels[i-img.width-1];//左上

/////衝突は今は考えない

}

}

}

}





}

voidmousePressed(){

if(mouseX>img.width&&img.width*2>mouseX){

intlabel=labels[mouseX-img.width+mouseY*img.width];

println(“label:”+label);

img_result=newPImage(img.width,img.height);

for(inti=0;i if(labels[i]==label)img_result.pixels[i]=color(0);

elseimg_result.pixels[i]=color(255);

}

image(img_result,img.width*2,0);

}

}

voidkeyPressed(){

//2値化閾値の調整

if(‘A’<=key&&key<='z'){

switch(key){

case’a’:

if(threshold>0)threshold–;

break;

case’s’:

if(threshold<255)threshold++;

break;

}

}

println(“threshold:”+threshold);

binarize();

}