/* * Add a completed configuration to the list. */ void addconf(struct config *cf0) { struct config *cf; struct nvlist *nv; const char *name; name = cf0->cf_name; cf = emalloc(sizeof *cf); if (ht_insert(cfhashtab, name, cf)) { error("configuration `%s' already defined", name); free(cf); goto bad; } *cf = *cf0; /* * Look for "swap generic". */ for (nv = cf->cf_swap; nv != NULL; nv = nv->nv_next) if (nv->nv_str == s_generic) break; if (nv != NULL) { /* * Make sure no root or dump device specified, and no * other swap devices. Note single | here (check all). */ nv = cf->cf_swap; if (exclude(cf->cf_root, name, "root device") | exclude(nv->nv_next, name, "additional swap devices") | exclude(cf->cf_dump, name, "dump device")) goto bad; } else { nv = cf->cf_root; if (nv == NULL) { error("%s: no root device specified", name); goto bad; } if (resolve(&cf->cf_root, name, "root", nv, 'a') | lresolve(&cf->cf_swap, name, "swap", nv, 'b') | resolve(&cf->cf_dump, name, "dumps", nv, 'b')) goto bad; } *nextcf = cf; nextcf = &cf->cf_next; return; bad: nvfreel(cf0->cf_root); nvfreel(cf0->cf_swap); nvfreel(cf0->cf_dump); }
/** * Image labeling algorithm. * * @param im pointer to input image of type PIXEL * @param width width input image in pixels * @param height height input image in pixels * @param connectivty number of connectivity directions (4 or 8) * @param minsize smallest allowable blob size, they get subsumed into the parent blob * @param limage pointer to label image, of same size as \p im (output) * @param parent_out pointer to pointer for return of an array of region parents. Can be NULL. (output) * @param color_out pointer to pointer for return of an array of region color. Can be NULL. (output) * @param edge_out pointer to pointer for return of an array of region edge points. Can be NULL. (output) * @return the number of regions found */ static int ilabel(PIXEL *im, int width, int height, int connectivity, int minsize, LABEL *limage, LABEL **parent_out, PIXEL **color_out, unsigned int **edge_out) { int *blobsize, row, col, i, j, nlabels; int newlabel; LABEL *lmap2; LABEL prevlab, curlab; LABEL *parents; PIXEL curpix, prevpix; PIXEL *color; unsigned int *edge; int maxlabel = width*height; /* allocate label map and initialize to zero */ lmap = (LABEL *)mxCalloc(maxlabel, sizeof(LABEL)); /* region size */ blobsize = (int *)mxCalloc(maxlabel, sizeof(int)); if (parent_out) parents = (LABEL *)mxCalloc(maxlabel, sizeof(LABEL)); if (color_out) color = (PIXEL *)mxCalloc(maxlabel, sizeof(PIXEL)); if (edge_out) edge = (unsigned int *)mxCalloc(maxlabel, sizeof(unsigned int)); /* * Blob labels are ints >= 1 * newlabel holds the most recently assigned label value. * labels are unique and never recycled. * * When 2 blobs merge: A := A + B an entry is placed in the label map * lmap[B] = A indicating that all pixels that were B are now A. * If lmap[X] = 0 then X is unmerged, X is X * It is possible that a later merge: C = C + A * lmap[A] = C indicating that all As are now Cs * A pixel that was once B is mapped to A, then to C, but lmap[C] is 0 so * the indirection stops there. B --> A --> C * * Resolving the indirection is the job of lresolve() * lresolve(A) --> C * lresolve(B) --> C * lresolve(C) --> C */ for (row=0; row<height; row++) { for (col=0; col<width; col++) { curpix = PIX(im,row,col); #ifdef DEBUG printf("%2d ", curpix); #endif } #ifdef DEBUG printf("\n"); #endif } /* * first pass labelling loop. Only does 4-way connectivity */ newlabel = 0; for (row=0; row<height; row++) { prevlab = UNKNOWN; for (col=0; col<width; col++) { curpix = PIX(im,row,col); curlab = UNKNOWN; // start with no known label if (col > 0) { prevpix = PIX(im,row,col-1); /* if no change in pixel value then inherit label from left */ if (curpix == prevpix) curlab = prevlab; } #ifdef DEBUG printf("(%d,%d) cp=%d, pp=%d, cl=%d, pl=%d\n", row, col, curpix, prevpix, curlab, prevlab); #endif /* * check whether a label merge should happen, adjacent * pixels with the same value but different labels * means that one should change. * * merge can only happen on second row onwards */ if (row > 0) { if ( (PIX(im,row-1,col) == curpix) && (lresolve(PIX(limage,row-1,col)) != curlab) ) { /* we have a label assignment from N */ int newlabel; newlabel = lresolve(PIX(limage,row-1,col)); /* newlabel = PIX(lim,row-1,col); */ #ifdef DEBUG printf("mergeN(%d,%d): %d becomes %d: curpix=%d, prevpix=%d\n", row, col, curlab, newlabel, curpix, PIX(im,row-1,col)); #endif // newlabel dominates if (curlab != UNKNOWN) { lmap[curlab] = newlabel; blobsize[newlabel] += blobsize[curlab]; //if (edge[curlab] < edge[newlabel]) //edge[newlabel] = edge[curlab]; if (parents[curlab] == 0) parents[newlabel] = 0; } curlab = newlabel; } else if ( connectivity == 8 && (col > 0) && (PIX(im,row-1,col-1) == curpix) && (lresolve(PIX(limage,row-1,col-1)) != curlab) ) { // TODO: factorize these two merge cases /* we have a merge to NW */ int newlabel; newlabel = lresolve(PIX(limage,row-1,col-1)); /* newlabel = PIX(lim,row-1,col); */ #ifdef DEBUG printf("mergeNW(%d,%d): %d becomes %d\n", row, col, curlab, newlabel); #endif if (curlab != UNKNOWN) lmap[curlab] = newlabel; if (parents[curlab] == 0) parents[newlabel] = 0; //if (edge[curlab] < edge[newlabel]) //edge[newlabel] = edge[curlab]; blobsize[newlabel] += blobsize[curlab]; curlab = newlabel; } else if ( connectivity == 8 && (col < (width-1)) && (PIX(im,row-1,col+1) == curpix) && (lresolve(PIX(limage,row-1,col+1)) != curlab) ) { /* we have a merge to NE */ int newlabel; newlabel = lresolve(PIX(limage,row-1,col+1)); /* newlabel = PIX(lim,row-1,col); */ #ifdef DEBUG printf("mergeNE(%d,%d): %d becomes %d\n", row, col, curlab, newlabel); #endif if (curlab != UNKNOWN) lmap[curlab] = newlabel; blobsize[newlabel] += blobsize[curlab]; //if (edge[curlab] < edge[newlabel]) //edge[newlabel] = edge[curlab]; curlab = newlabel; } } if ((row > 0) && (col > 0)) { /* * check for enclosure */ int left, above, northwest; left = prevlab; above = lresolve( PIX(limage,row-1,col) ); northwest = lresolve( PIX(limage,row-1,col-1) ); if ( (left == curlab) && (above == curlab) && (northwest != curlab) ) { #ifdef DEBUG printf("(%d,%d): label %d encloses %d\n", row, col, curlab, northwest); #endif /* we have an enclosure */ if (blobsize[curlab] > THRESH) { // mark the parent of this blob parents[northwest] = curlab; //edge[northwest] = (row-1) + height*(col-1) + 1; //printf("edge is %d\n", edge[northwest]); } else { // it's a runt, merge it with its parent lmap[curlab] = northwest; } } } /* if label still not known, assign new */ if (curlab == UNKNOWN) { curlab = NEWLABEL; color[curlab] = curpix; edge[curlab] = row + height*col + 1; //printf("color %d %f\n", curlab, curpix); #ifdef DEBUG printf("new label(%d,%d): %d\n", row, col, curlab); #endif } blobsize[curlab] += 1; PIX(limage,row,col) = curlab; prevlab = curlab; prevpix = curpix; } } #ifdef DEBUG printf("max lim is %d\n", newlabel); #endif /* * The label indirection map can have have quite long chains of indirection * as the result of region merges. * * We pass over the map, and set each entry to its final value, or 0 meaning * that it is not indirected. * */ /* * create a new label map that maps all old labels to new consecutive labels */ lmap2 = (LABEL *)mxCalloc(newlabel+1, sizeof(LABEL)); /* * Create a vector of all the final label values, ie. lmap[i] == 0 */ #ifdef DEBUG printf("----------------------\nlmap:\n"); #endif for (i=1,nlabels=0; i<=newlabel; i++) { #ifdef DEBUG printf("(%d) = %d\n", i, lmap[i]); #endif if (lmap[i] == 0) lmap2[i] = ++nlabels; /* assign new sequential label */ } /* * now resolve each labels appear in the * labelled image, */ for (i=0; i<=newlabel; i++) if (lmap[i] != 0) { j = lresolve(i); lmap2[i] = lmap2[j]; } #ifdef DEBUG printf("----------------------\nlmap2:\n"); for (i=1; i<=newlabel; i++) printf("old(%d) -> %d\n", i, lmap2[i]); #endif #ifdef DEBUG printf("----------------------\nparents:\n"); for (i=1; i<=newlabel; i++) printf("parent[%d] = %d\n", i, parents[i]); #endif /* * resolve the labels in the parent array and assign to double proc * output array */ if (parent_out) { LABEL *lab; lab = mxCalloc(nlabels, sizeof(LABEL)); for (i=1; i<=newlabel; i++) { LABEL par = parents[i], child; if (par) { child = lmap2[i]; par = lmap2[par]; lab[child-1] = par; //printf("parent [%d] = %d\n", child, par); } } mxFree(parents); *parent_out = lab; } if (color_out || edge_out) { PIXEL *c; unsigned int *e; c = (PIXEL *)mxCalloc(nlabels, sizeof(PIXEL)); e = (unsigned int *)mxCalloc(nlabels, sizeof(unsigned int)); for (i=1; i<=newlabel; i++) { LABEL l; l = lmap2[i]; c[l-1] = color[i]; if (e[l-1] == 0) e[l-1] = edge[i]; //printf("edge %d %d %d\n", i, l, edge[i]); //printf("color [%d] = %f\n", l, color[i]); } if (color_out) { mxFree(color); *color_out = c; } if (edge_out) { mxFree(edge); *edge_out = e; } } /* * resolve the labels in the integer labelled image and assign * to the double prec. output image */ for (row=0; row<height; row++) for (col=0; col<width; col++) PIX(limage,row,col) = lmap2[ PIX(limage,row,col) ]; mxFree(lmap); mxFree(lmap2); mxFree(blobsize); return(nlabels); }