File indexing completed on 2024-04-28 03:43:54

0001 /*
0002     SPDX-FileCopyrightText: 1993-2011 Emmanuel Bertin -- IAP /CNRS/UPMC
0003     SPDX-FileCopyrightText: 2014 SEP developers
0004 
0005     SPDX-License-Identifier: LGPL-3.0-or-later
0006 */
0007 
0008 /* Note: was extract.c in SExtractor. */
0009 
0010 #include <math.h>
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <string.h>
0014 #include "sep.h"
0015 #include "sepcore.h"
0016 #include "extract.h"
0017 
0018 #define NOBJ 256  /* starting number of obj. */
0019 
0020 void lutzsort(infostruct *, objliststruct *);
0021 
0022 /*------------------------- Static buffers for lutz() -----------------------*/
0023 
0024 static infostruct  *info=NULL, *store=NULL;
0025 static char    *marker=NULL;
0026 static pixstatus   *psstack=NULL;
0027 static int         *start=NULL, *end=NULL, *discan=NULL;
0028 static int         xmin, ymin, xmax, ymax;
0029 
0030 
0031 /******************************* lutzalloc ***********************************/
0032 /*
0033 Allocate once for all memory space for buffers used by lutz().
0034 */
0035 int lutzalloc(int width, int height)
0036 {
0037   int *discant;
0038   int stacksize, i, status=RETURN_OK;
0039 
0040   stacksize = width+1;
0041   xmin = ymin = 0;
0042   xmax = width-1;
0043   ymax = height-1;
0044   QMALLOC(info, infostruct, stacksize, status);
0045   QMALLOC(store, infostruct, stacksize, status);
0046   QMALLOC(marker, char, stacksize, status);
0047   QMALLOC(psstack, pixstatus, stacksize, status);
0048   QMALLOC(start, int, stacksize, status);
0049   QMALLOC(end, int, stacksize, status);
0050   QMALLOC(discan, int, stacksize, status);
0051   discant = discan;
0052   for (i=stacksize; i--;)
0053     *(discant++) = -1;
0054 
0055   return status;
0056 
0057  exit:
0058   lutzfree();
0059 
0060   return status;
0061 }
0062 
0063 /******************************* lutzfree ************************************/
0064 /*
0065 Free once for all memory space for buffers used by lutz().
0066 */
0067 void lutzfree()
0068 {
0069   free(discan);
0070   discan = NULL;
0071   free(info);
0072   info = NULL;
0073   free(store);
0074   store = NULL;
0075   free(marker);
0076   marker = NULL;
0077   free(psstack);
0078   psstack = NULL;
0079   free(start);
0080   start = NULL;
0081   free(end);
0082   end = NULL;
0083   return;
0084 }
0085 
0086 
0087 /********************************** lutz *************************************/
0088 /*
0089 C implementation of R.K LUTZ' algorithm for the extraction of 8-connected pi-
0090 xels in an image
0091 */
0092 int lutz(pliststruct *plistin,
0093      int *objrootsubmap, int subx, int suby, int subw,
0094      objstruct *objparent, objliststruct *objlist, int minarea)
0095 {
0096   static infostruct curpixinfo,initinfo;
0097   objstruct     *obj;
0098   pliststruct       *plist,*pixel, *plistint;
0099   
0100   char          newmarker;
0101   int           cn, co, luflag, pstop, xl,xl2,yl,
0102                         out, deb_maxarea, stx,sty,enx,eny, step,
0103                         nobjm = NOBJ,
0104             inewsymbol, *iscan;
0105   short             trunflag;
0106   PIXTYPE       thresh;
0107   pixstatus     cs, ps;
0108 
0109   out = RETURN_OK;
0110 
0111   deb_maxarea = minarea<MAXDEBAREA?minarea:MAXDEBAREA; /* 3 or less */
0112   plistint = plistin;
0113   stx = objparent->xmin;
0114   sty = objparent->ymin;
0115   enx = objparent->xmax;
0116   eny = objparent->ymax;
0117   thresh = objlist->thresh;
0118   initinfo.pixnb = 0;
0119   initinfo.flag = 0;
0120   initinfo.firstpix = initinfo.lastpix = -1;
0121   cn = 0;
0122 
0123   iscan = objrootsubmap + (sty-suby)*subw + (stx-subx);
0124 
0125   /* As we only analyze a fraction of the map, a step occurs between lines */
0126   step = subw - (++enx-stx);
0127   eny++;
0128 
0129   /*------Allocate memory to store object data */
0130   free(objlist->obj);
0131 
0132   if (!(obj=objlist->obj=(objstruct *)malloc(nobjm*sizeof(objstruct))))
0133     {
0134       out = MEMORY_ALLOC_ERROR;
0135       plist = NULL;         /* To avoid gcc -Wall warnings */
0136       goto exit_lutz;
0137     }
0138 
0139   /*------Allocate memory for the pixel list */
0140   free(objlist->plist);
0141   if (!(objlist->plist
0142     = (pliststruct *)malloc((eny-sty)*(enx-stx)*plistsize)))
0143     {
0144       out = MEMORY_ALLOC_ERROR;
0145       plist = NULL;         /* To avoid gcc -Wall warnings */
0146       goto exit_lutz;
0147     }
0148 
0149   pixel = plist = objlist->plist;
0150 
0151   /*----------------------------------------*/
0152   for (xl=stx; xl<=enx; xl++)
0153     marker[xl] = 0;
0154 
0155   objlist->nobj = 0;
0156   co = pstop = 0;
0157   curpixinfo.pixnb = 1;
0158 
0159   for (yl=sty; yl<=eny; yl++, iscan += step)
0160     {
0161       ps = COMPLETE;
0162       cs = NONOBJECT;
0163       trunflag = (yl==0 || yl==ymax) ? SEP_OBJ_TRUNC : 0;
0164       if (yl==eny)
0165     iscan = discan;
0166 
0167       for (xl=stx; xl<=enx; xl++)
0168     {
0169       newmarker = marker[xl];
0170       marker[xl] = 0;
0171       if ((inewsymbol = (xl!=enx)?*(iscan++):-1) < 0)
0172         luflag = 0;
0173       else
0174         {
0175           curpixinfo.flag = trunflag;
0176           plistint = plistin+inewsymbol;
0177           luflag = (PLISTPIX(plistint, cdvalue) > thresh?1:0);
0178         }
0179       if (luflag)
0180         {
0181           if (xl==0 || xl==xmax)
0182         curpixinfo.flag |= SEP_OBJ_TRUNC;
0183           memcpy(pixel, plistint, (size_t)plistsize);
0184           PLIST(pixel, nextpix) = -1;
0185           curpixinfo.lastpix = curpixinfo.firstpix = cn;
0186           cn += plistsize;
0187           pixel += plistsize;
0188 
0189           /*----------------- Start Segment -----------------------------*/
0190           if (cs != OBJECT)
0191         {
0192           cs = OBJECT;
0193           if (ps == OBJECT)
0194             {
0195               if (start[co] == UNKNOWN)
0196             {
0197               marker[xl] = 'S';
0198               start[co] = xl;
0199             }
0200               else  marker[xl] = 's';
0201             }
0202           else
0203             {
0204               psstack[pstop++] = ps;
0205               marker[xl] = 'S';
0206               start[++co] = xl;
0207               ps = COMPLETE;
0208               info[co] = initinfo;
0209             }
0210         }
0211         }
0212 
0213       /*-------------------Process New Marker ---------------------------*/
0214       if (newmarker)
0215         {
0216           if (newmarker == 'S')
0217         {
0218           psstack[pstop++] = ps;
0219           if (cs == NONOBJECT)
0220             {
0221               psstack[pstop++] = COMPLETE;
0222               info[++co] = store[xl];
0223               start[co] = UNKNOWN;
0224             }
0225           else
0226             update(&info[co], &store[xl], plist);
0227           ps = OBJECT;
0228         }
0229 
0230           else if (newmarker == 's')
0231         {
0232           if ((cs == OBJECT) && (ps == COMPLETE))
0233             {
0234               pstop--;
0235               xl2 = start[co];
0236               update(&info[co-1], &info[co], plist);
0237               if (start[--co] == UNKNOWN)
0238             start[co] = xl2;
0239               else
0240             marker[xl2] = 's';
0241             }
0242           ps = OBJECT;
0243         }
0244           else if (newmarker == 'f')
0245         ps = INCOMPLETE;
0246           else if (newmarker == 'F')
0247         {
0248           ps = psstack[--pstop];
0249           if ((cs == NONOBJECT) && (ps == COMPLETE))
0250             {
0251               if (start[co] == UNKNOWN)
0252             {
0253               if ((int)info[co].pixnb >= deb_maxarea)
0254                 {
0255                   if (objlist->nobj>=nobjm)
0256                 if (!(obj = objlist->obj = (objstruct *)
0257                       realloc(obj, (nobjm+=nobjm/2)*
0258                           sizeof(objstruct))))
0259                   {
0260                     out = MEMORY_ALLOC_ERROR;
0261                     goto exit_lutz;
0262                   }
0263                   lutzsort(&info[co], objlist);
0264                 }
0265             }
0266               else
0267             {
0268               marker[end[co]] = 'F';
0269               store[start[co]] = info[co];
0270             }
0271               co--;
0272               ps = psstack[--pstop];
0273             }
0274         }
0275         }
0276       /* end process new marker -----------------------------------------*/
0277 
0278       if (luflag)
0279         update (&info[co],&curpixinfo, plist);
0280       else
0281         {
0282           /* ----------------- End Segment ------------------------------*/
0283           if (cs == OBJECT)
0284         {
0285           cs = NONOBJECT;
0286           if (ps != COMPLETE)
0287             {
0288               marker[xl] = 'f';
0289               end[co] = xl;
0290             }
0291           else
0292             {
0293               ps = psstack[--pstop];
0294               marker[xl] = 'F';
0295               store[start[co]] = info[co];
0296               co--;
0297             }
0298         }
0299         }
0300     }
0301     }
0302 
0303  exit_lutz:
0304 
0305   if (objlist->nobj && out == RETURN_OK)
0306     {
0307       if (!(objlist->obj=
0308         (objstruct *)realloc(obj, objlist->nobj*sizeof(objstruct))))
0309     out = MEMORY_ALLOC_ERROR;
0310     }
0311   else
0312     {
0313       free(obj);
0314       objlist->obj = NULL;
0315     }
0316 
0317   if (cn && out == RETURN_OK)
0318     {
0319       if (!(objlist->plist=(pliststruct *)realloc(plist,cn)))
0320     out = MEMORY_ALLOC_ERROR;
0321     }
0322   else
0323     {
0324       free(objlist->plist);
0325       objlist->plist = NULL;
0326     }
0327 
0328   return out;
0329 }
0330 
0331 /********************************* lutzsort ***********************************/
0332 /*
0333 Add an object to the object list based on info (pixel info)
0334 */
0335 void  lutzsort(infostruct *info, objliststruct *objlist)
0336 {
0337   objstruct *obj = objlist->obj+objlist->nobj;
0338 
0339   memset(obj, 0, (size_t)sizeof(objstruct));
0340   obj->firstpix = info->firstpix;
0341   obj->lastpix = info->lastpix;
0342   obj->flag = info->flag;
0343   objlist->npix += info->pixnb;
0344   
0345   preanalyse(objlist->nobj, objlist);
0346   
0347   objlist->nobj++;
0348   
0349   return;
0350 }
0351 
0352 /********************************* update ************************************/
0353 /*
0354 update object's properties each time one of its pixels is scanned by lutz()
0355 */
0356 void  update(infostruct *infoptr1, infostruct *infoptr2, pliststruct *pixel)
0357 {
0358   infoptr1->pixnb += infoptr2->pixnb;
0359   infoptr1->flag |= infoptr2->flag;
0360   if (infoptr1->firstpix == -1)
0361     {
0362       infoptr1->firstpix = infoptr2->firstpix;
0363       infoptr1->lastpix = infoptr2->lastpix;
0364     }
0365   else if (infoptr2->lastpix != -1)
0366     {
0367       PLIST(pixel+infoptr1->lastpix, nextpix) = infoptr2->firstpix;
0368       infoptr1->lastpix = infoptr2->lastpix;
0369     }
0370 
0371   return;
0372 }