見出し画像

距離変換・骨格化

距離変換・骨格化


2024年11月6初稿

直接、アプリで使用するのは、骨格化ですが、骨格化を行う
為に距離変換が必要に成りますので距離変換と言う多値画像
が結果として得られる処理から説明します?!

骨格化概念図

2値図形の骨格化とは、概念としては、図形の背骨みたいな
物と考えて下さい!距離変換した距離画像の標高の高い尾根
を結んだ者です!
2値図形から距離変換した距離画像とは、図形の最外周を
「1」として一回り変換し、その内側を「2」の外周をぐるっ
とセットし、その内側を「3」と中に行くほど画素の値が、
大きく成る事で一番内側が一番大きな値に成る事で「距離」
とは、外周から内側に向かった外周からどれだけ離れて居る
かの数値です!丁度、地図で海面≒0で標高が海から離れる
と段々高く成る(数値が大きく成る)と考えて下さい?!
そして骨格化とは、その標高の高い尾根を結んだ物と考える
と図形の背骨の様な構造線に成ると想像して下さい!

距離変換例元画像

数値「1」が入っている升が有効な画素でその一塊を距離
変換して行きます

距離変換例結果画像

数値「1」が最外周でソノ内側が大きな数に成って居る事が
分かるでしょう!

1.距離変換

(1)ソースコード解説DistanceImage()

code:DistanceImage(仮引数){}

/************************************************************************/
/*****      距離画像作成                                    :実行部*****/
/*****      DISTANCE,s,d,c                            *****/
/************************************************************************/

int                 Filter::DistanceImage(
    TypeArray       *ps,                            // S画像情報
    TypeArray       *pd,                            // D画像情報
    int             c                               // 連結性
){
    int             sti;                            // ステータス情報

    if( c != 4 && c != 8 ){                         // 連結性間違い時
        return( STI_FLG );                          // 左記を返す
    }                                               //
    sti = distance( ps, pd, c );                    // 基本部で処理
    if( sti != END_STI ){                           // エラーがある場合
        return( sti );                              // ステータスを返す
    }                                               //
    ClearRoundImage( pd, 0, 1 );                    // 1周周囲クリア
    return( END_STI );                              // 正常終了
}

(1-1)関数名

「Distance」は、距離を意味する!
「Image」は、画像で画像の中で距離変換を行います!

(1-2)仮引数

code:仮引数

int                 Filter::DistanceImage(
    TypeArray       *ps,                            // S画像情報
    TypeArray       *pd,                            // D画像情報
    int             c                               // 連結性
){

「TypeArray* ps,」は、元画像(S≒ソース画像)
「TypeArray* pd,」は、結果画像(D≒ディスティネー
ション画像)
「int c,」は、連結性を示す選択コードで「4」なら4連結
「8」なら8連結です!

(1-3)ローカル変数

code:ローカル変数

){
    int             sti;                            // ステータス情報

「int sti;」は、関数のステータス情報(エラーコード)で
す!

(1-4)アルゴリズム

code:アルゴリズム

    if( c != 4 && c != 8 ){                         // 連結性間違い時
        return( STI_FLG );                          // 左記を返す
    }                                               //
    sti = distance( ps, pd, c );                    // 基本部で処理
    if( sti != END_STI ){                           // エラーがある場合
        return( sti );                              // ステータスを返す
    }                                               //
    ClearRoundImage( pd, 0, 1 );                    // 1周周囲クリア
    return( END_STI );                              // 正常終了
}

「if(c!=4&&c!=8){return(STI_FLG);}」は、連結性が4と
8以外ならば、エラー「STI_FLG」を関数辺値とし返し終了
「sti=distance(ps,pd,c);if(sti!=END_STI){
return(sti);}」は、下請け関数「
sti=distance(ps,pd,c);」で処理しステータスを取り出し、
正常終了以外ならば、そのエラーコードを関数辺値とし返し
終了!
「ClearRoundImage(pd,0,1);」は、外周一回り0クリア
「return(END_STI);」は、正常終了を関数辺値とし返し
終了!

(2)ソースコード解説distance()

code:distance(仮引数){}

/************************************************************************/
/*****      距離画像作成                            :実行部:基本部*****/
/*****      DISTANCE,s,d,c                            *****/
/************************************************************************/

int                 Filter::distance(
    TypeArray       *ps,                            // S画像情報
    TypeArray       *pd,                            // D画像情報
    int             c                               // 連結性
){
    TypeArray       s;                              // S画像情報:局所
    TypeArray       d;                              // D画像情報:局所
    int             sti;                            // ステータス情報

    if( ps->w != 1 || pd->w != 1 ){                 // 画素単位=1以外
        return( STI_ARY_5 );                        // 左記を返す
    }                                               // 
    sti = Copy( ps, pd );                           // S→T
    if( sti != END_STI ){                           // エラーがある場合
        return( sti );                              // ステータスを返す
    }                                               //
    s   = *ps;                                      // 一旦、S画像情報
    ps  = &s;                                       // を局所化
    d   = *pd;                                      // 一旦、D画像情報
    pd  = &d;                                       // を局所化
    PreProcessor3By3( ps, pd );                     // 前処理
    if( c == 4 ){                                   // 4連結なら
        distance_4( pd );                           // 左記で処理
    }else{                                          // 8連結なら
        distance_8( pd );                           // 左記で処理
    }                                               //
    return( END_STI );                              // 正常終了
}

(2-1)関数名

「distance」は、距離を意味する!

(2-2)仮引数

code:仮引数

int                 Filter::distance(
    TypeArray       *ps,                            // S画像情報
    TypeArray       *pd,                            // D画像情報
    int             c                               // 連結性
){

「TypeArray* ps,」は、元画像(S≒ソース画像)
「TypeArray* pd,」は、結果画像(D≒ディスティネー
ション画像)
「int c,」は、連結性を示す選択コードで「4」なら4連結
「8」なら8連結です!

(2-2)ローカル変数

code:ローカル変数

){
    TypeArray       s;                              // S画像情報:局所
    TypeArray       d;                              // D画像情報:局所
    int             sti;                            // ステータス情報

「TypeArray s;」は、元画像情報のローカル変数です!
「TypeArray d;」は、結果画像情報のローカル変数です!
「int sti;」は、関数のステータス情報(エラーコード)で
す!

(2-3)アルゴリズム

code:アルゴリズム

    if( ps->w != 1 || pd->w != 1 ){                 // 画素単位=1以外
        return( STI_ARY_5 );                        // 左記を返す
    }                                               // 
    sti = Copy( ps, pd );                           // S→T
    if( sti != END_STI ){                           // エラーがある場合
        return( sti );                              // ステータスを返す
    }                                               //
    s   = *ps;                                      // 一旦、S画像情報
    ps  = &s;                                       // を局所化
    d   = *pd;                                      // 一旦、D画像情報
    pd  = &d;                                       // を局所化
    PreProcessor3By3( ps, pd );                     // 前処理
    if( c == 4 ){                                   // 4連結なら
        distance_4( pd );                           // 左記で処理
    }else{                                          // 8連結なら
        distance_8( pd );                           // 左記で処理
    }                                               //
    return( END_STI );                              // 正常終了
}

「if(ps->w!=1||pd->w!=1){return(STI_ARY_5);}」は、
元画像(S≒ソース)も結果画像(D≒ディスティネーショ
ン)も画素単位が1バイト以外ならエラー「STI_ARY_5」を
関数辺値とし返し終了!
「sti=Copy(ps,pd);」は、結果画像に一旦コピー
「if(sti!=END_STI){return(sti);}」は、コピー関数で
エラー発生時は、エラーをステータス情報とし関数辺値と
し返し終了!
「s=*ps;ps=&s;d=*pd;pd=&d;」は、元画像結果画像情報の
ポインタ変数付替え
「PreProcessor3By3(ps,pd);」は、元画像結果画像両者の
有効な水平幅・垂直を算出し、3×3画像変数に相応しい
一回り内側に画像情報をセット!
「if(c==4){distance_4(pd);}else{distance_8(pd);}」は、
4連結なら下請け関数「distance_4(pd);」で処理し、
8連結なら下請け関数「distance_8(pd);」で処理
「return(END_STI);」は、正常終了を関数辺値とし返し
終了

(3)ソースコード解説distance_4()

code:distance_4(仮引数){}

/************************************************************************/
/*****  距離変換コマンド:ソフト実行部:4連結用                    *****/
/*****  DISTANCE,c,S,D                                   *****/
/************************************************************************/

void            Filter::distance_4(
    TypeArray   *pd                                 // D画像情報
){
    BYTE        *ptrd;                              // D画像Ptr
    int         h;                                  // 水平幅
    int         v;                                  // 垂直幅
    int         incd;                               // D画像:増加幅
    int         y;                                  // y座標方向CNT

    h    = pd->h;                                   // 画像のサイズを
    v    = pd->v;                                   // 取り出し
    incd = pd->inc;                                 // D画像増加幅取出
    ptrd = (BYTE*)pd->adr;                          // D画像Ptrを取出す
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        distance_4_x1( ptrd, incd, h );             // 1行分処理
        ptrd += incd;                               // 垂直方向増加
    }                                               //
    ptrd = (BYTE*)pd->adr                           // 右下Ptrを算出
                    + ( h - 1 ) + ( v - 1 ) * incd; //
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        distance_4_x2( ptrd, incd, h );             // 1行分処理
        ptrd -= incd;                               // 垂直方向減少
    }                                               //
}

(3-1)関数名

「distance」は、距離を意味する!
「_4」は、4連結の処理を意味!

(3-2)仮引数

code:仮引数

void            Filter::distance_4(
    TypeArray   *pd                                 // D画像情報
){

「TypeArray* pd,」は、結果画像(D≒ディスティネー
ション画像)

(3-2)ローカル変数

code:ローカル変数

){
    BYTE        *ptrd;                              // D画像Ptr
    int         h;                                  // 水平幅
    int         v;                                  // 垂直幅
    int         incd;                               // D画像:増加幅
    int         y;                                  // y座標方向CNT

「BYTE* ptrd;」は、結果画像画素をアクセスするポインタ
変数!
「int h;」は、水平幅
「int v;」は、垂直幅
「int incd;」は、垂直方向増加幅
「int y;」は、垂直(Y座標)方向繰り返しカウンタ

(3-3)アルゴリズム

code:アルゴリズム終了!

    h    = pd->h;                                   // 画像のサイズを
    v    = pd->v;                                   // 取り出し
    incd = pd->inc;                                 // D画像増加幅取出
    ptrd = (BYTE*)pd->adr;                          // D画像Ptrを取出す
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        distance_4_x1( ptrd, incd, h );             // 1行分処理
        ptrd += incd;                               // 垂直方向増加
    }                                               //
    ptrd = (BYTE*)pd->adr                           // 右下Ptrを算出
                    + ( h - 1 ) + ( v - 1 ) * incd; //
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        distance_4_x2( ptrd, incd, h );             // 1行分処理
        ptrd -= incd;                               // 垂直方向減少
    }                                               //
}

「h=pd->h;v=pd->v;」は、水平幅・垂直幅を取り出し!
「incd=pd->inc;」は、垂直方向増加幅を取り出し!
「ptrd=(BYTE*)pd->adr;」は、画素アクセスポインタを
画像始点(左上)にセット
「for(y=v;--y>=0;){・・ループ中身・・}」は、垂直幅分
ループ中身を繰り返す!そのループ中身は、
「distance_4_x1(ptrd,incd,h);」で下請け
関数「distance_4_x1(・・・)」で処理
「ptrd+=incd;」で垂直方向下方にポインタを進める!
※ここまでで始点から下方に処理して行きます!
「ptrd=(BYTE*)pd->adr+(h-1)+(v-1)*incd;」は、
画素アクセスポインタを画像終点(右下)にセット!
「for(y=v;--y>=0;){・・ループ中身・・}」は、垂直幅分
ループ中身を繰り返す!そのループ中身は、
「distance_4_x2(ptrd,incd,h);」で下請け
関数「distance_4_x2(・・・)」で処理
「ptrd-=incd;」で垂直方向上方にポインタを進める!
※ここまでで終点(右下)から上方に処理して行きます!
★「distance_4_x1(・・・)」で左上から右下への処理、
「distance_4_x2(・・・)」で右下から左上への処理と処理
する向きが異なる事に注意して下さい!

(4)ソースコード解説distance_4_x1()

code:distance_4_x1(仮引数){}

/************************************************************************/
/*****  距離変換コマンド:4連結用:上から下に処理:1行分          *****/
/*****  1行分の処理(左から右方向に処理を行う)                    *****/
/************************************************************************/

void            Filter::distance_4_x1(
    BYTE        *p,                                 // y軸用Ptr:左側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){
    int         d1;                                 // 近接データ1
    int         d2;                                 // 近接データ2
    int         d255;                               // 定数値255

    d255 = 255;                                     // 定数値255
    while( --h >= 0 ){                              // 水平方向に繰返し
        if( *p ){                                   // 注視点にData有り
            d1 = *( p - inc );                      // 上の値と
            d2 = *( p - 1 );                        // 左の値を取り出し
            if( d1 > d2 ){                          // 最小の値を算出し
                d1 = d2;                            //
            }                                       //
            d1 += 1;                                // 最小+1を算出
            if( d1 > d255 ){                        // 255超なら
                d1 = d255;                          // 255に補正
            }                                       //
            *p = d1;                                // 結果を出力
        }                                           //
        p++;                                        // 右方向へ進める
    }                                               //
}

(4-1)関数名

「distance」は、距離を意味する!
「_4」は、4連結の処理を意味!
「x1」は、X座標方向の処理で「左⇒右」方向の処理を
意味!

(4-2)仮引数

code:仮引数

void            Filter::distance_4_x1(
    BYTE        *p,                                 // y軸用Ptr:左側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){

「BYTE* p,」は、画像画素へのポインタ
「int inc,」は、垂直方向増加幅※上下オフセット
「int h」は、水平幅

(4-2)ローカル変数

code:ローカル変数

){
    int         d1;                                 // 近接データ1
    int         d2;                                 // 近接データ2
    int         d255;                               // 定数値255

「int d1;」は、近接画素データ1
「int d2;」は、近接画素データ2
「int d255;」は、定数値「255」※高速化技法

(4-3)アルゴリズム

code:アルゴリズム

    d255 = 255;                                     // 定数値255
    while( --h >= 0 ){                              // 水平方向に繰返し
        if( *p ){                                   // 注視点にData有り
            d1 = *( p - inc );                      // 上の値と
            d2 = *( p - 1 );                        // 左の値を取り出し
            if( d1 > d2 ){                          // 最小の値を算出し
                d1 = d2;                            //
            }                                       //
            d1 += 1;                                // 最小+1を算出
            if( d1 > d255 ){                        // 255超なら
                d1 = d255;                          // 255に補正
            }                                       //
            *p = d1;                                // 結果を出力
        }                                           //
        p++;                                        // 右方向へ進める
    }                                               //
}

「d255=255;」は、定数値「255」セット※高速化技法
「while(--h>=0){・・ループ中身・・}」は、水平幅分
繰り返しループ中身を処理、そのループ中身は、
「if(p){・・分岐中身・・」で条件「p」で有効画素(
≠0)の場合は、分岐中身の
「d1=(p-inc);d2=(p-1);」で上側と左側画素データを
取り出す!
「if(d1>d2){d1=d2;}」で条件「上側値>左側値」の場合
は、近接データ1(元は上側値)を左側値の値をセット、
つまり、上側・左側の最小値セット
「d1+=1;」で近接データ1を一つ増加、
「if(d1>d255){d1=d255;}」で上限※画像画素の型名「
BYTE≒unsigned char」と符号無し1バイトで
「0・・255」を採用≪更に実用的にこれで十分と判断≫し
たので値を制限
「*p=d1;」で注視点画素の値を更新し、分岐中身ブロック
終了、
「p++;」でループ中身最後に画素を示すポインタを右方向
に進める

(5)ソースコード解説distance_4_x2()

code:distance_4_x2(仮引数){}

/************************************************************************/
/*****  距離変換コマンド:4連結用:下から上に処理:1行分          *****/
/*****  1行分の処理(右から左方向に処理を行う)                    *****/
/************************************************************************/

void            Filter::distance_4_x2(
    BYTE        *p,                                 // y軸用Ptr:右側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){
    int         d0;                                 // 注視点データ
    int         d1;                                 // 近接データ1
    int         d2;                                 // 近接データ2
    int         d255;                               // 定数値255

    d255 = 255;                                     // 定数値255
    while( --h >= 0 ){                              // 水平方向に繰返し
        d0 = *p;                                    // 注視点Data取出し
        if( d0 ){                                   // Data有りなら
            d1 = *( p + inc );                      // 下の値と
            d2 = *( p + 1 );                        // 右の値を取り出し
            if( d1 > d2 ){                          // 最小の値を算出し
                d1 = d2;                            //
            }                                       //
            d1 += 1;                                // 最小+1を算出
            if( d1 > d0 ){                          // 注視点と比較し
                d1 = d0;                            // その最小を算出
            }                                       //
            if( d1 > d255 ){                        // 255超なら
                d1 = d255;                          // 255に補正
            }                                       //
            *p = d1;                                // 結果を出力
        }                                           //
        p--;                                        // 左方向へ進める
    }                                               //
}

(5-1)関数名

「distance」は、距離を意味する!
「_4」は、4連結の処理を意味!
「x2」は、X座標方向の処理で「左⇒右」方向の処理を
意味!

(5-2)仮引数

code:仮引数

void            Filter::distance_4_x2(
    BYTE        *p,                                 // y軸用Ptr:右側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){

「BYTE* p,」は、画像画素へのポインタ
「int inc,」は、垂直方向増加幅※上下オフセット
「int h」は、水平幅

(5-2)ローカル変数

code:ローカル変数

){
    int         d0;                                 // 注視点データ
    int         d1;                                 // 近接データ1
    int         d2;                                 // 近接データ2
    int         d255;                               // 定数値255

「int d0;」は、注視点画素データ
「int d1;」は、近接画素データ1
「int d2;」は、近接画素データ2
「int d255;」は、定数値「255」※高速化技法

(5-3)アルゴリズム

code:アルゴリズム

    d255 = 255;                                     // 定数値255
    while( --h >= 0 ){                              // 水平方向に繰返し
        d0 = *p;                                    // 注視点Data取出し
        if( d0 ){                                   // Data有りなら
            d1 = *( p + inc );                      // 下の値と
            d2 = *( p + 1 );                        // 右の値を取り出し
            if( d1 > d2 ){                          // 最小の値を算出し
                d1 = d2;                            //
            }                                       //
            d1 += 1;                                // 最小+1を算出
            if( d1 > d0 ){                          // 注視点と比較し
                d1 = d0;                            // その最小を算出
            }                                       //
            if( d1 > d255 ){                        // 255超なら
                d1 = d255;                          // 255に補正
            }                                       //
            *p = d1;                                // 結果を出力
        }                                           //
        p--;                                        // 左方向へ進める
    }                                               //
}

「d255=255;」は、定数値「255」セット※高速化技法
「while(--h>=0){・・ループ中身・・}」は、水平幅分
繰り返しループ中身を処理、そのループ中身は、
「d0=p;」で注視点画素データとしセット※何回も比較用
に使用するので高速化技法
「if(d0){・・分岐中身・・」で条件「d0」で有効画素(
≠0)の場合は、分岐中身の
「d1=(p+inc);d2=*(p+1);」で右側と下側画素データを
取り出す!
「if(d1>d2){d1=d2;}」で条件「右側値>下側値」の場合
は、近接データ1(元は右側値)を下側値の値をセット、
つまり、右側・下側の最小値セット
「d1+=1;」で近接データ1を一つ増加、
「if(d1>d0){d1=d0;}」で条件「近接データ1>注視点」の
場合は、近接データ1を注視点の値をセット、つまり、
依り近接データ1・注視点の最小値セット
「if(d1>d255){d1=d255;}」で上限※画像画素の型名「
BYTE≒unsigned char」と符号無し1バイトで
「0・・255」を採用≪更に実用的にこれで十分と判断≫し
たので値を制限
「*p=d1;」で注視点画素の値を更新し、分岐中身ブロック
終了、
「p--;」でループ中身最後に画素を示すポインタを左方向
に進める

(6)ソースコード解説distance_8()

code:distance_8(仮引数){}

/************************************************************************/
/*****  距離変換コマンド:ソフト実行部:8連結用                    *****/
/*****  DISTANCE,c,S,D                                   *****/
/************************************************************************/

void            Filter::distance_8(
    TypeArray   *pd                                 // D画像情報
){
    BYTE        *ptrd;                              // D画像Ptr
    int         h;                                  // 水平幅
    int         v;                                  // 垂直幅
    int         incd;                               // D画像:増加幅
    int         y;                                  // y座標方向CNT

    h    = pd->h;                                   // 画像のサイズを
    v    = pd->v;                                   // 取り出し
    incd = pd->inc;                                 // D画像増加幅取出
    ptrd = (BYTE*)pd->adr;                          // D画像Ptrを取出す
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        distance_8_x1( ptrd, incd, h );             // 1行分処理
        ptrd += incd;                               // 垂直方向増加
    }                                               //
    ptrd = (BYTE*)pd->adr                           // 右下Ptrを算出
                    + ( h - 1 ) + ( v - 1 ) * incd; //
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        distance_8_x2( ptrd, incd, h );             // 1行分処理
        ptrd -= incd;                               // 垂直方向減少
    }                                               //
}

(6-1)関数名

「distance」は、距離を意味する!
「_8」は、8連結の処理を意味!

(6-2)仮引数

code:仮引数

void            Filter::distance_8(
    TypeArray   *pd                                 // D画像情報
){

「TypeArray* pd,」は、結果画像(D≒ディスティネー
ション画像)

(6-2)ローカル変数

code:ローカル変数

){
    BYTE        *ptrd;                              // D画像Ptr
    int         h;                                  // 水平幅
    int         v;                                  // 垂直幅
    int         incd;                               // D画像:増加幅
    int         y;                                  // y座標方向CNT

「BYTE* ptrd;」は、結果画像画素をアクセスするポインタ
変数!
「int h;」は、水平幅
「int v;」は、垂直幅
「int incd;」は、垂直方向増加幅
「int y;」は、垂直(Y座標)方向繰り返しカウンタ

(6-3)アルゴリズム

code:アルゴリズム

    h    = pd->h;                                   // 画像のサイズを
    v    = pd->v;                                   // 取り出し
    incd = pd->inc;                                 // D画像増加幅取出
    ptrd = (BYTE*)pd->adr;                          // D画像Ptrを取出す
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        distance_8_x1( ptrd, incd, h );             // 1行分処理
        ptrd += incd;                               // 垂直方向増加
    }                                               //
    ptrd = (BYTE*)pd->adr                           // 右下Ptrを算出
                    + ( h - 1 ) + ( v - 1 ) * incd; //
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        distance_8_x2( ptrd, incd, h );             // 1行分処理
        ptrd -= incd;                               // 垂直方向減少
    }                                               //
}

「h=pd->h;v=pd->v;」は、水平幅・垂直幅を取り出し!
「incd=pd->inc;」は、垂直方向増加幅を取り出し!
「ptrd=(BYTE*)pd->adr;」は、画素アクセスポインタを
画像始点(左上)にセット
「for(y=v;--y>=0;){・・ループ中身・・}」は、垂直幅分
ループ中身を繰り返す!そのループ中身は、
「distance_8_x1(ptrd,incd,h);」で下請け
関数「distance_8_x1(・・・)」で処理
「ptrd+=incd;」で垂直方向下方にポインタを進める!
※ここまでで始点から下方に処理して行きます!
「ptrd=(BYTE*)pd->adr+(h-1)+(v-1)*incd;」は、
画素アクセスポインタを画像終点(右下)にセット!
「for(y=v;--y>=0;){・・ループ中身・・}」は、垂直幅分
ループ中身を繰り返す!そのループ中身は、
「distance_8_x2(ptrd,incd,h);」で下請け
関数「distance_8_x2(・・・)」で処理
「ptrd-=incd;」で垂直方向上方にポインタを進める!
※ここまでで終点(右下)から上方に処理して行きます!
★「distance_8_x1(・・・)」で左上から右下への処理、
「distance_8_x2(・・・)」で右下から左上への処理と処理
する向きが異なる事に注意して下さい!

(7)ソースコード解説distance_8_x1()

code:distance_8_x1(仮引数){}

/************************************************************************/
/*****  距離変換コマンド:8連結用:上から下方向:1行分            *****/
/*****  1行分の処理(左から右方向に処理を行う)                    *****/
/************************************************************************/

void            Filter::distance_8_x1(
    BYTE        *p,                                 // y軸用Ptr:左側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){
    BYTE        *pend;                              // 終点Ptr:右側
    int         d1;                                 // 近接データ1
    int         d2;                                 // 近接データ2
    int         d3;                                 // 近接データ3
    int         d4;                                 // 近接データ4
    int         d255;                               // 定数値255

    d255 = 255;                                     // 定数値255
    for( pend = p + h; p < pend; p++ ){             // 水平方向に繰返し
        if( *p ){                                   // 注視点にData有り
            d1  = *( p - inc - 1 );                 // 左上の値と
            d2  = *( p - inc );                     // 上の値と
            d3  = *( p - inc + 1 );                 // 右上の値と
            d4  = *( p - 1 );                       // 左の値を取り出し
            if( d1 > d2 ){                          // 最小の値を算出し
                d1 = d2;                            //
            }                                       //
            if( d1 > d3 ){                          //
                d1 = d3;                            //
            }                                       //
            if( d1 > d4 ){                          //
                d1 = d4;                            //
            }                                       //
            d1 += 1;                                // 最小+1を算出
            if( d1 > d255 ){                        // 255超なら
                d1 = d255;                          // 255に補正
            }                                       //
            *p = d1;                                // データ出力
        }                                           //
    }                                               //
}

(7-1)関数名

「distance」は、距離を意味する!
「_8」は、8連結の処理を意味!
「x1」は、X座標方向の処理で「左⇒右」方向の処理を
意味!

(7-2)仮引数

code:仮引数

void            Filter::distance_8_x1(
    BYTE        *p,                                 // y軸用Ptr:左側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){

「BYTE* p,」は、画像画素へのポインタ
「int inc,」は、垂直方向増加幅※上下オフセット
「int h」は、水平幅

(7-2)ローカル変数

code:ローカル変数

){
    BYTE        *pend;                              // 終点Ptr:右側
    int         d1;                                 // 近接データ1
    int         d2;                                 // 近接データ2
    int         d3;                                 // 近接データ3
    int         d4;                                 // 近接データ4
    int         d255;                               // 定数値255

「BYTE*pend;」は、水平方向画素ポインタ終点※目印で
何故ループ条件に使用したかは、元々ADS社画像処理装置
のCPUが68000系でコンパイラ「MCC68K」を
使用して居たためにループ条件としデータレジスターを使い
切り、アドレスレジスターに変数を割り当てる高速化技法と
して「BYTE*pend;」を終点目印に使用した名残です!

(7-3)アルゴリズム

code:アルゴリズム

    d255 = 255;                                     // 定数値255
    for( pend = p + h; p < pend; p++ ){             // 水平方向に繰返し
        if( *p ){                                   // 注視点にData有り
            d1  = *( p - inc - 1 );                 // 左上の値と
            d2  = *( p - inc );                     // 上の値と
            d3  = *( p - inc + 1 );                 // 右上の値と
            d4  = *( p - 1 );                       // 左の値を取り出し
            if( d1 > d2 ){                          // 最小の値を算出し
                d1 = d2;                            //
            }                                       //
            if( d1 > d3 ){                          //
                d1 = d3;                            //
            }                                       //
            if( d1 > d4 ){                          //
                d1 = d4;                            //
            }                                       //
            d1 += 1;                                // 最小+1を算出
            if( d1 > d255 ){                        // 255超なら
                d1 = d255;                          // 255に補正
            }                                       //
            *p = d1;                                // データ出力
        }                                           //
    }                                               //
}

「d255=255;」は、定数値「255」セット※高速化技法
「for(pend=p+h;p<pend;p++){・・ループ中身・・}」は、
水平幅分繰り返し「pend=p+h;」で終点目印を作成し
「p<pend;」で終点目印まで繰り返し「p++」で処理ポインタを左から右へ移動のforループでループ中身を処理、
そのループ中身は、
「if(p){・・分岐中身・・」で条件「p」で有効画素(
≠0)の場合は、分岐中身の
「d1=(p-inc-1);d2=(p-inc);d3=(p-inc+1);d4=(p-1);
」で左上側と上側画素と右上側と左側画素データを取り出
す!
「if(d1>d2){d1=d2;}if(d1>d3){d1=d3;}if(d1>d4){
d1=d4;}」で左上側・上側・右上側・左側との最小値セット
「d1+=1;」で近接データ1を一つ増加、
「if(d1>d255){d1=d255;}」で上限※画像画素の型名「
BYTE≒unsigned char」と符号無し1バイトで
「0・・255」を採用≪更に実用的にこれで十分と判断≫し
たので値を制限
「*p=d1;」で注視点画素の値を更新し、分岐中身ブロック
終了、
「p++;」でループ中身最後に画素を示すポインタを右方向
に進める

(8)ソースコード解説distance_8_x2()

code:distance_8_x2(仮引数){}

/************************************************************************/
/*****  距離変換コマンド:8連結用:下から上方向:1行分            *****/
/*****  1行分の処理(右から左方向に処理を行う)                    *****/
/************************************************************************/

void            Filter::distance_8_x2(
    BYTE        *p,                                 // y軸用Ptr:右側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){
    BYTE        *pend;                              // 終点Ptr:左側
    int         d0;                                 // 注視点データ
    int         d1;                                 // 近接データ1
    int         d2;                                 // 近接データ2
    int         d3;                                 // 近接データ3
    int         d4;                                 // 近接データ4
    int         d255;                               // 定数値255

    d255 = 255;                                     // 定数値255
    for( pend = p - h; p > pend; p-- ){             // 水平方向に繰返し
        d0 = *p;                                    // 注視点Data取出し
        if( d0 ){                                   // Data有りなら
            d1  = *( p + inc - 1 );                 // 左下の値と
            d2  = *( p + inc );                     // 下の値と
            d3  = *( p + inc + 1 );                 // 右下の値と
            d4  = *( p + 1 );                       // 右の値を取り出し
            if( d1 > d2 ){                          // 最小の値を算出し
                d1 = d2;                            //
            }                                       //
            if( d1 > d3 ){                          //
                d1 = d3;                            //
            }                                       //
            if( d1 > d4 ){                          //
                d1 = d4;                            //
            }                                       //
            d1 += 1;                                // 最小+1を算出
            if( d1 > d0 ){                          // 注視点と比較し
                d1 = d0;                            // その最小を算出
            }                                       //
            if( d1 > d255 ){                        // 255超なら
                d1 = d255;                          // 255に補正
            }                                       //
            *p = d1;                                // 結果を出力
        }                                           //
    }                                               //
}

(8-1)関数名

「distance」は、距離を意味する!
「_8」は、8連結の処理を意味!
「x2」は、X座標方向の処理で「左⇒右」方向の処理を
意味!

(8-2)仮引数

code:仮引数

void            Filter::distance_8_x2(
    BYTE        *p,                                 // y軸用Ptr:右側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){

「BYTE* p,」は、画像画素へのポインタ
「int inc,」は、垂直方向増加幅※上下オフセット
「int h」は、水平幅

(8-2)ローカル変数

code:ローカル変数

){
    BYTE        *pend;                              // 終点Ptr:左側
    int         d0;                                 // 注視点データ
    int         d1;                                 // 近接データ1
    int         d2;                                 // 近接データ2
    int         d3;                                 // 近接データ3
    int         d4;                                 // 近接データ4
    int         d255;                               // 定数値255

「BYTE *pend;」は、水平方向画素ポインタ終点※目印で
何故ループ条件に使用したかは、元々ADS社画像処理装置
のCPUが68000系でコンパイラ「MCC68K」を
使用して居たためにループ条件としデータレジスターを使い
切り、アドレスレジスターに変数を割り当てる高速化技法と
して「BYTE*pend;」を終点目印に使用した名残です!
「int d0;」は、注視点画素データ
「int d1;」は、近接画素データ1
「int d2;」は、近接画素データ2
「int d3;」は、近接画素データ3
「int d4;」は、近接画素データ4
「int d255;」は、定数値「255」※高速化技法

(8-3)アルゴリズム

code:アルゴリズム

    d255 = 255;                                     // 定数値255
    for( pend = p - h; p > pend; p-- ){             // 水平方向に繰返し
        d0 = *p;                                    // 注視点Data取出し
        if( d0 ){                                   // Data有りなら
            d1  = *( p + inc - 1 );                 // 左下の値と
            d2  = *( p + inc );                     // 下の値と
            d3  = *( p + inc + 1 );                 // 右下の値と
            d4  = *( p + 1 );                       // 右の値を取り出し
            if( d1 > d2 ){                          // 最小の値を算出し
                d1 = d2;                            //
            }                                       //
            if( d1 > d3 ){                          //
                d1 = d3;                            //
            }                                       //
            if( d1 > d4 ){                          //
                d1 = d4;                            //
            }                                       //
            d1 += 1;                                // 最小+1を算出
            if( d1 > d0 ){                          // 注視点と比較し
                d1 = d0;                            // その最小を算出
            }                                       //
            if( d1 > d255 ){                        // 255超なら
                d1 = d255;                          // 255に補正
            }                                       //
            *p = d1;                                // 結果を出力
        }                                           //
    }                                               //
}

「d255=255;」は、定数値「255」セット※高速化技法
「for(pend=p-h;p>pend;p--){・・ループ中身・・}」は、
水平幅分繰り返し「pend=p+h;」で終点目印を作成し
「p>pend;」で終点目印まで繰り返し「p--」で処理ポインタ
を右から左へ移動のforループでループ中身を処理、そのループ中身は、
「d0=p;」で注視点画素データとしセット※何回も比較用
に使用するので高速化技法
「if(d0){・・分岐中身・・」で条件「d0」で有効画素(
≠0)の場合は、分岐中身の
「d1=(p-inc-1);d2=(p-inc);」で左上側と上側画素
データを取り出す!
「d3=(p-inc+1);d4=*(p-1);」で右上側と左側画素
データを取り出す!
「if(d1>d2){d1=d2;}」で条件「左上側>上側値」の場合
は、近接データ1を上側値の値でセット、
「if(d1>d3){d1=d3;}」で条件「近接データ1>右上側値」
の場合は、近接データ1に右上値の値でセット、
「if(d1>d4){d1=d4;}」で条件「近接データ1>左側値」
の場合は、近接データ1に左側値の値でセット、
つまり、左上側・上側・右上側・左側との最小値セット
「d1+=1;」で近接データ1を一つ増加、
「if(d1>d0){d1=d0;}」で条件「近接データ1>注視点」の
場合は、近接データ1を注視点の値をセット、つまり、
依り近接データ1・注視点の最小値セット
「if(d1>d255){d1=d255;}」で上限※画像画素の型名「
BYTE≒unsigned char」と符号無し1バイトで
「0・・255」を採用≪更に実用的にこれで十分と判断≫し
たので値を制限
「*p=d1;」で注視点画素の値を更新し、分岐中身ブロック
終了

2.骨格化


(1)ソースコード解説SkeletonImage()

code:SkeletonImage(仮引数){}

/************************************************************************/
/*****      骨格化                                          :実行部*****/
/*****      SKELETON,s,d,c                            *****/
/************************************************************************/

int             Filter::SkeletonImage(
    TypeArray   *ps,                                // S画像情報
    TypeArray   *pd,                                // D画像情報
    int         c                                   // 連結性
){
    TypeArray   t;                                  // T画像情報:局所
    void        *p;                                 // 画像ポインタ
    int         sti;                                // ステータス情報

    if( c == 5 || c == 9 ){                         // 2値→骨格化時
        p = malloc( pd->h * pd->v );                // メモリを確保
        if( p == 0 ){                               // 確保失敗なら
            return( STI_MEM );                      // 左記を返す
        }                                           //
        t.SetByte( (int)p, pd->h, pd->v );          // 画像情報作成:BYTE
        c  -= 1;                                    // 5→4, 9→8
        sti = DistanceImage( ps, &t, c );           // 距離変換 S→T
        if( sti == END_STI ){                       // 上記成功時は
            sti = skeleton( &t, pd, c );            // 骨格化   T→D
        }                                           //
        free( p );                                  // メモリを解放し
        if( sti != END_STI ){                       // エラーがある場合
            return( sti );                          // ステータスを返す
        }                                           //
    }else if( c == 4 || c == 8 ){                   // 距離→骨格の時
        sti = skeleton( ps, pd, c );                // 骨格化   T→D
    }else{                                          // 距離→骨格の時
        return( STI_FLG );                          // 左記を返す
    }                                               //
    ClearRoundImage( pd, 0, 1 );                    // 1周周囲クリア
    return( sti );                                  // ステータスを返す
}

(1-1)関数名

「Skeleton」は、骨格を意味する!ここでは、骨格化
「Image」は、画像で画像の中で骨格化変換を行います!

(1-2)仮引数

code:仮引数

int             Filter::SkeletonImage(
    TypeArray   *ps,                                // S画像情報
    TypeArray   *pd,                                // D画像情報
    int         c                                   // 連結性
){

「TypeArray* ps,」は、元画像(S≒ソース画像)
「TypeArray* pd,」は、結果画像(D≒ディスティネー
ション画像)
※備考:同じ関数名でオーバーロード関数(画像がimgと
一つだけ)が有ります!
「int c,」は、連結性を示す選択コードで「4」なら4連結
「8」なら8連結です!
更に「5」の場合、一旦、2値化画像を4連結距離変換を
行った後で4連結で骨格化変換を行います!
「9」の場合、一旦、2値化画像を8連結距離変換を行った
後で8連結で骨格化変換を行います!

(1-3)ローカル変数

code:ローカル変数

){
    TypeArray   t;                                  // T画像情報:局所
    void        *p;                                 // 画像ポインタ
    int         sti;                                // ステータス情報

「TypeArray t;」は、連結性「c」が「5,9」指定で途中で
距離変換画像を作成する時の局所画像Tの画像情報です!
「void* p;」は、「void型ポインタ」と言う汎用ポインタ
を使用したのは、C言語からC++言語への途中切り替え
のクラスライブラリ編集中の課程でクラス「TypeArray」
でメモリ管理を確定して無かった時の名残です!
「int sti;」は、関数のステータス情報(エラーコード)で
す!

(1-4)アルゴリズム

code:アルゴリズムに進める

    if( c == 5 || c == 9 ){                         // 2値→骨格化時
        p = malloc( pd->h * pd->v );                // メモリを確保
        if( p == 0 ){                               // 確保失敗なら
            return( STI_MEM );                      // 左記を返す
        }                                           //
        t.SetByte( (int)p, pd->h, pd->v );          // 画像情報作成:BYTE
        c  -= 1;                                    // 5→4, 9→8
        sti = DistanceImage( ps, &t, c );           // 距離変換 S→T
        if( sti == END_STI ){                       // 上記成功時は
            sti = skeleton( &t, pd, c );            // 骨格化   T→D
        }                                           //
        free( p );                                  // メモリを解放し
        if( sti != END_STI ){                       // エラーがある場合
            return( sti );                          // ステータスを返す
        }                                           //
    }else if( c == 4 || c == 8 ){                   // 距離→骨格の時
        sti = skeleton( ps, pd, c );                // 骨格化   T→D
    }else{                                          // 距離→骨格の時
        return( STI_FLG );                          // 左記を返す
    }                                               //
    ClearRoundImage( pd, 0, 1 );                    // 1周周囲クリア
    return( sti );                                  // ステータスを返す
}

「if(c==5||c==9){・・成立分岐中身・・」は、条件「
c==5||c==9」で連結性指定が「5,9」の場合の処理で成立
分岐中身は、
「p=malloc(pd->hpd->v);if(p==0){return(STI_MEM);}」
で「malloc(pd->hpd->v);」とメモリ確保し、確保失敗し
たら、「return(STI_MEM);」でエラーコードを関数辺値と
し返し終了!
「t.SetByte((int)p,pd->h,pd->v);」は、画像情報Tに
画像画素ポインタや水平幅・垂直幅のサイズ等セット
「c-=1;」は、連結性指定が「5,9」を「4,8」に変換!
「sti=DistanceImage(ps,&t,c);」は、距離変換を行い、
「if(sti==END_STI){sti=skeleton(&t,pd,c);}」は、
距離変換が正常終了したら、下請け関数「
sti=skeleton(&t,pd,c);」で骨格化処理し、
「free(p);」は、メモリ確保「p=malloc(・・・)」の
後始末!
「if(sti!=END_STI){return(sti);}」は、エラー発生時
は、エラーコードを関数辺値とし返し終了!
「}else if(c==4||c==8){sti=skeleton(ps,pd,c);}」は、
連結性指定が「4,8」の場合の処理で下請け関数「
sti=skeleton(&t,pd,c);」で骨格化処理!
「else{return(STI_FLG);}」は連結性指定が「4,5,8,9」
以外なら、「STI_FLG」をエラーコード関数辺値とし返し
終了!
「ClearRoundImage(pd,0,1);return(sti);」は、
外周一回り0クリアし、ステータスを関数辺値とし返し
終了!

(2)ソースコード解説SkeletonImage()

code:SkeletonImage(仮引数){}

/************************************************************************/
/*****      骨格化:単一画像変換版                          :実行部*****/
/*****      SKELETON,img,c                            *****/
/************************************************************************/

int             Filter::SkeletonImage(
    TypeArray   *img,                               // 画像情報
    int         c                                   // 連結性
){
    TypeArray   w;                                  // 作業画像:一回り内側

    if( img == 0 ){                                 // ポインタ不正
        return( STI_ARY_0 );                        // 左記を返す
    }else if( img->adr == 0 ){                      // アドレス不正
        return( STI_ARY_1 );                        // 左記を返す
    }else if( img->h < 3 ){                         // 水平幅不正
        return( STI_ARY_2 );                        // 左記を返す
    }else if( img->v < 3 ){                         // 垂直幅不正
        return( STI_ARY_3 );                        // 左記を返す
    }else if( img->w != 1 ){                        // 画素単位=1以外
        return( STI_ARY_5 );                        // 左記を返す
    }                                               // 
    w.subset( img, 1, 1, img->h - 2, img->v - 2);   // 作業画像:一回り内側
    if( c == 4 ){                                   // 4連結なら
        skeleton_4( &w );                           // 左記で処理
    }else if( c == 8 ){                             // 8連結なら
        skeleton_8( &w );                           // 左記で処理
    }else{                                          // 連結性間違い時
        return( STI_FLG );                          // 左記を返す
    }                                               //
    ClearRoundImage( img, 0, 1 );                   // 1周周囲クリア
    return( END_STI );                              // 正常終了
}

(2-1)関数名

「Skeleton」は、骨格を意味する!ここでは、骨格化
「Image」は、画像で画像の中で骨格化変換を行います!

(2-2)仮引数

code:仮引数

int             Filter::SkeletonImage(
    TypeArray   *img,                               // 画像情報
    int         c                                   // 連結性
){

「TypeArray* img,」は、画像情報へのポインタ
※備考:同じ関数名でオーバーロード関数(画像がSDと
二つ)が有ります!
「int c,」は、連結性を示す選択コードで「4」なら4連結
「8」なら8連結です!

(2-3)ローカル変数

code:ローカル変数

){
    TypeArray   w;                                  // 作業画像:一回り内側

「TypeArray w;」は、作業用の部分画像

(2-4)アルゴリズム

code:アルゴリズム

    if( img == 0 ){                                 // ポインタ不正
        return( STI_ARY_0 );                        // 左記を返す
    }else if( img->adr == 0 ){                      // アドレス不正
        return( STI_ARY_1 );                        // 左記を返す
    }else if( img->h < 3 ){                         // 水平幅不正
        return( STI_ARY_2 );                        // 左記を返す
    }else if( img->v < 3 ){                         // 垂直幅不正
        return( STI_ARY_3 );                        // 左記を返す
    }else if( img->w != 1 ){                        // 画素単位=1以外
        return( STI_ARY_5 );                        // 左記を返す
    }                                               // 
    w.subset( img, 1, 1, img->h - 2, img->v - 2);   // 作業画像:一回り内側
    if( c == 4 ){                                   // 4連結なら
        skeleton_4( &w );                           // 左記で処理
    }else if( c == 8 ){                             // 8連結なら
        skeleton_8( &w );                           // 左記で処理
    }else{                                          // 連結性間違い時
        return( STI_FLG );                          // 左記を返す
    }                                               //
    ClearRoundImage( img, 0, 1 );                   // 1周周囲クリア
    return( END_STI );                              // 正常終了
}

「if(img==0){return(STI_ARY_0);}else
if(img->adr==0){return(STI_ARY_1);}else
if(img->h<3){return(STI_ARY_2);}else
if(img->v<3){return(STI_ARY_3);}else
if(img->w!=1){return(STI_ARY_5);}」は、骨格化可能な
画像か否かの検査で画像画素が存在・3×3以上の
水平幅・垂直幅か如何かで画素単位が1バイト整数か否か
を判定しエラーが有れば、状態に応じたエラーコードを
関数辺値とし返し終了!
「w.subset(img,1,1,img->h-2,img->v-2);」は、作業用の
部分画像を作成!
「if(c==4){skeleton_4(&w);}else
if(c==8){skeleton_8(&w);}」は、連結性を示す選択
コードで「4」なら下請け関数「skeleton_4(&w);」で処理
「8」なら下請け関数「skeleton_8(&w);」で処理
「else{return(STI_FLG);}」は、連結性を示す選択コード
が「4,8」で無ければ、「STI_FLG」をエラーコードとし
関数辺値とし返し終了
「ClearRoundImage(pd,0,1);return(sti);」は、
外周一回り0クリアし、ステータスを関数辺値とし返し
終了!

(3)ソースコード解説skeleton()

code:skeleton(仮引数){}

/************************************************************************/
/*****      骨格化                      :基本部(距離画像→骨格化)*****/
/*****      SKELETON,s,d,c                            *****/
/************************************************************************/

int                 Filter::skeleton(
    TypeArray       *ps,                            // S画像情報
    TypeArray       *pd,                            // D画像情報
    int             c                               // 連結性
){
    TypeArray       s;                              // S画像情報:局所
    TypeArray       d;                              // D画像情報:局所
    int             sti;                            // ステータス情報

    if( c != 4 && c != 8 ){                         // 連結性間違い時
        return( STI_FLG );                          // 左記を返す
    }                                               //
    sti = Copy( ps, pd );                           // S→T
    if( sti != END_STI ){                           // エラーがある場合
        return( sti );                              // ステータスを返す
    }                                               //
    s   = *ps;                                      // 一旦、S画像情報
    ps  = &s;                                       // を局所化
    d   = *pd;                                      // 一旦、D画像情報
    pd  = &d;                                       // を局所化
    PreProcessor3By3( ps, pd );                     // 前処理
    if( c == 4 ){                                   // 4連結なら
        skeleton_4( pd );                           // 左記で処理
    }else{                                          // 8連結なら
        skeleton_8( pd );                           // 左記で処理
    }                                               //
    return( END_STI );                              // 正常終了
}

(3-1)関数名

「skeleton」は、骨格を意味する!ここでは、骨格化

(3-2)仮引数

code:仮引数

int                 Filter::skeleton(
    TypeArray       *ps,                            // S画像情報
    TypeArray       *pd,                            // D画像情報
    int             c                               // 連結性
){

「TypeArray* ps,」は、元画像(S≒ソース画像)
「TypeArray* pd,」は、結果画像(D≒ディスティネー
ション画像)
「int c,」は、連結性を示す選択コードで「4」なら4連結
「8」なら8連結です!

(3-2)ローカル変数

code:ローカル変数

){
    TypeArray       s;                              // S画像情報:局所
    TypeArray       d;                              // D画像情報:局所
    int             sti;                            // ステータス情報

「TypeArray s;」は、元画像情報のローカル変数です!
「TypeArray d;」は、結果画像情報のローカル変数です!
「int sti;」は、関数のステータス情報(エラーコード)で
す!

(3-3)アルゴリズム

code:アルゴリズム

    if( c != 4 && c != 8 ){                         // 連結性間違い時
        return( STI_FLG );                          // 左記を返す
    }                                               //
    sti = Copy( ps, pd );                           // S→T
    if( sti != END_STI ){                           // エラーがある場合
        return( sti );                              // ステータスを返す
    }                                               //
    s   = *ps;                                      // 一旦、S画像情報
    ps  = &s;                                       // を局所化
    d   = *pd;                                      // 一旦、D画像情報
    pd  = &d;                                       // を局所化
    PreProcessor3By3( ps, pd );                     // 前処理
    if( c == 4 ){                                   // 4連結なら
        skeleton_4( pd );                           // 左記で処理
    }else{                                          // 8連結なら
        skeleton_8( pd );                           // 左記で処理
    }                                               //
    return( END_STI );                              // 正常終了
}

「if(c!=4&&c!=8){return(STI_FLG);}」は、連結性「c」
が「4,8」以外なら、エラーコード「STI_FLG」を関数
辺値とし返し終了
「sti=Copy(ps,pd);」は、一旦、結果画像に元画像を
コピー
「if(sti!=END_STI){return(sti);}」は、エラー発生時は
エラーコードを関数辺値とし返し終了!
「s=*ps;ps=&s;d=*pd;pd=&d;」は、元画像結果画像情報の
ポインタ変数付替え
「PreProcessor3By3(ps,pd);」は、元画像結果画像両者の
有効な水平幅・垂直を算出し、3×3画像変数に相応しい
一回り内側に画像情報をセット!
「if(c==4){skeleton_4(&w);}else
if(c==8){skeleton_8(&w);}」は、連結性を示す選択
コードで「4」なら下請け関数「skeleton_4(&w);」で処理
「8」なら下請け関数「skeleton_8(&w);」で処理
「return(END_STI);」は、で正常終了!
※備考:一旦、「sti=Copy(ps,pd);」で引数のエラー検査
が終わっている事に注意

(4)ソースコード解説skeleton_4()

code:skeleton_4(仮引数){}

/************************************************************************/
/*****  骨格化コマンド:ソフト実行部:4連結用                      *****/
/*****  SKELETON,c,S[,D]                               *****/
/************************************************************************/

void            Filter::skeleton_4(
    TypeArray   *pd                                 // D画像情報
){
    BYTE        *ptrd;                              // D画像Ptr
    int         h;                                  // 水平幅
    int         v;                                  // 垂直幅
    int         incd;                               // D画像:増加幅
    int         y;                                  // y座標方向CNT

    h    = pd->h;                                   // 画像のサイズを
    v    = pd->v;                                   // 取り出し
    incd = pd->inc;                                 // D画像増加幅取出
    ptrd = (BYTE*)pd->adr;                          // D画像Ptrを取出す
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        skeleton_4_x1( ptrd, incd, h );             // 1行分処理
        ptrd += incd;                               // 垂直方向増加
    }                                               //
    ptrd = (BYTE*)pd->adr                           // 右下Ptrを算出
                    + ( h - 1 ) + ( v - 1 ) * incd; //
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        skeleton_4_x2( ptrd, incd, h );             // 1行分処理
        ptrd -= incd;                               // 垂直方向減少
    }                                               //
}

(4-1)関数名

「skeleton」は、距離を意味する!
「_4」は、4連結の処理を意味!

(4-2)仮引数

code:仮引数

void            Filter::skeleton_4(
    TypeArray   *pd                                 // D画像情報
){

「TypeArray* pd,」は、結果画像(D≒ディスティネー
ション画像)

(4-2)ローカル変数

code:ローカル変数

){
    BYTE        *ptrd;                              // D画像Ptr
    int         h;                                  // 水平幅
    int         v;                                  // 垂直幅
    int         incd;                               // D画像:増加幅
    int         y;                                  // y座標方向CNT

「BYTE* ptrd;」は、結果画像画素をアクセスするポインタ
変数!
「int h;」は、水平幅
「int v;」は、垂直幅
「int incd;」は、垂直方向増加幅
「int y;」は、垂直(Y座標)方向繰り返しカウンタ

(4-3)アルゴリズム

code:アルゴリズム

    h    = pd->h;                                   // 画像のサイズを
    v    = pd->v;                                   // 取り出し
    incd = pd->inc;                                 // D画像増加幅取出
    ptrd = (BYTE*)pd->adr;                          // D画像Ptrを取出す
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        skeleton_4_x1( ptrd, incd, h );             // 1行分処理
        ptrd += incd;                               // 垂直方向増加
    }                                               //
    ptrd = (BYTE*)pd->adr                           // 右下Ptrを算出
                    + ( h - 1 ) + ( v - 1 ) * incd; //
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        skeleton_4_x2( ptrd, incd, h );             // 1行分処理
        ptrd -= incd;                               // 垂直方向減少
    }                                               //
}

「h=pd->h;v=pd->v;」は、水平幅・垂直幅を取り出し!
「incd=pd->inc;」は、垂直方向増加幅を取り出し!
「ptrd=(BYTE*)pd->adr;」は、画素アクセスポインタを
画像始点(左上)にセット
「for(y=v;--y>=0;){・・ループ中身・・}」は、垂直幅分
ループ中身を繰り返す!そのループ中身は、
「skeleton_4_x1(ptrd,incd,h);」で下請け
関数「skeleton_4_x1(・・・)」で処理
「ptrd+=incd;」で垂直方向下方にポインタを進める!
※ここまでで始点から下方に処理して行きます!
「ptrd=(BYTE*)pd->adr+(h-1)+(v-1)*incd;」は、
画素アクセスポインタを画像終点(右下)にセット!
「for(y=v;--y>=0;){・・ループ中身・・}」は、垂直幅分
ループ中身を繰り返す!そのループ中身は、
「skeleton_4_x2(ptrd,incd,h);」で下請け
関数「skeleton_4_x2(・・・)」で処理
「ptrd-=incd;」で垂直方向上方にポインタを進める!
※ここまでで終点(右下)から上方に処理して行きます!
★「skeleton_4_x1(・・・)」で左上から右下への処理、
「skeleton_4_x2(・・・)」で右下から左上への処理と処理
する向きが異なる事に注意して下さい!

(5)ソースコード解説skeleton_4_x1()

code:skeleton_4_x1(仮引数){}

/************************************************************************/
/*****  骨格化コマンド:4連結用:上から下に処理:1行分            *****/
/*****  1行分の処理(左から右方向に処理を行う)                    *****/
/************************************************************************/

void            Filter::skeleton_4_x1(
    BYTE        *p,                                 // y軸用Ptr:左側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){
    BYTE        d0;                                 // 注視点データ
    BYTE        d1;                                 // 近接データ1
    BYTE        d2;                                 // 近接データ2

    while( --h >= 0 ){                              // 水平方向に繰返し
        d0 = *p;                                    // 注視点Data取出し
        if( d0 ){                                   // Data有りなら
            d1 = *( p + inc );                      // 下の値と
            d2 = *( p + 1 );                        // 右の値を取り出し
            if( d1 < d2 ){                          // 最大の値を算出し
                d1 = d2;                            //
            }                                       //
            if( d0 < d1 ){                          // 注視点が最大値未
                *p = 0;                             // 満なら0にする
            }                                       //
        }                                           //
        p++;                                        // 右方向へ進める
    }                                               //
}

(5-1)関数名

「skeleton」は、距離を意味する!
「_4」は、4連結の処理を意味!
「x1」は、X座標方向の処理で「左⇒右」方向の処理を
意味!

(5-2)仮引数

code:仮引数

void            Filter::skeleton_4_x1(
    BYTE        *p,                                 // y軸用Ptr:左側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){

「BYTE* p,」は、画像画素へのポインタ
「int inc,」は、垂直方向増加幅※上下オフセット
「int h」は、水平幅

(5-2)ローカル変数

code:ローカル変数

){
    BYTE        d0;                                 // 注視点データ
    BYTE        d1;                                 // 近接データ1
    BYTE        d2;                                 // 近接データ2

「int d0;」は、注視点画素データ
「int d1;」は、近接画素データ1
「int d2;」は、近接画素データ2

(5-3)アルゴリズム

code:アルゴリズム

    while( --h >= 0 ){                              // 水平方向に繰返し
        d0 = *p;                                    // 注視点Data取出し
        if( d0 ){                                   // Data有りなら
            d1 = *( p + inc );                      // 下の値と
            d2 = *( p + 1 );                        // 右の値を取り出し
            if( d1 < d2 ){                          // 最大の値を算出し
                d1 = d2;                            //
            }                                       //
            if( d0 < d1 ){                          // 注視点が最大値未
                *p = 0;                             // 満なら0にする
            }                                       //
        }                                           //
        p++;                                        // 右方向へ進める
    }                                               //
}

「while(--h>=0){・・ループ中身・・}」は、水平幅分
繰り返しループ中身を処理、そのループ中身は、
「d0=p;」で注視点データを取り出し!
「if(d0){・・分岐成立・・}」で条件「d0」で注視点が
有効の場合に分岐成立ブロック実行するで分岐成立の
「d1=(p+inc);d2=*(p+1);」で右側と下側画素データを
取り出す!
「if(d1<d2){d1=d2;}」で右側の下側大きい方をデータ1に
「if(d0<d1){*p=0;}」で注視点の方が大きい場合は、
注視点を無効化(0をセット)、ここまでで分岐成立ブロッ
ク終了!
「p++;」で注視点ポインタを右方向に進める!

(6)ソースコード解説skeleton_4_x2()

code:skeleton_4_x2(仮引数){}

/************************************************************************/
/*****  骨格化コマンド:4連結用:下から上に処理:1行分            *****/
/*****  1行分の処理(右から左方向に処理を行う)                    *****/
/************************************************************************/

void            Filter::skeleton_4_x2(
    BYTE        *p,                                 // y軸用Ptr:右側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){
    BYTE        d0;                                 // 注視点データ
    BYTE        d1;                                 // 近接データ1
    BYTE        d2;                                 // 近接データ2

    while( --h >= 0 ){                              // 水平方向に繰返し
        d0 = *p;                                    // 注視点Data取出し
        if( d0 ){                                   // Data有りなら
            d1 = *( p - inc );                      // 上の値と
            d2 = *( p - 1 );                        // 左の値を取り出し
            if( d1 < d2 ){                          // 最大の値を算出し
                d1 = d2;                            //
            }                                       //
            if( d0 < d1 ){                          // 注視点が最大値未
                *p = 0;                             // 満なら0にする
            }                                       //
        }                                           //
        p--;                                        // 左方向へ進める
    }                                               //
}

(6-1)関数名

「skeleton」は、距離を意味する!
「_4」は、4連結の処理を意味!
「x2」は、X座標方向の処理で「左⇒右」方向の処理を
意味!

(6-2)仮引数

code:仮引数

void            Filter::skeleton_4_x2(
    BYTE        *p,                                 // y軸用Ptr:右側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){

「BYTE* p,」は、画像画素へのポインタ
「int inc,」は、垂直方向増加幅※上下オフセット
「int h」は、水平幅

(6-2)ローカル変数

code:ローカル変数

){
    BYTE        d0;                                 // 注視点データ
    BYTE        d1;                                 // 近接データ1
    BYTE        d2;                                 // 近接データ2

「int d0;」は、注視点画素データ
「int d1;」は、近接画素データ1
「int d2;」は、近接画素データ2

(6-3)アルゴリズム

code:アルゴリズム

    while( --h >= 0 ){                              // 水平方向に繰返し
        d0 = *p;                                    // 注視点Data取出し
        if( d0 ){                                   // Data有りなら
            d1 = *( p - inc );                      // 上の値と
            d2 = *( p - 1 );                        // 左の値を取り出し
            if( d1 < d2 ){                          // 最大の値を算出し
                d1 = d2;                            //
            }                                       //
            if( d0 < d1 ){                          // 注視点が最大値未
                *p = 0;                             // 満なら0にする
            }                                       //
        }                                           //
        p--;                                        // 左方向へ進める
    }                                               //
}

「while(--h>=0){・・ループ中身・・}」は、水平幅分
繰り返しループ中身を処理、そのループ中身は、
「d0=p;」で注視点データを取り出し!
「if(d0){・・分岐成立・・}」で条件「d0」で注視点が
有効の場合に分岐成立ブロック実行するで分岐成立の
「d1=(p-inc);d2=*(p-1);」で上側と側画素データを
取り出す!
「if(d1<d2){d1=d2;}」で大きい方をデータ1に
「if(d0<d1){*p=0;}」で注視点の方が大きい場合は、
注視点を無効化(0をセット)、ここまでで分岐成立ブロッ
ク終了!
「p--;」で注視点ポインタを左方向に進める!

(7)ソースコード解説skeleton_8()

code:skeleton_8(仮引数){}

/************************************************************************/
/*****  骨格化コマンド:ソフト実行部:8連結用                      *****/
/*****  SKELETON,c,S[,D]                               *****/
/************************************************************************/

void            Filter::skeleton_8(
    TypeArray   *pd                                 // D画像情報
){
    BYTE        *ptrd;                              // D画像Ptr
    int         h;                                  // 水平幅
    int         v;                                  // 垂直幅
    int         incd;                               // D画像:増加幅
    int         y;                                  // y座標方向CNT

    h    = pd->h;                                   // 画像のサイズを
    v    = pd->v;                                   // 取り出し
    incd = pd->inc;                                 // D画像増加幅取出
    ptrd = (BYTE*)pd->adr;                          // D画像Ptrを取出す
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        skeleton_8_x1( ptrd, incd, h );             // 1行分処理
        ptrd += incd;                               // 垂直方向増加
    }                                               //
    ptrd = (BYTE*)pd->adr                           // 右下Ptrを算出
                    + ( h - 1 ) + ( v - 1 ) * incd; //
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        skeleton_8_x2( ptrd, incd, h );             // 1行分処理
        ptrd -= incd;                               // 垂直方向減少
    }                                               //
}

(7-1)関数名

「skeleton」は、距離を意味する!
「_8」は、8連結の処理を意味!

(7-2)仮引数

code:仮引数

void            Filter::skeleton_8(
    TypeArray   *pd                                 // D画像情報
){

「TypeArray* pd,」は、結果画像(D≒ディスティネー
ション画像)

(7-2)ローカル変数

code:ローカル変数

){
    BYTE        *ptrd;                              // D画像Ptr
    int         h;                                  // 水平幅
    int         v;                                  // 垂直幅
    int         incd;                               // D画像:増加幅
    int         y;                                  // y座標方向CNT

「BYTE* ptrd;」は、結果画像画素をアクセスするポインタ
変数!
「int h;」は、水平幅
「int v;」は、垂直幅
「int incd;」は、垂直方向増加幅
「int y;」は、垂直(Y座標)方向繰り返しカウンタ

(7-3)アルゴリズム

code:アルゴリズム

    h    = pd->h;                                   // 画像のサイズを
    v    = pd->v;                                   // 取り出し
    incd = pd->inc;                                 // D画像増加幅取出
    ptrd = (BYTE*)pd->adr;                          // D画像Ptrを取出す
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        skeleton_8_x1( ptrd, incd, h );             // 1行分処理
        ptrd += incd;                               // 垂直方向増加
    }                                               //
    ptrd = (BYTE*)pd->adr                           // 右下Ptrを算出
                    + ( h - 1 ) + ( v - 1 ) * incd; //
    for( y = v; --y >= 0; ){                        // 垂直方向に繰返
        skeleton_8_x2( ptrd, incd, h );             // 1行分処理
        ptrd -= incd;                               // 垂直方向減少
    }                                               //
}    

「h=pd->h;v=pd->v;」は、水平幅・垂直幅を取り出し!
「incd=pd->inc;」は、垂直方向増加幅を取り出し!
「ptrd=(BYTE*)pd->adr;」は、画素アクセスポインタを
画像始点(左上)にセット
「for(y=v;--y>=0;){・・ループ中身・・}」は、垂直幅分
ループ中身を繰り返す!そのループ中身は、
「skeleton_8_x1(ptrd,incd,h);」で下請け
関数「skeleton_8_x1(・・・)」で処理
「ptrd+=incd;」で垂直方向下方にポインタを進める!
※ここまでで始点から下方に処理して行きます!
「ptrd=(BYTE*)pd->adr+(h-1)+(v-1)*incd;」は、
画素アクセスポインタを画像終点(右下)にセット!
「for(y=v;--y>=0;){・・ループ中身・・}」は、垂直幅分
ループ中身を繰り返す!そのループ中身は、
「skeleton_8_x2(ptrd,incd,h);」で下請け
関数「skeleton_8_x2(・・・)」で処理
「ptrd-=incd;」で垂直方向上方にポインタを進める!
※ここまでで終点(右下)から上方に処理して行きます!
★「skeleton_8_x1(・・・)」で左上から右下への処理、
「skeleton_8_x2(・・・)」で右下から左上への処理と処理
する向きが異なる事に注意して下さい!

(8)ソースコード解説skeleton_8_x1()

code:skeleton_8_x1(仮引数){}

/************************************************************************/
/*****  骨格化コマンド:8連結用:上から下に処理:1行分            *****/
/*****  1行分の処理(左から右方向に処理を行う)                    *****/
/************************************************************************/

void            Filter::skeleton_8_x1(
    BYTE        *p,                                 // y軸用Ptr:左側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){
    BYTE        *pend;                              // 終点Ptr:右側
    BYTE        d0;                                 // 注視点データ
    BYTE        d1;                                 // 近接データ1
    BYTE        d2;                                 // 近接データ2
    BYTE        d3;                                 // 近接データ3
    BYTE        d4;                                 // 近接データ4

    for( pend = p + h; p < pend; p++ ){             // 水平方向に繰返し
        d0 = *p;                                    // 注視点Data取出し
        if( d0 ){                                   // Data有りなら
            d1 = *( p + inc + 1 );                  // 右下の値と
            d2 = *( p + inc );                      // 下の値と
            d3 = *( p + inc - 1 );                  // 左下の値と
            d4 = *( p + 1 );                        // 右の値を取り出し
            if( d1 < d2 ){                          // 最大の値を算出し
                d1 = d2;                            //
            }                                       //
            if( d1 < d3 ){                          //
                d1 = d3;                            //
            }                                       //
            if( d1 < d4 ){                          //
                d1 = d4;                            //
            }                                       //
            if( d0 < d1 ){                          // 注視点が最大値未
                *p = 0;                             // 満なら0にする
            }                                       //
        }                                           //
    }                                               //
}

(8-1)関数名

「skeleton」は、距離を意味する!
「_8」は、8連結の処理を意味!
「x1」は、X座標方向の処理で「左⇒右」方向の処理を
意味!

(8-2)仮引数

code:仮引数

void            Filter::skeleton_8_x1(
    BYTE        *p,                                 // y軸用Ptr:左側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){

「BYTE *pend;」は、水平方向画素ポインタ終点※目印で
何故ループ条件に使用したかは、元々ADS社画像処理装置
のCPUが68000系でコンパイラ「MCC68K」を
使用して居たためにループ条件としデータレジスターを使い
切り、アドレスレジスターに変数を割り当てる高速化技法と
して「BYTE*pend;」を終点目印に使用した名残です!
「int inc,」は、垂直方向増加幅※上下オフセット
「int h」は、水平幅

(8-2)ローカル変数

code:ローカル変数

){
    BYTE        *pend;                              // 終点Ptr:右側
    BYTE        d0;                                 // 注視点データ
    BYTE        d1;                                 // 近接データ1
    BYTE        d2;                                 // 近接データ2
    BYTE        d3;                                 // 近接データ3
    BYTE        d4;                                 // 近接データ4

「BYTE *pend;」は、水平方向画素ポインタ終点※目印
「int d0;」は、注視点画素データ
「int d1;」は、近接画素データ1
「int d2;」は、近接画素データ2
「int d3;」は、近接画素データ3
「int d4;」は、近接画素データ4

(8-3)アルゴリズム

code:アルゴリズム

    for( pend = p + h; p < pend; p++ ){             // 水平方向に繰返し
        d0 = *p;                                    // 注視点Data取出し
        if( d0 ){                                   // Data有りなら
            d1 = *( p + inc + 1 );                  // 右下の値と
            d2 = *( p + inc );                      // 下の値と
            d3 = *( p + inc - 1 );                  // 左下の値と
            d4 = *( p + 1 );                        // 右の値を取り出し
            if( d1 < d2 ){                          // 最大の値を算出し
                d1 = d2;                            //
            }                                       //
            if( d1 < d3 ){                          //
                d1 = d3;                            //
            }                                       //
            if( d1 < d4 ){                          //
                d1 = d4;                            //
            }                                       //
            if( d0 < d1 ){                          // 注視点が最大値未
                *p = 0;                             // 満なら0にする
            }                                       //
        }                                           //
    }                                               //
}

「for(pend=p+h;p<pend;p++){・・ループ中身・・}」は、
水平幅分繰り返し「pend=p+h;」で終点目印を作成し
「p<pend;」で終点目印まで繰り返し「p++」で処理ポインタを左から右へ移動のforループでループ中身を処理、
そのループ中身は、
「d0=p;」で注視点画素データとしセット※何回も比較用
に使用するので高速化技法
「if(d0){・・分岐中身・・」で条件「d0」で有効画素(
≠0)の場合は、分岐中身の
「d1=(p+inc+1);d2=(p+inc);d3=(p+inc-1);d4=*(p+1);
」で右下・下・左下・左隣のデータを取り出し!
「if(d1<d2){d1=d2;}if(d1<d3){d1=d3;}if(d1<d4){d1=d4;}
」で右下・下・左下・左隣のデータ最大値を変数「d1」に
セット
「if(d0<d1){*p=0;}」で注視点が近接データ未満ならば、
「*p=0;」で注視点画素を無効(=0)に更新し、
分岐中身ブロック終了

(9)ソースコード解説skeleton_8_x2()

code:skeleton_8_x2(仮引数){}

/************************************************************************/
/*****  骨格化コマンド:8連結用:下から上に処理:1行分            *****/
/*****  1行分の処理(右から左方向に処理を行う)                    *****/
/************************************************************************/

void            Filter::skeleton_8_x2(
    BYTE        *p,                                 // y軸用Ptr:右側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){
    BYTE        *pend;                              // 終点Ptr:左側
    BYTE        d0;                                 // 注視点データ
    BYTE        d1;                                 // 近接データ1
    BYTE        d2;                                 // 近接データ2
    BYTE        d3;                                 // 近接データ3
    BYTE        d4;                                 // 近接データ4

    for( pend = p - h; p > pend; p-- ){             // 水平方向に繰返し
        d0 = *p;                                    // 注視点Data取出し
        if( d0 ){                                   // Data有りなら
            d1 = *( p - inc - 1 );                  // 左上の値と
            d2 = *( p - inc );                      // 上の値と
            d3 = *( p - inc + 1 );                  // 右上の値と
            d4 = *( p - 1 );                        // 左の値を取り出し
            if( d1 < d2 ){                          // 最大の値を算出し
                d1 = d2;                            //
            }                                       //
            if( d1 < d3 ){                          //
                d1 = d3;                            //
            }                                       //
            if( d1 < d4 ){                          //
                d1 = d4;                            //
            }                                       //
            if( d0 < d1 ){                          // 注視点が最大値未
                *p = 0;                             // 満なら0にする
            }                                       //
        }                                           //
    }                                               //
}

(9-1)関数名

「skeleton」は、距離を意味する!
「_8」は、8連結の処理を意味!
「x2」は、X座標方向の処理で「左⇒右」方向の処理を
意味!

(9-2)仮引数

code:仮引数

void            Filter::skeleton_8_x2(
    BYTE        *p,                                 // y軸用Ptr:右側
    int         inc,                                // 増加幅
    int         h                                   // 水平方向大きさ
){

「BYTE* p,」は、画像画素へのポインタ
「int inc,」は、垂直方向増加幅※上下オフセット
「int h」は、水平幅

(9-2)ローカル変数

code:ローカル変数

){
    BYTE        *pend;                              // 終点Ptr:左側
    BYTE        d0;                                 // 注視点データ
    BYTE        d1;                                 // 近接データ1
    BYTE        d2;                                 // 近接データ2
    BYTE        d3;                                 // 近接データ3
    BYTE        d4;                                 // 近接データ4

「BYTE *pend;」は、水平方向画素ポインタ終点※目印で
何故ループ条件に使用したかは、元々ADS社画像処理装置
のCPUが68000系でコンパイラ「MCC68K」を
使用して居たためにループ条件としデータレジスターを使い
切り、アドレスレジスターに変数を割り当てる高速化技法と
して「BYTE*pend;」を終点目印に使用した名残です!
「int d0;」は、注視点画素データ
「int d1;」は、近接画素データ1
「int d2;」は、近接画素データ2
「int d3;」は、近接画素データ3
「int d4;」は、近接画素データ4

(9-3)アルゴリズム

code:アルゴリズム

    for( pend = p - h; p > pend; p-- ){             // 水平方向に繰返し
        d0 = *p;                                    // 注視点Data取出し
        if( d0 ){                                   // Data有りなら
            d1 = *( p - inc - 1 );                  // 左上の値と
            d2 = *( p - inc );                      // 上の値と
            d3 = *( p - inc + 1 );                  // 右上の値と
            d4 = *( p - 1 );                        // 左の値を取り出し
            if( d1 < d2 ){                          // 最大の値を算出し
                d1 = d2;                            //
            }                                       //
            if( d1 < d3 ){                          //
                d1 = d3;                            //
            }                                       //
            if( d1 < d4 ){                          //
                d1 = d4;                            //
            }                                       //
            if( d0 < d1 ){                          // 注視点が最大値未
                *p = 0;                             // 満なら0にする
            }                                       //
        }                                           //
    }                                               //
}

「for(pend=p-h;p>pend;p--){・・ループ中身・・}」は、
水平幅分繰り返し「pend=p+h;」で終点目印を作成し
「p>pend;」で終点目印まで繰り返し「p--」で処理ポインタ
を右から左へ移動のforループでループ中身を処理、
そのループ中身は、
「d0=p;」で注視点画素データとしセット※何回も比較用
に使用するので高速化技法
「if(d0){・・分岐中身・・」で条件「d0」で有効画素(
≠0)の場合は、分岐中身の
「d1=(p+inc+1);d2=(p+inc);d3=(p+inc-1);d4=*(p+1);
」で右下・下・左下・左隣のデータを取り出し!
「if(d1<d2){d1=d2;}if(d1<d3){d1=d3;}if(d1<d4){d1=d4;}
」で右下・下・左下・左隣のデータ最大値を変数「d1」に
セット
「if(d0<d1){*p=0;}」で注視点が近接データ未満ならば、
「*p=0;」で注視点画素を無効(=0)に更新し、
分岐中身ブロック終了分岐中身ブロック終了


文末

いいなと思ったら応援しよう!