/*
Copyright (c) 2011, Cryst.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of
      conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of
      conditions and the following disclaimer in the documentation and/or other materials
      provided with the distribution.
    * Neither the name of the Cryst nor the names of its contributors may be used to endorse or
      promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// alloc2D に関しては、下記のヘッダーファイルをインクルードする方法を利用しても良い
allocArray.h

プログラムの説明は、IPFundamentals から確認してください。 By Cryst.

ラベリング処理用の関数群

// 8連結のラベリング処理のメイン部 C言語のソースコード

typedef struct PIXEL { unsigned char B, G, R, A; } PIXEL ;

#define IMAGEPROCESSING labeling // 関数名を定義する
int
IMAGEPROCESSING(PIXEL *src, PIXEL *dst, int wlx, int wly)
{ /** 利用手順 その2:ここに画像処理用の関数を作成する。他の部分は変更せず流用
読み込んだ2値画像の連結性解析(ラベリング)を行い、結果と擬似カラー画像の作成。
読み込んだ画像は、0を背景、0以外の値(数値自体は無視)は対象物と認識する
(カラー画像を入力しても、0とそれ以外の2値画像として処理する事に注意する事) */

#define ucr unsigned char
register int x, y, lx=wlx, ly=wly, i, l=lx*ly, label=1, st=1 ;
register int *s=(int *)src, *d=(int *)dst, llx=lx+2, lly=ly+2, llxy=llx*lly ;
register ucr *img=(ucr *)malloc(llx*lly*sizeof(ucr)) ; // 作業用画像領域の確保 ((wlx+2)*(wly+2))画素分  処理フローの簡略化用
register int *wk =(int *)malloc(llx*lly*sizeof(int)) ; // ラベルデータ用領域の確保 ((wlx+2)*(wly+2))画素分  作業用画像領域対応
register ucr **sa=(ucr **)alloc2D(img, sizeof(ucr), llx, lly) ; // 作業用画像領域を配列としてアクセス可能にする処理
register int **da=(int **)alloc2D( wk, sizeof(int), llx, lly) ; // ラベルデータ用領域を配列としてアクセス可能にする処理

if( (s==NULL) || (d==NULL) || (lx<1) || (ly<1) || (img==NULL) || (wk==NULL) || (sa==NULL) || (da==NULL) ) goto GOOD_BY ;

memset( img, 0, llxy*sizeof(ucr) ) ; // 画像データエリアの初期化   本来の画素数(wlx*wly)より左右上下に1画素大きな領域
memset( wk, 0, llxy*sizeof(int) ) ; // labeling エリアの初期化   作業用領域の画素数(大きさ)は、((wlx+2)*(wly+2))
for( y=1, i=0; y<=ly; y++ ) for( x=1; x<=lx; sa[y][x]=s[i++]==0?0:255, x++ ) ; // 画像を2値化し、作業用領域((wlx+2)*(wly+2))に格納
for( y=1; y<=ly; y++ ) {// 作業用領域中の2値画像を対象としたラベリング処理を行い結果を作業用のラベリングデータ領域に格納
for( x=1; x<=lx; x++ ) {// forループ内の 8連結 の記述のある行(4箇所)をコメントアウト(削除)すれば、4連結のラベリング処理
if( sa[y][x]!=0 ) { // 対象物を構成する画素が見つかった
if(sa[y][x-1]!=0){ da[y][x] = da[ y ][x-1] ; // 4連結の連結性解析部
if(da[y-1][ x ]!=0 && da[y][x]!=da[y-1][ x ]) displacement((int *)wk, da[y][x], da[y-1][ x ], llx*y+x) ; // 4連結でのコンフリクト処理
if(da[y-1][x+1]!=0 && da[y][x]!=da[y-1][x+1]) displacement((int *)wk, da[y][x], da[y-1][x+1], llx*y+x) ; // 8連結でのコンフリクト処理
} else if(sa[y-1][x]!=0){ da[y][x] = da[y-1][ x ] ; // 4連結の連結性解析部
} else if(sa[y-1][x-1]!=0){ da[y][x] = da[y-1][x-1] ; // 8連結の連結性解析部
if(da[y-1][x+1]!=0 && da[y][x]!=da[y-1][x+1]) displacement((int *)wk, da[y][x], da[y-1][x+1], llx*y+x) ; // 8連結でのコンフリクト処理
} else if(sa[y-1][x+1]!=0){ da[y][x] = da[y-1][x+1] ; // 8連結の連結性解析部
} else da[y][x] = label++ ; // 新規ラベル番号の割り当て(処理済みのデータとは連結性を持たない)
}
}
}
for( y=1, i=0; y<=ly; y++ ) for( x=1; x<=lx; d[i++]=da[y][x++] ) ; // 本来のバッファー(ラベルデータ用)にデータを格納(wlx*wly)

// 以下の4行は、リラベリング処理 不要なら省略可能。 その後の処理(領域を統合や、領域の削除処理)により、虫食い状態が再度生じる為
memset( wk, 0, label*sizeof(int) ) ; // for( i=0; i<label; wk[i++]=0 ) ; と同じ処理結果(memset関数の処理速度の方が速い)
for( i=0; i<l; wk[d[i++]]=1 ) ; // 使用されて有効なラベル番号の抽出
for( i=1, x=1, wk[0]=0; i<label; i++ ) if( wk[i]!=0 ) wk[i] = x++ ; // 再番処理用のルックアップテーブルの作成
for( i=0; i<l; d[i]=wk[d[i]], i++ ) ; // 虫食い状態のラベル番号を、連続したラベル番号に変換

#define CFGFINALFNAMEIS(fname) #fname // labeling.cfg -> "labeling.cfg"
#define CFGEXTRACTING(fname) CFGFINALFNAMEIS(fname.cfg) // labeling -> labeling.cfg
#define CFGNAMEIS(fname) CFGEXTRACTING(fname) // IMAGEPROCESSING -> labeling
saveRawLabelConf( CFGNAMEIS(IMAGEPROCESSING), lx, ly ) ; // ラベルデータのサイズ情報を保存します。

#define LBLFINALFNAMEIS(fname) #fname // labeling.lbl -> "labeling.lbl"
#define LBLEXTRACTING(fname) LBLFINALFNAMEIS(fname.lbl) // labeling -> labeling.lbl
#define LBLNAMEIS(fname) LBLEXTRACTING(fname) // IMAGEPROCESSING -> labeling
saveRawLabelData( LBLNAMEIS(IMAGEPROCESSING), d, lx, ly ) ; // ラベルデータ(dst)を保存します。

for( i=0; i<l; i++ ) d[i]=int2PseudoColor(d[i]) ; // labelエリアのラベル番号を擬似カラー画像データに変換
st = 0 ;
GOOD_BY: free(da) ; free(sa) ; free(wk) ; free(img) ;
return st ;
}

// 同一対象物に異なる番号が与えられてしまった時の統合処理。(ラベリング処理の補助処理部)

inline void displacement( int *lbl, int a, int b, int len )
{/** 同一のラベル番号を持つべき領域が異なるラベル番号を持つているので、小さい値に統一する */
register int *l=lbl, fair=a<b?a:b, misguided=a<b?b:a, i, s=len ;

for( i=0; i<=s; i++ ) if( l[i]==misguided ) l[i]=fair ;
}

// その他のラベリング処理関連関数

// ラベルデータのサイズ情報を保存します。(本ホームページで提供する形式との互換性確保用)
int saveRawLabelConf(  char *fname, int lx, int ly )

// ラベルデータを保存します。(本ホームページで提供する形式との互換性確保用)
int saveRawLabelData( char *fname, void *dst, int lx, int ly )

// ラベルデータを擬似カラーデータに変換します。(本ホームページで提供する形式との互換性確保用)
unsigned int  int2PseudoColor(unsigned int v)

go to TopPage go to CategoryTop