/* * $Id: spm_bwlabel.c 4929 2012-09-17 14:21:01Z guillaume $ * Jesper Andersson */ /**************************************************************** ** ** Set of routines implementing a 2D or 3D connected component ** labelling algorithm. Its interface is modelled on bwlabel ** (which is a routine in the image processing toolbox) and ** takes as input a binary image and (optionally) a connectednes ** criterion (6, 18 or 26, in 2D 6 will correspond to 4 and 18 ** and 26 to 8). It will output an image/volume where each ** connected component will have a unique label. ** ** The implementation is not recursive (i.e. will no crash for ** large connected components) and is losely based on ** Thurfjell et al. 1992, A new three-dimensional connected ** components labeling algorithm with simultaneous object ** feature extraction capability. CVGIP: Graphical Models ** and Image Processing 54(4):357-364. ** ***************************************************************/ #include #include #include #include "mex.h" /* Macros */ #define index(A,B,C,DIM) ((C)*DIM[0]*DIM[1] + (B)*DIM[0] + (A)) #ifndef MIN #define MIN(A,B) ((A) > (B) ? (B) : (A)) #endif #ifndef MAX #define MAX(A,B) ((A) > (B) ? (A) : (B)) #endif /* fill_tratab */ void fill_tratab(unsigned int *tt, /* Translation table */ unsigned int ttn, /* Size of translation table */ unsigned int *nabo, /* Set of neighbours */ unsigned int nr_set) /* Number of neighbours in nabo */ { int i = 0, j = 0, cntr = 0; unsigned int tn[9]; unsigned int ltn = UINT_MAX; /* Find smallest terminal number in neighbourhood */ for (i=0; i100) {printf("\nOoh no!!"); break;} } tn[i] = j; ltn = MIN(ltn,j); } /* Replace all terminal numbers in neighbourhood by the smallest one */ for (i=0; i= 6) { if ((l = il[index(r,c,sl-1,dim)])) {nabo[nr_set++] = l;} } if (conn >= 18) { if (r) {if ((l = il[index(r-1,c,sl-1,dim)])) {nabo[nr_set++] = l;}} if (c) {if ((l = il[index(r,c-1,sl-1,dim)])) {nabo[nr_set++] = l;}} if (r < dim[0]-1) {if ((l = il[index(r+1,c,sl-1,dim)])) {nabo[nr_set++] = l;}} if (c < dim[1]-1) {if ((l = il[index(r,c+1,sl-1,dim)])) {nabo[nr_set++] = l;}} } if (conn == 26) { if (r && c) {if ((l = il[index(r-1,c-1,sl-1,dim)])) {nabo[nr_set++] = l;}} if ((r < dim[0]-1) && c) {if ((l = il[index(r+1,c-1,sl-1,dim)])) {nabo[nr_set++] = l;}} if (r && (c < dim[1]-1)) {if ((l = il[index(r-1,c+1,sl-1,dim)])) {nabo[nr_set++] = l;}} if ((r < dim[0]-1) && (c < dim[1]-1)) {if ((l = il[index(r+1,c+1,sl-1,dim)])) {nabo[nr_set++] = l;}} } if (nr_set) { fill_tratab(tt,ttn,nabo,nr_set); return(nabo[0]); } else {return(0);} } /* do_initial_labelling */ unsigned int do_initial_labelling(double *bw, /* Binary map */ mwSize *dim, /* Dimensions of bw */ unsigned int conn, /* Connectivity criterion */ unsigned int *il, /* Initially labelled map */ unsigned int **tt) /* Translation table */ { unsigned int i = 0, j = 0; unsigned int nabo[8]; unsigned int label = 1; unsigned int nr_set = 0; unsigned int l = 0; mwIndex sl, r, c; unsigned int ttn = 1000; *tt = (unsigned int *) mxCalloc(ttn,sizeof(unsigned int)); for (sl=0; sl= 6) { if (r) { if ((l = il[index(r-1,c,sl,dim)])) {nabo[nr_set++] = l;} } if (c) { if ((l = il[index(r,c-1,sl,dim)])) {nabo[nr_set++] = l;} } } /* For 18(edge)-connectivity N.B. In current slice no difference to 26. */ if (conn >= 18) { if (c && r) { if ((l = il[index(r-1,c-1,sl,dim)])) {nabo[nr_set++] = l;} } if (c && (r < dim[0]-1)) { if ((l = il[index(r+1,c-1,sl,dim)])) {nabo[nr_set++] = l;} } } if (nr_set) { il[index(r,c,sl,dim)] = nabo[0]; fill_tratab(*tt,ttn,nabo,nr_set); } else { il[index(r,c,sl,dim)] = label; if (label >= ttn) {ttn += 1000; *tt = mxRealloc(*tt,ttn*sizeof(unsigned int));} (*tt)[label-1] = label; label++; } } } } } /* Finalise translation table */ for (i=0; i<(label-1); i++) { j = i; while ((*tt)[j] != j+1) { j = (*tt)[j]-1; } (*tt)[i] = j+1; } return(label-1); } /* translate_labels */ double translate_labels(unsigned int *il, /* Map of initial labels. */ mwSize dim[3], /* Dimensions of il. */ unsigned int *tt, /* Translation table. */ unsigned int ttn, /* Size of translation table. */ double *l) /* Final map of labels. */ { int n=0; int i=0; unsigned int ml=0; double cl = 0.0; double *fl = NULL; n = dim[0]*dim[1]*dim[2]; for (i=0; i 2) mexErrMsgTxt("Too many input arguments."); if (nlhs > 2) mexErrMsgTxt("Too many output arguments."); /* Get binary map */ if (!mxIsNumeric(prhs[0]) || mxIsComplex(prhs[0]) || mxIsSparse(prhs[0]) || !mxIsDouble(prhs[0])) { mexErrMsgTxt("spm_bwlabel: BW must be numeric, real, full and double"); } ndim = mxGetNumberOfDimensions(prhs[0]); if ((ndim < 2) || (ndim > 3)) { mexErrMsgTxt("spm_bwlabel: BW must be 2 or 3-dimensional"); } cdim = mxGetDimensions(prhs[0]); dim[0]=cdim[0]; dim[1]=cdim[1]; if (ndim==2) {dim[2]=1; ndim=3;} else {dim[2]=cdim[2];} for (i=0, n=1; i 1) { plhs[1] = mxCreateDoubleScalar(nl); } /* Clean up a bit */ mxFree(il); mxFree(tt); }