Leptonica 1.68
C Image Processing Library

watershed.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 /*
00017  *  watershed.c
00018  *
00019  *      Top-level
00020  *            L_WSHED         *wshedCreate()
00021  *            void             wshedDestroy()
00022  *            l_int32          wshedApply()
00023  *
00024  *      Helpers
00025  *            static l_int32   identifyWatershedBasin()
00026  *            static l_int32   mergeLookup()
00027  *            static l_int32   wshedGetHeight()
00028  *            static void      pushNewPixel()
00029  *            static void      popNewPixel()
00030  *            static void      pushWSPixel()
00031  *            static void      popWSPixel()
00032  *            static void      debugPrintLUT()
00033  *            static void      debugWshedMerge()
00034  *
00035  *      Output
00036  *            l_int32          wshedBasins()
00037  *            PIX             *wshedRenderFill()
00038  *            PIX             *wshedRenderColors()
00039  *
00040  *  The watershed function identifies the "catch basins" of the input
00041  *  8 bpp image, with respect to the specified seeds or "markers".
00042  *  The use is in segmentation, but the selection of the markers is
00043  *  critical to getting meaningful results.
00044  *
00045  *  How are the markers selected?  You can't simply use the local
00046  *  minima, because a typical image has sufficient noise so that 
00047  *  a useful catch basin can easily have multiple local minima.  However
00048  *  they are selected, the question for the watershed function is
00049  *  how to handle local minima that are not markers.  The reason
00050  *  this is important is because of the algorithm used to find the
00051  *  watersheds, which is roughly like this:
00052  *
00053  *    (1) Identify the markers and the local minima, and enter them
00054  *        into a priority queue based on the pixel value.  Each marker
00055  *        is shrunk to a single pixel, if necessary, before the
00056  *        operation starts.
00057  *    (2) Feed the priority queue with neighbors of pixels that are
00058  *        popped off the queue.  Each of these queue pixels is labelled
00059  *        with the index value of its parent.
00060  *    (3) Each pixel is also labelled, in a 32-bit image, with the marker
00061  *        or local minimum index, from which it was originally derived.
00062  *    (4) There are actually 3 classes of labels: seeds, minima, and
00063  *        fillers.  The fillers are labels of regions that have already
00064  *        been identified as watersheds and are continuing to fill, for
00065  *        the purpose of finding higher watersheds.
00066  *    (5) When a pixel is popped that has already been labelled in the
00067  *        32-bit image and that label differs from the label of its
00068  *        parent (stored in the queue pixel), a boundary has been crossed.
00069  *        There are several cases:
00070  *         (a) Both parents are derived from markers but at least one
00071  *             is not deep enough to become a watershed.  Absorb the
00072  *             shallower basin into the deeper one, fixing the LUT to
00073  *             redirect the shallower index to the deeper one.
00074  *         (b) Both parents are derived from markers and both are deep
00075  *             enough.  Identify and save the watershed for each marker.
00076  *         (c) One parent was derived from a marker and the other from
00077  *             a minima: absorb the minima basin into the marker basin.
00078  *         (d) One parent was derived from a marker and the other is
00079  *             a filler: identify and save the watershed for the marker.
00080  *         (e) Both parents are derived from minima: merge them.
00081  *         (f) One parent is a filler and the other is derived from a
00082  *             minima: merge the minima into the filler.
00083  *    (6) The output of the watershed operation consists of:
00084  *         - a pixa of the basins
00085  *         - a pta of the markers
00086  *         - a numa of the watershed levels
00087  *
00088  *  Typical usage:
00089  *      L_WShed *wshed = wshedCreate(pixs, pixseed, mindepth, 0);
00090  *      wshedApply(wshed);
00091 *
00092  *      wshedBasins(wshed, &pixa, &nalevels);
00093  *        ... do something with pixa, nalevels ...
00094  *      pixaDestroy(&pixa);
00095  *      numaDestroy(&nalevels);
00096  *
00097  *      Pix *pixd = wshedRenderFill(wshed);
00098  *
00099  *      wshedDestroy(&wshed);
00100  */
00101 
00102 #include <stdio.h>
00103 #include <stdlib.h>
00104 #include "allheaders.h"
00105 
00106 #ifndef  NO_CONSOLE_IO
00107 #define   DEBUG_WATERSHED     0
00108 #endif  /* ~NO_CONSOLE_IO */
00109 
00110 static const l_uint32  MAX_LABEL_VALUE = 0x7fffffff;  /* largest l_int32 */
00111 
00112 struct L_NewPixel
00113 {
00114     l_int32    x;
00115     l_int32    y;
00116 };
00117 typedef struct L_NewPixel  L_NEWPIXEL;
00118 
00119 struct L_WSPixel
00120 {
00121     l_float32  val;    /* pixel value */
00122     l_int32    x;
00123     l_int32    y;
00124     l_int32    index;  /* label for set to which pixel belongs */
00125 };
00126 typedef struct L_WSPixel  L_WSPIXEL;
00127 
00128 
00129     /* Static functions for obtaining bitmap of watersheds  */
00130 static void wshedSaveBasin(L_WSHED *wshed, l_int32 index, l_int32 level);
00131 
00132 static l_int32 identifyWatershedBasin(L_WSHED *wshed,
00133                                       l_int32 index, l_int32 level,
00134                                       BOX **pbox, PIX **ppixd);
00135 
00136     /* Static function for merging lut and backlink arrays */
00137 static l_int32 mergeLookup(L_WSHED *wshed, l_int32 sindex, l_int32 dindex);
00138 
00139     /* Static function for finding the height of the current pixel
00140        above its seed or minima in the watershed.  */
00141 static l_int32 wshedGetHeight(L_WSHED *wshed, l_int32 val, l_int32 label,
00142                               l_int32 *pheight);
00143 
00144     /* Static accessors for NewPixel on a queue */
00145 static void pushNewPixel(L_QUEUE *lq, l_int32 x, l_int32 y,
00146                          l_int32 *pminx, l_int32 *pmaxx,
00147                          l_int32 *pminy, l_int32 *pmaxy);
00148 static void popNewPixel(L_QUEUE *lq, l_int32 *px, l_int32 *py);
00149 
00150     /* Static accessors for WSPixel on a heap */
00151 static void pushWSPixel(L_HEAP *lh, L_STACK *stack, l_int32 val,
00152                         l_int32 x, l_int32 y, l_int32 index);
00153 static void popWSPixel(L_HEAP *lh, L_STACK *stack, l_int32 *pval,
00154                        l_int32 *px, l_int32 *py, l_int32 *pindex);
00155 
00156     /* Static debug print output */
00157 static void debugPrintLUT(l_int32 *lut, l_int32 size, l_int32 debug);
00158 
00159 static void debugWshedMerge(L_WSHED *wshed, char *descr, l_int32 x,
00160                             l_int32 y, l_int32 label, l_int32 index);
00161 
00162 
00163 /*-----------------------------------------------------------------------*
00164  *                        Top-level watershed                            *
00165  *-----------------------------------------------------------------------*/
00166 /*!
00167  *  wshedCreate()
00168  *
00169  *      Input:  pixs  (8 bpp source)
00170  *              pixm  (1 bpp 'marker' seed)
00171  *              mindepth (minimum depth; anything less is not saved)
00172  *              debugflag (1 for debug output)
00173  *      Return: WShed, or null on error
00174  *
00175  *  Notes:
00176  *      (1) It is not necessary for the fg pixels in the seed image
00177  *          be at minima, or that they be isolated.  We extract a
00178  *          single pixel from each connected component, and a seed
00179  *          anywhere in a watershed will eventually label the watershed
00180  *          when the filling level reaches it.
00181  *      (2) Set mindepth to some value to ignore noise in pixs that
00182  *          can create small local minima.  Any watershed shallower
00183  *          than mindepth, even if it has a seed, will not be saved;
00184  *          It will either be incorporated in another watershed or
00185  *          eliminated.
00186  */
00187 L_WSHED *
00188 wshedCreate(PIX     *pixs,
00189             PIX     *pixm,
00190             l_int32  mindepth,
00191             l_int32  debugflag)
00192 {
00193 l_int32   w, h;
00194 L_WSHED  *wshed;
00195 
00196     PROCNAME("wshedCreate");
00197 
00198     if (!pixs)
00199         return (L_WSHED *)ERROR_PTR("pixs is not defined", procName, NULL);
00200     if (pixGetDepth(pixs) != 8)
00201         return (L_WSHED *)ERROR_PTR("pixs is not 8 bpp", procName, NULL);
00202     if (!pixm)
00203         return (L_WSHED *)ERROR_PTR("pixm is not defined", procName, NULL);
00204     if (pixGetDepth(pixm) != 1)
00205         return (L_WSHED *)ERROR_PTR("pixm is not 1 bpp", procName, NULL);
00206     pixGetDimensions(pixs, &w, &h, NULL);
00207     if (pixGetWidth(pixm) != w || pixGetHeight(pixm) != h)
00208         return (L_WSHED *)ERROR_PTR("pixs/m sizes are unequal", procName, NULL);
00209 
00210     if ((wshed = (L_WSHED *)CALLOC(1, sizeof(L_WSHED))) == NULL)
00211         return (L_WSHED *)ERROR_PTR("wshed not made", procName, NULL);
00212 
00213     wshed->pixs = pixClone(pixs);
00214     wshed->pixm = pixClone(pixm);
00215     wshed->mindepth = L_MAX(1, mindepth);
00216     wshed->pixlab = pixCreate(w, h, 32);
00217     pixSetAllArbitrary(wshed->pixlab, MAX_LABEL_VALUE);
00218     wshed->pixt = pixCreate(w, h, 1);
00219     wshed->lines8 = pixGetLinePtrs(pixs, NULL);
00220     wshed->linem1 = pixGetLinePtrs(pixm, NULL);
00221     wshed->linelab32 = pixGetLinePtrs(wshed->pixlab, NULL);
00222     wshed->linet1 = pixGetLinePtrs(wshed->pixt, NULL);
00223     wshed->debug = debugflag;
00224     return wshed;
00225 }
00226 
00227 
00228 /*!
00229  *  wshedDestroy()
00230  *
00231  *      Input:  &wshed (<will be set to null before returning>)
00232  *      Return: void
00233  */
00234 void
00235 wshedDestroy(L_WSHED  **pwshed)
00236 {
00237 l_int32   i;
00238 L_WSHED  *wshed;
00239 
00240     PROCNAME("wshedDestroy");
00241 
00242     if (pwshed == NULL) {
00243         L_WARNING("ptr address is null!", procName);
00244         return;
00245     }
00246 
00247     if ((wshed = *pwshed) == NULL)
00248         return;
00249 
00250     pixDestroy(&wshed->pixs);
00251     pixDestroy(&wshed->pixm);
00252     pixDestroy(&wshed->pixlab);
00253     pixDestroy(&wshed->pixt);
00254     if (wshed->lines8) FREE(wshed->lines8);
00255     if (wshed->linem1) FREE(wshed->linem1);
00256     if (wshed->linelab32) FREE(wshed->linelab32);
00257     if (wshed->linet1) FREE(wshed->linet1);
00258     pixaDestroy(&wshed->pixad);
00259     ptaDestroy(&wshed->ptas);
00260     numaDestroy(&wshed->nash);
00261     numaDestroy(&wshed->nasi);
00262     numaDestroy(&wshed->namh);
00263     numaDestroy(&wshed->nalevels);
00264     if (wshed->lut)
00265          FREE(wshed->lut);
00266     if (wshed->links) {
00267         for (i = 0; i < wshed->arraysize; i++)
00268             numaDestroy(&wshed->links[i]); 
00269         FREE(wshed->links);
00270     }
00271     FREE(wshed);
00272     *pwshed = NULL;
00273     return;
00274 }
00275 
00276 
00277 /*!
00278  *  wshedApply()
00279  *
00280  *      Input:  wshed (generated from wshedCreate())
00281  *      Return: 0 if OK, 1 on error
00282  *
00283  *  Iportant note:
00284  *      (1) This is buggy.  It seems to locate watersheds that are
00285  *          duplicates.  The watershed extraction after complete fill
00286  *          grabs some regions belonging to existing watersheds.
00287  *          See prog/watershedtest.c for testing.
00288  */
00289 l_int32
00290 wshedApply(L_WSHED  *wshed)
00291 {
00292 char      two_new_watersheds[] = "Two new watersheds";
00293 char      seed_absorbed_into_seeded_basin[] = "Seed absorbed into seeded basin";
00294 char      one_new_watershed_label[] = "One new watershed (label)";
00295 char      one_new_watershed_index[] = "One new watershed (index)";
00296 char      minima_absorbed_into_seeded_basin[] =
00297                  "Minima absorbed into seeded basin";
00298 char      minima_absorbed_by_filler_or_another[] =
00299                  "Minima absorbed by filler or another";
00300 l_int32   nseeds, nother, nboth, arraysize;
00301 l_int32   i, j, val, x, y, w, h, index, mindepth;
00302 l_int32   imin, imax, jmin, jmax, cindex, clabel, nindex;
00303 l_int32   hindex, hlabel, hmin, hmax, minhindex, maxhindex;
00304 l_int32  *lut;
00305 l_uint32  ulabel, uval;
00306 void    **lines8, **linelab32;
00307 NUMA     *nalut, *nalevels, *nash, *namh, *nasi;
00308 NUMA    **links;
00309 L_HEAP   *lh;
00310 PIX      *pixmin, *pixsd;
00311 PIXA     *pixad;
00312 L_STACK  *rstack;
00313 PTA      *ptas, *ptao;
00314 
00315     PROCNAME("wshedApply");
00316 
00317     if (!wshed)
00318         return ERROR_INT("wshed not defined", procName, 1);
00319 
00320     /* ------------------------------------------------------------ * 
00321      *  Initialize priority queue and pixlab with seeds and minima  *
00322      * ------------------------------------------------------------ */
00323 
00324     lh = lheapCreate(0, L_SORT_INCREASING);  /* remove lowest values first */
00325     rstack = lstackCreate(0);  /* for reusing the WSPixels */
00326     pixGetDimensions(wshed->pixs, &w, &h, NULL);
00327     lines8 = wshed->lines8;  /* wshed owns this */
00328     linelab32 = wshed->linelab32;  /* ditto */
00329 
00330         /* Identify seed (marker) pixels, 1 for each c.c. in pixm */
00331     ptas = pixSelectMinInConnComp(wshed->pixs, wshed->pixm, &nash);
00332     pixsd = pixGenerateFromPta(ptas, w, h);
00333     nseeds = ptaGetCount(ptas);
00334     for (i = 0; i < nseeds; i++) {
00335         ptaGetIPt(ptas, i, &x, &y);
00336         uval = GET_DATA_BYTE(lines8[y], x);
00337         pushWSPixel(lh, rstack, (l_int32)uval, x, y, i);
00338     }
00339     wshed->ptas = ptas;
00340     nasi = numaMakeConstant(1, nseeds);  /* indicator array */
00341     wshed->nasi = nasi;
00342     wshed->nash = nash;
00343     wshed->nseeds = nseeds;
00344 
00345         /* Identify minima that are not seeds.  Use these 4 steps:
00346          *  (1) Get the local minima, which can have components
00347          *      of arbitrary size.  This will be a clipping mask.
00348          *  (2) Get the image of the actual seeds (pixsd)
00349          *  (3) Remove all elements of the clipping mask that have a seed.
00350          *  (4) Shrink each of the remaining elements of the minima mask
00351          *      to a single pixel.  */
00352     pixLocalExtrema(wshed->pixs, 200, 0, &pixmin, NULL);
00353     pixRemoveSeededComponents(pixmin, pixsd, pixmin, 8, 2);
00354     ptao = pixSelectMinInConnComp(wshed->pixs, pixmin, &namh);
00355     nother = ptaGetCount(ptao);
00356     for (i = 0; i < nother; i++) {
00357         ptaGetIPt(ptao, i, &x, &y);
00358         uval = GET_DATA_BYTE(lines8[y], x);
00359         pushWSPixel(lh, rstack, (l_int32)uval, x, y, nseeds + i);
00360     }
00361     wshed->namh = namh;
00362 
00363     /* ------------------------------------------------------------ * 
00364      *                Initialize merging lookup tables              *
00365      * ------------------------------------------------------------ */
00366 
00367         /* nalut should always give the current after-merging index.
00368          * links are effectively backpointers: they are numas associated with
00369          * a dest index of all indices in nalut that point to that index. */
00370     mindepth = wshed->mindepth;
00371     nboth = nseeds + nother;
00372     arraysize = 2 * nboth;
00373     wshed->arraysize = arraysize;
00374     nalut = numaMakeSequence(0, 1, arraysize);
00375     lut = numaGetIArray(nalut);
00376     wshed->lut = lut;  /* wshed owns this */
00377     links = (NUMA **)CALLOC(arraysize, sizeof(NUMA *));
00378     wshed->links = links;  /* wshed owns this */
00379     nindex = nseeds + nother;  /* the next unused index value */
00380 
00381     /* ------------------------------------------------------------ * 
00382      *              Fill the basins, using the priority queue       *
00383      * ------------------------------------------------------------ */
00384 
00385     pixad = pixaCreate(nseeds);
00386     wshed->pixad = pixad;  /* wshed owns this */
00387     nalevels = numaCreate(nseeds);
00388     wshed->nalevels = nalevels;  /* wshed owns this */
00389     L_INFO_INT2("nseeds = %d, nother = %d\n", procName, nseeds, nother);
00390     while (lheapGetCount(lh) > 0) {
00391         popWSPixel(lh, rstack, &val, &x, &y, &index);
00392 /*        fprintf(stderr, "x = %d, y = %d, index = %d\n", x, y, index); */
00393         ulabel = GET_DATA_FOUR_BYTES(linelab32[y], x);
00394         if (ulabel == MAX_LABEL_VALUE)
00395             clabel = ulabel;
00396         else
00397             clabel = lut[ulabel];
00398         cindex = lut[index];
00399         if (clabel == cindex) continue;  /* have already seen this one */
00400         if (clabel == MAX_LABEL_VALUE) {  /* new one; assign index and try to
00401                                            * propagate to all neighbors */
00402             SET_DATA_FOUR_BYTES(linelab32[y], x, cindex);
00403             imin = L_MAX(0, y - 1);
00404             imax = L_MIN(h - 1, y + 1);
00405             jmin = L_MAX(0, x - 1);
00406             jmax = L_MIN(w - 1, x + 1);
00407             for (i = imin; i <= imax; i++) {
00408                 for (j = jmin; j <= jmax; j++) {
00409                     if (i == y && j == x) continue;
00410                     uval = GET_DATA_BYTE(lines8[i], j);
00411                     pushWSPixel(lh, rstack, (l_int32)uval, j, i, cindex);
00412                 }
00413             }
00414         }
00415         else {  /* this pixel is already labeled (differently); must resolve */
00416 
00417                 /* If both indices are seeds, check if the min height is
00418                  * greater than mindepth.  If so, we have two new watersheds;
00419                  * locate them and assign to both regions a new index
00420                  * for further waterfill.  If not, absorb the shallower
00421                  * watershed into the deeper one and continue filling it. */
00422             pixGetPixel(pixsd, x, y, &uval);
00423             if (clabel < nseeds && cindex < nseeds) {
00424                 wshedGetHeight(wshed, val, clabel, &hlabel);
00425                 wshedGetHeight(wshed, val, cindex, &hindex);
00426                 hmin = L_MIN(hlabel, hindex);
00427                 hmax = L_MAX(hlabel, hindex);
00428                 if (hmin == hmax) {
00429                     hmin = hlabel;
00430                     hmax = hindex;
00431                 }
00432                 if (wshed->debug) {
00433                     fprintf(stderr, "clabel,hlabel = %d,%d\n", clabel, hlabel);
00434                     fprintf(stderr, "hmin = %d, hmax = %d\n", hmin, hmax);
00435                     fprintf(stderr, "cindex,hindex = %d,%d\n", cindex, hindex);
00436                     if (hmin < mindepth)
00437                         fprintf(stderr, "Too shallow!\n");
00438                 }
00439 
00440                 if (hmin >= mindepth) {
00441                     debugWshedMerge(wshed, two_new_watersheds,
00442                                     x, y, clabel, cindex);
00443                     wshedSaveBasin(wshed, cindex, val - 1);
00444                     wshedSaveBasin(wshed, clabel, val - 1);
00445                     numaSetValue(nasi, cindex, 0);
00446                     numaSetValue(nasi, clabel, 0);
00447 
00448                     if (wshed->debug) fprintf(stderr, "nindex = %d\n", nindex);
00449                     debugPrintLUT(lut, nindex, wshed->debug);
00450                     mergeLookup(wshed, clabel, nindex); 
00451                     debugPrintLUT(lut, nindex, wshed->debug);
00452                     mergeLookup(wshed, cindex, nindex); 
00453                     debugPrintLUT(lut, nindex, wshed->debug);
00454                     nindex++;
00455                 }
00456                 else  /* extraneous seed within seeded basin; absorb */
00457                     debugWshedMerge(wshed, seed_absorbed_into_seeded_basin,
00458                                     x, y, clabel, cindex);
00459                     maxhindex = clabel;
00460                     minhindex = cindex;
00461                     if (hindex > hlabel) {
00462                         maxhindex = cindex;
00463                         minhindex = clabel;
00464                     }
00465                     mergeLookup(wshed, minhindex, maxhindex);
00466             }
00467 
00468                 /* If one index is a seed and the other is a merge of
00469                  * 2 watersheds, generate a single watershed. */
00470             else if (clabel < nseeds && cindex >= nboth) {
00471                 debugWshedMerge(wshed, one_new_watershed_label,
00472                                 x, y, clabel, cindex);
00473                 wshedSaveBasin(wshed, clabel, val - 1);
00474                 numaSetValue(nasi, clabel, 0);
00475                 mergeLookup(wshed, clabel, cindex); 
00476             }
00477             else if (cindex < nseeds && clabel >= nboth) {
00478                 debugWshedMerge(wshed, one_new_watershed_index,
00479                                 x, y, clabel, cindex);
00480                 wshedSaveBasin(wshed, cindex, val - 1);
00481                 numaSetValue(nasi, cindex, 0);
00482                 mergeLookup(wshed, cindex, clabel); 
00483             }
00484                 /* If one index is a seed and the other is from a minimum,
00485                  * merge the minimum wshed into the seed wshed. */
00486             else if (clabel < nseeds) {  /* cindex from minima; absorb */
00487                 debugWshedMerge(wshed, minima_absorbed_into_seeded_basin,
00488                                 x, y, clabel, cindex);
00489                 mergeLookup(wshed, cindex, clabel); 
00490             }
00491             else if (cindex < nseeds) {  /* clabel from minima; absorb */
00492                 debugWshedMerge(wshed, minima_absorbed_into_seeded_basin,
00493                                 x, y, clabel, cindex);
00494                 mergeLookup(wshed, clabel, cindex); 
00495             }
00496                 /* If neither index is a seed, just merge */
00497             else {
00498                 debugWshedMerge(wshed, minima_absorbed_by_filler_or_another,
00499                                 x, y, clabel, cindex);
00500                 mergeLookup(wshed, clabel, cindex); 
00501             }
00502         }
00503     }
00504 
00505 #if 0
00506         /*  Use the indicator array to save any watersheds that fill
00507          *  to the maximum value.  This seems to screw things up!  */
00508     for (i = 0; i < nseeds; i++) {
00509         numaGetIValue(nasi, i, &ival);
00510         if (ival == 1) { 
00511             wshedSaveBasin(wshed, lut[i], val - 1);
00512             numaSetValue(nasi, i, 0);
00513         }
00514     }
00515 #endif
00516 
00517     numaDestroy(&nalut);
00518     pixDestroy(&pixmin);
00519     pixDestroy(&pixsd);
00520     ptaDestroy(&ptao);
00521     lheapDestroy(&lh, TRUE);
00522     lstackDestroy(&rstack, TRUE);
00523     return 0;
00524 }
00525 
00526 
00527 /*-----------------------------------------------------------------------*
00528  *                               Helpers                                 *
00529  *-----------------------------------------------------------------------*/
00530 /*!
00531  *  wshedSaveBasin()
00532  *
00533  *      Input:  wshed
00534  *              index (index of basin to be located)
00535  *              level (filling level reached at the time this function
00536  *                     is called)
00537  *      Return: 0 if OK, 1 on error
00538  *
00539  *  Notes:
00540  *      (1) This identifies a single watershed.  It does not change
00541  *          the LUT, which must be done subsequently.
00542  *      (2) The fill level of a basin is taken to be @level - 1.
00543  */
00544 static void
00545 wshedSaveBasin(L_WSHED  *wshed,
00546                l_int32   index,
00547                l_int32   level)
00548 {
00549 BOX  *box;
00550 PIX  *pix;
00551 
00552     PROCNAME("wshedSaveBasin");
00553 
00554     if (!wshed) {
00555         L_ERROR("wshed not defined", procName);
00556         return;
00557     }
00558 
00559     if (identifyWatershedBasin(wshed, index, level, &box, &pix) == 0) {
00560         pixaAddPix(wshed->pixad, pix, L_INSERT);
00561         pixaAddBox(wshed->pixad, box, L_INSERT);
00562         numaAddNumber(wshed->nalevels, level - 1);
00563     }
00564     return;
00565 }
00566 
00567 
00568 /*!
00569  *  identifyWatershedBasin()
00570  *
00571  *      Input:  wshed
00572  *              index (index of basin to be located)
00573  *              level (of basin at point at which the two basins met)
00574  *              &box (<return> bounding box of basin)
00575  *              &pixd (<return> pix of basin, cropped to its bounding box)
00576  *      Return: 0 if OK, 1 on error
00577  *
00578  *  Notes:
00579  *      (1) This is a static function, so we assume pixlab, pixs and pixt
00580  *          exist and are the same size.
00581  *      (2) It selects all pixels that have the label @index in pixlab
00582  *          and that have a value in pixs that is less than @level.
00583  *      (3) It is used whenever two seeded basins meet (typically at a saddle),
00584  *          or when one seeded basin meets a 'filler'.  All identified
00585  *          basins are saved as a watershed.
00586  */
00587 static l_int32
00588 identifyWatershedBasin(L_WSHED  *wshed,
00589                        l_int32   index,
00590                        l_int32   level,
00591                        BOX     **pbox,
00592                        PIX     **ppixd)
00593 {
00594 l_int32   imin, imax, jmin, jmax, minx, miny, maxx, maxy;
00595 l_int32   bw, bh, i, j, w, h, x, y;
00596 l_int32  *lut;
00597 l_uint32  label, bval, lval;
00598 void    **lines8, **linelab32, **linet1;
00599 BOX      *box;
00600 PIX      *pixs, *pixlab, *pixt, *pixd;
00601 L_QUEUE  *lq;
00602 
00603     PROCNAME("identifyWatershedBasin");
00604 
00605     if (!pbox)
00606         return ERROR_INT("&box not defined", procName, 1);
00607     *pbox = NULL;
00608     if (!ppixd)
00609         return ERROR_INT("&pixd not defined", procName, 1);
00610     *ppixd = NULL;
00611     if (!wshed)
00612         return ERROR_INT("wshed not defined", procName, 1);
00613 
00614         /* Make a queue and an auxiliary stack */
00615     lq = lqueueCreate(0);
00616     lq->stack = lstackCreate(0);
00617 
00618     pixs = wshed->pixs;
00619     pixlab = wshed->pixlab;
00620     pixt = wshed->pixt;
00621     lines8 = wshed->lines8;
00622     linelab32 = wshed->linelab32;
00623     linet1 = wshed->linet1;
00624     lut = wshed->lut;
00625     pixGetDimensions(pixs, &w, &h, NULL);
00626 
00627         /* Prime the queue with the seed pixel for this watershed. */
00628     minx = miny = 1000000;
00629     maxx = maxy = 0;
00630     ptaGetIPt(wshed->ptas, index, &x, &y);
00631     pixSetPixel(pixt, x, y, 1);
00632     pushNewPixel(lq, x, y, &minx, &maxx, &miny, &maxy);
00633     if (wshed->debug) fprintf(stderr, "prime: (x,y) = (%d, %d)\n", x, y);
00634 
00635         /* Each pixel in a spreading breadth-first search is inspected.
00636          * It is accepted as part of this watershed, and pushed on
00637          * the search queue, if:
00638          *     (1) It has a label value equal to @index
00639          *     (2) The pixel value is less than @level, the overflow
00640          *         height at which the two basins join.
00641          *     (3) It has not yet been seen in this search.  */
00642     while (lqueueGetCount(lq) > 0) {
00643         popNewPixel(lq, &x, &y);
00644         imin = L_MAX(0, y - 1);
00645         imax = L_MIN(h - 1, y + 1);
00646         jmin = L_MAX(0, x - 1);
00647         jmax = L_MIN(w - 1, x + 1);
00648         for (i = imin; i <= imax; i++) {
00649             for (j = jmin; j <= jmax; j++) {
00650                 if (j == x && i == y) continue;  /* parent */
00651                 label = GET_DATA_FOUR_BYTES(linelab32[i], j);
00652                 if (label == MAX_LABEL_VALUE || lut[label] != index) continue;
00653                 bval = GET_DATA_BIT(linet1[i], j);
00654                 if (bval == 1) continue;  /* already seen */
00655                 lval = GET_DATA_BYTE(lines8[i], j);
00656                 if (lval >= level) continue;  /* too high */
00657                 SET_DATA_BIT(linet1[i], j);
00658                 pushNewPixel(lq, j, i, &minx, &maxx, &miny, &maxy);
00659             }
00660         }
00661     }
00662 
00663         /* Extract the box and pix, and clear pixt */
00664     bw = maxx - minx + 1;
00665     bh = maxy - miny + 1;
00666     box = boxCreate(minx, miny, bw, bh);
00667     pixd = pixClipRectangle(pixt, box, NULL);
00668     pixRasterop(pixt, minx, miny, bw, bh, PIX_SRC ^ PIX_DST, pixd, 0, 0);
00669     *pbox = box;
00670     *ppixd = pixd;
00671 
00672     lqueueDestroy(&lq, 1);
00673     return 0;
00674 }
00675 
00676 
00677 /*!
00678  *  mergeLookup()
00679  *
00680  *      Input:  wshed
00681  *              sindex (primary index being changed in the merge)
00682  *              dindex (index that @sindex will point to after the merge)
00683  *      Return: 0 if OK, 1 on error
00684  *
00685  *  Notes:
00686  *      (1) The links are a sparse array of Numas showing current back-links.
00687  *          The lut gives the current index (of the seed or the minima
00688  *          for the wshed  in which it is located.
00689  *      (2) Think of each entry in the lut.  There are two types:
00690  *             owner:     lut[index] = index
00691  *             redirect:  lut[index] != index
00692  *      (3) This is called each time a merge occurs.  It puts the lut
00693  *          and backlinks in a canonical form after the merge, where
00694  *          all entries in the lut point to the current "owner", which
00695  *          has all backlinks.  That is, every "redirect" in the lut
00696  *          points to an "owner".  The lut always gives the index of
00697  *          the current owner.
00698  */
00699 static l_int32
00700 mergeLookup(L_WSHED  *wshed,
00701             l_int32   sindex,
00702             l_int32   dindex)
00703 {
00704 l_int32   i, n, size, index;
00705 l_int32  *lut;
00706 NUMA     *na;
00707 NUMA    **links;
00708 
00709     PROCNAME("mergeLookup");
00710 
00711     if (!wshed)
00712         return ERROR_INT("wshed not defined", procName, 1);
00713     size = wshed->arraysize;
00714     if (sindex < 0 || sindex >= size)
00715         return ERROR_INT("invalid sindex", procName, 1);
00716     if (dindex < 0 || dindex >= size)
00717         return ERROR_INT("invalid dindex", procName, 1);
00718 
00719         /* Redirect links in the lut */
00720     n = 0;
00721     links = wshed->links;
00722     lut = wshed->lut;
00723     if ((na = links[sindex]) != NULL) {
00724         n = numaGetCount(na);
00725         for (i = 0; i < n; i++) {
00726             numaGetIValue(na, i, &index);
00727             lut[index] = dindex;
00728         }
00729     }
00730     lut[sindex] = dindex;
00731 
00732         /* Shift the backlink arrays from sindex to dindex.
00733          * sindex should have no backlinks because all entries in the
00734          * lut that were previously pointing to it have been redirected
00735          * to dindex. */
00736     if (!links[dindex])
00737         links[dindex] = numaCreate(n);
00738     numaJoin(links[dindex], links[sindex], 0, 0);
00739     numaAddNumber(links[dindex], sindex);
00740     numaDestroy(&links[sindex]);
00741 
00742     return 0;
00743 }
00744 
00745 
00746 /*!
00747  *  wshedGetHeight()
00748  *
00749  *      Input:  wshed (array of current indices)
00750  *              val (value of current pixel popped off queue)
00751  *              label (of pixel or 32 bpp label image)
00752  *              &height (<return> height of current value from seed
00753  *                       or minimum of watershed)
00754  *      Return: 0 if OK, 1 on error
00755  *
00756  *  Notes:
00757  *      (1) It is only necessary to find the height for a watershed
00758  *          that is indexed by a seed or a minima.  This function should
00759  *          not be called on a finished watershed (that continues to fill).
00760  */
00761 static l_int32
00762 wshedGetHeight(L_WSHED  *wshed,
00763                l_int32   val,
00764                l_int32   label,
00765                l_int32  *pheight)
00766 {
00767 l_int32  minval;
00768 
00769     PROCNAME("wshedGetHeight");
00770 
00771     if (!pheight)
00772         return ERROR_INT("&height not defined", procName, 1);
00773     *pheight = 0;
00774     if (!wshed)
00775         return ERROR_INT("wshed not defined", procName, 1);
00776 
00777     if (label < wshed->nseeds)
00778         numaGetIValue(wshed->nash, label, &minval);
00779     else if (label < wshed->nseeds + wshed->nother)
00780         numaGetIValue(wshed->namh, label, &minval);
00781     else
00782         return ERROR_INT("finished watershed; should not call", procName, 1);
00783 
00784     *pheight = val - minval;
00785     return 0;
00786 }
00787 
00788 
00789 /*
00790  *  pushNewPixel()
00791  *
00792  *      Input:  lqueue
00793  *              x, y   (pixel coordinates)
00794  *              &minx, &maxx, &miny, &maxy  (<return> bounding box update)
00795  *      Return: void
00796  *
00797  *  Notes:
00798  *      (1) This is a wrapper for adding a NewPixel to a queue, which
00799  *          updates the bounding box for all pixels on that queue and
00800  *          uses the storage stack to retrieve a NewPixel.
00801  */
00802 static void
00803 pushNewPixel(L_QUEUE  *lq,
00804              l_int32   x,
00805              l_int32   y,
00806              l_int32  *pminx,
00807              l_int32  *pmaxx,
00808              l_int32  *pminy,
00809              l_int32  *pmaxy)
00810 {
00811 L_NEWPIXEL  *np;
00812 
00813     PROCNAME("pushNewPixel");
00814 
00815     if (!lq) {
00816         L_ERROR(procName, "queue not defined");
00817         return;
00818     }
00819 
00820         /* Adjust bounding box */
00821     *pminx = L_MIN(*pminx, x);
00822     *pmaxx = L_MAX(*pmaxx, x);
00823     *pminy = L_MIN(*pminy, y);
00824     *pmaxy = L_MAX(*pmaxy, y);
00825 
00826         /* Get a newpixel to use */
00827     if (lstackGetCount(lq->stack) > 0)
00828         np = (L_NEWPIXEL *)lstackRemove(lq->stack);
00829     else
00830         np = (L_NEWPIXEL *)CALLOC(1, sizeof(L_NEWPIXEL));
00831 
00832     np->x = x;
00833     np->y = y;
00834     lqueueAdd(lq, np);
00835     return;
00836 }
00837 
00838 
00839 /*
00840  *  popNewPixel()
00841  *
00842  *      Input:  lqueue
00843  *              &x, &y   (<return> pixel coordinates)
00844  *      Return: void
00845  *
00846  *   Notes:
00847  *       (1) This is a wrapper for removing a NewPixel from a queue,
00848  *           which returns the pixel coordinates and saves the NewPixel
00849  *           on the storage stack.
00850  */
00851 static void
00852 popNewPixel(L_QUEUE  *lq,
00853             l_int32  *px,
00854             l_int32  *py)
00855 {
00856 L_NEWPIXEL  *np;
00857 
00858     PROCNAME("popNewPixel");
00859 
00860     if (!lq) {
00861         L_ERROR(procName, "lqueue not defined");
00862         return;
00863     }
00864 
00865     if ((np = (L_NEWPIXEL *)lqueueRemove(lq)) == NULL)
00866         return;
00867     *px = np->x;
00868     *py = np->y;
00869     lstackAdd(lq->stack, np);  /* save for re-use */
00870     return;
00871 }
00872 
00873 
00874 /*
00875  *  pushWSPixel()
00876  *
00877  *      Input:  lh  (priority queue)
00878  *              stack  (of reusable WSPixels)
00879  *              val  (pixel value: used for ordering the heap)
00880  *              x, y  (pixel coordinates)
00881  *              index  (label for set to which pixel belongs)
00882  *      Return: void
00883  *
00884  *  Notes:
00885  *      (1) This is a wrapper for adding a WSPixel to a heap.  It
00886  *          uses the storage stack to retrieve a WSPixel.
00887  */
00888 static void
00889 pushWSPixel(L_HEAP   *lh,
00890             L_STACK  *stack,
00891             l_int32   val,
00892             l_int32   x,
00893             l_int32   y,
00894             l_int32   index)
00895 {
00896 L_WSPIXEL  *wsp;
00897 
00898     PROCNAME("pushWSPixel");
00899 
00900     if (!lh) {
00901         L_ERROR(procName, "heap not defined");
00902         return;
00903     }
00904     if (!stack) {
00905         L_ERROR(procName, "stack not defined");
00906         return;
00907     }
00908 
00909         /* Get a wspixel to use */
00910     if (lstackGetCount(stack) > 0)
00911         wsp = (L_WSPIXEL *)lstackRemove(stack);
00912     else
00913         wsp = (L_WSPIXEL *)CALLOC(1, sizeof(L_WSPIXEL));
00914 
00915     wsp->val = (l_float32)val;
00916     wsp->x = x;
00917     wsp->y = y;
00918     wsp->index = index;
00919     lheapAdd(lh, wsp);
00920     return;
00921 }
00922 
00923 
00924 /*
00925  *  popWSPixel()
00926  *
00927  *      Input:  lh  (priority queue)
00928  *              stack  (of reusable WSPixels)
00929  *              &val  (<return> pixel value)
00930  *              &x, &y  (<return> pixel coordinates)
00931  *              &index  (<return> label for set to which pixel belongs)
00932  *      Return: void
00933  *
00934  *   Notes:
00935  *       (1) This is a wrapper for removing a WSPixel from a heap,
00936  *           which returns the WSPixel data and saves the WSPixel
00937  *           on the storage stack.
00938  */
00939 static void
00940 popWSPixel(L_HEAP   *lh,
00941            L_STACK  *stack,
00942            l_int32  *pval,
00943            l_int32  *px,
00944            l_int32  *py,
00945            l_int32  *pindex)
00946 {
00947 L_WSPIXEL  *wsp;
00948 
00949     PROCNAME("popWSPixel");
00950 
00951     if (!lh) {
00952         L_ERROR(procName, "lheap not defined");
00953         return;
00954     }
00955     if (!stack) {
00956         L_ERROR(procName, "stack not defined");
00957         return;
00958     }
00959     if (!pval || !px || !py || !pindex) {
00960         L_ERROR(procName, "data can't be returned");
00961         return;
00962     }
00963 
00964     if ((wsp = (L_WSPIXEL *)lheapRemove(lh)) == NULL)
00965         return;
00966     *pval = (l_int32)wsp->val;
00967     *px = wsp->x;
00968     *py = wsp->y;
00969     *pindex = wsp->index;
00970     lstackAdd(stack, wsp);  /* save for re-use */
00971     return;
00972 }
00973 
00974 
00975 static void
00976 debugPrintLUT(l_int32  *lut,
00977               l_int32   size,
00978               l_int32   debug)
00979 {
00980 l_int32  i;
00981 
00982     if (!debug) return;
00983     fprintf(stderr, "lut: ");
00984     for (i = 0; i < size; i++)
00985         fprintf(stderr, "%d ", lut[i]);
00986     fprintf(stderr, "\n");
00987     return;
00988 }
00989 
00990 
00991 static void
00992 debugWshedMerge(L_WSHED *wshed,
00993                 char    *descr,
00994                 l_int32  x,
00995                 l_int32  y,
00996                 l_int32  label,
00997                 l_int32  index)
00998 {
00999     if (!wshed || (wshed->debug == 0))
01000          return;
01001     fprintf(stderr, "%s:\n", descr);
01002     fprintf(stderr, "   (x, y) = (%d, %d)\n", x, y);
01003     fprintf(stderr, "   clabel = %d, cindex = %d\n", label, index);
01004     return;
01005 }
01006 
01007 
01008 /*-----------------------------------------------------------------------*
01009  *                                 Output                                *
01010  *-----------------------------------------------------------------------*/
01011 /*!
01012  *  wshedBasins()
01013  *
01014  *      Input:  wshed
01015  *              &pixa  (<optional return> mask of watershed basins)
01016  *              &nalevels   (<optional return> watershed levels)
01017  *      Return: 0 if OK, 1 on error
01018  */
01019 l_int32
01020 wshedBasins(L_WSHED  *wshed,
01021             PIXA    **ppixa,
01022             NUMA    **pnalevels)
01023 {
01024     PROCNAME("wshedBasins");
01025 
01026     if (!wshed)
01027         return ERROR_INT("wshed not defined", procName, 1);
01028 
01029     if (ppixa)
01030         *ppixa = pixaCopy(wshed->pixad, L_CLONE);
01031     if (pnalevels)
01032         *pnalevels = numaClone(wshed->nalevels);
01033     return 0;
01034 }
01035 
01036 
01037 /*!
01038  *  wshedRenderFill()
01039  *
01040  *      Input:  wshed
01041  *      Return: pixd (initial image with all basins filled), or null on error
01042  */
01043 PIX *
01044 wshedRenderFill(L_WSHED  *wshed)
01045 {
01046 l_int32  i, n, level, bx, by;
01047 NUMA    *na;
01048 PIX     *pix, *pixd;
01049 PIXA    *pixa;
01050 
01051     PROCNAME("wshedRenderFill");
01052 
01053     if (!wshed)
01054         return (PIX *)ERROR_PTR("wshed not defined", procName, NULL);
01055 
01056     wshedBasins(wshed, &pixa, &na);
01057     pixd = pixCopy(NULL, wshed->pixs);
01058     n = pixaGetCount(pixa);
01059     for (i = 0; i < n; i++) {
01060         pix = pixaGetPix(pixa, i, L_CLONE);
01061         pixaGetBoxGeometry(pixa, i, &bx, &by, NULL, NULL);
01062         numaGetIValue(na, i, &level);
01063         pixPaintThroughMask(pixd, pix, bx, by, level);
01064         pixDestroy(&pix);
01065     }
01066 
01067     pixaDestroy(&pixa);
01068     numaDestroy(&na);
01069     return pixd;
01070 }
01071 
01072 
01073 /*!
01074  *  wshedRenderColors()
01075  *
01076  *      Input:  wshed
01077  *      Return: pixd (initial image with all basins filled), or null on error
01078  */
01079 PIX *
01080 wshedRenderColors(L_WSHED  *wshed)
01081 {
01082 l_int32  w, h;
01083 PIX     *pixg, *pixt, *pixc, *pixm, *pixd;
01084 PIXA    *pixa;
01085 
01086     PROCNAME("wshedRenderColors");
01087 
01088     if (!wshed)
01089         return (PIX *)ERROR_PTR("wshed not defined", procName, NULL);
01090 
01091     wshedBasins(wshed, &pixa, NULL);
01092     pixg = pixCopy(NULL, wshed->pixs);
01093     pixGetDimensions(wshed->pixs, &w, &h, NULL);
01094     pixd = pixConvertTo32(pixg);
01095     pixt = pixaDisplayRandomCmap(pixa, w, h);
01096     pixc = pixConvertTo32(pixt);
01097     pixm = pixaDisplay(pixa, w, h);
01098     pixCombineMasked(pixd, pixc, pixm);
01099 
01100     pixDestroy(&pixg);
01101     pixDestroy(&pixt);
01102     pixDestroy(&pixc);
01103     pixDestroy(&pixm);
01104     pixaDestroy(&pixa);
01105     return pixd;
01106 }
01107 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines