116#include <config_auto.h>
119#include "allheaders.h"
122#define DEBUG_WATERSHED 0
125static const l_uint32 MAX_LABEL_VALUE = 0x7fffffff;
150 l_int32
index, l_int32 level,
162static void pushNewPixel(
L_QUEUE *lq, l_int32
x, l_int32
y,
163 l_int32 *pminx, l_int32 *pmaxx,
164 l_int32 *pminy, l_int32 *pmaxy);
165static void popNewPixel(
L_QUEUE *lq, l_int32 *px, l_int32 *py);
169 l_int32
x, l_int32
y, l_int32
index);
170static void popWSPixel(
L_HEAP *lh,
L_STACK *stack, l_int32 *pval,
171 l_int32 *px, l_int32 *py, l_int32 *pindex);
174static void debugPrintLUT(l_int32 *lut, l_int32 size, l_int32 debug);
176static void debugWshedMerge(
L_WSHED *wshed,
char *descr, l_int32
x,
177 l_int32
y, l_int32 label, l_int32
index);
216 return (
L_WSHED *)ERROR_PTR(
"pixs is not defined", __func__, NULL);
217 if (pixGetDepth(pixs) != 8)
218 return (
L_WSHED *)ERROR_PTR(
"pixs is not 8 bpp", __func__, NULL);
220 return (
L_WSHED *)ERROR_PTR(
"pixm is not defined", __func__, NULL);
221 if (pixGetDepth(pixm) != 1)
222 return (
L_WSHED *)ERROR_PTR(
"pixm is not 1 bpp", __func__, NULL);
223 pixGetDimensions(pixs, &w, &h, NULL);
224 if (pixGetWidth(pixm) != w || pixGetHeight(pixm) != h)
225 return (
L_WSHED *)ERROR_PTR(
"pixs/m sizes are unequal", __func__, NULL);
228 return (
L_WSHED *)ERROR_PTR(
"wshed not made", __func__, NULL);
230 wshed->
pixs = pixClone(pixs);
231 wshed->
pixm = pixClone(pixm);
232 wshed->
mindepth = L_MAX(1, mindepth);
233 wshed->
pixlab = pixCreate(w, h, 32);
234 pixSetAllArbitrary(wshed->
pixlab, MAX_LABEL_VALUE);
235 wshed->
pixt = pixCreate(w, h, 1);
236 wshed->
lines8 = pixGetLinePtrs(pixs, NULL);
237 wshed->
linem1 = pixGetLinePtrs(pixm, NULL);
239 wshed->
linet1 = pixGetLinePtrs(wshed->
pixt, NULL);
240 wshed->
debug = debugflag;
257 if (pwshed == NULL) {
258 L_WARNING(
"ptr address is null!\n", __func__);
262 if ((wshed = *pwshed) == NULL)
265 pixDestroy(&wshed->
pixs);
266 pixDestroy(&wshed->
pixm);
267 pixDestroy(&wshed->
pixlab);
268 pixDestroy(&wshed->
pixt);
273 pixaDestroy(&wshed->
pixad);
274 ptaDestroy(&wshed->
ptas);
275 numaDestroy(&wshed->
nash);
276 numaDestroy(&wshed->
nasi);
277 numaDestroy(&wshed->
namh);
280 LEPT_FREE(wshed->
lut);
283 numaDestroy(&wshed->
links[i]);
284 LEPT_FREE(wshed->
links);
308char two_new_watersheds[] =
"Two new watersheds";
309char seed_absorbed_into_seeded_basin[] =
"Seed absorbed into seeded basin";
310char one_new_watershed_label[] =
"One new watershed (label)";
311char one_new_watershed_index[] =
"One new watershed (index)";
312char minima_absorbed_into_seeded_basin[] =
313 "Minima absorbed into seeded basin";
314char minima_absorbed_by_filler_or_another[] =
315 "Minima absorbed by filler or another";
316l_int32 nseeds, nother, nboth, arraysize;
317l_int32 i, j,
val,
x,
y, w, h,
index, mindepth;
318l_int32 imin, imax, jmin, jmax, cindex, clabel, nindex;
319l_int32 hindex, hlabel, hmin, hmax, minhindex, maxhindex;
321l_uint32 ulabel, uval;
322void **lines8, **linelab32;
323NUMA *nalut, *nalevels, *nash, *namh, *nasi;
332 return ERROR_INT(
"wshed not defined", __func__, 1);
339 rstack = lstackCreate(0);
340 pixGetDimensions(wshed->
pixs, &w, &h, NULL);
345 pixSelectMinInConnComp(wshed->
pixs, wshed->
pixm, &ptas, &nash);
346 pixsd = pixGenerateFromPta(ptas, w, h);
347 nseeds = ptaGetCount(ptas);
348 for (i = 0; i < nseeds; i++) {
349 ptaGetIPt(ptas, i, &
x, &
y);
351 pushWSPixel(lh, rstack, (l_int32)uval,
x,
y, i);
354 nasi = numaMakeConstant(1, nseeds);
366 pixLocalExtrema(wshed->
pixs, 200, 0, &pixmin, NULL);
367 pixRemoveSeededComponents(pixmin, pixsd, pixmin, 8, 2);
368 pixSelectMinInConnComp(wshed->
pixs, pixmin, &ptao, &namh);
369 nother = ptaGetCount(ptao);
370 for (i = 0; i < nother; i++) {
371 ptaGetIPt(ptao, i, &
x, &
y);
373 pushWSPixel(lh, rstack, (l_int32)uval,
x,
y, nseeds + i);
385 nboth = nseeds + nother;
386 arraysize = 2 * nboth;
388 nalut = numaMakeSequence(0, 1, arraysize);
389 lut = numaGetIArray(nalut);
391 links = (
NUMA **)LEPT_CALLOC(arraysize,
sizeof(
NUMA *));
392 wshed->
links = links;
393 nindex = nseeds + nother;
399 pixad = pixaCreate(nseeds);
400 wshed->
pixad = pixad;
401 nalevels = numaCreate(nseeds);
403 L_INFO(
"nseeds = %d, nother = %d\n", __func__, nseeds, nother);
404 while (lheapGetCount(lh) > 0) {
408 if (ulabel == MAX_LABEL_VALUE)
411 clabel = lut[ulabel];
413 if (clabel == cindex)
continue;
414 if (clabel == MAX_LABEL_VALUE) {
417 imin = L_MAX(0,
y - 1);
418 imax = L_MIN(h - 1,
y + 1);
419 jmin = L_MAX(0,
x - 1);
420 jmax = L_MIN(w - 1,
x + 1);
421 for (i = imin; i <= imax; i++) {
422 for (j = jmin; j <= jmax; j++) {
423 if (i ==
y && j ==
x)
continue;
425 pushWSPixel(lh, rstack, (l_int32)uval, j, i, cindex);
435 pixGetPixel(pixsd,
x,
y, &uval);
436 if (clabel < nseeds && cindex < nseeds) {
439 hmin = L_MIN(hlabel, hindex);
440 hmax = L_MAX(hlabel, hindex);
446 lept_stderr(
"clabel,hlabel = %d,%d\n", clabel, hlabel);
447 lept_stderr(
"hmin = %d, hmax = %d\n", hmin, hmax);
448 lept_stderr(
"cindex,hindex = %d,%d\n", cindex, hindex);
450 lept_stderr(
"Too shallow!\n");
453 if (hmin >= mindepth) {
454 debugWshedMerge(wshed, two_new_watersheds,
455 x,
y, clabel, cindex);
458 numaSetValue(nasi, cindex, 0);
459 numaSetValue(nasi, clabel, 0);
461 if (wshed->
debug) lept_stderr(
"nindex = %d\n", nindex);
462 debugPrintLUT(lut, nindex, wshed->
debug);
464 debugPrintLUT(lut, nindex, wshed->
debug);
466 debugPrintLUT(lut, nindex, wshed->
debug);
469 debugWshedMerge(wshed, seed_absorbed_into_seeded_basin,
470 x,
y, clabel, cindex);
474 if (hindex > hlabel) {
479 }
else if (clabel < nseeds && cindex >= nboth) {
482 debugWshedMerge(wshed, one_new_watershed_label,
483 x,
y, clabel, cindex);
485 numaSetValue(nasi, clabel, 0);
487 }
else if (cindex < nseeds && clabel >= nboth) {
488 debugWshedMerge(wshed, one_new_watershed_index,
489 x,
y, clabel, cindex);
491 numaSetValue(nasi, cindex, 0);
493 }
else if (clabel < nseeds) {
496 debugWshedMerge(wshed, minima_absorbed_into_seeded_basin,
497 x,
y, clabel, cindex);
499 }
else if (cindex < nseeds) {
500 debugWshedMerge(wshed, minima_absorbed_into_seeded_basin,
501 x,
y, clabel, cindex);
504 debugWshedMerge(wshed, minima_absorbed_by_filler_or_another,
505 x,
y, clabel, cindex);
514 for (i = 0; i < nseeds; i++) {
515 numaGetIValue(nasi, i, &ival);
518 numaSetValue(nasi, i, 0);
527 lheapDestroy(&lh, TRUE);
528 lstackDestroy(&rstack, TRUE);
561 L_ERROR(
"wshed not defined\n", __func__);
568 numaAddNumber(wshed->
nalevels, level - 1);
601l_int32 imin, imax, jmin, jmax, minx, miny, maxx, maxy;
602l_int32 bw, bh, i, j, w, h,
x,
y;
604l_uint32 label, bval, lval;
605void **lines8, **linelab32, **linet1;
607PIX *pixs, *pixt, *pixd;
611 return ERROR_INT(
"&box not defined", __func__, 1);
614 return ERROR_INT(
"&pixd not defined", __func__, 1);
617 return ERROR_INT(
"wshed not defined", __func__, 1);
620 lq = lqueueCreate(0);
621 lq->
stack = lstackCreate(0);
629 pixGetDimensions(pixs, &w, &h, NULL);
632 minx = miny = 1000000;
635 pixSetPixel(pixt,
x,
y, 1);
636 pushNewPixel(lq,
x,
y, &minx, &maxx, &miny, &maxy);
637 if (wshed->
debug) lept_stderr(
"prime: (x,y) = (%d, %d)\n",
x,
y);
646 while (lqueueGetCount(lq) > 0) {
647 popNewPixel(lq, &
x, &
y);
648 imin = L_MAX(0,
y - 1);
649 imax = L_MIN(h - 1,
y + 1);
650 jmin = L_MAX(0,
x - 1);
651 jmax = L_MIN(w - 1,
x + 1);
652 for (i = imin; i <= imax; i++) {
653 for (j = jmin; j <= jmax; j++) {
654 if (j ==
x && i ==
y)
continue;
656 if (label == MAX_LABEL_VALUE || lut[label] !=
index)
continue;
658 if (bval == 1)
continue;
660 if (lval >= level)
continue;
662 pushNewPixel(lq, j, i, &minx, &maxx, &miny, &maxy);
668 bw = maxx - minx + 1;
669 bh = maxy - miny + 1;
670 box = boxCreate(minx, miny, bw, bh);
671 pixd = pixClipRectangle(pixt, box, NULL);
672 pixRasterop(pixt, minx, miny, bw, bh,
PIX_SRC ^
PIX_DST, pixd, 0, 0);
676 lqueueDestroy(&lq, 1);
710l_int32 i, n, size,
index;
716 return ERROR_INT(
"wshed not defined", __func__, 1);
718 if (sindex < 0 || sindex >= size)
719 return ERROR_INT(
"invalid sindex", __func__, 1);
720 if (dindex < 0 || dindex >= size)
721 return ERROR_INT(
"invalid dindex", __func__, 1);
725 links = wshed->
links;
727 if ((na = links[sindex]) != NULL) {
728 n = numaGetCount(na);
729 for (i = 0; i < n; i++) {
730 numaGetIValue(na, i, &
index);
734 lut[sindex] = dindex;
741 links[dindex] = numaCreate(n);
742 numaJoin(links[dindex], links[sindex], 0, -1);
743 numaAddNumber(links[dindex], sindex);
744 numaDestroy(&links[sindex]);
776 return ERROR_INT(
"&height not defined", __func__, 1);
779 return ERROR_INT(
"wshed not defined", __func__, 1);
781 if (label < wshed->nseeds)
782 numaGetIValue(wshed->
nash, label, &minval);
783 else if (label < wshed->nseeds + wshed->
nother)
784 numaGetIValue(wshed->
namh, label, &minval);
786 return ERROR_INT(
"finished watershed; should not call", __func__, 1);
788 *pheight =
val - minval;
820 L_ERROR(
"queue not defined\n", __func__);
825 *pminx = L_MIN(*pminx,
x);
826 *pmaxx = L_MAX(*pmaxx,
x);
827 *pminy = L_MIN(*pminy,
y);
828 *pmaxy = L_MAX(*pmaxy,
y);
831 if (lstackGetCount(lq->
stack) > 0)
864 L_ERROR(
"lqueue not defined\n", __func__);
868 if ((np = (
L_NEWPIXEL *)lqueueRemove(lq)) == NULL)
872 lstackAdd(lq->
stack, np);
903 L_ERROR(
"heap not defined\n", __func__);
907 L_ERROR(
"stack not defined\n", __func__);
912 if (lstackGetCount(stack) > 0)
917 wsp->
val = (l_float32)
val;
953 L_ERROR(
"lheap not defined\n", __func__);
957 L_ERROR(
"stack not defined\n", __func__);
960 if (!pval || !px || !py || !pindex) {
961 L_ERROR(
"data can't be returned\n", __func__);
965 if ((wsp = (
L_WSPIXEL *)lheapRemove(lh)) == NULL)
967 *pval = (l_int32)wsp->
val;
970 *pindex = wsp->
index;
971 lstackAdd(stack, wsp);
976debugPrintLUT(l_int32 *lut,
983 lept_stderr(
"lut: ");
984 for (i = 0; i < size; i++)
985 lept_stderr(
"%d ", lut[i]);
998 if (!wshed || (wshed->
debug == 0))
1000 lept_stderr(
"%s:\n", descr);
1001 lept_stderr(
" (x, y) = (%d, %d)\n",
x,
y);
1002 lept_stderr(
" clabel = %d, cindex = %d\n", label,
index);
1023 return ERROR_INT(
"wshed not defined", __func__, 1);
1028 *pnalevels = numaClone(wshed->
nalevels);
1042l_int32 i, n, level, bx, by;
1048 return (
PIX *)ERROR_PTR(
"wshed not defined", __func__, NULL);
1051 pixd = pixCopy(NULL, wshed->
pixs);
1052 n = pixaGetCount(pixa);
1053 for (i = 0; i < n; i++) {
1054 pix = pixaGetPix(pixa, i,
L_CLONE);
1055 pixaGetBoxGeometry(pixa, i, &bx, &by, NULL, NULL);
1056 numaGetIValue(na, i, &level);
1057 pixPaintThroughMask(pixd, pix, bx, by, level);
1077PIX *pixg, *pixt, *pixc, *pixm, *pixd;
1081 return (
PIX *)ERROR_PTR(
"wshed not defined", __func__, NULL);
1084 pixg = pixCopy(NULL, wshed->
pixs);
1085 pixGetDimensions(wshed->
pixs, &w, &h, NULL);
1086 pixd = pixConvertTo32(pixg);
1087 pixt = pixaDisplayRandomCmap(pixa, w, h);
1088 pixc = pixConvertTo32(pixt);
1089 pixm = pixaDisplay(pixa, w, h);
1090 pixCombineMasked(pixd, pixc, pixm);
#define SET_DATA_BIT(pdata, n)
#define SET_DATA_FOUR_BYTES(pdata, n, val)
#define GET_DATA_BYTE(pdata, n)
#define GET_DATA_FOUR_BYTES(pdata, n)
#define GET_DATA_BIT(pdata, n)
PIX * wshedRenderColors(L_WSHED *wshed)
wshedRenderColors()
PIX * wshedRenderFill(L_WSHED *wshed)
wshedRenderFill()
static l_int32 wshedGetHeight(L_WSHED *wshed, l_int32 val, l_int32 label, l_int32 *pheight)
wshedGetHeight()
static l_int32 identifyWatershedBasin(L_WSHED *wshed, l_int32 index, l_int32 level, BOX **pbox, PIX **ppixd)
identifyWatershedBasin()
void wshedDestroy(L_WSHED **pwshed)
wshedDestroy()
static l_int32 mergeLookup(L_WSHED *wshed, l_int32 sindex, l_int32 dindex)
mergeLookup()
L_WSHED * wshedCreate(PIX *pixs, PIX *pixm, l_int32 mindepth, l_int32 debugflag)
wshedCreate()
l_ok wshedBasins(L_WSHED *wshed, PIXA **ppixa, NUMA **pnalevels)
wshedBasins()
static void wshedSaveBasin(L_WSHED *wshed, l_int32 index, l_int32 level)
wshedSaveBasin()
l_ok wshedApply(L_WSHED *wshed)
wshedApply()