ふと目が覚めたのでbuilt with processing。
ラベリング処理をやってみた。
画像を読み込んで2値化し、2値化画像のマウスクリックしたパーツだけを抜き出して一番右に表示する。
■4近傍ラベリング処理
ラベリング処理は、2値化(白黒化)した画像のピクセルを走査して、ピクセルの塊り毎にラベル(番号)を付けてやる処理のこと。
視覚センサを用いた自律移動ロボットの行動決定(pdf)という論文がとてもわかりやすかった。
今回使った4近傍の他にも、ラインブロックを使ったラベリング処理やヒストグラムを用いた連結成分検出が解説・ベンチマークされている。
左上から右へ、一番右までたどり着いたら1段下の左端に戻る。
そして、毎ピクセル毎に左、左上、上、右上の4近傍ピクセルをチェックする(図の赤と青の部分)
(画像は視覚センサを用いた自律移動ロボットの行動決定より)
今回俺は未実装だが、この方法でやると「ラベルの衝突」が起こる。図では1と2のピクセル塊が実は右下の部分でつながっていた、という事。遡って書き換えてやる必要がある。
(画像は視覚センサを用いた自律移動ロボットの行動決定より)
衝突処理をしていないので、目の部分を選択しても頭とつながって認識されない。
■ソースコード
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;icolorpix=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;iif(bins[i]){//黒の時
if(!bins[i-1]){
labels[i]=++label;//新しいラベルを付ける
}
else{
labels[i]=labels[i-1];//ラベルのコピー
}
}
}
for(inty=1;yfor(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;iif(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();
}