見出し画像

この仕事は天職だと感じたアルゴリズム開発(続2)

この仕事は天職だと感じたアルゴリズム開発(続2)


2024年12月12日初稿


このエッセイは、
『この仕事は天職だと感じたアルゴリズム開発(続1)』の直接の続編です!

1.図形個別のフェレ計測4連結
search4fere()

/****************************************************************************/
/*****      図形のフェレ計測:処理部:ラベル個別のフェレ計測            *****/
/*****  時計回りに輪郭を追跡します                                      *****/
/*****  まず、仮想原点として原点の左隣から処理を始めます。              *****/
/*****  終了条件は、仮想原点をサーチした時とします。                    *****/
/*****  ☆注意:仮想原点を使用するのは、方向サーチを孤立点の時に無      *****/
/*****          限ループにしないためです。                              *****/
/*****  ☆注意:dir_off[]を使用して4連結で時計回りにサーチ             *****/
/*****   dir_off[0..3] = 右・下・左・上の方向のオフセット               *****/
/*****  ☆注意:方向オフセットが、サーチ成功時→戻し、失敗時1つ進      *****/
/*****   める事により、処理ポインタを更新し輪郭を追尾します            *****/
/*****   4連結なので1方向分戻します                                  *****/
/*****  ☆注意:画素は、0・正・負と3つに分けて、正の値の画素を追      *****/
/*****         跡します                                                *****/
/*****  注:メモリのサイズもここで変更した分を返します。                *****/
/*****  返値:追跡点履歴Buffer(Overした場合は付け替えした新規メモリ)  *****/
/****************************************************************************/

char**          Filter::search4fere(
    char*       bufptr[],                               // 追跡点履歴Buffer
    char*       p,                                      // 輪郭追跡 Ptr
    int         x,                                      // x座標カウンタ
    int         y,                                      // y座標カウンタ
    TypeSf*     buf,                                    // 計測結果Buffer
    int         dir_off[],                              // 方向OffSetTbl
    int         clr_dt,                                 // ClrData -1 / -2
    int&        size                                    // 座標Bufferサイズ
){
    static const int    tblx[] = {                      // 方向に対するx座
        1, 0, -1, 0                                     // 標の変位
    };                                                  //
    static const int    tbly[] = {                      // 方向に対するy座
        0, 1, 0, -1                                     // 標の変位
    };                                                  //
    char        **pbufptr;                              // 履歴BufferPtr
    char        **bufNew;                               // 履歴BufferPtr:新規
    char        *ptemp;                                 // 原点
    char        *pp;                                    // 仮想原点
    char        *p1;                                    // 輪郭追跡 Ptr
    int         n;                                      // 履歴個数DownCnt
    int         min_x;                                  // x座標最小値
    int         max_x;                                  // x座標最大値
    int         max_y;                                  // y座標最大値
    int         h;                                      // 水平フェレ径
    int         v;                                      // 垂直フェレ径
    int         len;                                    // 周囲長
    int         dir;                                    // 方向 0..3
                                                        // 0:右
                                                        // 1:下
                                                        // 2:左
                                                        // 3:上
    int         inc;                                    // インクリ幅

    pbufptr = bufptr;                                   // 履歴BufferptrSet
    n       = size - 3;                                 // 履歴制限数初期値
    buf->xl = x;                                        // Labelx座標格納
    buf->y  = y;                                        // Labely座標格納
    ptemp   = p;                                        // 原点を保存
    pp      = p - 1;                                    // 仮想原点をセット
    dir     = 0;                                        // 初期値=右
    min_x   = x;                                        // x座標の最小/最
    max_x   = x;                                        // 大値を初期化
    max_y   = y;                                        // y最大座標初期化
    len     = 0;                                        // 周囲長の初期化
    for(;;){                                            // 以下を繰り返す
        p1 = p + dir_off[ dir ];                        // 次追跡点をセット
        if( p1 == pp ){                                 // 仮想原点なら
            break;                                      // Loopを抜ける
        }                                               //
        if( *p1 > 0 ){                                  // サーチ成功なら
            if( --n <= 0 ){                             // 履歴BufferがOverしたら
                bufNew = reMallocSearchFere( size );    // 再メモリ確保
                if( bufNew == 0 ){                      // 確保失敗時は
                    return( 0 );                        // 「空」を返す
                }else{                                  // 確保成功時は
                    pbufptr = copyXYSearchFere(         // 新規履歴バッファーへ
                            bufptr, pbufptr, bufNew,    // コピー
                            size, n );                  // 
                    free( bufptr );                     // 元の追跡履歴バッファー解放
                    bufptr = bufNew;                    // 新規履歴バッファーをセット
                }                                       // 
            }                                           //
            *pbufptr++ = p;                             // 追跡履歴を取る
            p  = p1;                                    // 追跡点を更新
            x += tblx[ dir ];                           // x座標を更新
            y += tbly[ dir ];                           // y座標を更新
            if( min_x > x ){                            // x座標最小値を
                min_x = x;                              // 更新
            }                                           // 
            if( max_x < x ){                            // x座標最大値を
                max_x = x;                              // 更新
            }                                           //
            if( max_y < y ){                            // y座標最大値を
                max_y = y;                              // 更新
            }                                           //
            len++;                                      // 周囲長計数UP
            dir = ( dir - 1 ) & 0x03;                   // 方向を戻す
        }else{                                          // なければ
            dir = ( dir + 1 ) & 0x03;                   // 方向を進める
        }                                               //
    }                                                   //
    *pbufptr++ = p;                                     // 最終履歴をSetし
    *pbufptr   = 0;                                     // 追跡終点をセット
    h          = max_x - min_x + 1;                     // 水平径算出
    v          = max_y - buf->y + 1;                    // 垂直径算出
    buf->x     = min_x;                                 // フェレx座標格納
    buf->h     = h;                                     // 水平径格納
    buf->v     = v;                                     // 垂直径格納
    if( len == 0 ){                                     // 連結数=0の時
        len = 1;                                        // 1に補正
    }                                                   //
    buf->len = len;                                     // 周囲長格納
    if( h < 3 || v < 3 ){                               // 水平垂直が3未満
        search_clear( bufptr, clr_dt );                 // 輪郭をクリア
    }else if( h == 3 ){                                 // 水平が3の時
        search_clear_right( bufptr, clr_dt );           // 輪郭+右側 クリア
    }else if( v == 3 ){                                 // 垂直が3の時
        inc = dir_off[1];                               // インクリ幅を取出
        search_clear_down( bufptr, inc, clr_dt );       // 輪郭+下側 クリア
    }else if( h == 4 ){                                 // 水平が4の時
        search_clear_rl( bufptr, clr_dt );              // 輪郭+左右 クリア
    }else if( v == 4 ){                                 // 垂直が4の時
        inc = dir_off[1];                               // インクリ幅を取出
        search_clear_ud( bufptr, inc, clr_dt );         // 輪郭+上下 クリア
    }else{                                              // 5×5以上なら
        inc = dir_off[1];                               // インクリ幅を取出
        if( m_swMeasureBorder ){                        // 「真→輪郭線図形計測」時
            search_clear_rl( bufptr, clr_dt );          // 輪郭+左右 クリア
            search_clear_ud( bufptr, inc, clr_dt );     // 輪郭+上下 クリア
        }else{                                          // 「偽→任意図形」時
            search_clear( bufptr, clr_dt );             // 輪郭をクリア
            p = ptemp - buf->xl + min_x + inc + 1;      // 一回内側始点算出
            search4clear_base( p, h - 2, v - 2, inc,    // Labeling手法でCLR
                                            clr_dt );   //
        }                                               // 
    }                                                   //
    return( bufptr );                                   // 正常終了
}

(1)関数名

「search」は、カタカナ語「サーチ」でココでは、図形を
サーチする意味
「4」は、「4連結」を意味
「fere」は、「フェレ計測」を意味
だから、「search4fere」でフェレ計測用に4連結図形を
サーチするを意味します!

(2)仮引数

char**          Filter::search4fere(
    char*       bufptr[],                               // 追跡点履歴Buffer
    char*       p,                                      // 輪郭追跡 Ptr
    int         x,                                      // x座標カウンタ
    int         y,                                      // y座標カウンタ
    TypeSf*     buf,                                    // 計測結果Buffer
    int         dir_off[],                              // 方向OffSetTbl
    int         clr_dt,                                 // ClrData -1 / -2
    int&        size                                    // 座標Bufferサイズ
){

「char* bufptr[],」は、追跡点履歴バッファー≪輪郭サーチ
を行った画素の場所「char*」型でポイントをバッファーに
格納する為のバッファー≫
「char* p,」は、輪郭サーチ用の画像画素ポインタ
「int x,」は、X座標
「int y,」は、Y座標
「TypeSf* buf,」は、計測結果バッファーを示すポインタ
「int dir_off[],」は、方向オフセットテーブル≪輪郭
サーチ用の次の画素ポインタへのオフセットを格納した
テーブル≫
「int clr_dt,」は、図形≪連結した塊≫を計測後、目印と
してクリアする画素のデータ
「int& size」は、追跡点履歴バッファーのサイズで
「int&」と成って居る事に注意≪内部でバッファーサイズを
変更する可能性が有る≫
ココで「char** Filter::search4fere()」と関数辺値の型は
「char**」と追跡点履歴バッファー自身を関数辺値とし
返します≪内部でバッファーサイズがオーバーした場合に
新たにバッファーを拡大する為です!≫

(3)ローカル変数

){
    static const int    tblx[] = {                      // 方向に対するx座
        1, 0, -1, 0                                     // 標の変位
    };                                                  //
    static const int    tbly[] = {                      // 方向に対するy座
        0, 1, 0, -1                                     // 標の変位
    };                                                  //
    char        **pbufptr;                              // 履歴BufferPtr
    char        **bufNew;                               // 履歴BufferPtr:新規
    char        *ptemp;                                 // 原点
    char        *pp;                                    // 仮想原点
    char        *p1;                                    // 輪郭追跡 Ptr
    int         n;                                      // 履歴個数DownCnt
    int         min_x;                                  // x座標最小値
    int         max_x;                                  // x座標最大値
    int         max_y;                                  // y座標最大値
    int         h;                                      // 水平フェレ径
    int         v;                                      // 垂直フェレ径
    int         len;                                    // 周囲長
    int         dir;                                    // 方向 0..3
                                                        // 0:右
                                                        // 1:下
                                                        // 2:左
                                                        // 3:上
    int         inc;                                    // インクリ幅

「static const int tblx[]={1,0,-1,0};」は、X座標位置
進行テーブル≪添字を「int dir;」の周回方向カウンタでの
位置情報変換テーブル≫
「static const int tbly[]={0,1,0,-1};」は、Y座標位置
進行テーブル≪添字を「int dir;」の周回方向カウンタでの
位置情報変換テーブル≫
「char** pbufptr;」は、追跡点履歴バッファー
「char* bufptr;」へのポインタ
「char* bufNew;」は、追跡点履歴バッファーがサイズ
オーバーした場合の新規バッファーへのポインタ
「char* ptemp;」は、仮引数「char* p,」を原点とし保存用
「char* pp;」は、仮想原点
「char* p1;」は、作業用追跡ポインタ
「int n;」は、ダウンカウントする個数カウンタ
「int min_x;」は、X座標最小値≪フェレ計測X始点計測用≫
「int max_x;」は、X座標最大値≪フェレ計測X終点計測用≫
「int max_y;」は、Y座標最大値≪フェレ計測Y終点計測用≫
「int h;」は、水平フェレ径≪max_x-min_x+1;≫
「int v;」は、水平フェレ径≪max_y-min_y+1;≫
「int len;」は、周囲長
「int dir;」は、周回方向カウンタ≪0..3の間をリングカウ
ンタとし方向「0:右、1:下、2:左、3:上」≫
「int inc;」は、インクリメント幅≪画像画素を垂直方向に
ポインタ移動用の増加幅≫

(4)アルゴリズム

    pbufptr = bufptr;                                   // 履歴BufferptrSet
    n       = size - 3;                                 // 履歴制限数初期値
    buf->xl = x;                                        // Labelx座標格納
    buf->y  = y;                                        // Labely座標格納
    ptemp   = p;                                        // 原点を保存
    pp      = p - 1;                                    // 仮想原点をセット
    dir     = 0;                                        // 初期値=右
    min_x   = x;                                        // x座標の最小/最
    max_x   = x;                                        // 大値を初期化
    max_y   = y;                                        // y最大座標初期化
    len     = 0;                                        // 周囲長の初期化
    for(;;){                                            // 以下を繰り返す
        p1 = p + dir_off[ dir ];                        // 次追跡点をセット
        if( p1 == pp ){                                 // 仮想原点なら
            break;                                      // Loopを抜ける
        }                                               //
        if( *p1 > 0 ){                                  // サーチ成功なら
            if( --n <= 0 ){                             // 履歴BufferがOverしたら
                bufNew = reMallocSearchFere( size );    // 再メモリ確保
                if( bufNew == 0 ){                      // 確保失敗時は
                    return( 0 );                        // 「空」を返す
                }else{                                  // 確保成功時は
                    pbufptr = copyXYSearchFere(         // 新規履歴バッファーへ
                            bufptr, pbufptr, bufNew,    // コピー
                            size, n );                  // 
                    free( bufptr );                     // 元の追跡履歴バッファー解放
                    bufptr = bufNew;                    // 新規履歴バッファーをセット
                }                                       // 
            }                                           //
            *pbufptr++ = p;                             // 追跡履歴を取る
            p  = p1;                                    // 追跡点を更新
            x += tblx[ dir ];                           // x座標を更新
            y += tbly[ dir ];                           // y座標を更新
            if( min_x > x ){                            // x座標最小値を
                min_x = x;                              // 更新
            }                                           // 
            if( max_x < x ){                            // x座標最大値を
                max_x = x;                              // 更新
            }                                           //
            if( max_y < y ){                            // y座標最大値を
                max_y = y;                              // 更新
            }                                           //
            len++;                                      // 周囲長計数UP
            dir = ( dir - 1 ) & 0x03;                   // 方向を戻す
        }else{                                          // なければ
            dir = ( dir + 1 ) & 0x03;                   // 方向を進める
        }                                               //
    }                                                   //
    *pbufptr++ = p;                                     // 最終履歴をSetし
    *pbufptr   = 0;                                     // 追跡終点をセット
    h          = max_x - min_x + 1;                     // 水平径算出
    v          = max_y - buf->y + 1;                    // 垂直径算出
    buf->x     = min_x;                                 // フェレx座標格納
    buf->h     = h;                                     // 水平径格納
    buf->v     = v;                                     // 垂直径格納
    if( len == 0 ){                                     // 連結数=0の時
        len = 1;                                        // 1に補正
    }                                                   //
    buf->len = len;                                     // 周囲長格納
    if( h < 3 || v < 3 ){                               // 水平垂直が3未満
        search_clear( bufptr, clr_dt );                 // 輪郭をクリア
    }else if( h == 3 ){                                 // 水平が3の時
        search_clear_right( bufptr, clr_dt );           // 輪郭+右側 クリア
    }else if( v == 3 ){                                 // 垂直が3の時
        inc = dir_off[1];                               // インクリ幅を取出
        search_clear_down( bufptr, inc, clr_dt );       // 輪郭+下側 クリア
    }else if( h == 4 ){                                 // 水平が4の時
        search_clear_rl( bufptr, clr_dt );              // 輪郭+左右 クリア
    }else if( v == 4 ){                                 // 垂直が4の時
        inc = dir_off[1];                               // インクリ幅を取出
        search_clear_ud( bufptr, inc, clr_dt );         // 輪郭+上下 クリア
    }else{                                              // 5×5以上なら
        inc = dir_off[1];                               // インクリ幅を取出
        if( m_swMeasureBorder ){                        // 「真→輪郭線図形計測」時
            search_clear_rl( bufptr, clr_dt );          // 輪郭+左右 クリア
            search_clear_ud( bufptr, inc, clr_dt );     // 輪郭+上下 クリア
        }else{                                          // 「偽→任意図形」時
            search_clear( bufptr, clr_dt );             // 輪郭をクリア
            p = ptemp - buf->xl + min_x + inc + 1;      // 一回内側始点算出
            search4clear_base( p, h - 2, v - 2, inc,    // Labeling手法でCLR
                                            clr_dt );   //
        }                                               // 
    }                                                   //
    return( bufptr );                                   // 正常終了
}

「pbufptr=bufptr;」は、輪郭サーチ用追跡バッファー
ポインタ初期化
「n=size-3;」は、輪郭サーチ用追跡バッファー格納制限値
≪カウントダウン方式数計数≫初期化
「buf->xl=x;buf->y=y;」は、ラベル始点XY座標を計測
「ptemp=p;」は、輪郭サーチ用原点保存
「pp=p-1;」は、仮想原点≪原点の左隣≫をセット

4連結方向

「dir=0;」は、追跡方向を「0=右側」にセット
「min_x=x;max_x=x;max_y=y;」は、計測対象のX座標最小
最大値及びY座標最大値を初期化
「len=0;」は、周囲長を初期化
「for(;;){・・処理ループ・・}」は、無限forループで
処理ループ≪ループから抜けるのは正常動作なら「break;」
でループから抜け、エラー発生時は「return(0);」で関数
終了≫、で処理ループは、以下に説明します!
「p1=p+dir_off[dir];」は、注視点の隣接周辺追跡点作成
「if(p1==pp){break;}」は、条件「p1==pp」で追跡点が、
仮想原点≪時計回り一筆書きなので一周回った事に成る≫に
到達した事で図形の輪郭サーチ処理ループ終了で「break;」
とループを抜ける!
「if(*p1>0){・・処理・・}else{dir=(dir+1)&0x03;}」は、
条件「*p1>0」で有効画素(正の値)なら、以下に説明する
処理で図形≪4連結での塊≫を計測し、「else」詰まり無効
画素の場合で
「dir=(dir+1)&0x03;」と方向「dir」を示す値を更新≪
「dir+1」でカウントアップ≪「+1」と進行する事で【時計
回り方向「右⇒下⇒左⇒上」】の次へ≫、「&0x03」で
※ビット毎の論理積(AND演算)とビット毎論理式に馴染
まない人への解説【C言語算術演算で書き換えると
「(dir+1)%4;」と4で除算した余りと成りますが、多くの
CPUでは高速化手法として使用出来ます】≫、では、
有効画素の場合、
「if(--n<=0){・・履歴バッファー限度超え処置・・}」は、
条件「--n<=0」で「--n」は、バッファー格納制限をダウン
カウントで減じ、0以下に成ったら、履歴バッファー限度超
え処置を行う事で履歴バッファー限度以上に輪郭サーチ履歴
を可能に出来る処置を行う!その処置は、
「bufNew=reMallocSearchFere(size);」で下請け関数
「reMallocSearchFere(size);」でサイズ「size」を大幅に
増やし、この関数の仮引数「int& size」と増やした値を
引数で返し、関数の内部で動的にメモリ確保し新しく確保し
たバッファーの先頭ポインタを返す!
「if(bufNew==0){return(0);}」でメモリ確保に失敗したら
関数辺値とし「0=空ポインタ」返し終了≪メモリ確保失敗
エラーとし扱う≫
「else{pbufptr=copyXYSearchFere(
bufptr,pbufptr,bufNew,size,n);free(bufptr);
bufptr=bufNew;}」で下請け関数「copyXYSearchFere()」で
新しいメモリ確保バッファー「bufNew」に元の履歴バッ
ファー「bufptr」の内容をコピーし、
「free(bufptr);」と元のバッファー「bufptr」を解放≪
動的にメモリ確保した領域をOSに返す≫し、
「bufptr=bufNew;」と履歴バッファーを付け替える!
「*pbufptr++=p;」は、現在の注視点画像画素ポインタを
「*pbufptr++」と履歴バッファーに格納し、
「p=p1;」は、注視点画像画素ポインタを次追跡点に進行
「x+=tblx[dir];y+=tbly[dir];」は、XY座標を更新
「if(min_x>x){min_x=x;}」は、X座標最小値更新
「if(max_x<x){max_x=x;}」は、X座標最大値更新
「if(max_y<y){max_y=y;}」は、Y座標最大値更新
「len++;」は、周囲長≪画素数≫カウントアップ
「dir=(dir-1)&0x03;」は、「dir」を示す値を変更「一つ戻
す」≪「dir-1」でカウントダウン≪「-1」と逆進する事で
【反時計回り方向「上⇒左⇒下⇒右」】の次へ≫、
「&0x03」で※ビット毎の論理積(AND演算)とビット毎
論理式に馴染まない人への解説【C言語算術演算で書き換え
ると「(dir-1)%4;」と4で除算した余りと成りますが、
多くのCPUでは高速化手法として使用出来ます】≫
「*pbufptr++=p;」は、輪郭サーチ最後の画像画素ポインタ
を履歴バッファーに格納
「*pbufptr=0;」は、目印として履歴バッファー最後に
空ポインタ「=0」をセット
「h=max_x-min_x+1;」は、水平フェレ径算出
「v=max_y-buf->y+1;」は、垂直フェレ径算出
「buf->x=min_x;」は、フェレX座標を計測値としセット
「buf->h=h;buf->v=v;」は、フェレ水平垂直径を計測値とし
セット
「if(len==0){len=1;}」は、周囲長≪画素数≫が0なら、
「len=1;」としてセット
「buf->len=len;」は、計測値として周囲長をセット
「if(h<3||v<3){search_clear(bufptr,clr_dt);}」は、
条件「h<3||v<3」で図形≪4連結での塊≫水平径か垂直径が
3画素未満の場合は、下請け
関数「search_clear(bufptr,clr_dt);」で図形をクリア
「else if(h==3){search_clear_right(bufptr,clr_dt);}」
は、条件「h==3」で図形水平径が3画素の場合は、下請け
関数「search_clear_right(bufptr,clr_dt);」で図形を
クリア
「else if(v==3){inc=dir_off[1];
search_clear_down(bufptr,inc,clr_dt);}」は、
条件「v==3」で図形垂直径が3画素の場合は、
「inc=dir_off[1];」で画像の増加幅を取り出し、下請け
関数「search_clear_down(bufptr,inc,clr_dt);」で図形
をクリア
「else if(h==4){search_clear_rl(bufptr,clr_dt);}」は、
条件「h==4」で図形水平径が4画素の場合は、下請け
関数「search_clear_rl(bufptr,clr_dt);」で図形をクリア
「else if(v==4){inc=dir_off[1];
search_clear_ud(bufptr,inc,clr_dt);}」は、
条件「v==4」で図形垂直径が4画素の場合は、
「inc=dir_off[1];」で画像の増加幅を取り出し、下請け
関数「search_clear_ud(bufptr,inc,clr_dt);」で図形を
クリア
「else{・・5×5図形をクリア・・」は、
「inc=dir_off[1];」で画像の増加幅を取り出し、
「if(m_swMeasureBorder){
search_clear_rl(bufptr,clr_dt);
search_clear_ud(bufptr,inc,clr_dt);}」で
条件「m_swMeasureBorder」でこのスイッチが真の場合は、
下請け関数「search_clear_rl(bufptr,clr_dt);」と
下請け関数「search_clear_ud(bufptr,inc,clr_dt);}」で
図形をクリア、
「else{
search_clear(bufptr,clr_dt);
p=ptemp-buf->xl+min_x+inc+1;
search4clear_base(p,h-2,v-2,inc,clr_dt);}
」と「else{」で条件「m_swMeasureBorder」でこの
スイッチが偽の場合は、
「search_clear(bufptr,clr_dt);」で下請け関数
「search_clear(bufptr,clr_dt);」で輪郭クリアし、
「p=ptemp-buf->xl+min_x+inc+1;」で図形画像の一回り
内側の始点をセットし、下請け関数
「search4clear_base(p,h-2,v-2,inc,clr_dt);」で
図形をクリア
「return(bufptr);」は、追跡点履歴バッファーのポインタ
を関数辺値とし返し終了

2.メモリ再確保reMallocSearchFere()

/************************************************************************/
/*****      図形のフェレ計測:処理部:メモリ再確保                  *****/
/*****  メモリオーバ時にここでメモリ確保&処理を行う                *****/
/*****  注:メモリのサイズもここで変更した分を返します。            *****/
/*****  引数返値:  新規メモリサイズ                                *****/
/*****  返値    :  新規に確保したメモリ、0→確保失敗              *****/
/************************************************************************/

char**          Filter::reMallocSearchFere(
    int&        size                                            // 座標Bufferサイズ
){
    char        **bufNew;                                       // 履歴BufferPtr:新規
    int         n;                                              // 新規確保サイズ

    n      = size * 8;                                          // 次サイズ=8倍
    bufNew = (char**)malloc( sizeof(char*) * n );               // メモリ確保
    if( bufNew == 0 ){                                          // 8倍確保失敗時は
        n      = size * 4;                                      // 次サイズ=4倍
        bufNew = (char**)malloc( sizeof(char*) * n );           // メモリ確保
        if( bufNew == 0 ){                                      // 4倍確保失敗時は
            n      = size * 2;                                  // 次サイズ=2倍
            bufNew = (char**)malloc( sizeof(char*) * n );       // メモリ確保
            if( bufNew == 0 ){                                  // 2倍確保失敗時は
                n      = size * 3 / 2;                          // 次サイズ=1.5倍
                bufNew = (char**)malloc( sizeof(char*) * n );   // メモリ確保
                if( bufNew == 0 ){                              // 1.5倍確保失敗時は
                    return( 0 );                                // 空→失敗を返す
                }                                               //
            }                                                   //
        }                                                       //
    }                                                           //
    size = n;                                                   // サイズの値を再セット
    return( bufNew );                                           // 確保したメモリを返す
}

(1)関数名

「re」は、「再」再びを意味
「Malloc」は、動的メモリ確保を意味し、「reMalloc」で
「再確保」を意味
「Search」は、カタカナ語「サーチ」でココでは、図形を
サーチする意味
「Fere」は、「フェレ計測」を意味
だから、「Searchfere」でフェレ計測を意味します!
そして「reMallocSearchFere」でフェレ計測用の
バッファーを動的メモリ再確保を意味します

(2)仮引数

char**          Filter::reMallocSearchFere(
    int&        size                                            // 座標Bufferサイズ
){

「int& size」は、追跡点履歴バッファーのサイズで
「int&」と成って居る事に注意≪内部でバッファーサイズを
変更します!≫
関数辺値「char** Filter::reMallocSearchFere()」は、
新規に確保したメモリへのポインタ値

(3)ローカル変数

){
    char        **bufNew;                                       // 履歴BufferPtr:新規
    int         n;                                              // 新規確保サイズ

「char** bufNew;」は、追跡点履歴バッファーがサイズ
「int n;」は、新規確保サイズ

(4)アルゴリズム

    n      = size * 8;                                          // 次サイズ=8倍
    bufNew = (char**)malloc( sizeof(char*) * n );               // メモリ確保
    if( bufNew == 0 ){                                          // 8倍確保失敗時は
        n      = size * 4;                                      // 次サイズ=4倍
        bufNew = (char**)malloc( sizeof(char*) * n );           // メモリ確保
        if( bufNew == 0 ){                                      // 4倍確保失敗時は
            n      = size * 2;                                  // 次サイズ=2倍
            bufNew = (char**)malloc( sizeof(char*) * n );       // メモリ確保
            if( bufNew == 0 ){                                  // 2倍確保失敗時は
                n      = size * 3 / 2;                          // 次サイズ=1.5倍
                bufNew = (char**)malloc( sizeof(char*) * n );   // メモリ確保
                if( bufNew == 0 ){                              // 1.5倍確保失敗時は
                    return( 0 );                                // 空→失敗を返す
                }                                               //
            }                                                   //
        }                                                       //
    }                                                           //
    size = n;                                                   // サイズの値を再セット
    return( bufNew );                                           // 確保したメモリを返す
}

「n=size8;」は、新規確保サイズを元のサイズの8倍≪
十分な大きさとして考えた≫
「bufNew=(char**)malloc(sizeof(char)n);」は、
画像画素へのポインタの型「char」へのポインタ即ち、
格納するバッファーをC言語標準関数「malloc()」で動的に
メモリ確保
「if(bufNew==0){・・確保失敗時処理1・・}」は、
条件「bufNew==0」と動的にメモリ確保失敗したので
「n=size4;」は、新規確保サイズを元のサイズの4倍≪
8倍で確保失敗したので半分の4倍で再確保と考えた≫
「bufNew=(char**)malloc(sizeof(char)n);」は、再び
動的にメモリ確保
「if(bufNew==0){・・確保失敗時処理2・・}」は、
条件「bufNew==0」と動的にメモリ確保失敗したので
「n=size2;」は、新規確保サイズを元のサイズの2倍≪
4倍で確保失敗したので半分の2倍で再確保と考えた≫
「bufNew=(char**)malloc(sizeof(char*)n);」は、再び
動的にメモリ確保
「if(bufNew==0){・・確保失敗時処理3・・}」は、
条件「bufNew==0」と動的にメモリ確保失敗したので
「n=size3/2;」は、新規確保サイズを元のサイズの1.5
倍≪2倍で確保失敗したので若干下げて1.5倍で再確保と
考えた≫
「bufNew=(char**)malloc(sizeof(char*)*n);」は、再び
動的にメモリ確保
「if(bufNew==0){return(0);}」は、1.5倍でも確保失敗
の場合は、空ポインタ(=0)を関数辺値とし返し終了
「size=n;」は、仮引数「int& size」に新規のサイズを
セット
「return(bufNew);」は、メモリ確保したバッファーへの
ポインタを返し終了

3.メモリ再確保後コピーcopyXYSearchFere()

/****************************************************************************/
/*****      図形のフェレ計測:処理部:メモリ再確保後の画像画素Ptrコピー *****/
/*****  引数返値:  コピー後の有効数(バッファーOverの目安)            *****/
/*****  返値:      次から格納する履歴BufferPtr                         *****/
/****************************************************************************/

char**          Filter::copyXYSearchFere(
    char**      bufptr,                                     // 追跡点履歴Buffer
    char**      pbufptr,                                    // 履歴BufferPtr
    char**      pnewptr,                                    // 新規確保Buffer
    int         size,                                       // 新規確保Bufferサイズ
    int&        n                                           // コピー後の有効数
){
    n = size - 3;                                           // 有効数初期化
    while( bufptr < pbufptr ){                              // 以下繰り返し
        *pnewptr++ = *bufptr++;                             // 画素Ptrを取り出し
        n--;                                                // 有効数を減じる
    }                                                       // コピー
    return( pnewptr );                                      // 新規格納先Ptrを返す
}

(1)関数名

「copy」は、「コピーする」を意味
「XY」は、XY座標を意味
「Search」は、カタカナ語「サーチ」でココでは、図形を
サーチする意味
「Fere」は、「フェレ計測」を意味
だから、「XYSearch」で輪郭座標サーチを意味します!
そして「copyXYSearchFere」でフェレ計測用のバッファーを
動的メモリ再確保した後で計測済のXY座標データを新規
バッファーにコピーするを意味します

(2)仮引数

char**          Filter::copyXYSearchFere(
    char**      bufptr,                                     // 追跡点履歴Buffer
    char**      pbufptr,                                    // 履歴BufferPtr
    char**      pnewptr,                                    // 新規確保Buffer
    int         size,                                       // 新規確保Bufferサイズ
    int&        n                                           // コピー後の有効数
){

「char**bufptr,」は、追跡点履歴バッファー
char**pbufptr,」は、追跡点履歴の追跡点保存場所を示す
ポインタ
「char**pnewptr,」は、新規動的にメモリ確保場所
「int size,」は、新規動的にメモリ確保したサイズ
「int&n」は、コピー後の履歴個数ダウンカウンタ

(3)アルゴリズム

){
    n = size - 3;                                           // 有効数初期化
    while( bufptr < pbufptr ){                              // 以下繰り返し
        *pnewptr++ = *bufptr++;                             // 画素Ptrを取り出し
        n--;                                                // 有効数を減じる
    }                                                       // コピー
    return( pnewptr );                                      // 新規格納先Ptrを返す
}

「n=size-3;」は、輪郭サーチ用追跡バッファー格納制限値
≪カウントダウン方式数計数≫初期化
「while(bufptr<pbufptr){*pnewptr++=*bufptr++;n--;}」は
whileループでループ条件「bufptr<pbufptr」で元の
追跡点履歴バッファーの最初から最後までを意味し、中身
「*pnewptr++=*bufptr++;n--;」で先ず、
「*pnewptr++=*bufptr++;」で履歴画像画素ポインタを
コピーし、ソレゾレポインタを増加、「n--;」で履歴個数
カウントダウン
「return(pnewptr);」は、次から格納する履歴バッファーの
ポインタを関数辺値とし返し終了!

4.輪郭のクリアsearch_clear()

/************************************************************************/
/*****      図形のフェレ計測:処理部:輪郭のクリア                  *****/
/*****  輪郭線を履歴バッファーを使用してクリア                      *****/
/************************************************************************/

void        Filter::search_clear(
    char    **pbufptr,                              // 追跡点履歴 Ptr
    int     clr_dt                                  // クリアデータ
){
    char    *p;                                     // 書き込みポインタ

    while( ( p = *pbufptr++ ) != 0 ){               // ポインタを取出し
        *p = clr_dt;                                // 輪郭点をクリア
    }                                               //
}

(1)関数名

「search」は、カタカナ語「サーチ」でココでは、図形を
サーチする意味でココではサーチした履歴バッファー
「clear」は、「クリア」消去を意味
だから、「search_clear」で輪郭座標サーチデータで
輪郭サーチした輪郭をクリア

(2)仮引数

void        Filter::search_clear(
    char    **pbufptr,                              // 追跡点履歴 Ptr
    int     clr_dt                                  // クリアデータ
){

「char**pbufptr,」は、追跡点履歴バッファー
「int clr_dt」は、輪郭画素をクリアするデータ

(3)ローカル変数

){
    char    *p;                                     // 書き込みポインタ

「char *p;」は、画素書き込みポインタ

(4)アルゴリズム

    while( ( p = *pbufptr++ ) != 0 ){               // ポインタを取出し
        *p = clr_dt;                                // 輪郭点をクリア
    }                                               //
}

「while((p=*pbufptr++)!=0){*p=clr_dt;}」は、
ループ条件「(p=*pbufptr++)!=0」で「p=*pbufptr++」で
画素書き込みポインタを取り出し、
条件「(p=*pbufptr++)!=0」で空ポインタ≪バッファーの
最後を番兵とし空ポインタをセットして有る≫で無い場合は
ループ本体を繰り返し、ループ本体「*p=clr_dt;」で
画像画素を仮引数「int clr_dt」でクリア

5.輪郭(+右隣)のクリアsearch_clear_right()

/************************************************************************/
/*****      図形のフェレ計測:処理部:輪郭のクリア+右隣クリア      *****/
/*****  輪郭線を履歴バッファーを使用してクリアすると共に            *****/
/*****  輪郭の右側に正のデータがあればクリアする                    *****/
/*****  クリアは、-1 か -2 でクリア                             *****/
/*****  フェレ径 H × V = 3 × 3以上 が対象                   *****/
/************************************************************************/

void        Filter::search_clear_right(
    char    **pbufptr,                              // 追跡点履歴 Ptr
    int     clr_dt                                  // クリアデータ
){
    char    *p;                                     // 書き込みポインタ

    while( ( p = *pbufptr++ ) != 0 ){               // ポインタを取出し
        *p++ = clr_dt;                              // 輪郭点をクリアし
        if( *p > 0 ){                               // 右隣が正なら
            *p = clr_dt;                            // クリア
        }                                           //
    }                                               //
}

(1)関数名

「search」は、カタカナ語「サーチ」でココでは、図形を
サーチする意味でココではサーチした履歴バッファー
「clear」は、「クリア」消去を意味
「right」は、右隣を意味
だから、「search_clear_right」で輪郭座標サーチデータで
輪郭とサーチした輪郭右隣をクリア

(2)仮引数

void        Filter::search_clear_right(
    char    **pbufptr,                              // 追跡点履歴 Ptr
    int     clr_dt                                  // クリアデータ
){

「char**pbufptr,」は、追跡点履歴バッファー
「int clr_dt」は、輪郭画素をクリアするデータ

(3)ローカル変数

){
    char    *p;                                     // 書き込みポインタ

「char *p;」は、画素書き込みポインタ

(4)アルゴリズム

    while( ( p = *pbufptr++ ) != 0 ){               // ポインタを取出し
        *p++ = clr_dt;                              // 輪郭点をクリアし
        if( *p > 0 ){                               // 右隣が正なら
            *p = clr_dt;                            // クリア
        }                                           //
    }                                               //
}

「while((p=*pbufptr++)!=0){・・ループ本体・・}」は、
ループ条件「(p=*pbufptr++)!=0」で「p=*pbufptr++」で
画素書き込みポインタを取り出し、
条件「(p=*pbufptr++)!=0」で空ポインタ≪バッファーの
最後を番兵とし空ポインタをセットして有る≫で無い場合は
ループ本体を繰り返し、ループ本体「*p++=clr_dt;」で
画像画素を仮引数「int clr_dt」でクリアしポインタを右隣
に移動、次の
「if(*p>0){*p=clr_dt;}」で右隣が有効画素ならばクリア

6.輪郭(+下隣)のクリアsearch_clear_down()

/************************************************************************/
/*****      図形のフェレ計測:処理部:輪郭のクリア+下隣クリア      *****/
/*****  輪郭線を履歴バッファーを使用してクリアすると共に            *****/
/*****  輪郭の下側に正のデータがあればクリアする                    *****/
/*****  クリアは、-1 か -2 でクリア                             *****/
/*****  フェレ径 H × V = 3以上 × 3 が対象                   *****/
/************************************************************************/

void        Filter::search_clear_down(
    char    **pbufptr,                              // 追跡点履歴 Ptr
    int     inc,                                    // インクリメント幅
    int     clr_dt                                  // クリアデータ
){
    char    *p;                                     // 書き込みポインタ

    while( ( p = *pbufptr++ ) != 0 ){               // ポインタを取出し
        *p = clr_dt;                                // 輪郭点をクリアし
        p += inc;                                   // 下隣をセット
        if( *p > 0 ){                               // 下隣が正なら
            *p = clr_dt;                            // クリア
        }                                           //
    }                                               //
}

(1)関数名

「search」は、カタカナ語「サーチ」でココでは、図形を
サーチする意味でココではサーチした履歴バッファー
「clear」は、「クリア」消去を意味
「down」は、下隣を意味
だから、「search_clear_down」で輪郭座標サーチデータで
輪郭とサーチした輪郭下右隣をクリア

(2)仮引数

void        Filter::search_clear_down(
    char    **pbufptr,                              // 追跡点履歴 Ptr
    int     inc,                                    // インクリメント幅
    int     clr_dt                                  // クリアデータ
){

「char**pbufptr,」は、追跡点履歴バッファー
「int inc,」は、画像の増加幅
「int clr_dt」は、輪郭画素をクリアするデータ

(3)ローカル変数

){
    char    *p;                                     // 書き込みポインタ

「char *p;」は、画素書き込みポインタ

(4)アルゴリズム

    while( ( p = *pbufptr++ ) != 0 ){               // ポインタを取出し
        *p = clr_dt;                                // 輪郭点をクリアし
        p += inc;                                   // 下隣をセット
        if( *p > 0 ){                               // 下隣が正なら
            *p = clr_dt;                            // クリア
        }                                           //
    }                                               //
}

「while((p=*pbufptr++)!=0){・・ループ本体・・}」は、
ループ条件「(p=*pbufptr++)!=0」で「p=*pbufptr++」で
画素書き込みポインタを取り出し、
条件「(p=*pbufptr++)!=0」で空ポインタ≪バッファーの
最後を番兵とし空ポインタをセットして有る≫で無い場合は
ループ本体を繰り返し、ループ本体「*p=clr_dt;」で
画像画素を仮引数「int clr_dt」でクリアしポインタを
「p+=inc;」で下隣に移動、次の
「if(*p>0){*p=clr_dt;}」で下隣が有効画素ならばクリア

7.輪郭(+左右)のクリアsearch_clear_rl()

/************************************************************************/
/*****      図形のフェレ計測:処理部:輪郭のクリア+左右隣クリア    *****/
/*****  輪郭線を履歴バッファーを使用してクリアすると共に            *****/
/*****  輪郭の左右に正のデータがあればクリアする                    *****/
/*****  クリアは、-1 か -2 でクリア                             *****/
/*****  フェレ径 H × V = 4 × 4以上 が対象                   *****/
/************************************************************************/

void        Filter::search_clear_rl(
    char    **pbufptr,                              // 追跡点履歴 Ptr
    int     clr_dt                                  // クリアデータ
){
    char    *p;                                     // 書き込みポインタ

    while( ( p = *pbufptr++ ) != 0 ){               // ポインタを取出し
        *p++ = clr_dt;                              // 輪郭点をクリアし
        if( *p > 0 ){                               // 右隣が正なら
            *p = clr_dt;                            // クリア
        }                                           //
        p -= 2;                                     // 左隣をセット
        if( *p > 0 ){                               // 右隣が正なら
            *p = clr_dt;                            // クリア
        }                                           //
    }                                               //
}

(1)関数名

「search」は、カタカナ語「サーチ」でココでは、図形を
サーチする意味でココではサーチした履歴バッファー
「clear」は、「クリア」消去を意味
「rl」は、左右隣を意味
だから、「search_clear_rl」で輪郭座標サーチデータで
輪郭とサーチした輪郭左右隣をクリア

(2)仮引数

void        Filter::search_clear_rl(
    char    **pbufptr,                              // 追跡点履歴 Ptr
    int     clr_dt                                  // クリアデータ
){

「char**pbufptr,」は、追跡点履歴バッファー
「int clr_dt」は、輪郭画素をクリアするデータ

(3)ローカル変数

){
    char    *p;                                     // 書き込みポインタ

「char *p;」は、画素書き込みポインタ

(4)アルゴリズム

    while( ( p = *pbufptr++ ) != 0 ){               // ポインタを取出し
        *p++ = clr_dt;                              // 輪郭点をクリアし
        if( *p > 0 ){                               // 右隣が正なら
            *p = clr_dt;                            // クリア
        }                                           //
        p -= 2;                                     // 左隣をセット
        if( *p > 0 ){                               // 右隣が正なら
            *p = clr_dt;                            // クリア
        }                                           //
    }                                               //
}

「while((p=*pbufptr++)!=0){・・ループ本体・・}」は、
ループ条件「(p=*pbufptr++)!=0」で「p=*pbufptr++」で
画素書き込みポインタを取り出し、
条件「(p=*pbufptr++)!=0」で空ポインタ≪バッファーの
最後を番兵とし空ポインタをセットして有る≫で無い場合は
ループ本体を繰り返し、ループ本体「*p++=clr_dt;」で
画像画素を仮引数「int clr_dt」でクリアしポインタを
「p++」で右隣に移動、次の
「if(*p>0){*p=clr_dt;}」で右隣が有効画素ならばクリア
「p-=2;」で左隣に移動、次の
「if(*p>0){*p=clr_dt;}」で左隣が有効画素ならばクリア

8.輪郭(+上下隣)のクリアsearch_clear_ud()

/************************************************************************/
/*****      図形のフェレ計測:処理部:輪郭のクリア+上下クリア      *****/
/*****  輪郭線を履歴バッファーを使用してクリアすると共に            *****/
/*****  輪郭の上下に正のデータがあればクリアする                    *****/
/*****  クリアは、-1 か -2 でクリア                             *****/
/*****  フェレ径 H × V = 4以上 × 4 が対象                   *****/
/************************************************************************/

void        Filter::search_clear_ud(
    char    **pbufptr,                              // 追跡点履歴 Ptr
    int     inc,                                    // インクリメント幅
    int     clr_dt                                  // クリアデータ
){
    char    *p;                                     // 書き込みポインタ
    int     inc2;                                   // インクリ幅×2

    inc2 = inc * 2;                                 // インクリ幅×2
    while( ( p = *pbufptr++ ) != 0 ){               // ポインタを取出し
        *p = clr_dt;                                // 輪郭点をクリアし
        p += inc;                                   // 下隣をセット
        if( *p > 0 ){                               // 下隣が正なら
            *p = clr_dt;                            // クリア
        }                                           //
        p -= inc2;                                  // 上隣をセット
        if( *p > 0 ){                               // 上隣が正なら
            *p = clr_dt;                            // クリア
        }                                           //
    }                                               //
}

(1)関数名

「search」は、カタカナ語「サーチ」でココでは、図形を
サーチする意味でココではサーチした履歴バッファー
「clear」は、「クリア」消去を意味
「ud」は、上下隣を意味
だから、「search_clear_down」で輪郭座標サーチデータで
輪郭とサーチした輪郭上下隣をクリア

(2)仮引数

void        Filter::search_clear_ud(
    char    **pbufptr,                              // 追跡点履歴 Ptr
    int     inc,                                    // インクリメント幅
    int     clr_dt                                  // クリアデータ
){

「char**pbufptr,」は、追跡点履歴バッファー
「int inc,」は、画像の垂直方向増加幅
「int clr_dt」は、輪郭画素をクリアするデータ

(3)ローカル変数

){
    char    *p;                                     // 書き込みポインタ
    int     inc2;                                   // インクリ幅×2

「char *p;」は、画素書き込みポインタ
「int inc2;」は、増加幅×2≪高速化の為≫

(4)アルゴリズム

    inc2 = inc * 2;                                 // インクリ幅×2
    while( ( p = *pbufptr++ ) != 0 ){               // ポインタを取出し
        *p = clr_dt;                                // 輪郭点をクリアし
        p += inc;                                   // 下隣をセット
        if( *p > 0 ){                               // 下隣が正なら
            *p = clr_dt;                            // クリア
        }                                           //
        p -= inc2;                                  // 上隣をセット
        if( *p > 0 ){                               // 上隣が正なら
            *p = clr_dt;                            // クリア
        }                                           //
    }                                               //
}

「inc2=inc*2;」は、増加幅×2を算出しセット
「while((p=*pbufptr++)!=0){・・ループ本体・・}」は、
ループ条件「(p=*pbufptr++)!=0」で「p=*pbufptr++」で
画素書き込みポインタを取り出し、
条件「(p=*pbufptr++)!=0」で空ポインタ≪バッファーの
最後を番兵とし空ポインタをセットして有る≫で無い場合は
ループ本体を繰り返し、ループ本体「*p=clr_dt;」で
画像画素を仮引数「int clr_dt」でクリアしポインタを
「p+=inc;」で下隣に移動、次の
「if(*p>0){*p=clr_dt;}」で下隣が有効画素ならばクリア
「p-=inc;」で上隣に移動、次の
「if(*p>0){*p=clr_dt;}」で上隣が有効画素ならばクリア

9.簡易ラベリングで4連結クリアsearch4clear_base()

/************************************************************************/
/*****      図形のフェレ計測:4連結:  図形のフェレ範囲内で        *****/
/*****                              :簡易ラベリングを使用          *****/
/*****  クリアは、対象図形の輪郭をクリアデータでクリアしてるものとし*****/
/*****  対象画素をクリアします。                                    *****/
/*****  フェレ径 H × V = 5 × 5 以上が対象                   *****/
/************************************************************************/

void        Filter::search4clear_base(
    char    *p,                                                 // フェレ始点
    int     h,                                                  // 水平フェレ径
    int     v,                                                  // 垂直フェレ径
    int     inc,                                                // 増加幅
    int     clr_dt                                              // クリアデータ
){
    char    *px;                                                // 追跡点:水平
    char    *py;                                                // 追跡点:垂直
    int     x;                                                  // 水平方向Cnt
    int     y;                                                  // 垂直方向Cnt
    int     sw;                                                 // 変更有Switch

    sw = TRUE;                                                  // 変更Sw初期化
    while( sw ){                                                // 繰り返し条件
        sw = FALSE;                                             // 変更Swクリア
        py = p;                                                 // 左上追跡点Set
        for( y = v; --y >= 0; py += inc ){                      // 垂直幅分繰返
            px = py;                                            // 水平追跡点Set
            if( sw ){                                           // 変更Swセット済みなら
                for( x = h; --x >= 0; px++ ){                   // 水平幅分繰返
                    if( *px > 0 ){                              // 未連結画素→
                        if( *( px - 1 ) == clr_dt ){            // 左隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                        }else if( *( px - inc ) == clr_dt ){    // 上隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                        }                                       //
                    }                                           //
                }                                               //
            }else{                                              // 変更Swセット未設定なら
                for( x = h; --x >= 0; px++ ){                   // 水平幅分繰返
                    if( *px > 0 ){                              // 未連結画素→
                        if( *( px - 1 ) == clr_dt ){            // 左隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                            sw  = TRUE;                         // 変更有を示す
                        }else if( *( px - inc ) == clr_dt ){    // 上隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                            sw  = TRUE;                         // 変更有を示す
                        }                                       //
                    }                                           //
                }                                               //
            }                                                   // 
        }                                                       //
        py = p + ( v - 1 ) * inc + h - 1;                       // 右下追跡点Set
        for( y = v; --y >= 0; py -= inc ){                      // 垂直幅分繰返
            px = py;                                            // 水平追跡点Set
            if( sw ){                                           // 変更Swセット済みなら
                for( x = h; --x >= 0; px-- ){                   // 水平幅分繰返
                    if( *px > 0 ){                              // 未連結画素→
                        if( *( px + 1 ) == clr_dt ){            // 右隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                        }else if( *( px + inc ) == clr_dt ){    // 下隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                        }                                       //
                    }                                           //
                }                                               //
            }else{                                              // 変更Swセット未設定なら
                for( x = h; --x >= 0; px-- ){                   // 水平幅分繰返
                    if( *px > 0 ){                              // 未連結画素→
                        if( *( px + 1 ) == clr_dt ){            // 右隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                            sw  = TRUE;                         // 変更有を示す
                        }else if( *( px + inc ) == clr_dt ){    // 下隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                            sw  = TRUE;                         // 変更有を示す
                        }                                       //
                    }                                           //
                }                                               //
            }                                                   // 
        }                                                       //
        p += inc + 1;                                           // 一つ内側に
        h -= 2;                                                 // 始点と範囲を
        v -= 2;                                                 // 補正
    }                                                           //
}                                                               //

(1)関数名

「search」は、カタカナ語「サーチ」でココでは、図形を
サーチする意味でココではサーチした履歴バッファー
「4」は、4連結を意味で「search4」で4連結サーチ
「clear」は、「クリア」消去を意味
「base」は基本を意味
だから、「search4clear_base」で輪郭座標サーチデータで
輪郭とその中を4連結でクリア

(2)仮引数

void        Filter::search4clear_base(
    char    *p,                                                 // フェレ始点
    int     h,                                                  // 水平フェレ径
    int     v,                                                  // 垂直フェレ径
    int     inc,                                                // 増加幅
    int     clr_dt                                              // クリアデータ
){

「char*p,」は、フェレ始点画像画素へのポインタ
「int h,」は、水平フェレ径
「int v,」は、垂直フェレ径
「int inc,」は、画像の垂直方向増加幅
「int clr_dt」は、輪郭画素をクリアするデータ

(3)ローカル変数

){
    char    *px;                                                // 追跡点:水平
    char    *py;                                                // 追跡点:垂直
    int     x;                                                  // 水平方向Cnt
    int     y;                                                  // 垂直方向Cnt
    int     sw;                                                 // 変更有Switch

「char* px;」は、フェレ径内画像をラスタースキャンする
X座標方向作業ポインタ
「char* py;」は、フェレ径内画像をラスタースキャンする
Y座標方向作業ポインタ
「int x;」は、水平方向(X座標方向)ダウンカウンタ
「int y;」は、垂直方向(Y座標方向)ダウンカウンタ
「int sw;」は、画素変更スィッチとし連結していたら
連続してクリアし、スィッチがOFFならクリアするデータ
が有るとONに成るON/OFFスィッチ

(4)アルゴリズム

    sw = TRUE;                                                  // 変更Sw初期化
    while( sw ){                                                // 繰り返し条件
        sw = FALSE;                                             // 変更Swクリア
        py = p;                                                 // 左上追跡点Set
        for( y = v; --y >= 0; py += inc ){                      // 垂直幅分繰返
            px = py;                                            // 水平追跡点Set
            if( sw ){                                           // 変更Swセット済みなら
                for( x = h; --x >= 0; px++ ){                   // 水平幅分繰返
                    if( *px > 0 ){                              // 未連結画素→
                        if( *( px - 1 ) == clr_dt ){            // 左隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                        }else if( *( px - inc ) == clr_dt ){    // 上隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                        }                                       //
                    }                                           //
                }                                               //
            }else{                                              // 変更Swセット未設定なら
                for( x = h; --x >= 0; px++ ){                   // 水平幅分繰返
                    if( *px > 0 ){                              // 未連結画素→
                        if( *( px - 1 ) == clr_dt ){            // 左隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                            sw  = TRUE;                         // 変更有を示す
                        }else if( *( px - inc ) == clr_dt ){    // 上隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                            sw  = TRUE;                         // 変更有を示す
                        }                                       //
                    }                                           //
                }                                               //
            }                                                   // 
        }                                                       //
        py = p + ( v - 1 ) * inc + h - 1;                       // 右下追跡点Set
        for( y = v; --y >= 0; py -= inc ){                      // 垂直幅分繰返
            px = py;                                            // 水平追跡点Set
            if( sw ){                                           // 変更Swセット済みなら
                for( x = h; --x >= 0; px-- ){                   // 水平幅分繰返
                    if( *px > 0 ){                              // 未連結画素→
                        if( *( px + 1 ) == clr_dt ){            // 右隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                        }else if( *( px + inc ) == clr_dt ){    // 下隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                        }                                       //
                    }                                           //
                }                                               //
            }else{                                              // 変更Swセット未設定なら
                for( x = h; --x >= 0; px-- ){                   // 水平幅分繰返
                    if( *px > 0 ){                              // 未連結画素→
                        if( *( px + 1 ) == clr_dt ){            // 右隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                            sw  = TRUE;                         // 変更有を示す
                        }else if( *( px + inc ) == clr_dt ){    // 下隣と連結時
                            *px = clr_dt;                       // CLRデータSet
                            sw  = TRUE;                         // 変更有を示す
                        }                                       //
                    }                                           //
                }                                               //
            }                                                   // 
        }                                                       //
        p += inc + 1;                                           // 一つ内側に
        h -= 2;                                                 // 始点と範囲を
        v -= 2;                                                 // 補正
    }                                                           //
}                                                               //

「sw=TRUE;」は、初期化としスィッチON
「while(sw){・・最外側ループ・・}」は、条件「sw」で
スィッチONで繰り返す、そして最外側ループは、
「sw=FALSE;」でループ本体、即、スィッチOFF
「py=p;」は、ラスタースキャン用のY座標方向画像画素
ポインタをセット
「for(y=v;--y>=0;py+=inc){・Y座標方向処理・}」は、
forループ「y=v;--y>=0;py+=inc」で
「y=v;--y>=0;」とダウンカウント方式≪往々にしてこの
記載の方が、コンパイラに依って高速化処理コード生成≫で
垂直径「v」の回数繰り返す、ループ終了時に「py+=inc」と
Y座標方向(垂直方向)にポインタを進行する!そして
Y座標方向処理は、
「px=py;」は、ラスタースキャン用のX座標方向画像画素
ポインタをセット
「if(sw){・・ON時処理・・}else{・・OFF時処理・・
}」は、条件「sw」でON時処理は、
「for(x=h;--x>=0;px++){・X座標方向処理・}」は、
forループ「x=h;--x>=0;px++」で「x=h;--x>=0;」と
ダウンカウント方式≪往々にしてこの記載の方が、
コンパイラに依って高速化処理コード生成≫で水平径「h」
の回数繰り返す、ループ終了時に「px++」とX座標方向
(水平方向)にポインタを進行する!そしてX座標方向処理
は、「if(px>0){・・分岐中身・・}」は、
条件「px>0」と有効画素の場合で処理、その分岐中身は、
「if((px-1)==clr_dt){px=clr_dt;}」と
条件「(px-1)==clr_dt」で左隣「(px-1)」がクリアデータ
の場合は、「px=clr_dt;」と注視点画素をクリア
「else」と左隣がクリアデータ以外ならば、
「if((px-inc)==clr_dt){px=clr_dt;}」と
条件「(px-inc)==clr_dt」で上隣「*(px-inc)」がクリア
データの時、「px=clr_dt;」と注視点画素をクリア
条件「sw」がOFFの時は、
「for(x=h;--x>=0;px++){・X座標方向処理・」は、
forループ「x=h;--x>=0;px++」で「x=h;--x>=0;」と
ダウンカウント方式≪往々にしてこの記載の方が、
コンパイラに依って高速化処理コード生成≫で水平径「h」
の回数繰り返す、ループ終了時に「px++」とX座標方向
(水平方向)にポインタを進行する!そしてX座標方向処理
は、「if(px>0){・・分岐中身・・}」は、
条件「px>0」と有効画素の場合で処理、その分岐中身は、
「if((px-1)==clr_dt){px=clr_dt;sw=TRUE;}」と
条件「(px-1)==clr_dt」で左隣「(px-1)」がクリアデータ
の場合は、「px=clr_dt;」と注視点画素をクリア、そして
「sw=TRUE;」とスィッチON
「else」と左隣がクリアデータ以外ならば、
「if((px-inc)==clr_dt){px=clr_dt;sw=TRUE;}」と
条件「(px-inc)==clr_dt」で上隣「(px-inc)」がクリア
データの時、「*px=clr_dt;」と注視点画素をクリア、
そして「sw=TRUE;」とスィッチON
※備考※この前半部でラスタースキャンが上からの下へ、
左から右へ、スキャンして居る事に留意して下さい!後半の
ラスタースキャンは逆進スキャンです!
「py=p+(v-1)inc+h-1;」は、逆進ラスタースキャン用の
Y座標方向画像画素ポインタをセット
「for(y=v;--y>=0;py-=inc){){・Y座標逆方向処理・}」は
forループ「y=v;--y>=0;py-=inc」で
「y=v;--y>=0;」とダウンカウント方式≪往々にしてこの
記載の方が、コンパイラに依って高速化処理コード生成≫で
垂直径「v」の回数繰り返す、ループ終了時に「py-=inc」と
Y座標方向(垂直方向)にポインタを逆進行する!そして
Y座標方向処理は、
「px=py;」は、ラスタースキャン用のX座標方向画像画素
ポインタをセット
「if(sw){・・ON時処理・・}else{・・OFF時処理・・
}」は、条件「sw」でON時処理は、
「for(x=h;--x>=0;px--){・X座標逆方向処理・}」は、
forループ「x=h;--x>=0;px--」で「x=h;--x>=0;」と
ダウンカウント方式≪往々にしてこの記載の方が、
コンパイラに依って高速化処理コード生成≫で水平径「h」
の回数繰り返す、ループ終了時に「px--」とX座標方向
(水平方向)にポインタを逆進する!そしてX座標方向処理
は、「if(px>0){・・分岐中身・・}」は、
条件「px>0」と有効画素の場合で処理、その分岐中身は、
「if((px+1)==clr_dt){px=clr_dt;}」と
条件「(px+1)==clr_dt」で右隣「(px+1)」がクリアデータ
の場合は、「px=clr_dt;」と注視点画素をクリア
「else」と左隣がクリアデータ以外ならば、
「if((px+inc)==clr_dt){px=clr_dt;}」と
条件「(px+inc)==clr_dt」で下隣「(px+inc)」がクリア
データの時、「px=clr_dt;」と注視点画素をクリア
条件「sw」がOFFの時は、
「for(x=h;--x>=0;px--){・X座標逆方向処理・」は、
forループ「x=h;--x>=0;px--」で「x=h;--x>=0;」と
ダウンカウント方式≪往々にしてこの記載の方が、
コンパイラに依って高速化処理コード生成≫で水平径「h」
の回数繰り返す、ループ終了時に「px--」とX座標方向
(水平方向)にポインタを逆進する!そしてX座標方向処理
は、「if(px>0){・・分岐中身・・}」は、
条件「px>0」と有効画素の場合で処理、その分岐中身は、
「if((px+1)==clr_dt){px=clr_dt;sw=TRUE;}」と
条件「(px+1)==clr_dt」で右隣「(px+1)」がクリアデータ
の場合は、「px=clr_dt;」と注視点画素をクリア、そして
「sw=TRUE;」とスィッチON
「else」と左隣がクリアデータ以外ならば、
「if((px+inc)==clr_dt){px=clr_dt;sw=TRUE;}」と
条件「(px+inc)==clr_dt」で下隣「(px+inc)」がクリア
データの時、「*px=clr_dt;」と注視点画素をクリア、
そして「sw=TRUE;」とスィッチON
ココで後半の逆進ラスタースキャンのfor2重ループを
終え
「p+=inc+1;」は、ラスタースキャンの始点をフェレ図形の
一回り内側のポインタにセット
「h-=2;v-=2;」は、処理する水平垂直の幅を一回り内側に
補正

(4-1)アルゴリズム概要

長々とアルゴリズムの文書での解説を辛抱強く読んで頂き
ありがとうございます!確認の為に概要とし、掻い摘んだ事
も記載します!
メインのwhileループ
「while(sw){・・最外側ループ・・}」での処理が、
画素変更スィッチ「int sw;」ループを処理するが、最初は
内部で「sw=FALSE;」にして正方向ラスタースキャン≪上か
ら下への外側ループと左から右への内側ループ※内側ループ
は、変更スィッチON時とOFF時2種有り≫で
変更スィッチONの時は、
4連結で注視点左隣・上隣が既にクリア済ならば、注視点を
クリアする処理で
変更スィッチOFFの時は、ONの時の処理に比べて注視点
をクリアすると同時に「sw =TRUE;」と変更スィッチをON
にする!
正方向ラスタースキャンの二重ループを終えると次は、
逆方向ラスタースキャン≪下から上への外側ループと
右から左への内側ループ※内側ループは、正方向と同じく
変更スィッチON時とOFF時2種有り≫で変更スィッチ
ONの時は、
4連結で注視点右隣・下隣が既にクリア済ならば、注視点を
クリアする処理で
変更スィッチOFFの時は、ONの時の処理に比べて注視点
をクリアすると同時に「sw =TRUE;」と変更スィッチをON
にする事で逆方向ラスタースキャンの二重ループを終える!
事を詳細の「アルゴリズム」解説で読み取って下さい!
そして正方向・逆方向のラスタースキャンする画像範囲を
「p+=inc+1;h-=2;v-=2;」で一回り内側にしてメインの
whileループを実行する事と理解して下さい!
詰まり、ループ先頭で「sw=FALSE;」と変更スィッチOFF
にして居ますので内部で変更スィッチをONにする処置が
無ければ、ループを終了します!

10.ここの説明は、ここまでとします!


実際に輪郭サーチを実行する
4連結の処理は、「search4fere()」で説明しました?!
これで図形≪4連結でツナガル画像画素の塊≫に対しての
フェレ計測≪図形塊の水平垂直幅や周囲長としての輪郭画素
の画素数等で解説『解説クラスTypeSf』で説明≫等と
基本的な図形の計測方法を解説しました!先ずは、これを
理解して下さい!そして
8連結の処理は、「search8fere()」と成りますが、
次の『この仕事は天職だと感じたアルゴリズム開発(続3)
で説明します!そして図形の面積の計測を
関数「measureBase_area()」、関数「search_area()」の
説明で行います!

文末


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