この仕事は天職だと感じたアルゴリズム開発(続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;」は、仮想原点≪原点の左隣≫をセット
「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()」の
説明で行います!