この仕事は天職だと感じたアルゴリズム開発(続3)
この仕事は天職だと感じたアルゴリズム開発(続3)
2024年12月14日初稿
このエッセイは、
『この仕事は天職だと感じたアルゴリズム開発(続2)』の
直接の続編です!
1.図形個別のフェレ計測8連結search8fere()
/****************************************************************************/
/***** 図形のフェレ計測:処理部:ラベル個別のフェレ計測 *****/
/***** 時計回りに輪郭を追跡します *****/
/***** まず、仮想原点として原点の左隣から処理を始めます。 *****/
/***** 終了条件は、仮想原点をサーチした時とします。 *****/
/***** ☆注意:仮想原点を使用するのは、方向サーチを孤立点の時に無 *****/
/***** 限ループにしないためです。 *****/
/***** ☆注意:dir_off[]を使用して8連結で時計回りにサーチ *****/
/***** dir_off[0..7] = 右・右下・下・左下・左・左上・上・右上の *****/
/***** 方向のオフセット *****/
/***** ☆注意:方向オフセットが、サーチ成功時→戻し、失敗時1つ進 *****/
/***** める事により、処理ポインタを更新し輪郭を追尾します *****/
/***** 8連結なので2方向分戻します *****/
/***** ☆注意:画素は、0・正・負と3つに分けて、正の値の画素を追 *****/
/***** 跡します *****/
/***** 注:メモリのサイズもここで変更した分を返します。 *****/
/***** 返値:追跡点履歴Buffer(Overした場合は付け替えした新規メモリ) *****/
/****************************************************************************/
char** Filter::search8fere(
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, 1, 0, -1, -1, -1, 0, 1 // 標の変位
}; //
static const int tbly[] = { // 方向に対するy座
0, 1, 1, 1, 0, -1, -1, -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 len1; // 周囲長:縦横
int len2; // 周囲長:斜め
int dir; // 方向 0..7
// 0:右, 1:右下
// 2:下, 3:左下
// 4:左, 5:左上
// 6:上, 7:右上
int inc; // インクリ幅
pbufptr = bufptr; // 履歴BufferptrSet
n = size - 3; // 履歴制限数初期値
buf->xl = x; // Labelx座標格納
buf->y = y; // Labely座標格納
ptemp = p; // 原点を保存
pp = p + dir_off[ 5 ]; // 仮想原点をセット
dir = 0; // 初期値=右
min_x = x; // x座標の最小/最
max_x = x; // 大値を初期化
max_y = y; // y最大座標初期化
len1 = 0; // 縦横成分の初期化
len2 = 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; // 更新
} //
if( ( dir & 0x01 ) == 0 ){ // 縦横成分なら
len1++; // 縦横成分計数UP
}else{ // 斜め成分なら
len2++; // 斜め成分計数UP
} //
dir = ( dir - 2 ) & 0x07; // 方向を二つ戻す
}else{ // なければ
dir = ( dir + 1 ) & 0x07; // 方向を進める
} //
} //
*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( len1 == 0 && len2 == 0 ){ // 連結数=0の時は
len1 = 1; // 1に補正
} //
buf->len = len1 + (int)( // 周囲長算出格納
(double)len2 * 1.41421356 + 0.5 ); // 縦+√2×横成分
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[2]; // インクリ幅を取出
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[2]; // インクリ幅を取出
search_clear_ud( bufptr, inc, clr_dt ); // 輪郭+上下 クリア
}else{ // 5×5以上なら
inc = dir_off[2]; // インクリ幅を取出
if( m_swMeasureBorder ){ // 「真→輪郭線図形計測」時
search_clear_round( bufptr, inc, clr_dt ); // 輪郭+周辺をクリア
}else{ // 「偽→任意図形」時
search_clear( bufptr, clr_dt ); // 輪郭をクリア
p = ptemp - buf->xl + min_x + inc + 1; // 一回内側始点算出
search8clear_base( p, h - 2, v - 2, inc, // Labeling手法でCLR
clr_dt ); //
} //
} //
return( bufptr ); // 正常終了
}
(1)関数名
「search」は、カタカナ語「サーチ」でココでは、図形を
サーチする意味
「8」は、「8連結」を意味
「fere」は、「フェレ計測」を意味
だから、「search8fere」でフェレ計測様に8連結図形を
サーチするを意味します!
(2)仮引数
char** Filter::search8fere(
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::search8fere()」と関数辺値の型は
「char**」と追跡点履歴バッファー自身を関数辺値とし
返します≪内部でバッファーサイズがオーバーした場合に
新たにバッファーを拡大する為です!≫
(3)ローカル変数
){
static const int tblx[] = { // 方向に対するx座
1, 1, 0, -1, -1, -1, 0, 1 // 標の変位
}; //
static const int tbly[] = { // 方向に対するy座
0, 1, 1, 1, 0, -1, -1, -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 len1; // 周囲長:縦横
int len2; // 周囲長:斜め
int dir; // 方向 0..7
// 0:右, 1:右下
// 2:下, 3:左下
// 4:左, 5:左上
// 6:上, 7:右上
int inc; // インクリ幅
「static const int tblx[]={1,1,0,-1,-1,-1,0,1};」は、
X座標位置進行テーブル≪添字を「int dir;」の周回方向
カウンタでの位置情報変換テーブル≫
「static const int tbly[]={0,1,1,1,0,-1,-1,-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座標最大値≪フェレ計測X終点計測用
≫
「int h;」は、水平フェレ径≪max_x-min_x+1;≫
「int v;」は、水平フェレ径≪max_y-min_y+1;≫
「int len1;」は、周囲長≪縦横ツナガリ画素数≫
「int len2;」は、周囲長≪斜め隣ツナガリ画素数≫
※備考※斜めは長さとして√2を計測値とし乗算します!
「int dir;」は、周回方向カウンタ≪0..7の間をリングカウ
ンタとし方向「0:右、1:右下、2:下、3:左下、4:左、
5:左上、6:上、7:右上」≫
「int inc;」は、インクリメント幅≪画像画素を垂直方向に
ポインタ移動用の増加幅≫
(4)アルゴリズム
pbufptr = bufptr; // 履歴BufferptrSet
n = size - 3; // 履歴制限数初期値
buf->xl = x; // Labelx座標格納
buf->y = y; // Labely座標格納
ptemp = p; // 原点を保存
pp = p + dir_off[ 5 ]; // 仮想原点をセット
dir = 0; // 初期値=右
min_x = x; // x座標の最小/最
max_x = x; // 大値を初期化
max_y = y; // y最大座標初期化
len1 = 0; // 縦横成分の初期化
len2 = 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; // 更新
} //
if( ( dir & 0x01 ) == 0 ){ // 縦横成分なら
len1++; // 縦横成分計数UP
}else{ // 斜め成分なら
len2++; // 斜め成分計数UP
} //
dir = ( dir - 2 ) & 0x07; // 方向を二つ戻す
}else{ // なければ
dir = ( dir + 1 ) & 0x07; // 方向を進める
} //
} //
*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( len1 == 0 && len2 == 0 ){ // 連結数=0の時は
len1 = 1; // 1に補正
} //
buf->len = len1 + (int)( // 周囲長算出格納
(double)len2 * 1.41421356 + 0.5 ); // 縦+√2×横成分
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[2]; // インクリ幅を取出
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[2]; // インクリ幅を取出
search_clear_ud( bufptr, inc, clr_dt ); // 輪郭+上下 クリア
}else{ // 5×5以上なら
inc = dir_off[2]; // インクリ幅を取出
if( m_swMeasureBorder ){ // 「真→輪郭線図形計測」時
search_clear_round( bufptr, inc, clr_dt ); // 輪郭+周辺をクリア
}else{ // 「偽→任意図形」時
search_clear( bufptr, clr_dt ); // 輪郭をクリア
p = ptemp - buf->xl + min_x + inc + 1; // 一回内側始点算出
search8clear_base( p, h - 2, v - 2, inc, // Labeling手法でCLR
clr_dt ); //
} //
} //
return( bufptr ); // 正常終了
}
「dir=0;」は、追跡方向を「0=右側」にセット
「min_x=x;max_x=x;max_y=y;」は、計測対象のX座標最小
最大値及びY座標最大値を初期化
「len1=0;len2=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)&0x07;}」は、
条件「*p1>0」で有効画素(正の値)なら、以下に説明する
処理で図形≪8連結での塊≫を計測し、「else」詰まり無効
画素の場合で
「dir=(dir+1)&0x07;」と方向「dir」を示す値を更新≪
「dir+1」でカウントアップ≪「+1」と進行する事で【時計
回り方向「右⇒右下⇒下⇒左下⇒左⇒左上⇒上⇒右上】の
次へ≫、「&0x07」で
※ビット毎の論理積(AND演算)とビット毎論理式に馴染
まない人への解説【C言語算術演算で書き換えると
「(dir+1)%8;」と8で除算した余りと成りますが、多くの
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座標最大値更新
「if((dir&0x01)==0){len1++;}else{len2++;}」は、周囲長
≪条件「(dir&0x01)==0」で※ビット毎の論理積(
AND演算)とビット毎論理式に馴染まない人への解説
【C言語算術演算で書き換えると「(dir+1)%2;」と2で除算
した余りと成りますが、多くのCPUでは高速化手法として
使用出来ます】で偶奇判定で偶数が縦横直交画素数なので
「len1++;」で処理・奇数が斜め方向画素数なので
「len2++;」で処理≫でそれぞれカウントアップ!
「dir=(dir-2)&0x07;」は、「dir」を示す値を変更「二つ戻
す」≪「dir-2」でカウントダウン≪「-2」と逆進する事で
【反時計回り方向「上⇒左上⇒左⇒左下⇒下⇒右下⇒右⇒
左上」】の次へ≫、
「&0x07」で※ビット毎の論理積(AND演算)とビット毎
論理式に馴染まない人への解説【C言語算術演算で書き換え
ると「(dir-1)%8;」と8で除算した余りと成りますが、
多くの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(len1==0&&len2==0){len1=1;}」は、周囲長≪画素数≫が
0なら、「len=1;」としてセット
「buf->len=len1+(int)((double)len*21.41421356+0.5);」
は、計測値として周囲長を
算出「len1+(int)((double)len*21.41421356+0.5)」して、
※備考※「(double)len*21.41421356+0.5)」と斜め画素連結
は、√2≒1.41421356を乗算し「+0.5」と四捨五入用の値を
付加して「(int)((double)len*21.41421356+0.5);」と四捨
五入した整数値とし、「buf->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[2];
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[2];」で画像の増加幅を取り出し、下請け
関数「search_clear_ud(bufptr,inc,clr_dt);」で図形を
クリア
「else{・・5×5以上図形をクリア・・」は、
「inc=dir_off[2];」で画像の増加幅を取り出し、
「if(m_swMeasureBorder){
search_clear_round(bufptr,inc,clr_dt);
」で条件「m_swMeasureBorder」でこのスイッチが真の場合
は、下請け関数「search_clear_round(bufptr,inc,clr_dt);
」で図形をクリア、
「else{
search_clear(bufptr,clr_dt);
p=ptemp-buf->xl+min_x+inc+1;
search8clear_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;」で図形画像の一回り
内側の始点をセットし、下請け関数
「search8clear_base(p,h-2,v-2,inc,clr_dt);」で
図形をクリア
「return(bufptr);」は、追跡点履歴バッファーのポインタ
を関数辺値とし返し終了
2.輪郭のクリア+1周クリア
search_clear_round()
/************************************************************************/
/***** 図形のフェレ計測:処理部:輪郭のクリア+1周クリア *****/
/***** 輪郭線を履歴バッファーを使用してクリアすると共に *****/
/***** 輪郭の上下左右斜めに正のデータがあればクリアする *****/
/***** クリアは、-1 か -2 でクリア *****/
/***** 8連結で「輪郭」や「線分」図形が対象 *****/
/************************************************************************/
void Filter::search_clear_round(
char **pbufptr, // 追跡点履歴 Ptr
int inc, // インクリメント幅
int clr_dt // クリアデータ
){
char *p; // 書き込みポインタ
char *p1; // 書き込みポインタ:隣
while( ( p = *pbufptr++ ) != 0 ){ // ポインタを取出し
*p = clr_dt; // 輪郭点をクリアし
p1 = p - inc - 1; // 左上セット
if( *p1 > 0 ){ // 左上隣が正なら
*p1 = clr_dt; // クリア
} //
p1++; // 上に移動
if( *p1 > 0 ){ // 上隣が正なら
*p1 = clr_dt; // クリア
} //
p1++; // 右上に移動
if( *p1 > 0 ){ // 右上隣が正なら
*p1 = clr_dt; // クリア
} //
p1 = p - 1; // 左セット
if( *p1 > 0 ){ // 左隣が正なら
*p1 = clr_dt; // クリア
} //
p1 = p + 1; // 右セット
if( *p1 > 0 ){ // 右隣が正なら
*p1 = clr_dt; // クリア
} //
p1 = p + inc - 1; // 左下セット
if( *p1 > 0 ){ // 左下隣が正なら
*p1 = clr_dt; // クリア
} //
p1++; // 下に移動
if( *p1 > 0 ){ // 下隣が正なら
*p1 = clr_dt; // クリア
} //
p1++; // 右下に移動
if( *p1 > 0 ){ // 右下隣が正なら
*p1 = clr_dt; // クリア
} //
} //
}
(1)関数名
「search」は、カタカナ語「サーチ」でココでは、図形を
サーチする意味でココではサーチした履歴バッファー
「clear」は、「クリア」消去を意味
「round」は、「1周」を意味≪作成時は恐らく苦し紛れの
命名です私は英単語は苦手なのだ!≫
だから、「search_clear_round」で輪郭のクリア+
1周クリアと無理な命名をしました!
(2)仮引数
void Filter::search_clear_round(
char **pbufptr, // 追跡点履歴 Ptr
int inc, // インクリメント幅
int clr_dt // クリアデータ
){
「char**pbufptr,」は、追跡点履歴バッファー
「int inc,」は、画像の垂直方向増加幅、
「int clr_dt」は、輪郭画素をクリアするデータ
(3)ローカル変数
){
char *p; // 書き込みポインタ
char *p1; // 書き込みポインタ:隣
「char *p;」は、画素書き込みポインタ
「char *p1」は、画素書き込みポインタ隣
(4)アルゴリズム
while( ( p = *pbufptr++ ) != 0 ){ // ポインタを取出し
*p = clr_dt; // 輪郭点をクリアし
p1 = p - inc - 1; // 左上セット
if( *p1 > 0 ){ // 左上隣が正なら
*p1 = clr_dt; // クリア
} //
p1++; // 上に移動
if( *p1 > 0 ){ // 上隣が正なら
*p1 = clr_dt; // クリア
} //
p1++; // 右上に移動
if( *p1 > 0 ){ // 右上隣が正なら
*p1 = clr_dt; // クリア
} //
p1 = p - 1; // 左セット
if( *p1 > 0 ){ // 左隣が正なら
*p1 = clr_dt; // クリア
} //
p1 = p + 1; // 右セット
if( *p1 > 0 ){ // 右隣が正なら
*p1 = clr_dt; // クリア
} //
p1 = p + inc - 1; // 左下セット
if( *p1 > 0 ){ // 左下隣が正なら
*p1 = clr_dt; // クリア
} //
p1++; // 下に移動
if( *p1 > 0 ){ // 下隣が正なら
*p1 = clr_dt; // クリア
} //
p1++; // 右下に移動
if( *p1 > 0 ){ // 右下隣が正なら
*p1 = clr_dt; // クリア
} //
} //
}
「while((p=*pbufptr++)!=0){・・ループ本体・・}」は、
ループ条件「(p=*pbufptr++)!=0」で「p=*pbufptr++」で
画素書き込みポインタを取り出し、
条件「(p=*pbufptr++)!=0」で空ポインタ≪バッファーの
最後を番兵とし空ポインタをセットして有る≫で無い場合は
ループ本体を繰り返し、ループ本体は、
「*p=clr_dt;」で画像画素をクリア≪仮引数「int clr_dt」
を書き込む≫
「p1=p-inc-1;」で左上隣を書き込みポインタにセット
「if(*p1>0){*p1=clr_dt;}」で条件「*p1>0」で有効画素な
ら、「*p1=clr_dt;」と画像画素をクリア
「p1++;」で書き込みポインタを上隣に移動
「if(*p1>0){*p1=clr_dt;}」で条件「*p1>0」で有効画素な
ら、「*p1=clr_dt;」と画像画素をクリア
「p1++;」で書き込みポインタを右上隣に移動
「if(*p1>0){*p1=clr_dt;}」で条件「*p1>0」で有効画素な
ら、「*p1=clr_dt;」と画像画素をクリア
「p1=p-1;」で左隣を書き込みポインタにセット
「if(*p1>0){*p1=clr_dt;}」で条件「*p1>0」で有効画素な
ら、「*p1=clr_dt;」と画像画素をクリア
「p1=p+1;」で右隣を書き込みポインタにセット
「if(*p1>0){*p1=clr_dt;}」で条件「*p1>0」で有効画素な
ら、「*p1=clr_dt;」と画像画素をクリア
「p1=p+inc-1;」で左下を書き込みポインタにセット
「if(*p1>0){*p1=clr_dt;}」で条件「*p1>0」で有効画素な
ら、「*p1=clr_dt;」と画像画素をクリア
「p1++;」で書き込みポインタを下隣に移動
「if(*p1>0){*p1=clr_dt;}」で条件「*p1>0」で有効画素な
ら、「*p1=clr_dt;」と画像画素をクリア
「p1++;」で書き込みポインタを右下隣に移動
「if(*p1>0){*p1=clr_dt;}」で条件「*p1>0」で有効画素な
ら、「*p1=clr_dt;」と画像画素をクリア
3.簡易ラベリングで8連結クリアsearch8clear_base()
/************************************************************************/
/***** 図形のフェレ計測:8連結: 図形のフェレ範囲内で *****/
/***** :簡易ラベリングを使用 *****/
/***** クリアは、対象図形の輪郭をクリアデータでクリアしてるものとし*****/
/***** 対象画素をクリアします。 *****/
/***** フェレ径 H × V = 5 × 5 以上が対象 *****/
/************************************************************************/
void Filter::search8clear_base(
char *p, // フェレ始点
int h, // 水平フェレ径
int v, // 垂直フェレ径
int inc, // 増加幅
int clr_dt // クリアデータ
){
char *px; // 追跡点:水平
char *py; // 追跡点:垂直
char *p1; // 追跡点:上下
char c; // データ
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{ // それ以外
p1 = px - inc - 1; // 左上をセット
c = *p1++; // 左上を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
}else{ // 非連結ならば
c = *p1++; // 上を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
}else{ // 非連結ならば
c = *p1; // 右上を取出し
if( c == 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{ // それ以外
p1 = px - inc - 1; // 左上をセット
c = *p1++; // 左上を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
sw = TRUE; // 変更有を示す
}else{ // 非連結ならば
c = *p1++; // 上を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
sw = TRUE; // 変更有を示す
}else{ // 非連結ならば
c = *p1; // 右上を取出し
if( c == 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{ // それ以外
p1 = px + inc - 1; // 左下をセット
c = *p1++; // 左下を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
}else{ // 非連結ならば
c = *p1++; // 下を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
}else{ // 非連結ならば
c = *p1; // 右下を取出し
if( c == 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{ // それ以外
p1 = px + inc - 1; // 左下をセット
c = *p1++; // 左下を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
sw = TRUE; // 変更有を示す
}else{ // 非連結ならば
c = *p1++; // 下を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
sw = TRUE; // 変更有を示す
}else{ // 非連結ならば
c = *p1; // 右下を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
sw = TRUE; // 変更有を示す
} //
} //
} //
} //
} //
} //
} //
} //
p += inc + 1; // 一つ内側に
h -= 2; // 始点と範囲を
v -= 2; // 補正
} //
} //
(1)関数名
code:
「search」は、カタカナ語「サーチ」でココでは、図形を
サーチする意味でココではサーチした履歴バッファー
「8」は、8連結を意味で「search8」で8連結サーチ
「clear」は、「クリア」消去を意味
「base」は基本を意味
だから、「search8clear_base」で輪郭座標サーチデータで
輪郭とその中を8連結でクリア
(2)仮引数
void Filter::search8clear_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; // 追跡点:垂直
char *p1; // 追跡点:上下
char c; // データ
int x; // 水平方向Cnt
int y; // 垂直方向Cnt
int sw; // 変更有Switch
「char* px;」は、フェレ径内画像をラスタースキャンする
X座標方向作業ポインタ
「char* py;」は、フェレ径内画像をラスタースキャンする
Y座標方向作業ポインタ
「char* p1;」は、追跡点作業ポインタ
Y座標方向作業ポインタ
「char c;」は、画素データ
「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{ // それ以外
p1 = px - inc - 1; // 左上をセット
c = *p1++; // 左上を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
}else{ // 非連結ならば
c = *p1++; // 上を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
}else{ // 非連結ならば
c = *p1; // 右上を取出し
if( c == 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{ // それ以外
p1 = px - inc - 1; // 左上をセット
c = *p1++; // 左上を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
sw = TRUE; // 変更有を示す
}else{ // 非連結ならば
c = *p1++; // 上を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
sw = TRUE; // 変更有を示す
}else{ // 非連結ならば
c = *p1; // 右上を取出し
if( c == 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{ // それ以外
p1 = px + inc - 1; // 左下をセット
c = *p1++; // 左下を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
}else{ // 非連結ならば
c = *p1++; // 下を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
}else{ // 非連結ならば
c = *p1; // 右下を取出し
if( c == 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{ // それ以外
p1 = px + inc - 1; // 左下をセット
c = *p1++; // 左下を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
sw = TRUE; // 変更有を示す
}else{ // 非連結ならば
c = *p1++; // 下を取出し
if( c == clr_dt ){ // 連結ならば
*px = clr_dt; // CLRデータSet
sw = TRUE; // 変更有を示す
}else{ // 非連結ならば
c = *p1; // 右下を取出し
if( c == 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
ここから、暫く、正方向ラスタースキャン≪外側ループと
してのY座標方向は上から下、内側のX座標方向は左から
右へ≫を二重ループとし処理します!
「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」と左隣がクリアデータ以外ならば、
「p1=px-inc-1;」で追跡点ポインタを左上にセットし、
「c=*p1++;」で左上画素データを取り出し、ポインタを上に
進行
「if(c==clr_dt){*px=clr_dt;}」で追跡点(左上)が
クリアデータなら「*px=clr_dt;」と注視点をクリア
「else{・・条件不成立・・」と追跡点(左上)がクリア
データ以外なら
「c=*p1++;」で上画素データを取り出し、ポインタを右上に
進行
「if(c==clr_dt){*px=clr_dt;}」で追跡点(上)がクリア
データなら「*px=clr_dt;」と注視点をクリア
「else{c=*p1;if(c==clr_dt){*px=clr_dt;}}」で
追跡点(上)がクリアデータ以外なら
「c=*p1;」で右上画素データを取り出し、
「if(c==clr_dt){*px=clr_dt;}」で追跡点(右上)が
クリアデータなら「*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」と左隣がクリアデータ以外ならば、
「p1=px-inc-1;」で追跡点ポインタを左上にセットし、
「c=*p1++;」で左上画素データを取り出し、ポインタを上に
進行
「if(c==clr_dt){*px=clr_dt;sw=TRUE;}」で
追跡点(左上)がクリアデータなら「*px=clr_dt;」と
注視点をクリアし、「sw=TRUE;」とスィッチON
「else{・・条件不成立・・」と追跡点(左上)がクリア
データ以外なら
「c=*p1++;」で上画素データを取り出し、ポインタを上に
進行
「if(c==clr_dt){*px=clr_dt;sw=TRUE;}」で追跡点(上)が
クリアデータなら「*px=clr_dt;」と注視点をクリアし、
「sw=TRUE;」とスィッチON
「else{c=*p1;if(c==clr_dt){*px=clr_dt;sw=TRUE;}}」で
追跡点(下)がクリアデータ以外なら
「c=*p1;」で右下画素データを取り出し、
「if(c==clr_dt){*px=clr_dt;sw=TRUE;}」で
追跡点(右下)がクリアデータなら「*px=clr_dt;」と
注視点をクリアし、「sw=TRUE;」とスィッチON
「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」と左隣がクリアデータ以外ならば、
「p1=px-inc-1;c=*p1++;」で追跡点を左上側にセットし、
画素データ取り出し追跡点を上側に進行、
「if(c==clr_dt){*px=clr_dt;}」で左上隣「c」がクリア
データの場合は、「*px=clr_dt;」と注視点画素をクリア
「else」と左上隣がクリアデータ以外ならば、
「c=*p1++;」で上側画素データ取り出し追跡点を右上側に
進行、「if(c==clr_dt){*px=clr_dt;}」で上隣「c」が
クリアデータの場合は、「*px=clr_dt;」と注視点画素を
クリア
「else」と上隣がクリアデータ以外ならば、
「c=*p1;」で右上側画素データ取り出し、
「if(c==clr_dt){*px=clr_dt;}」で右上隣「c」がクリア
データの場合は、「*px=clr_dt;」と注視点画素をクリアと
X座標方向の内側ループを終え、
条件「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」と左隣がクリアデータ以外ならば、
「p1=px-inc-1;c=*p1++;」で追跡点を左上側にセットし、
画素データ取り出し追跡点を上側に進行、
「if(c==clr_dt){*px=clr_dt;sw=TRUE;}」で左上隣「c」が
クリア、スイッチをONにセット
データの場合は、「*px=clr_dt;」と注視点画素をクリア
「else」と左上隣がクリアデータ以外ならば、
「c=*p1++;」で上側画素データ取り出し追跡点を右上側に
進行、「if(c==clr_dt){*px=clr_dt;sw=TRUE;}」で
上隣「c」がクリアデータの場合は、「*px=clr_dt;」と
注視点画素をクリア、スイッチをONにセット
「else」と上隣がクリアデータ以外ならば、
「c=*p1;」で右上側画素データ取り出し、
「if(c==clr_dt){*px=clr_dt;sw=TRUE;}」で右上隣「c」が
クリア、スイッチをONにセット
データの場合は、「*px=clr_dt;」と注視点画素をクリアと
X座標方向の内側ループを終えとスイッチON/OFF両方
の処理を終える事で正方向ラスタースキャンを終了!
今度は、暫く、逆方向ラスタースキャン≪外側ループと
してのY座標方向は下から、上に内側のX座標方向は右から
左へ≫を二重ループとし処理します!
「py=p+(v-1)*inc+h-1;」は、ラスタースキャン用のY座標
方向画像画素ポインタ()右下隅をセット
forループ「for(y=v;--y>=0;py-=inc){・
Y座標方向処理・}」は、
「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」と右隣がクリアデータ以外ならば、
「p1=px+inc-1;」で追跡点ポインタを左下にセットし、
「c=*p1++;」で左下画素データを取り出し、ポインタを下に
進行
「if(c==clr_dt){*px=clr_dt;}」で追跡点(左下)が
クリアデータなら「*px=clr_dt;」と注視点をクリア
「else{・・条件不成立・・」と追跡点(左下)がクリア
データ以外なら
「c=*p1++;」で下画素データを取り出し、ポインタを右下に
進行
「if(c==clr_dt){*px=clr_dt;}」で追跡点(下)がクリア
データなら「*px=clr_dt;」と注視点をクリア
「else{c=*p1;if(c==clr_dt){*px=clr_dt;}}」で
追跡点(下)がクリアデータ以外なら
「c=*p1;」で右下画素データを取り出し、
「if(c==clr_dt){*px=clr_dt;}」で追跡点(右下)が
クリアデータなら「*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;」と注視点画素をクリア
「else」と右隣がクリアデータ以外ならば、
「p1=px+inc-1;」で追跡点ポインタを左下にセットし、
「c=*p1++;」で左下画素データを取り出し、ポインタを下に
進行
「if(c==clr_dt){*px=clr_dt;sw=TRUE;}」で追跡点(左下)
がクリアデータなら「*px=clr_dt;」と注視点をクリアし、
「sw=TRUE;」でとスィッチON
「else{・・条件不成立・・」と追跡点(左下)がクリア
データ以外なら
「c=*p1++;」で下画素データを取り出し、ポインタを右下に
進行
「if(c==clr_dt){*px=clr_dt;sw=TRUE;}」で追跡点(下)が
クリアデータなら「*px=clr_dt;」と注視点をクリア、
「sw=TRUE;」でとスィッチON
「else{c=*p1;if(c==clr_dt){*px=clr_dt;sw=TRUE;}}」で
追跡点(下)がクリアデータ以外なら
「c=*p1;」で右下画素データを取り出し、
「if(c==clr_dt){*px=clr_dt;sw=TRUE;}」で追跡点(右下)
がクリアデータなら「*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の時は、
8連結で注視点隣が既にクリア済ならば、注視点をクリア
する処理で変更スィッチOFFの時は、ONの時の処理に比
べて注視点をクリアすると同時に「sw =TRUE;」と変更
スィッチをONにする事で逆方向ラスタースキャンの
二重ループを終える!
事を詳細の「アルゴリズム」解説で読み取って下さい!
そして正方向・逆方向のラスタースキャンする画像範囲を
「p+=inc+1;h-=2;v-=2;」で一回り内側にしてメインの
whileループを実行する事と理解して下さい!
詰まり、ループ先頭で「sw=FALSE;」と変更スィッチOFF
にして居ますので内部で変更スィッチをONにする処置が
無ければ、ループを終了します!
フェレ計測での8連結の処理は、「search8fere()」と成り
ここまで説明しましたが、分量が多いので一旦、ここまでと
して続きの面積・一次モーメント・重心座標等の処理は、
次の『この仕事は天職だと感じたアルゴリズム開発(続4)
』で説明します!