2値化画像に対する画像処理の例題です。例題では、収縮/膨張, 細線化を取り上げています。それぞれの処理は、最大尤度しきい値選定法による2値化処理により2値化画像を取得後、計算を行っています。
元画像 | 細線化画像 (Hilditchの方法:線幅1) |
|
実行ファイルのダウンロード: bwproc.exe
//----------------------------------------------------------------- // bwproc.cpp // 2値画像の画像処理[収縮/膨張/細線化] // Last Update: <2004/12/01 07:03:20 A.Murakami> //----------------------------------------------------------------- #include <stdio.h> #include <math.h> #include <windows.h> #include "wingui.h" #include "opthmdthr.h" // 2値化: 最大尤度しきい値選定法 extern UINT iHeight,iWidth,iLength; // 画像: 高さ,幅,1ラインの長さ extern LPBYTE lpOrgBMP,lpBMP; // オリジナル画像, 表示画像 //----------------------------------------------------------------- void toBin(); void Erosion(); void Dilatation(); void bwExpand(int opt,int repetition,LPBYTE inBuf); void Thinning(); void bw_thinning(LPBYTE inBuf); int func_cconc(int *inb); //----------------------------------------------------------------- // メニューへの追加内容 //----------------------------------------------------------------- MenuInfo MI[] = { {"収縮処理",Erosion}, {"膨張処理",Dilatation}, {"細線化",Thinning}, {NULL,NULL} }; //----------------------------------------------------------------- // 2値画像の収縮/膨張処理 enum BW_EXPAND_OPTION { BW_EROSION = 0, //収縮 BW_DILATATION = 1, //膨張 }; //----------------------------------------------------------------- // 2値化 //----------------------------------------------------------------- void toBin() { BYTE r,g,b,gray; int isize,hist[256],thr[10]; FillMemory(hist,sizeof(int)*256,0); // ヒストグラムの作成[濃淡化] for(int i=0;i<iHeight;i++) for(int j=0;j<iWidth;j++) { b=lpOrgBMP[j*3+i*iLength]; g=lpOrgBMP[j*3+i*iLength+1]; r=lpOrgBMP[j*3+i*iLength+2]; gray=(BYTE)(r*0.299+g*0.587+b*0.144); FillMemory(lpBMP+j*3+i*iLength,3,gray); hist[gray]++; } // [2..]値化最適しきい値の計算 isize = iWidth*iHeight; calc_opthmdthr(2,256,isize,hist,thr); // 2値画像の作成 for(int i=0;i<iHeight;i++) for(int j=0;j<iWidth;j++) { gray=lpBMP[j*3+i*iLength]; if(gray>thr[1]){ FillMemory(lpBMP+j*3+i*iLength,3,255); } else { FillMemory(lpBMP+j*3+i*iLength,3,0); } hist[gray]++; } } //----------------------------------------------------------------- // 2値画像の収縮/膨張処理 //----------------------------------------------------------------- void Erosion() { toBin(); bwExpand(BW_EROSION,1,lpBMP); } void Dilatation() { toBin(); bwExpand(BW_DILATATION,2,lpBMP); } //----------------------------------------------------------------- // 2値画像の8近傍収縮/膨張処理(Erosion/Dilatation) // repetition: 処理回数 //----------------------------------------------------------------- void bwExpand(int opt,int repetition,LPBYTE inBuf) { int counter; // 近傍中の背景画素の数 int p_x,p_y; // 近傍の(x,y)座標 int i,x,y,m,n; // 制御変数 int iFIND,iFILL; // 白/黒 色:2値画像 LPBYTE tempBuf; // 一時保存 if(opt==BW_EROSION) { // 収縮 iFIND = 255; iFILL = 0; } else { // 膨張 iFIND = 0; iFILL = 255; } // 複製 tempBuf=(LPBYTE)GlobalAlloc(GPTR,iHeight*iLength); CopyMemory(tempBuf,inBuf,iLength*iHeight); for(i=0;i<repetition;i++){ for(y=0;y<iHeight;y++) for(x=0;x<iWidth;x++){ if(inBuf[x*3+y*iLength] == iFIND){ counter = 0; for(m=-1;m<2;m++) for(n=-1;n<2;n++){ p_x=x+n; p_y=y+m; if(p_x>0 && p_x<iWidth && p_y>0 && p_y<iHeight && inBuf[p_x*3+p_y*iLength]==iFILL) counter ++; } if(counter>0) FillMemory(tempBuf+x*3+y*iLength,3,iFILL); } } CopyMemory(inBuf,tempBuf,iLength*iHeight); } GlobalFree(tempBuf); } //----------------------------------------------------------------- // 2値画像の細線化処理 //----------------------------------------------------------------- void Thinning() { toBin(); bw_thinning(lpBMP); } //----------------------------------------------------------------- // 2値画像の細線化処理 (Hilditch の方法) //----------------------------------------------------------------- void bw_thinning(LPBYTE inBuf) { int offset[8][2] = { {0,1},{-1,1},{-1,0}, {-1,-1},{0,-1},{1,-1}, {1,0},{1,1} }; // 近傍画素へのオフセット int ia[9],ic[9],i,ix,iy,px,py,m,ir,iv,iw; int iWH=255,iBW=0,iGRAY=100; // 白/黒 色:2値画像 LPBYTE tempBuf; // 一時保存 // 複製 tempBuf=(LPBYTE)GlobalAlloc(GPTR,iHeight*iLength); CopyMemory(tempBuf,inBuf,iLength*iHeight); // 処理開始 m=iGRAY; ir=1; while(ir!=0){ ir=0; for(iy=1;iy<iHeight-1;iy++) for(ix=1;ix<iWidth-1;ix++){ if(tempBuf[ix*3+iy*iLength]!=iWH) continue; for(i=0;i<8;i++){ px = ix+offset[i][0]; py = iy+offset[i][1]; ia[i] = tempBuf[px*3+py*iLength]; } for(i=0;i<8;i++){ if(ia[i]==m){ ia[i] = iWH; ic[i] = 0; } else { if(ia[i]<iWH) ia[i]=0; ic[i] = ia[i]; } } ia[8] = ia[0]; ic[8] = ic[0]; if(ia[0]+ia[2]+ia[4]+ia[6] == iWH*4) continue; for(i=0,iv=0,iw=0;i<8;i++){ if(ia[i]==iWH) iv++; if(ic[i]==iWH) iw++; } if(iv<=1) continue; if(iw==1) continue; if(func_cconc(ia)!=1) continue; if(tempBuf[ix*3+(iy-1)*iLength]==m){ ia[2] = 0; if(func_cconc(ia)!=1) continue; ia[2] = iWH; } if(tempBuf[(ix-1)*3+iy*iLength]==m){ ia[4] = 0; if(func_cconc(ia)!=1) continue; ia[4] = iWH; } tempBuf[ix*3+iy*iLength]=m; ir++; } m++; } for(iy=1;iy<iHeight-1;iy++) for(ix=1;ix<iWidth-1;ix++){ if(tempBuf[ix*3+iy*iLength]<iWH) FillMemory(tempBuf+ix*3+iy*iLength,3,iBW); } // 複製 CopyMemory(inBuf,tempBuf,iLength*iHeight); GlobalFree(tempBuf); } //----------------------------------------------------------------- // 注目画素の連結度(8連結)を求める関数 //----------------------------------------------------------------- int func_cconc(int *inb) { int iWH=255,iBL=0; int i,icn=0; for(i=0;i<8;i+=2) if(inb[i]==iBL) if(inb[i+1]==iWH || inb[i+2]==iWH) icn++; return(icn); } |