/* * extract.c * * Extract connected pixels from an image raster. * *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% * * This file part of: SExtractor * * Copyright: (C) 1993-2020 IAP/CNRS/SorbonneU * * License: GNU General Public License * * SExtractor is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * SExtractor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with SExtractor. If not, see . * * Last modified: 15/07/2020 * *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "define.h" #include "globals.h" #include "prefs.h" #include "extract.h" #include "plist.h" /*------------------------- Static buffers for lutz() -----------------------*/ static infostruct *info, *store; static char *marker; static status *psstack; static int *start, *end, *discan, xmin,ymin,xmax,ymax; PIXTYPE *dumscan; /******************************* lutzalloc ***********************************/ /* Allocate once for all memory space for buffers used by lutz(). */ void lutzalloc(int width, int height) { int *discant, stacksize, i; stacksize = width+1; xmin = ymin = 0; xmax = width-1; ymax = height-1; QMALLOC(info, infostruct, stacksize); QMALLOC(store, infostruct, stacksize); QMALLOC(marker, char, stacksize); QMALLOC(psstack, status, stacksize); QMALLOC(start, int, stacksize); QMALLOC(end, int, stacksize); QMALLOC(discan, int, stacksize); discant = discan; for (i=stacksize; i--;) *(discant++) = -1; return; } /******************************* lutzfree ************************************/ /* Free once for all memory space for buffers used by lutz(). */ void lutzfree() { free(discan); free(info); free(store); free(marker); free(psstack); free(start); free(end); return; } /********************************** lutz *************************************/ /* C implementation of R.K LUTZ' algorithm for the extraction of 8-connected pi- xels in an image */ int lutz(objliststruct *objlistroot, int nroot, objstruct *objparent, objliststruct *objlist) { static infostruct curpixinfo,initinfo; objstruct *obj, *objroot; pliststruct *plist,*pixel, *plistin, *plistint; char newmarker; int cn, co, luflag, objnb, pstop, xl,xl2,yl, out, minarea, stx,sty,enx,eny, step, nobjm = NOBJ, inewsymbol, *iscan; short trunflag; PIXTYPE thresh; status cs, ps; out = RETURN_OK; minarea = prefs.deb_maxarea; plistint = plistin = objlistroot->plist; objroot = &objlistroot->obj[nroot]; stx = objparent->xmin; sty = objparent->ymin; enx = objparent->xmax; eny = objparent->ymax; thresh = objlist->dthresh; initinfo.pixnb = 0; initinfo.flag = 0; initinfo.firstpix = initinfo.lastpix = -1; cn = 0; iscan = objroot->submap + (sty-objroot->suby)*objroot->subw + (stx-objroot->subx); /* As we only analyse a fraction of the map, a step occurs between lines */ step = objroot->subw - (++enx-stx); eny++; /*------Allocate memory to store object data */ free(objlist->obj); if (!(obj=objlist->obj=(objstruct *)malloc(nobjm*sizeof(objstruct)))) { out = RETURN_FATAL_ERROR; plist = NULL; /* To avoid gcc -Wall warnings */ goto exit_lutz; } /*------Allocate memory for the pixel list */ free(objlist->plist); if (!(objlist->plist = (pliststruct *)malloc((eny-sty)*(enx-stx)*plistsize))) { out = RETURN_FATAL_ERROR; plist = NULL; /* To avoid gcc -Wall warnings */ goto exit_lutz; } pixel = plist = objlist->plist; /*----------------------------------------*/ for (xl=stx; xl<=enx; xl++) marker[xl] = 0 ; objnb = objlist->nobj = 0; co = pstop = 0; curpixinfo.pixnb = 1; for (yl=sty; yl<=eny; yl++, iscan += step) { ps = COMPLETE; cs = NONOBJECT; trunflag = (yl==0 || yl==ymax) ? OBJ_TRUNC : 0; if (yl==eny) iscan = discan; for (xl=stx; xl<=enx; xl++) { newmarker = marker[xl]; marker[xl] = 0; if ((inewsymbol = (xl!=enx)?*(iscan++):-1) < 0) luflag = 0; else { curpixinfo.flag = trunflag; plistint = plistin+inewsymbol; luflag = (PLISTPIX(plistint, cdvalue) > thresh?1:0); } if (luflag) { if (xl==0 || xl==xmax) curpixinfo.flag |= OBJ_TRUNC; memcpy(pixel, plistint, (size_t)plistsize); PLIST(pixel, nextpix) = -1; curpixinfo.lastpix = curpixinfo.firstpix = cn; cn += plistsize; pixel += plistsize; if (cs != OBJECT) /*------------------------------- Start Segment -----------------------------*/ { cs = OBJECT; if (ps == OBJECT) { if (start[co] == UNKNOWN) { marker[xl] = 'S'; start[co] = xl; } else marker[xl] = 's'; } else { psstack[pstop++] = ps; marker[xl] = 'S'; start[++co] = xl; ps = COMPLETE; info[co] = initinfo; } } } /*---------------------------------------------------------------------------*/ if (newmarker) /*---------------------------- Process New Marker ---------------------------*/ { if (newmarker == 'S') { psstack[pstop++] = ps; if (cs == NONOBJECT) { psstack[pstop++] = COMPLETE; info[++co] = store[xl]; start[co] = UNKNOWN; } else update (&info[co],&store[xl], plist); ps = OBJECT; } else if (newmarker == 's') { if ((cs == OBJECT) && (ps == COMPLETE)) { pstop--; xl2 = start[co]; update (&info[co-1],&info[co], plist); if (start[--co] == UNKNOWN) start[co] = xl2; else marker[xl2] = 's'; } ps = OBJECT; } else if (newmarker == 'f') ps = INCOMPLETE; else if (newmarker == 'F') { ps = psstack[--pstop]; if ((cs == NONOBJECT) && (ps == COMPLETE)) { if (start[co] == UNKNOWN) { if ((int)info[co].pixnb >= minarea) { if (objlist->nobj>=nobjm) if (!(obj = objlist->obj = (objstruct *) realloc(obj, (nobjm+=nobjm/2)* sizeof(objstruct)))) { out = RETURN_FATAL_ERROR; goto exit_lutz; } lutzsort(&info[co], objlist); } } else { marker[end[co]] = 'F'; store[start[co]] = info[co]; } co--; ps = psstack[--pstop]; } } } /*---------------------------------------------------------------------------*/ if (luflag) update (&info[co],&curpixinfo, plist); else { if (cs == OBJECT) /*-------------------------------- End Segment ------------------------------*/ { cs = NONOBJECT; if (ps != COMPLETE) { marker[xl] = 'f'; end[co] = xl; } else { ps = psstack[--pstop]; marker[xl] = 'F'; store[start[co]] = info[co]; co--; } } } /*---------------------------------------------------------------------------*/ } } exit_lutz: if (objlist->nobj && out == RETURN_OK) { if (!(objlist->obj=(objstruct *)realloc(obj, objlist->nobj*sizeof(objstruct)))) error(EXIT_FAILURE,"problem with mem. realloc. in lutz()",""); } else { free(obj); objlist->obj = NULL; } if (cn && out == RETURN_OK) { if (!(objlist->plist=(pliststruct *)realloc(plist,cn))) error(EXIT_FAILURE,"problem with mem. realloc. in lutz()",""); } else { free(objlist->plist); objlist->plist = NULL; } return out; } /********************************* lutzsort ***********************************/ /* Build the object structure. */ void lutzsort(infostruct *info, objliststruct *objlist) { objstruct *obj = objlist->obj+objlist->nobj; memset(obj, 0, (size_t)sizeof(objstruct)); obj->firstpix = info->firstpix; obj->lastpix = info->lastpix; obj->flag = info->flag; objlist->npix += info->pixnb; preanalyse(objlist->nobj, objlist, ANALYSE_FAST); objlist->nobj++; return; }