2値化画像の画像処理

2値化画像に対する画像処理の例題です。例題では、収縮/膨張, 細線化を取り上げています。それぞれの処理は、最大尤度しきい値選定法による2値化処理により2値化画像を取得後、計算を行っています。

元画像   細線化画像
(Hilditchの方法:線幅1)
 

実行ファイルのダウンロード: bwproc.exe

2値化画像の画像処理(bwproc.cpp)
//-----------------------------------------------------------------
// 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);
}
inserted by FC2 system