Leptonica  1.82.0
Image processing and image analysis suite
ccbord.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
27 
250 #ifdef HAVE_CONFIG_H
251 #include <config_auto.h>
252 #endif /* HAVE_CONFIG_H */
253 
254 #include <string.h>
255 #include "allheaders.h"
256 
257 static const l_int32 INITIAL_PTR_ARRAYSIZE = 20; /* n'import quoi */
258 
259  /* In ccbaGenerateSinglePath(): don't save holes
260  * in c.c. with ridiculously many small holes */
261 static const l_int32 NMAX_HOLES = 150;
262 
263  /* Tables used to trace the border.
264  * - The 8 pixel positions of neighbors Q are labeled clockwise
265  * starting from the west:
266  * 1 2 3
267  * 0 P 4
268  * 7 6 5
269  * where the labels are the index offset [0, ... 7] of Q relative to P.
270  * - xpostab[] and ypostab[] give the actual x and y pixel offsets
271  * of Q relative to P, indexed by the index offset.
272  * - qpostab[pos] gives the new index offset of Q relative to P, at
273  * the time that a new P has been chosen to be in index offset
274  * position 'pos' relative to the previous P. The relation
275  * between P and Q is always 4-connected. */
276 static const l_int32 xpostab[] = {-1, -1, 0, 1, 1, 1, 0, -1};
277 static const l_int32 ypostab[] = {0, -1, -1, -1, 0, 1, 1, 1};
278 static const l_int32 qpostab[] = {6, 6, 0, 0, 2, 2, 4, 4};
279 
280  /* Static functions */
281 static l_int32 ccbaExtendArray(CCBORDA *ccba);
282 static CCBORD *pixGetCCBorders(PIX *pixs, BOX *box);
283 static PTA *pixGetOuterBorderPta(PIX *pixs, BOX *box);
284 static l_ok pixGetHoleBorder(CCBORD *ccb, PIX *pixs, BOX *box,
285  l_int32 xs, l_int32 ys);
286 static l_int32 findNextBorderPixel(l_int32 w, l_int32 h, l_uint32 *data,
287  l_int32 wpl, l_int32 px, l_int32 py,
288  l_int32 *pqpos, l_int32 *pnpx,
289  l_int32 *pnpy);
290 static void locateOutsideSeedPixel(l_int32 fpx, l_int32 fpy, l_int32 spx,
291  l_int32 spy, l_int32 *pxs, l_int32 *pys);
292 
293 #ifndef NO_CONSOLE_IO
294 #define DEBUG_PRINT 0
295 #endif /* NO CONSOLE_IO */
296 
297 
298 /*---------------------------------------------------------------------*
299  * ccba and ccb creation and destruction *
300  *---------------------------------------------------------------------*/
308 CCBORDA *
310  l_int32 n)
311 {
312 CCBORDA *ccba;
313 
314  PROCNAME("ccbaCreate");
315 
316  if (n <= 0)
317  n = INITIAL_PTR_ARRAYSIZE;
318 
319  ccba = (CCBORDA *)LEPT_CALLOC(1, sizeof(CCBORDA));
320  if (pixs) {
321  ccba->pix = pixClone(pixs);
322  ccba->w = pixGetWidth(pixs);
323  ccba->h = pixGetHeight(pixs);
324  }
325  ccba->n = 0;
326  ccba->nalloc = n;
327  if ((ccba->ccb = (CCBORD **)LEPT_CALLOC(n, sizeof(CCBORD *))) == NULL) {
328  ccbaDestroy(&ccba);
329  return (CCBORDA *)ERROR_PTR("ccba ptrs not made", procName, NULL);
330  }
331  return ccba;
332 }
333 
334 
341 void
343 {
344 l_int32 i;
345 CCBORDA *ccba;
346 
347  PROCNAME("ccbaDestroy");
348 
349  if (pccba == NULL) {
350  L_WARNING("ptr address is NULL!\n", procName);
351  return;
352  }
353 
354  if ((ccba = *pccba) == NULL)
355  return;
356 
357  pixDestroy(&ccba->pix);
358  for (i = 0; i < ccba->n; i++)
359  ccbDestroy(&ccba->ccb[i]);
360  LEPT_FREE(ccba->ccb);
361  LEPT_FREE(ccba);
362  *pccba = NULL;
363 }
364 
365 
372 CCBORD *
374 {
375 BOXA *boxa;
376 CCBORD *ccb;
377 PTA *start;
378 PTAA *local;
379 
380  PROCNAME("ccbCreate");
381 
382  if (pixs && pixGetDepth(pixs) != 1) /* pixs can be null */
383  return (CCBORD *)ERROR_PTR("pixs defined and not 1bpp", procName, NULL);
384 
385  ccb = (CCBORD *)LEPT_CALLOC(1, sizeof(CCBORD));
386  ccb->refcount++;
387  if (pixs)
388  ccb->pix = pixClone(pixs);
389  boxa = boxaCreate(1);
390  ccb->boxa = boxa;
391  start = ptaCreate(1);
392  ccb->start = start;
393  local = ptaaCreate(1);
394  ccb->local = local;
395  return ccb;
396 }
397 
398 
405 void
407 {
408 CCBORD *ccb;
409 
410  PROCNAME("ccbDestroy");
411 
412  if (pccb == NULL) {
413  L_WARNING("ptr address is NULL!\n", procName);
414  return;
415  }
416 
417  if ((ccb = *pccb) == NULL)
418  return;
419 
420  ccb->refcount--;
421  if (ccb->refcount == 0) {
422  if (ccb->pix)
423  pixDestroy(&ccb->pix);
424  if (ccb->boxa)
425  boxaDestroy(&ccb->boxa);
426  if (ccb->start)
427  ptaDestroy(&ccb->start);
428  if (ccb->local)
429  ptaaDestroy(&ccb->local);
430  if (ccb->global)
431  ptaaDestroy(&ccb->global);
432  if (ccb->step)
433  numaaDestroy(&ccb->step);
434  if (ccb->splocal)
435  ptaDestroy(&ccb->splocal);
436  if (ccb->spglobal)
437  ptaDestroy(&ccb->spglobal);
438  LEPT_FREE(ccb);
439  *pccb = NULL;
440  }
441 }
442 
443 
444 /*---------------------------------------------------------------------*
445  * ccba addition *
446  *---------------------------------------------------------------------*/
454 l_ok
456  CCBORD *ccb)
457 {
458 l_int32 n;
459 
460  PROCNAME("ccbaAddCcb");
461 
462  if (!ccba)
463  return ERROR_INT("ccba not defined", procName, 1);
464  if (!ccb)
465  return ERROR_INT("ccb not defined", procName, 1);
466 
467  n = ccbaGetCount(ccba);
468  if (n >= ccba->nalloc) {
469  if (ccbaExtendArray(ccba))
470  return ERROR_INT("extension failed", procName, 1);
471  }
472  ccba->ccb[n] = ccb;
473  ccba->n++;
474  return 0;
475 }
476 
477 
484 static l_int32
486 {
487  PROCNAME("ccbaExtendArray");
488 
489  if (!ccba)
490  return ERROR_INT("ccba not defined", procName, 1);
491 
492  if ((ccba->ccb = (CCBORD **)reallocNew((void **)&ccba->ccb,
493  sizeof(CCBORD *) * ccba->nalloc,
494  2 * sizeof(CCBORD *) * ccba->nalloc)) == NULL)
495  return ERROR_INT("new ptr array not returned", procName, 1);
496 
497  ccba->nalloc = 2 * ccba->nalloc;
498  return 0;
499 }
500 
501 
502 
503 /*---------------------------------------------------------------------*
504  * ccba accessors *
505  *---------------------------------------------------------------------*/
512 l_int32
514 {
515 
516  PROCNAME("ccbaGetCount");
517 
518  if (!ccba)
519  return ERROR_INT("ccba not defined", procName, 0);
520 
521  return ccba->n;
522 }
523 
524 
537 CCBORD *
539  l_int32 index)
540 {
541 CCBORD *ccb;
542 
543  PROCNAME("ccbaGetCcb");
544 
545  if (!ccba)
546  return (CCBORD *)ERROR_PTR("ccba not defined", procName, NULL);
547  if (index < 0 || index >= ccba->n)
548  return (CCBORD *)ERROR_PTR("index out of bounds", procName, NULL);
549 
550  ccb = ccba->ccb[index];
551  ccb->refcount++;
552  return ccb;
553 }
554 
555 
556 
557 /*---------------------------------------------------------------------*
558  * Top-level border-finding routines *
559  *---------------------------------------------------------------------*/
566 CCBORDA *
568 {
569 l_int32 n, i;
570 BOX *box;
571 BOXA *boxa;
572 CCBORDA *ccba;
573 CCBORD *ccb;
574 PIX *pix;
575 PIXA *pixa;
576 
577  PROCNAME("pixGetAllCCBorders");
578 
579  if (!pixs)
580  return (CCBORDA *)ERROR_PTR("pixs not defined", procName, NULL);
581  if (pixGetDepth(pixs) != 1)
582  return (CCBORDA *)ERROR_PTR("pixs not binary", procName, NULL);
583 
584  if ((boxa = pixConnComp(pixs, &pixa, 8)) == NULL)
585  return (CCBORDA *)ERROR_PTR("boxa not made", procName, NULL);
586  n = boxaGetCount(boxa);
587 
588  if ((ccba = ccbaCreate(pixs, n)) == NULL) {
589  boxaDestroy(&boxa);
590  pixaDestroy(&pixa);
591  return (CCBORDA *)ERROR_PTR("ccba not made", procName, NULL);
592  }
593  for (i = 0; i < n; i++) {
594  if ((pix = pixaGetPix(pixa, i, L_CLONE)) == NULL) {
595  ccbaDestroy(&ccba);
596  pixaDestroy(&pixa);
597  boxaDestroy(&boxa);
598  return (CCBORDA *)ERROR_PTR("pix not found", procName, NULL);
599  }
600  if ((box = pixaGetBox(pixa, i, L_CLONE)) == NULL) {
601  ccbaDestroy(&ccba);
602  pixaDestroy(&pixa);
603  boxaDestroy(&boxa);
604  pixDestroy(&pix);
605  return (CCBORDA *)ERROR_PTR("box not found", procName, NULL);
606  }
607  ccb = pixGetCCBorders(pix, box);
608  pixDestroy(&pix);
609  boxDestroy(&box);
610  if (!ccb) {
611  ccbaDestroy(&ccba);
612  pixaDestroy(&pixa);
613  boxaDestroy(&boxa);
614  return (CCBORDA *)ERROR_PTR("ccb not made", procName, NULL);
615  }
616 /* ptaWriteStream(stderr, ccb->local, 1); */
617  ccbaAddCcb(ccba, ccb);
618  }
619 
620  boxaDestroy(&boxa);
621  pixaDestroy(&pixa);
622  return ccba;
623 }
624 
625 
652 static CCBORD *
654  BOX *box)
655 {
656 l_int32 allzero, i, x, xh, w, nh;
657 l_int32 xs, ys; /* starting hole border pixel, relative in pixs */
658 l_uint32 val;
659 BOX *boxt, *boxe;
660 BOXA *boxa;
661 CCBORD *ccb;
662 PIX *pixh; /* for hole components */
663 PIX *pixt;
664 PIXA *pixa;
665 
666  PROCNAME("pixGetCCBorders");
667 
668  if (!pixs)
669  return (CCBORD *)ERROR_PTR("pixs not defined", procName, NULL);
670  if (!box)
671  return (CCBORD *)ERROR_PTR("box not defined", procName, NULL);
672  if (pixGetDepth(pixs) != 1)
673  return (CCBORD *)ERROR_PTR("pixs not binary", procName, NULL);
674 
675  pixZero(pixs, &allzero);
676  if (allzero)
677  return (CCBORD *)ERROR_PTR("pixs all 0", procName, NULL);
678 
679  if ((ccb = ccbCreate(pixs)) == NULL)
680  return (CCBORD *)ERROR_PTR("ccb not made", procName, NULL);
681 
682  /* Get the exterior border */
683  pixGetOuterBorder(ccb, pixs, box);
684 
685  /* Find the holes, if any */
686  if ((pixh = pixHolesByFilling(pixs, 4)) == NULL) {
687  ccbDestroy(&ccb);
688  return (CCBORD *)ERROR_PTR("pixh not made", procName, NULL);
689  }
690  pixZero(pixh, &allzero);
691  if (allzero) { /* no holes */
692  pixDestroy(&pixh);
693  return ccb;
694  }
695 
696  /* Get c.c. and locations of the holes */
697  if ((boxa = pixConnComp(pixh, &pixa, 4)) == NULL) {
698  ccbDestroy(&ccb);
699  pixDestroy(&pixh);
700  return (CCBORD *)ERROR_PTR("boxa not made", procName, NULL);
701  }
702  nh = boxaGetCount(boxa);
703 /* lept_stderr("%d holes\n", nh); */
704 
705  /* For each hole, find an interior pixel within the hole,
706  * then march to the right and stop at the first border
707  * pixel. Save the bounding box of the border, which
708  * is 1 pixel bigger on each side than the bounding box
709  * of the hole itself. Note that we use a pix of the
710  * c.c. of the hole itself to be sure that we start
711  * with a pixel in the hole of the proper component.
712  * If we did everything from the parent component, it is
713  * possible to start in a different hole that is within
714  * the b.b. of a larger hole. */
715  w = pixGetWidth(pixs);
716  for (i = 0; i < nh; i++) {
717  boxt = boxaGetBox(boxa, i, L_CLONE);
718  pixt = pixaGetPix(pixa, i, L_CLONE);
719  ys = boxt->y; /* there must be a hole pixel on this raster line */
720  for (x = 0; x < boxt->w; x++) { /* look for (fg) hole pixel */
721  pixGetPixel(pixt, x, 0, &val);
722  if (val == 1) {
723  xh = x;
724  break;
725  }
726  }
727  if (x == boxt->w) {
728  L_WARNING("no hole pixel found!\n", procName);
729  continue;
730  }
731  for (x = xh + boxt->x; x < w; x++) { /* look for (fg) border pixel */
732  pixGetPixel(pixs, x, ys, &val);
733  if (val == 1) {
734  xs = x;
735  break;
736  }
737  }
738  boxe = boxCreate(boxt->x - 1, boxt->y - 1, boxt->w + 2, boxt->h + 2);
739 #if DEBUG_PRINT
740  boxPrintStreamInfo(stderr, box);
741  boxPrintStreamInfo(stderr, boxe);
742  lept_stderr("xs = %d, ys = %d\n", xs, ys);
743 #endif /* DEBUG_PRINT */
744  pixGetHoleBorder(ccb, pixs, boxe, xs, ys);
745  boxDestroy(&boxt);
746  boxDestroy(&boxe);
747  pixDestroy(&pixt);
748  }
749 
750  boxaDestroy(&boxa);
751  pixaDestroy(&pixa);
752  pixDestroy(&pixh);
753  return ccb;
754 }
755 
756 
763 PTAA *
765 {
766 l_int32 i, n;
767 BOX *box;
768 BOXA *boxa;
769 PIX *pix;
770 PIXA *pixa;
771 PTA *pta;
772 PTAA *ptaa;
773 
774  PROCNAME("pixGetOuterBordersPtaa");
775 
776  if (!pixs)
777  return (PTAA *)ERROR_PTR("pixs not defined", procName, NULL);
778  if (pixGetDepth(pixs) != 1)
779  return (PTAA *)ERROR_PTR("pixs not binary", procName, NULL);
780 
781  boxa = pixConnComp(pixs, &pixa, 8);
782  n = boxaGetCount(boxa);
783  if (n == 0) {
784  boxaDestroy(&boxa);
785  pixaDestroy(&pixa);
786  return (PTAA *)ERROR_PTR("pixs empty", procName, NULL);
787  }
788 
789  ptaa = ptaaCreate(n);
790  for (i = 0; i < n; i++) {
791  box = boxaGetBox(boxa, i, L_CLONE);
792  pix = pixaGetPix(pixa, i, L_CLONE);
793  pta = pixGetOuterBorderPta(pix, box);
794  if (pta)
795  ptaaAddPta(ptaa, pta, L_INSERT);
796  boxDestroy(&box);
797  pixDestroy(&pix);
798  }
799 
800  pixaDestroy(&pixa);
801  boxaDestroy(&boxa);
802  return ptaa;
803 }
804 
805 
823 static PTA *
825  BOX *box)
826 {
827 l_int32 allzero, x, y;
828 BOX *boxt;
829 CCBORD *ccb;
830 PTA *ptaloc, *ptad;
831 
832  PROCNAME("pixGetOuterBorderPta");
833 
834  if (!pixs)
835  return (PTA *)ERROR_PTR("pixs not defined", procName, NULL);
836  if (pixGetDepth(pixs) != 1)
837  return (PTA *)ERROR_PTR("pixs not binary", procName, NULL);
838 
839  pixZero(pixs, &allzero);
840  if (allzero)
841  return (PTA *)ERROR_PTR("pixs all 0", procName, NULL);
842 
843  if ((ccb = ccbCreate(pixs)) == NULL)
844  return (PTA *)ERROR_PTR("ccb not made", procName, NULL);
845  if (!box)
846  boxt = boxCreate(0, 0, pixGetWidth(pixs), pixGetHeight(pixs));
847  else
848  boxt = boxClone(box);
849 
850  /* Get the exterior border in local coords */
851  pixGetOuterBorder(ccb, pixs, boxt);
852  if ((ptaloc = ptaaGetPta(ccb->local, 0, L_CLONE)) == NULL) {
853  ccbDestroy(&ccb);
854  boxDestroy(&boxt);
855  return (PTA *)ERROR_PTR("ptaloc not made", procName, NULL);
856  }
857 
858  /* Transform to global coordinates, if they are given */
859  if (box) {
860  boxGetGeometry(box, &x, &y, NULL, NULL);
861  ptad = ptaTransform(ptaloc, x, y, 1.0, 1.0);
862  } else {
863  ptad = ptaClone(ptaloc);
864  }
865 
866  ptaDestroy(&ptaloc);
867  boxDestroy(&boxt);
868  ccbDestroy(&ccb);
869  return ptad;
870 }
871 
872 
873 /*---------------------------------------------------------------------*
874  * Lower-level border-finding routines *
875  *---------------------------------------------------------------------*/
896 l_ok
898  PIX *pixs,
899  BOX *box)
900 {
901 l_int32 fpx, fpy, spx, spy, qpos;
902 l_int32 px, py, npx, npy;
903 l_int32 w, h, wpl;
904 l_uint32 *data;
905 PTA *pta;
906 PIX *pixb; /* with 1 pixel border */
907 
908  PROCNAME("pixGetOuterBorder");
909 
910  if (!ccb)
911  return ERROR_INT("ccb not defined", procName, 1);
912  if (!pixs)
913  return ERROR_INT("pixs not defined", procName, 1);
914  if (!box)
915  return ERROR_INT("box not defined", procName, 1);
916 
917  /* Add 1-pixel border all around, and find start pixel */
918  if ((pixb = pixAddBorder(pixs, 1, 0)) == NULL)
919  return ERROR_INT("pixs not made", procName, 1);
920  if (!nextOnPixelInRaster(pixb, 1, 1, &px, &py)) {
921  pixDestroy(&pixb);
922  return ERROR_INT("no start pixel found", procName, 1);
923  }
924  qpos = 0; /* relative to p */
925  fpx = px; /* save location of first pixel on border */
926  fpy = py;
927 
928  /* Save box and start pixel in relative coords */
929  boxaAddBox(ccb->boxa, box, L_COPY);
930  ptaAddPt(ccb->start, px - 1, py - 1);
931 
932  pta = ptaCreate(0);
933  ptaaAddPta(ccb->local, pta, L_INSERT);
934  ptaAddPt(pta, px - 1, py - 1); /* initial point */
935  pixGetDimensions(pixb, &w, &h, NULL);
936  data = pixGetData(pixb);
937  wpl = pixGetWpl(pixb);
938 
939  /* Get the second point; if there is none, return */
940  if (findNextBorderPixel(w, h, data, wpl, px, py, &qpos, &npx, &npy)) {
941  pixDestroy(&pixb);
942  return 0;
943  }
944 
945  spx = npx; /* save location of second pixel on border */
946  spy = npy;
947  ptaAddPt(pta, npx - 1, npy - 1); /* second point */
948  px = npx;
949  py = npy;
950 
951  while (1) {
952  findNextBorderPixel(w, h, data, wpl, px, py, &qpos, &npx, &npy);
953  if (px == fpx && py == fpy && npx == spx && npy == spy)
954  break;
955  ptaAddPt(pta, npx - 1, npy - 1);
956  px = npx;
957  py = npy;
958  }
959 
960  pixDestroy(&pixb);
961  return 0;
962 }
963 
964 
984 static l_ok
986  PIX *pixs,
987  BOX *box,
988  l_int32 xs,
989  l_int32 ys)
990 {
991 l_int32 fpx, fpy, spx, spy, qpos;
992 l_int32 px, py, npx, npy;
993 l_int32 w, h, wpl;
994 l_uint32 *data;
995 PTA *pta;
996 
997  PROCNAME("pixGetHoleBorder");
998 
999  if (!ccb)
1000  return ERROR_INT("ccb not defined", procName, 1);
1001  if (!pixs)
1002  return ERROR_INT("pixs not defined", procName, 1);
1003  if (!box)
1004  return ERROR_INT("box not defined", procName, 1);
1005 
1006  /* Add border and find start pixel */
1007  qpos = 0; /* orientation of Q relative to P */
1008  fpx = xs; /* save location of first pixel on border */
1009  fpy = ys;
1010 
1011  /* Save box and start pixel */
1012  boxaAddBox(ccb->boxa, box, L_COPY);
1013  ptaAddPt(ccb->start, xs, ys);
1014 
1015  pta = ptaCreate(0);
1016  ptaaAddPta(ccb->local, pta, L_INSERT);
1017  ptaAddPt(pta, xs, ys); /* initial pixel */
1018 
1019  w = pixGetWidth(pixs);
1020  h = pixGetHeight(pixs);
1021  data = pixGetData(pixs);
1022  wpl = pixGetWpl(pixs);
1023 
1024  /* Get the second point; there should always be at least 4 pts
1025  * in a minimal hole border! */
1026  if (findNextBorderPixel(w, h, data, wpl, xs, ys, &qpos, &npx, &npy))
1027  return ERROR_INT("isolated hole border point!", procName, 1);
1028 
1029  spx = npx; /* save location of second pixel on border */
1030  spy = npy;
1031  ptaAddPt(pta, npx, npy); /* second pixel */
1032  px = npx;
1033  py = npy;
1034 
1035  while (1) {
1036  findNextBorderPixel(w, h, data, wpl, px, py, &qpos, &npx, &npy);
1037  if (px == fpx && py == fpy && npx == spx && npy == spy)
1038  break;
1039  ptaAddPt(pta, npx, npy);
1040  px = npx;
1041  py = npy;
1042  }
1043 
1044  return 0;
1045 }
1046 
1047 
1066 static l_int32
1068  l_int32 h,
1069  l_uint32 *data,
1070  l_int32 wpl,
1071  l_int32 px,
1072  l_int32 py,
1073  l_int32 *pqpos,
1074  l_int32 *pnpx,
1075  l_int32 *pnpy)
1076 {
1077 l_int32 qpos, i, pos, npx, npy, val;
1078 l_uint32 *line;
1079 
1080  qpos = *pqpos;
1081  for (i = 1; i < 8; i++) {
1082  pos = (qpos + i) % 8;
1083  npx = px + xpostab[pos];
1084  npy = py + ypostab[pos];
1085  if (npx < 0 || npx >= w || npy < 0 || npy >= h)
1086  continue;
1087  line = data + npy * wpl;
1088  val = GET_DATA_BIT(line, npx);
1089  if (val) {
1090  *pnpx = npx;
1091  *pnpy = npy;
1092  *pqpos = qpostab[pos];
1093  return 0;
1094  }
1095  }
1096 
1097  return 1;
1098 }
1099 
1100 
1119 static void
1121  l_int32 fpy,
1122  l_int32 spx,
1123  l_int32 spy,
1124  l_int32 *pxs,
1125  l_int32 *pys)
1126 {
1127 l_int32 dx, dy;
1128 
1129  dx = spx - fpx;
1130  dy = spy - fpy;
1131 
1132  if (dx * dy == 1) {
1133  *pxs = fpx + dx;
1134  *pys = fpy;
1135  } else if (dx * dy == -1) {
1136  *pxs = fpx;
1137  *pys = fpy + dy;
1138  } else if (dx == 0) {
1139  *pxs = fpx + dy;
1140  *pys = fpy + dy;
1141  } else /* dy == 0 */ {
1142  *pxs = fpx + dx;
1143  *pys = fpy - dx;
1144  }
1145 
1146  return;
1147 }
1148 
1149 
1150 
1151 /*---------------------------------------------------------------------*
1152  * Border conversions *
1153  *---------------------------------------------------------------------*/
1167 l_ok
1169 {
1170 l_int32 ncc, nb, n, i, j, k, xul, yul, x, y;
1171 CCBORD *ccb;
1172 PTAA *ptaal, *ptaag;
1173 PTA *ptal, *ptag;
1174 
1175  PROCNAME("ccbaGenerateGlobalLocs");
1176 
1177  if (!ccba)
1178  return ERROR_INT("ccba not defined", procName, 1);
1179 
1180  ncc = ccbaGetCount(ccba); /* number of c.c. */
1181  for (i = 0; i < ncc; i++) {
1182  ccb = ccbaGetCcb(ccba, i);
1183 
1184  /* Get the UL corner in global coords, (xul, yul), of the c.c. */
1185  boxaGetBoxGeometry(ccb->boxa, 0, &xul, &yul, NULL, NULL);
1186 
1187  /* Make a new global ptaa, removing any old one */
1188  ptaal = ccb->local;
1189  nb = ptaaGetCount(ptaal); /* number of borders */
1190  if (ccb->global) /* remove old one */
1191  ptaaDestroy(&ccb->global);
1192  if ((ptaag = ptaaCreate(nb)) == NULL) {
1193  ccbDestroy(&ccb);
1194  return ERROR_INT("ptaag not made", procName, 1);
1195  }
1196  ccb->global = ptaag; /* save new one */
1197 
1198  /* Iterate through the borders for this c.c. */
1199  for (j = 0; j < nb; j++) {
1200  ptal = ptaaGetPta(ptaal, j, L_CLONE);
1201  n = ptaGetCount(ptal); /* number of pixels in border */
1202  ptag = ptaCreate(n);
1203  ptaaAddPta(ptaag, ptag, L_INSERT);
1204  for (k = 0; k < n; k++) {
1205  ptaGetIPt(ptal, k, &x, &y);
1206  ptaAddPt(ptag, x + xul, y + yul);
1207  }
1208  ptaDestroy(&ptal);
1209  }
1210  ccbDestroy(&ccb);
1211  }
1212 
1213  return 0;
1214 }
1215 
1216 
1239 l_ok
1241 {
1242 l_int32 ncc, nb, n, i, j, k;
1243 l_int32 px, py, cx, cy, stepdir;
1244 l_int32 dirtab[][3] = {{1, 2, 3}, {0, -1, 4}, {7, 6, 5}};
1245 CCBORD *ccb;
1246 NUMA *na;
1247 NUMAA *naa; /* step chain code; to be made */
1248 PTA *ptal;
1249 PTAA *ptaal; /* local chain code */
1250 
1251  PROCNAME("ccbaGenerateStepChains");
1252 
1253  if (!ccba)
1254  return ERROR_INT("ccba not defined", procName, 1);
1255 
1256  ncc = ccbaGetCount(ccba); /* number of c.c. */
1257  for (i = 0; i < ncc; i++) {
1258  ccb = ccbaGetCcb(ccba, i);
1259 
1260  /* Make a new step numaa, removing any old one */
1261  ptaal = ccb->local;
1262  nb = ptaaGetCount(ptaal); /* number of borders */
1263  if (ccb->step) /* remove old one */
1264  numaaDestroy(&ccb->step);
1265  if ((naa = numaaCreate(nb)) == NULL) {
1266  ccbDestroy(&ccb);
1267  return ERROR_INT("naa not made", procName, 1);
1268  }
1269  ccb->step = naa; /* save new one */
1270 
1271  /* Iterate through the borders for this c.c. */
1272  for (j = 0; j < nb; j++) {
1273  ptal = ptaaGetPta(ptaal, j, L_CLONE);
1274  n = ptaGetCount(ptal); /* number of pixels in border */
1275  if (n == 1) { /* isolated pixel */
1276  na = numaCreate(1); /* but leave it empty */
1277  } else { /* trace out the boundary */
1278  na = numaCreate(n);
1279  ptaGetIPt(ptal, 0, &px, &py);
1280  for (k = 1; k < n; k++) {
1281  ptaGetIPt(ptal, k, &cx, &cy);
1282  stepdir = dirtab[1 + cy - py][1 + cx - px];
1283  numaAddNumber(na, stepdir);
1284  px = cx;
1285  py = cy;
1286  }
1287  }
1288  numaaAddNuma(naa, na, L_INSERT);
1289  ptaDestroy(&ptal);
1290  }
1291  ccbDestroy(&ccb); /* just decrement refcount */
1292  }
1293 
1294  return 0;
1295 }
1296 
1297 
1314 l_ok
1316  l_int32 coordtype)
1317 {
1318 l_int32 ncc, nb, n, i, j, k;
1319 l_int32 xul, yul, xstart, ystart, x, y, stepdir;
1320 BOXA *boxa;
1321 CCBORD *ccb;
1322 NUMA *na;
1323 NUMAA *naa;
1324 PTAA *ptaan; /* new pix coord ptaa */
1325 PTA *ptas, *ptan;
1326 
1327  PROCNAME("ccbaStepChainsToPixCoords");
1328 
1329  if (!ccba)
1330  return ERROR_INT("ccba not defined", procName, 1);
1331  if (coordtype != CCB_GLOBAL_COORDS && coordtype != CCB_LOCAL_COORDS)
1332  return ERROR_INT("coordtype not valid", procName, 1);
1333 
1334  ncc = ccbaGetCount(ccba); /* number of c.c. */
1335  for (i = 0; i < ncc; i++) {
1336  ccb = ccbaGetCcb(ccba, i);
1337  if ((naa = ccb->step) == NULL) {
1338  ccbDestroy(&ccb);
1339  return ERROR_INT("step numaa not found", procName, 1);
1340  } if ((boxa = ccb->boxa) == NULL) {
1341  ccbDestroy(&ccb);
1342  return ERROR_INT("boxa not found", procName, 1);
1343  } if ((ptas = ccb->start) == NULL) {
1344  ccbDestroy(&ccb);
1345  return ERROR_INT("start pta not found", procName, 1);
1346  }
1347 
1348  /* For global coords, get the (xul, yul) of the c.c.;
1349  * otherwise, use relative coords. */
1350  if (coordtype == CCB_LOCAL_COORDS) {
1351  xul = 0;
1352  yul = 0;
1353  } else { /* coordtype == CCB_GLOBAL_COORDS */
1354  /* Get UL corner in global coords */
1355  if (boxaGetBoxGeometry(boxa, 0, &xul, &yul, NULL, NULL)) {
1356  ccbDestroy(&ccb);
1357  return ERROR_INT("bounding rectangle not found", procName, 1);
1358  }
1359  }
1360 
1361  /* Make a new ptaa, removing any old one */
1362  nb = numaaGetCount(naa); /* number of borders */
1363  if ((ptaan = ptaaCreate(nb)) == NULL) {
1364  ccbDestroy(&ccb);
1365  return ERROR_INT("ptaan not made", procName, 1);
1366  }
1367  if (coordtype == CCB_LOCAL_COORDS) {
1368  if (ccb->local) /* remove old one */
1369  ptaaDestroy(&ccb->local);
1370  ccb->local = ptaan; /* save new local chain */
1371  } else { /* coordtype == CCB_GLOBAL_COORDS */
1372  if (ccb->global) /* remove old one */
1373  ptaaDestroy(&ccb->global);
1374  ccb->global = ptaan; /* save new global chain */
1375  }
1376 
1377  /* Iterate through the borders for this c.c. */
1378  for (j = 0; j < nb; j++) {
1379  na = numaaGetNuma(naa, j, L_CLONE);
1380  n = numaGetCount(na); /* number of steps in border */
1381  if ((ptan = ptaCreate(n + 1)) == NULL) {
1382  ccbDestroy(&ccb);
1383  numaDestroy(&na);
1384  return ERROR_INT("ptan not made", procName, 1);
1385  }
1386  ptaaAddPta(ptaan, ptan, L_INSERT);
1387  ptaGetIPt(ptas, j, &xstart, &ystart);
1388  x = xul + xstart;
1389  y = yul + ystart;
1390  ptaAddPt(ptan, x, y);
1391  for (k = 0; k < n; k++) {
1392  numaGetIValue(na, k, &stepdir);
1393  x += xpostab[stepdir];
1394  y += ypostab[stepdir];
1395  ptaAddPt(ptan, x, y);
1396  }
1397  numaDestroy(&na);
1398  }
1399  ccbDestroy(&ccb);
1400  }
1401 
1402  return 0;
1403 }
1404 
1405 
1425 l_ok
1427  l_int32 ptsflag)
1428 {
1429 l_int32 ncc, npt, i, j, xul, yul, x, y, delx, dely;
1430 l_int32 xp, yp, delxp, delyp; /* prev point and increments */
1431 CCBORD *ccb;
1432 PTA *ptal, *ptag;
1433 
1434  PROCNAME("ccbaGenerateSPGlobalLocs");
1435 
1436  if (!ccba)
1437  return ERROR_INT("ccba not defined", procName, 1);
1438 
1439  /* Make sure we have a local single path representation */
1440  if ((ccb = ccbaGetCcb(ccba, 0)) == NULL)
1441  return ERROR_INT("no ccb", procName, 1);
1442  if (!ccb->splocal)
1443  ccbaGenerateSinglePath(ccba);
1444  ccbDestroy(&ccb); /* clone ref */
1445 
1446  ncc = ccbaGetCount(ccba); /* number of c.c. */
1447  for (i = 0; i < ncc; i++) {
1448  ccb = ccbaGetCcb(ccba, i);
1449 
1450  /* Get the UL corner in global coords, (xul, yul), of the c.c. */
1451  if (boxaGetBoxGeometry(ccb->boxa, 0, &xul, &yul, NULL, NULL)) {
1452  ccbDestroy(&ccb);
1453  return ERROR_INT("bounding rectangle not found", procName, 1);
1454  }
1455 
1456  /* Make a new spglobal pta, removing any old one */
1457  ptal = ccb->splocal;
1458  npt = ptaGetCount(ptal); /* number of points */
1459  if (ccb->spglobal) /* remove old one */
1460  ptaDestroy(&ccb->spglobal);
1461  if ((ptag = ptaCreate(npt)) == NULL) {
1462  ccbDestroy(&ccb);
1463  return ERROR_INT("ptag not made", procName, 1);
1464  }
1465  ccb->spglobal = ptag; /* save new one */
1466 
1467  /* Convert local to global */
1468  if (ptsflag == CCB_SAVE_ALL_PTS) {
1469  for (j = 0; j < npt; j++) {
1470  ptaGetIPt(ptal, j, &x, &y);
1471  ptaAddPt(ptag, x + xul, y + yul);
1472  }
1473  } else { /* ptsflag = CCB_SAVE_TURNING_PTS */
1474  ptaGetIPt(ptal, 0, &xp, &yp); /* get the 1st pt */
1475  ptaAddPt(ptag, xp + xul, yp + yul); /* save the 1st pt */
1476  if (npt == 2) { /* get and save the 2nd pt */
1477  ptaGetIPt(ptal, 1, &x, &y);
1478  ptaAddPt(ptag, x + xul, y + yul);
1479  } else if (npt > 2) {
1480  ptaGetIPt(ptal, 1, &x, &y);
1481  delxp = x - xp;
1482  delyp = y - yp;
1483  xp = x;
1484  yp = y;
1485  for (j = 2; j < npt; j++) {
1486  ptaGetIPt(ptal, j, &x, &y);
1487  delx = x - xp;
1488  dely = y - yp;
1489  if (delx != delxp || dely != delyp)
1490  ptaAddPt(ptag, xp + xul, yp + yul);
1491  xp = x;
1492  yp = y;
1493  delxp = delx;
1494  delyp = dely;
1495  }
1496  ptaAddPt(ptag, xp + xul, yp + yul);
1497  }
1498  }
1499 
1500  ccbDestroy(&ccb); /* clone ref */
1501  }
1502 
1503  return 0;
1504 }
1505 
1506 
1507 
1508 /*---------------------------------------------------------------------*
1509  * Conversion to single path *
1510  *---------------------------------------------------------------------*/
1546 l_ok
1548 {
1549 l_int32 i, j, k, ncc, nb, ncut, npt, dir, len, state, lostholes;
1550 l_int32 x, y, xl, yl, xf, yf;
1551 BOX *boxinner;
1552 BOXA *boxa;
1553 CCBORD *ccb;
1554 PTA *pta, *ptac, *ptah;
1555 PTA *ptahc; /* cyclic permutation of hole border, with end pts at cut */
1556 PTA *ptas; /* output result: new single path for c.c. */
1557 PTA *ptaf; /* points on the hole borders that intersect with cuts */
1558 PTA *ptal; /* points on outer border that intersect with cuts */
1559 PTA *ptap, *ptarp; /* path and reverse path between borders */
1560 PTAA *ptaa;
1561 PTAA *ptaap; /* ptaa for all paths between borders */
1562 
1563  PROCNAME("ccbaGenerateSinglePath");
1564 
1565  if (!ccba)
1566  return ERROR_INT("ccba not defined", procName, 1);
1567 
1568  ncc = ccbaGetCount(ccba); /* number of c.c. */
1569  lostholes = 0;
1570  for (i = 0; i < ncc; i++) {
1571  ccb = ccbaGetCcb(ccba, i);
1572  if ((ptaa = ccb->local) == NULL) {
1573  L_WARNING("local pixel loc array not found\n", procName);
1574  continue;
1575  }
1576  nb = ptaaGetCount(ptaa); /* number of borders in the c.c. */
1577 
1578  /* Prepare the output pta */
1579  if (ccb->splocal)
1580  ptaDestroy(&ccb->splocal);
1581  ptas = ptaCreate(0);
1582  ccb->splocal = ptas;
1583 
1584  /* If no holes, just concat the outer border */
1585  pta = ptaaGetPta(ptaa, 0, L_CLONE);
1586  if (nb == 1 || nb > NMAX_HOLES + 1) {
1587  ptaJoin(ptas, pta, 0, -1);
1588  ptaDestroy(&pta); /* remove clone */
1589  ccbDestroy(&ccb); /* remove clone */
1590  continue;
1591  }
1592 
1593  /* Find the (nb - 1) cut paths that connect holes
1594  * with outer border */
1595  boxa = ccb->boxa;
1596  ptaap = ptaaCreate(nb - 1);
1597  ptaf = ptaCreate(nb - 1);
1598  ptal = ptaCreate(nb - 1);
1599  for (j = 1; j < nb; j++) {
1600  boxinner = boxaGetBox(boxa, j, L_CLONE);
1601 
1602  /* Find a short path and store it */
1603  ptac = getCutPathForHole(ccb->pix, pta, boxinner, &dir, &len);
1604  if (len == 0) { /* lost the hole */
1605  lostholes++;
1606 /* boxPrintStreamInfo(stderr, boxa->box[0]); */
1607  }
1608  ptaaAddPta(ptaap, ptac, L_INSERT);
1609 /* lept_stderr("dir = %d, length = %d\n", dir, len); */
1610 /* ptaWriteStream(stderr, ptac, 1); */
1611 
1612  /* Store the first and last points in the cut path,
1613  * which must be on a hole border and the outer
1614  * border, respectively */
1615  ncut = ptaGetCount(ptac);
1616  if (ncut == 0) { /* missed hole; neg coords won't match */
1617  ptaAddPt(ptaf, -1, -1);
1618  ptaAddPt(ptal, -1, -1);
1619  } else {
1620  ptaGetIPt(ptac, 0, &x, &y);
1621  ptaAddPt(ptaf, x, y);
1622  ptaGetIPt(ptac, ncut - 1, &x, &y);
1623  ptaAddPt(ptal, x, y);
1624  }
1625  boxDestroy(&boxinner);
1626  }
1627 
1628  /* Make a single path for the c.c. using these connections */
1629  npt = ptaGetCount(pta); /* outer border pts */
1630  for (k = 0; k < npt; k++) {
1631  ptaGetIPt(pta, k, &x, &y);
1632  if (k == 0) { /* if there is a cut at the first point,
1633  * we can wait until the end to take it */
1634  ptaAddPt(ptas, x, y);
1635  continue;
1636  }
1637  state = L_NOT_FOUND;
1638  for (j = 0; j < nb - 1; j++) { /* iterate over cut end pts */
1639  ptaGetIPt(ptal, j, &xl, &yl); /* cut point on outer border */
1640  if (x == xl && y == yl) { /* take this cut to the hole */
1641  state = L_FOUND;
1642  ptap = ptaaGetPta(ptaap, j, L_CLONE);
1643  ptarp = ptaReverse(ptap, 1);
1644  /* Cut point on hole border: */
1645  ptaGetIPt(ptaf, j, &xf, &yf);
1646  /* Hole border: */
1647  ptah = ptaaGetPta(ptaa, j + 1, L_CLONE);
1648  ptahc = ptaCyclicPerm(ptah, xf, yf);
1649 /* ptaWriteStream(stderr, ptahc, 1); */
1650  ptaJoin(ptas, ptarp, 0, -1);
1651  ptaJoin(ptas, ptahc, 0, -1);
1652  ptaJoin(ptas, ptap, 0, -1);
1653  ptaDestroy(&ptap);
1654  ptaDestroy(&ptarp);
1655  ptaDestroy(&ptah);
1656  ptaDestroy(&ptahc);
1657  break;
1658  }
1659  }
1660  if (state == L_NOT_FOUND)
1661  ptaAddPt(ptas, x, y);
1662  }
1663 
1664 /* ptaWriteStream(stderr, ptas, 1); */
1665  ptaaDestroy(&ptaap);
1666  ptaDestroy(&ptaf);
1667  ptaDestroy(&ptal);
1668  ptaDestroy(&pta); /* remove clone */
1669  ccbDestroy(&ccb); /* remove clone */
1670  }
1671 
1672  if (lostholes > 0)
1673  L_INFO("***** %d lost holes *****\n", procName, lostholes);
1674  return 0;
1675 }
1676 
1677 
1704 PTA *
1706  PTA *pta,
1707  BOX *boxinner,
1708  l_int32 *pdir,
1709  l_int32 *plen)
1710 {
1711 l_int32 w, h, nc, x, y, xl, yl, xmid, ymid;
1712 l_uint32 val;
1713 PTA *ptac;
1714 
1715  PROCNAME("getCutPathForHole");
1716 
1717  if (!pix)
1718  return (PTA *)ERROR_PTR("pix not defined", procName, NULL);
1719  if (!pta)
1720  return (PTA *)ERROR_PTR("pta not defined", procName, NULL);
1721  if (!boxinner)
1722  return (PTA *)ERROR_PTR("boxinner not defined", procName, NULL);
1723 
1724  pixGetDimensions(pix, &w, &h, NULL);
1725  ptac = ptaCreate(4);
1726  xmid = boxinner->x + boxinner->w / 2;
1727  ymid = boxinner->y + boxinner->h / 2;
1728 
1729  /* try top first */
1730  for (y = ymid; y >= 0; y--) {
1731  pixGetPixel(pix, xmid, y, &val);
1732  if (val == 1) {
1733  ptaAddPt(ptac, xmid, y);
1734  break;
1735  }
1736  }
1737  for (y = y - 1; y >= 0; y--) {
1738  pixGetPixel(pix, xmid, y, &val);
1739  if (val == 1)
1740  ptaAddPt(ptac, xmid, y);
1741  else
1742  break;
1743  }
1744  nc = ptaGetCount(ptac);
1745  ptaGetIPt(ptac, nc - 1, &xl, &yl);
1746  if (ptaContainsPt(pta, xl, yl)) {
1747  *pdir = 1;
1748  *plen = nc;
1749  return ptac;
1750  }
1751 
1752  /* Next try bottom */
1753  ptaEmpty(ptac);
1754  for (y = ymid; y < h; y++) {
1755  pixGetPixel(pix, xmid, y, &val);
1756  if (val == 1) {
1757  ptaAddPt(ptac, xmid, y);
1758  break;
1759  }
1760  }
1761  for (y = y + 1; y < h; y++) {
1762  pixGetPixel(pix, xmid, y, &val);
1763  if (val == 1)
1764  ptaAddPt(ptac, xmid, y);
1765  else
1766  break;
1767  }
1768  nc = ptaGetCount(ptac);
1769  ptaGetIPt(ptac, nc - 1, &xl, &yl);
1770  if (ptaContainsPt(pta, xl, yl)) {
1771  *pdir = 3;
1772  *plen = nc;
1773  return ptac;
1774  }
1775 
1776  /* Next try left */
1777  ptaEmpty(ptac);
1778  for (x = xmid; x >= 0; x--) {
1779  pixGetPixel(pix, x, ymid, &val);
1780  if (val == 1) {
1781  ptaAddPt(ptac, x, ymid);
1782  break;
1783  }
1784  }
1785  for (x = x - 1; x >= 0; x--) {
1786  pixGetPixel(pix, x, ymid, &val);
1787  if (val == 1)
1788  ptaAddPt(ptac, x, ymid);
1789  else
1790  break;
1791  }
1792  nc = ptaGetCount(ptac);
1793  ptaGetIPt(ptac, nc - 1, &xl, &yl);
1794  if (ptaContainsPt(pta, xl, yl)) {
1795  *pdir = 0;
1796  *plen = nc;
1797  return ptac;
1798  }
1799 
1800  /* Finally try right */
1801  ptaEmpty(ptac);
1802  for (x = xmid; x < w; x++) {
1803  pixGetPixel(pix, x, ymid, &val);
1804  if (val == 1) {
1805  ptaAddPt(ptac, x, ymid);
1806  break;
1807  }
1808  }
1809  for (x = x + 1; x < w; x++) {
1810  pixGetPixel(pix, x, ymid, &val);
1811  if (val == 1)
1812  ptaAddPt(ptac, x, ymid);
1813  else
1814  break;
1815  }
1816  nc = ptaGetCount(ptac);
1817  ptaGetIPt(ptac, nc - 1, &xl, &yl);
1818  if (ptaContainsPt(pta, xl, yl)) {
1819  *pdir = 2;
1820  *plen = nc;
1821  return ptac;
1822  }
1823 
1824  /* Sometimes, there is nothing. */
1825  ptaEmpty(ptac);
1826  *plen = 0;
1827  return ptac;
1828 }
1829 
1830 
1831 
1832 /*---------------------------------------------------------------------*
1833  * Border rendering *
1834  *---------------------------------------------------------------------*/
1848 PIX *
1850 {
1851 l_int32 ncc, nb, n, i, j, k, x, y;
1852 CCBORD *ccb;
1853 PIX *pixd;
1854 PTAA *ptaa;
1855 PTA *pta;
1856 
1857  PROCNAME("ccbaDisplayBorder");
1858 
1859  if (!ccba)
1860  return (PIX *)ERROR_PTR("ccba not defined", procName, NULL);
1861 
1862  if ((pixd = pixCreate(ccba->w, ccba->h, 1)) == NULL)
1863  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1864  ncc = ccbaGetCount(ccba); /* number of c.c. */
1865  for (i = 0; i < ncc; i++) {
1866  ccb = ccbaGetCcb(ccba, i);
1867  if ((ptaa = ccb->global) == NULL) {
1868  L_WARNING("global pixel loc array not found", procName);
1869  ccbDestroy(&ccb);
1870  continue;
1871  }
1872  nb = ptaaGetCount(ptaa); /* number of borders in the c.c. */
1873  for (j = 0; j < nb; j++) {
1874  pta = ptaaGetPta(ptaa, j, L_CLONE);
1875  n = ptaGetCount(pta); /* number of pixels in the border */
1876  for (k = 0; k < n; k++) {
1877  ptaGetIPt(pta, k, &x, &y);
1878  pixSetPixel(pixd, x, y, 1);
1879  }
1880  ptaDestroy(&pta);
1881  }
1882  ccbDestroy(&ccb);
1883  }
1884 
1885  return pixd;
1886 }
1887 
1888 
1902 PIX *
1904 {
1905 l_int32 ncc, npt, i, j, x, y;
1906 CCBORD *ccb;
1907 PIX *pixd;
1908 PTA *ptag;
1909 
1910  PROCNAME("ccbaDisplaySPBorder");
1911 
1912  if (!ccba)
1913  return (PIX *)ERROR_PTR("ccba not defined", procName, NULL);
1914 
1915  if ((pixd = pixCreate(ccba->w, ccba->h, 1)) == NULL)
1916  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1917  ncc = ccbaGetCount(ccba); /* number of c.c. */
1918  for (i = 0; i < ncc; i++) {
1919  ccb = ccbaGetCcb(ccba, i);
1920  if ((ptag = ccb->spglobal) == NULL) {
1921  L_WARNING("spglobal pixel loc array not found\n", procName);
1922  ccbDestroy(&ccb);
1923  continue;
1924  }
1925  npt = ptaGetCount(ptag); /* number of pixels on path */
1926  for (j = 0; j < npt; j++) {
1927  ptaGetIPt(ptag, j, &x, &y);
1928  pixSetPixel(pixd, x, y, 1);
1929  }
1930  ccbDestroy(&ccb); /* clone ref */
1931  }
1932 
1933  return pixd;
1934 }
1935 
1936 
1993 PIX *
1995 {
1996 l_int32 ncc, i, nb, n, j, k, x, y, xul, yul, xoff, yoff, w, h;
1997 l_int32 fpx, fpy, spx, spy, xs, ys;
1998 BOX *box;
1999 BOXA *boxa;
2000 CCBORD *ccb;
2001 PIX *pixd, *pixt, *pixh;
2002 PTAA *ptaa;
2003 PTA *pta;
2004 
2005  PROCNAME("ccbaDisplayImage1");
2006 
2007  if (!ccba)
2008  return (PIX *)ERROR_PTR("ccba not defined", procName, NULL);
2009 
2010  if ((pixd = pixCreate(ccba->w, ccba->h, 1)) == NULL)
2011  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2012  ncc = ccbaGetCount(ccba);
2013  for (i = 0; i < ncc; i++) {
2014  ccb = ccbaGetCcb(ccba, i);
2015  if ((boxa = ccb->boxa) == NULL) {
2016  pixDestroy(&pixd);
2017  ccbDestroy(&ccb);
2018  return (PIX *)ERROR_PTR("boxa not found", procName, NULL);
2019  }
2020 
2021  /* Render border in pixt */
2022  if ((ptaa = ccb->local) == NULL) {
2023  L_WARNING("local chain array not found\n", procName);
2024  ccbDestroy(&ccb);
2025  continue;
2026  }
2027 
2028  nb = ptaaGetCount(ptaa); /* number of borders in the c.c. */
2029  for (j = 0; j < nb; j++) {
2030  if ((box = boxaGetBox(boxa, j, L_CLONE)) == NULL) {
2031  pixDestroy(&pixd);
2032  ccbDestroy(&ccb);
2033  return (PIX *)ERROR_PTR("b. box not found", procName, NULL);
2034  }
2035  if (j == 0) {
2036  boxGetGeometry(box, &xul, &yul, &w, &h);
2037  xoff = yoff = 0;
2038  } else {
2039  boxGetGeometry(box, &xoff, &yoff, &w, &h);
2040  }
2041  boxDestroy(&box);
2042 
2043  /* Render the border in a minimum-sized pix;
2044  * subtract xoff and yoff because the pixel
2045  * location is stored relative to the c.c., but
2046  * we need it relative to just the hole border. */
2047  if ((pixt = pixCreate(w, h, 1)) == NULL) {
2048  pixDestroy(&pixd);
2049  ccbDestroy(&ccb);
2050  return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
2051  }
2052  pta = ptaaGetPta(ptaa, j, L_CLONE);
2053  n = ptaGetCount(pta); /* number of pixels in the border */
2054  for (k = 0; k < n; k++) {
2055  ptaGetIPt(pta, k, &x, &y);
2056  pixSetPixel(pixt, x - xoff, y - yoff, 1);
2057  if (j > 0) { /* need this for finding hole border pixel */
2058  if (k == 0) {
2059  fpx = x - xoff;
2060  fpy = y - yoff;
2061  }
2062  if (k == 1) {
2063  spx = x - xoff;
2064  spy = y - yoff;
2065  }
2066  }
2067  }
2068  ptaDestroy(&pta);
2069 
2070  /* Get the filled component */
2071  if (j == 0) { /* if outer border, fill from outer boundary */
2072  if ((pixh = pixFillClosedBorders(pixt, 4)) == NULL) {
2073  pixDestroy(&pixd);
2074  pixDestroy(&pixt);
2075  ccbDestroy(&ccb);
2076  return (PIX *)ERROR_PTR("pixh not made", procName, NULL);
2077  }
2078  } else { /* fill the hole from inside */
2079  /* get the location of a seed pixel in the hole */
2080  locateOutsideSeedPixel(fpx, fpy, spx, spy, &xs, &ys);
2081 
2082  /* Put seed in hole and fill interior of hole,
2083  * using pixt as clipping mask */
2084  pixh = pixCreateTemplate(pixt);
2085  pixSetPixel(pixh, xs, ys, 1); /* put seed pixel in hole */
2086  pixInvert(pixt, pixt); /* to make filling mask */
2087  pixSeedfillBinary(pixh, pixh, pixt, 4); /* 4-fill hole */
2088  }
2089 
2090  /* XOR into the dest */
2091  pixRasterop(pixd, xul + xoff, yul + yoff, w, h, PIX_XOR,
2092  pixh, 0, 0);
2093  pixDestroy(&pixt);
2094  pixDestroy(&pixh);
2095  }
2096  ccbDestroy(&ccb);
2097  }
2098  return pixd;
2099 }
2100 
2101 
2102 
2124 PIX *
2126 {
2127 l_int32 ncc, nb, n, i, j, k, x, y, xul, yul, w, h;
2128 l_int32 fpx, fpy, spx, spy, xs, ys;
2129 BOXA *boxa;
2130 CCBORD *ccb;
2131 PIX *pixd, *pixc, *pixs;
2132 PTAA *ptaa;
2133 PTA *pta;
2134 
2135  PROCNAME("ccbaDisplayImage2");
2136 
2137  if (!ccba)
2138  return (PIX *)ERROR_PTR("ccba not defined", procName, NULL);
2139 
2140  if ((pixd = pixCreate(ccba->w, ccba->h, 1)) == NULL)
2141  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2142  ncc = ccbaGetCount(ccba);
2143  for (i = 0; i < ncc; i++) {
2144  /* Generate clipping mask from border pixels and seed image
2145  * from one seed for each closed border. */
2146  ccb = ccbaGetCcb(ccba, i);
2147  if ((boxa = ccb->boxa) == NULL) {
2148  pixDestroy(&pixd);
2149  ccbDestroy(&ccb);
2150  return (PIX *)ERROR_PTR("boxa not found", procName, NULL);
2151  }
2152  if (boxaGetBoxGeometry(boxa, 0, &xul, &yul, &w, &h)) {
2153  pixDestroy(&pixd);
2154  ccbDestroy(&ccb);
2155  return (PIX *)ERROR_PTR("b. box not found", procName, NULL);
2156  }
2157  pixc = pixCreate(w + 2, h + 2, 1);
2158  pixs = pixCreateTemplate(pixc);
2159 
2160  if ((ptaa = ccb->local) == NULL) {
2161  pixDestroy(&pixc);
2162  pixDestroy(&pixs);
2163  ccbDestroy(&ccb);
2164  L_WARNING("local chain array not found\n", procName);
2165  continue;
2166  }
2167  nb = ptaaGetCount(ptaa); /* number of borders in the c.c. */
2168  for (j = 0; j < nb; j++) {
2169  pta = ptaaGetPta(ptaa, j, L_CLONE);
2170  n = ptaGetCount(pta); /* number of pixels in the border */
2171 
2172  /* Render border pixels in pixc */
2173  for (k = 0; k < n; k++) {
2174  ptaGetIPt(pta, k, &x, &y);
2175  pixSetPixel(pixc, x + 1, y + 1, 1);
2176  if (k == 0) {
2177  fpx = x + 1;
2178  fpy = y + 1;
2179  } else if (k == 1) {
2180  spx = x + 1;
2181  spy = y + 1;
2182  }
2183  }
2184 
2185  /* Get and set seed pixel for this border in pixs */
2186  if (n > 1)
2187  locateOutsideSeedPixel(fpx, fpy, spx, spy, &xs, &ys);
2188  else /* isolated c.c. */
2189  xs = ys = 0;
2190  pixSetPixel(pixs, xs, ys, 1);
2191  ptaDestroy(&pta);
2192  }
2193 
2194  /* Fill from seeds in pixs, using pixc as the clipping mask,
2195  * to reconstruct the c.c. */
2196  pixInvert(pixc, pixc); /* to convert clipping -> filling mask */
2197  pixSeedfillBinary(pixs, pixs, pixc, 4); /* 4-fill */
2198  pixInvert(pixs, pixs); /* to make the c.c. */
2199 
2200  /* XOR into the dest */
2201  pixRasterop(pixd, xul, yul, w, h, PIX_XOR, pixs, 1, 1);
2202 
2203  pixDestroy(&pixc);
2204  pixDestroy(&pixs);
2205  ccbDestroy(&ccb); /* ref-counted */
2206  }
2207  return pixd;
2208 }
2209 
2210 
2211 /*---------------------------------------------------------------------*
2212  * Serialize for I/O *
2213  *---------------------------------------------------------------------*/
2221 l_ok
2222 ccbaWrite(const char *filename,
2223  CCBORDA *ccba)
2224 {
2225 FILE *fp;
2226 
2227  PROCNAME("ccbaWrite");
2228 
2229  if (!filename)
2230  return ERROR_INT("filename not defined", procName, 1);
2231  if (!ccba)
2232  return ERROR_INT("ccba not defined", procName, 1);
2233 
2234  if ((fp = fopenWriteStream(filename, "wb+")) == NULL)
2235  return ERROR_INT("stream not opened", procName, 1);
2236  if (ccbaWriteStream(fp, ccba)) {
2237  fclose(fp);
2238  return ERROR_INT("ccba not written to stream", procName, 1);
2239  }
2240 
2241  fclose(fp);
2242  return 0;
2243 }
2244 
2245 
2246 
2273 l_ok
2275  CCBORDA *ccba)
2276 {
2277 char strbuf[256];
2278 l_uint8 bval;
2279 l_uint8 *datain, *dataout;
2280 l_int32 i, j, k, bx, by, bw, bh, val, startx, starty;
2281 l_int32 ncc, nb, n;
2282 l_uint32 w, h;
2283 size_t inbytes, outbytes;
2284 L_BBUFFER *bbuf;
2285 CCBORD *ccb;
2286 NUMA *na;
2287 NUMAA *naa;
2288 PTA *pta;
2289 
2290  PROCNAME("ccbaWriteStream");
2291 
2292 #if !HAVE_LIBZ /* defined in environ.h */
2293  return ERROR_INT("no libz: can't write data", procName, 1);
2294 #else
2295 
2296  if (!fp)
2297  return ERROR_INT("stream not open", procName, 1);
2298  if (!ccba)
2299  return ERROR_INT("ccba not defined", procName, 1);
2300 
2301  if ((bbuf = bbufferCreate(NULL, 1000)) == NULL)
2302  return ERROR_INT("bbuf not made", procName, 1);
2303 
2304  ncc = ccbaGetCount(ccba);
2305  snprintf(strbuf, sizeof(strbuf), "ccba: %7d cc\n", ncc);
2306  bbufferRead(bbuf, (l_uint8 *)strbuf, 18);
2307  w = pixGetWidth(ccba->pix);
2308  h = pixGetHeight(ccba->pix);
2309  bbufferRead(bbuf, (l_uint8 *)&w, 4); /* width */
2310  bbufferRead(bbuf, (l_uint8 *)&h, 4); /* height */
2311  for (i = 0; i < ncc; i++) {
2312  ccb = ccbaGetCcb(ccba, i);
2313  if (boxaGetBoxGeometry(ccb->boxa, 0, &bx, &by, &bw, &bh)) {
2314  bbufferDestroy(&bbuf);
2315  ccbDestroy(&ccb);
2316  return ERROR_INT("bounding box not found", procName, 1);
2317  }
2318  bbufferRead(bbuf, (l_uint8 *)&bx, 4); /* ulx of c.c. */
2319  bbufferRead(bbuf, (l_uint8 *)&by, 4); /* uly of c.c. */
2320  bbufferRead(bbuf, (l_uint8 *)&bw, 4); /* w of c.c. */
2321  bbufferRead(bbuf, (l_uint8 *)&bh, 4); /* h of c.c. */
2322  if ((naa = ccb->step) == NULL) {
2323  ccbaGenerateStepChains(ccba);
2324  naa = ccb->step;
2325  }
2326  nb = numaaGetCount(naa);
2327  bbufferRead(bbuf, (l_uint8 *)&nb, 4); /* number of borders in c.c. */
2328  pta = ccb->start;
2329  for (j = 0; j < nb; j++) {
2330  ptaGetIPt(pta, j, &startx, &starty);
2331  bbufferRead(bbuf, (l_uint8 *)&startx, 4); /* starting x in border */
2332  bbufferRead(bbuf, (l_uint8 *)&starty, 4); /* starting y in border */
2333  na = numaaGetNuma(naa, j, L_CLONE);
2334  n = numaGetCount(na);
2335  for (k = 0; k < n; k++) {
2336  numaGetIValue(na, k, &val);
2337  if (k % 2 == 0)
2338  bval = (l_uint8)val << 4;
2339  else
2340  bval |= (l_uint8)val;
2341  if (k % 2 == 1)
2342  bbufferRead(bbuf, (l_uint8 *)&bval, 1); /* 2 border steps */
2343  }
2344  if (n % 2 == 1) {
2345  bval |= 0x8;
2346  bbufferRead(bbuf, (l_uint8 *)&bval, 1); /* end with 0xz8, */
2347  /* where z = {0..7} */
2348  } else { /* n % 2 == 0 */
2349  bval = 0x88;
2350  bbufferRead(bbuf, (l_uint8 *)&bval, 1); /* end with 0x88 */
2351  }
2352  numaDestroy(&na);
2353  }
2354  ccbDestroy(&ccb);
2355  }
2356 
2357  datain = bbufferDestroyAndSaveData(&bbuf, &inbytes);
2358  dataout = zlibCompress(datain, inbytes, &outbytes);
2359  fwrite(dataout, 1, outbytes, fp);
2360 
2361  LEPT_FREE(datain);
2362  LEPT_FREE(dataout);
2363  return 0;
2364 
2365 #endif /* !HAVE_LIBZ */
2366 }
2367 
2368 
2375 CCBORDA *
2376 ccbaRead(const char *filename)
2377 {
2378 FILE *fp;
2379 CCBORDA *ccba;
2380 
2381  PROCNAME("ccbaRead");
2382 
2383  if (!filename)
2384  return (CCBORDA *)ERROR_PTR("filename not defined", procName, NULL);
2385 
2386  if ((fp = fopenReadStream(filename)) == NULL)
2387  return (CCBORDA *)ERROR_PTR("stream not opened", procName, NULL);
2388  ccba = ccbaReadStream(fp);
2389  fclose(fp);
2390 
2391  if (!ccba)
2392  return (CCBORDA *)ERROR_PTR("ccba not returned", procName, NULL);
2393  return ccba;
2394 }
2395 
2396 
2421 CCBORDA *
2423 {
2424 char strbuf[256];
2425 l_uint8 bval;
2426 l_uint8 *datain, *dataout;
2427 l_int32 i, j, startx, starty;
2428 l_int32 offset, nib1, nib2;
2429 l_int32 ncc, nb;
2430 l_uint32 width, height, w, h, xoff, yoff;
2431 size_t inbytes, outbytes;
2432 BOX *box;
2433 CCBORD *ccb;
2434 CCBORDA *ccba;
2435 NUMA *na;
2436 NUMAA *step;
2437 
2438  PROCNAME("ccbaReadStream");
2439 
2440 #if !HAVE_LIBZ /* defined in environ.h */
2441  return (CCBORDA *)ERROR_PTR("no libz: can't read data", procName, NULL);
2442 #else
2443 
2444  if (!fp)
2445  return (CCBORDA *)ERROR_PTR("stream not open", procName, NULL);
2446 
2447  if ((datain = l_binaryReadStream(fp, &inbytes)) == NULL)
2448  return (CCBORDA *)ERROR_PTR("data not read from file", procName, NULL);
2449  dataout = zlibUncompress(datain, inbytes, &outbytes);
2450  LEPT_FREE(datain);
2451  if (!dataout)
2452  return (CCBORDA *)ERROR_PTR("dataout not made", procName, NULL);
2453 
2454  offset = 18;
2455  memcpy(strbuf, dataout, offset);
2456  strbuf[17] = '\0';
2457  if (memcmp(strbuf, "ccba:", 5) != 0) {
2458  LEPT_FREE(dataout);
2459  return (CCBORDA *)ERROR_PTR("file not type ccba", procName, NULL);
2460  }
2461  sscanf(strbuf, "ccba: %7d cc\n", &ncc);
2462 /* lept_stderr("ncc = %d\n", ncc); */
2463  if ((ccba = ccbaCreate(NULL, ncc)) == NULL) {
2464  LEPT_FREE(dataout);
2465  return (CCBORDA *)ERROR_PTR("ccba not made", procName, NULL);
2466  }
2467 
2468  memcpy(&width, dataout + offset, 4);
2469  offset += 4;
2470  memcpy(&height, dataout + offset, 4);
2471  offset += 4;
2472  ccba->w = width;
2473  ccba->h = height;
2474 /* lept_stderr("width = %d, height = %d\n", width, height); */
2475 
2476  for (i = 0; i < ncc; i++) { /* should be ncc */
2477  ccb = ccbCreate(NULL);
2478  ccbaAddCcb(ccba, ccb);
2479 
2480  memcpy(&xoff, dataout + offset, 4);
2481  offset += 4;
2482  memcpy(&yoff, dataout + offset, 4);
2483  offset += 4;
2484  memcpy(&w, dataout + offset, 4);
2485  offset += 4;
2486  memcpy(&h, dataout + offset, 4);
2487  offset += 4;
2488  box = boxCreate(xoff, yoff, w, h);
2489  boxaAddBox(ccb->boxa, box, L_INSERT);
2490 /* lept_stderr("xoff = %d, yoff = %d, w = %d, h = %d\n",
2491  xoff, yoff, w, h); */
2492 
2493  memcpy(&nb, dataout + offset, 4);
2494  offset += 4;
2495 /* lept_stderr("num borders = %d\n", nb); */
2496  step = numaaCreate(nb);
2497  ccb->step = step;
2498 
2499  for (j = 0; j < nb; j++) { /* should be nb */
2500  memcpy(&startx, dataout + offset, 4);
2501  offset += 4;
2502  memcpy(&starty, dataout + offset, 4);
2503  offset += 4;
2504  ptaAddPt(ccb->start, startx, starty);
2505 /* lept_stderr("startx = %d, starty = %d\n", startx, starty); */
2506  na = numaCreate(0);
2507  numaaAddNuma(step, na, L_INSERT);
2508 
2509  while(1) {
2510  bval = *(dataout + offset);
2511  offset++;
2512  nib1 = (bval >> 4);
2513  nib2 = bval & 0xf;
2514  if (nib1 != 8)
2515  numaAddNumber(na, nib1);
2516  else
2517  break;
2518  if (nib2 != 8)
2519  numaAddNumber(na, nib2);
2520  else
2521  break;
2522  }
2523  }
2524  }
2525  LEPT_FREE(dataout);
2526  return ccba;
2527 
2528 #endif /* !HAVE_LIBZ */
2529 }
2530 
2531 
2532 /*---------------------------------------------------------------------*
2533  * SVG Output *
2534  *---------------------------------------------------------------------*/
2542 l_ok
2543 ccbaWriteSVG(const char *filename,
2544  CCBORDA *ccba)
2545 {
2546 char *svgstr;
2547 
2548  PROCNAME("ccbaWriteSVG");
2549 
2550  if (!filename)
2551  return ERROR_INT("filename not defined", procName, 1);
2552  if (!ccba)
2553  return ERROR_INT("ccba not defined", procName, 1);
2554 
2555  if ((svgstr = ccbaWriteSVGString(ccba)) == NULL)
2556  return ERROR_INT("svgstr not made", procName, 1);
2557 
2558  l_binaryWrite(filename, "w", svgstr, strlen(svgstr));
2559  LEPT_FREE(svgstr);
2560 
2561  return 0;
2562 }
2563 
2564 
2572 char *
2574 {
2575 char *svgstr;
2576 char smallbuf[256];
2577 char line0[] = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>";
2578 char line1[] = "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20000303 Stylable//EN\" \"http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd\">";
2579 char line2[] = "<svg>";
2580 char line3[] = "<polygon style=\"stroke-width:1;stroke:black;\" points=\"";
2581 char line4[] = "\" />";
2582 char line5[] = "</svg>";
2583 char space[] = " ";
2584 l_int32 i, j, ncc, npt, x, y;
2585 CCBORD *ccb;
2586 PTA *pta;
2587 SARRAY *sa;
2588 
2589  PROCNAME("ccbaWriteSVGString");
2590 
2591  if (!ccba)
2592  return (char *)ERROR_PTR("ccba not defined", procName, NULL);
2593 
2594  sa = sarrayCreate(0);
2595  sarrayAddString(sa, line0, L_COPY);
2596  sarrayAddString(sa, line1, L_COPY);
2597  sarrayAddString(sa, line2, L_COPY);
2598  ncc = ccbaGetCount(ccba);
2599  for (i = 0; i < ncc; i++) {
2600  if ((ccb = ccbaGetCcb(ccba, i)) == NULL) {
2601  sarrayDestroy(&sa);
2602  return (char *)ERROR_PTR("ccb not found", procName, NULL);
2603  }
2604  if ((pta = ccb->spglobal) == NULL) {
2605  sarrayDestroy(&sa);
2606  ccbDestroy(&ccb);
2607  return (char *)ERROR_PTR("spglobal not made", procName, NULL);
2608  }
2609  sarrayAddString(sa, line3, L_COPY);
2610  npt = ptaGetCount(pta);
2611  for (j = 0; j < npt; j++) {
2612  ptaGetIPt(pta, j, &x, &y);
2613  snprintf(smallbuf, sizeof(smallbuf), "%0d,%0d", x, y);
2614  sarrayAddString(sa, smallbuf, L_COPY);
2615  }
2616  sarrayAddString(sa, line4, L_COPY);
2617  ccbDestroy(&ccb);
2618  }
2619  sarrayAddString(sa, line5, L_COPY);
2620  sarrayAddString(sa, space, L_COPY);
2621 
2622  svgstr = sarrayToString(sa, 1);
2623 /* lept_stderr("%s", svgstr); */
2624 
2625  sarrayDestroy(&sa);
2626  return svgstr;
2627 }
l_int32 ccbaGetCount(CCBORDA *ccba)
ccbaGetCount()
Definition: ccbord.c:513
l_ok ccbaGenerateStepChains(CCBORDA *ccba)
ccbaGenerateStepChains()
Definition: ccbord.c:1240
struct Pta * splocal
Definition: ccbord.h:102
char * sarrayToString(SARRAY *sa, l_int32 addnlflag)
sarrayToString()
Definition: sarray1.c:785
PIX * pixHolesByFilling(PIX *pixs, l_int32 connectivity)
pixHolesByFilling()
Definition: seedfill.c:609
struct Ptaa * global
Definition: ccbord.h:100
CCBORDA * ccbaCreate(PIX *pixs, l_int32 n)
ccbaCreate()
Definition: ccbord.c:309
L_BBUFFER * bbufferCreate(const l_uint8 *indata, l_int32 nalloc)
bbufferCreate()
Definition: bbuffer.c:130
l_ok ccbaGenerateSPGlobalLocs(CCBORDA *ccba, l_int32 ptsflag)
ccbaGenerateSPGlobalLocs()
Definition: ccbord.c:1426
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:383
PIX * ccbaDisplaySPBorder(CCBORDA *ccba)
ccbaDisplaySPBorder()
Definition: ccbord.c:1903
CCBORD * ccbCreate(PIX *pixs)
ccbCreate()
Definition: ccbord.c:373
l_ok ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:343
Definition: pix.h:713
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
void ccbaDestroy(CCBORDA **pccba)
ccbaDestroy()
Definition: ccbord.c:342
l_int32 nextOnPixelInRaster(PIX *pixs, l_int32 xstart, l_int32 ystart, l_int32 *px, l_int32 *py)
nextOnPixelInRaster()
Definition: conncomp.c:457
PIX * ccbaDisplayImage1(CCBORDA *ccba)
ccbaDisplayImage1()
Definition: ccbord.c:1994
l_int32 n
Definition: ccbord.h:113
static l_int32 findNextBorderPixel(l_int32 w, l_int32 h, l_uint32 *data, l_int32 wpl, l_int32 px, l_int32 py, l_int32 *pqpos, l_int32 *pnpx, l_int32 *pnpy)
findNextBorderPixel()
Definition: ccbord.c:1067
Definition: pix.h:712
PIX * ccbaDisplayBorder(CCBORDA *ccba)
ccbaDisplayBorder()
Definition: ccbord.c:1849
l_ok pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:204
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:120
CCBORDA * ccbaRead(const char *filename)
ccbaRead()
Definition: ccbord.c:2376
l_int32 y
Definition: pix.h:483
CCBORDA * ccbaReadStream(FILE *fp)
ccbaReadStream()
Definition: ccbord.c:2422
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
static CCBORD * pixGetCCBorders(PIX *pixs, BOX *box)
pixGetCCBorders()
Definition: ccbord.c:653
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:170
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1509
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
l_int32 ptaGetCount(PTA *pta)
ptaGetCount()
Definition: ptabasic.c:527
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:583
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
BOX * pixaGetBox(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetBox()
Definition: pixabasic.c:816
l_ok ccbaWriteStream(FILE *fp, CCBORDA *ccba)
ccbaWriteStream()
Definition: ccbord.c:2274
l_uint8 * zlibUncompress(const l_uint8 *datain, size_t nin, size_t *pnout)
zlibUncompress()
Definition: zlibmem.c:196
l_ok ccbaWriteSVG(const char *filename, CCBORDA *ccba)
ccbaWriteSVG()
Definition: ccbord.c:2543
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
NUMAA * numaaCreate(l_int32 n)
numaaCreate()
Definition: numabasic.c:1407
Definition: pix.h:491
PIX * ccbaDisplayImage2(CCBORDA *ccba)
ccbaDisplayImage2()
Definition: ccbord.c:2125
void numaaDestroy(NUMAA **pnaa)
numaaDestroy()
Definition: numabasic.c:1510
l_ok ptaJoin(PTA *ptad, PTA *ptas, l_int32 istart, l_int32 iend)
ptaJoin()
Definition: ptafunc1.c:167
Definition: array.h:126
struct CCBord ** ccb
Definition: ccbord.h:115
l_uint8 * bbufferDestroyAndSaveData(L_BBUFFER **pbb, size_t *pnbytes)
bbufferDestroyAndSaveData()
Definition: bbuffer.c:206
PIX * pixAddBorder(PIX *pixs, l_int32 npix, l_uint32 val)
pixAddBorder()
Definition: pix2.c:1823
static l_int32 ccbaExtendArray(CCBORDA *ccba)
ccbaExtendArray()
Definition: ccbord.c:485
BOX * boxClone(BOX *box)
boxClone()
Definition: boxbasic.c:256
l_ok l_binaryWrite(const char *filename, const char *operation, const void *data, size_t nbytes)
l_binaryWrite()
Definition: utils2.c:1569
struct Boxa * boxa
Definition: ccbord.h:96
static void locateOutsideSeedPixel(l_int32 fpx, l_int32 fpy, l_int32 spx, l_int32 spy, l_int32 *pxs, l_int32 *pys)
locateOutsideSeedPixel()
Definition: ccbord.c:1120
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:151
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1740
PTA * ptaaGetPta(PTAA *ptaa, l_int32 index, l_int32 accessflag)
ptaaGetPta()
Definition: ptabasic.c:1145
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:754
Definition: array.h:70
char * ccbaWriteSVGString(CCBORDA *ccba)
ccbaWriteSVGString()
Definition: ccbord.c:2573
Definition: ccbord.h:93
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:658
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:451
l_int32 w
Definition: pix.h:484
PTA * ptaClone(PTA *pta)
ptaClone()
Definition: ptabasic.c:297
CCBORDA * pixGetAllCCBorders(PIX *pixs)
pixGetAllCCBorders()
Definition: ccbord.c:567
struct Pta * spglobal
Definition: ccbord.h:103
l_ok boxaGetBoxGeometry(BOXA *boxa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetBoxGeometry()
Definition: boxbasic.c:879
Definition: pix.h:530
struct Pix * pix
Definition: ccbord.h:110
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:263
PTA * getCutPathForHole(PIX *pix, PTA *pta, BOX *boxinner, l_int32 *pdir, l_int32 *plen)
getCutPathForHole()
Definition: ccbord.c:1705
struct Ptaa * local
Definition: ccbord.h:99
void ptaaDestroy(PTAA **pptaa)
ptaaDestroy()
Definition: ptabasic.c:1003
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:620
PTA * ptaCyclicPerm(PTA *ptas, l_int32 xs, l_int32 ys)
ptaCyclicPerm()
Definition: ptafunc1.c:333
struct Pta * start
Definition: ccbord.h:97
l_int32 refcount
Definition: ccbord.h:98
l_int32 ptaContainsPt(PTA *pta, l_int32 x, l_int32 y)
ptaContainsPt()
Definition: ptafunc1.c:670
l_int32 h
Definition: ccbord.h:112
l_int32 w
Definition: ccbord.h:111
CCBORD * ccbaGetCcb(CCBORDA *ccba, l_int32 index)
ccbaGetCcb()
Definition: ccbord.c:538
void * reallocNew(void **pindata, size_t oldsize, size_t newsize)
reallocNew()
Definition: utils2.c:1302
l_ok ccbaGenerateGlobalLocs(CCBORDA *ccba)
ccbaGenerateGlobalLocs()
Definition: ccbord.c:1168
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
Definition: array.h:82
struct Numaa * step
Definition: ccbord.h:101
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
PIX * pixFillClosedBorders(PIX *pixs, l_int32 connectivity)
pixFillClosedBorders()
Definition: seedfill.c:660
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:779
Definition: pix.h:711
l_int32 x
Definition: pix.h:482
static l_ok pixGetHoleBorder(CCBORD *ccb, PIX *pixs, BOX *box, l_int32 xs, l_int32 ys)
pixGetHoleBorder()
Definition: ccbord.c:985
Definition: pix.h:455
l_ok ccbaWrite(const char *filename, CCBORDA *ccba)
ccbaWrite()
Definition: ccbord.c:2222
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
void bbufferDestroy(L_BBUFFER **pbb)
bbufferDestroy()
Definition: bbuffer.c:172
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:190
l_ok bbufferRead(L_BBUFFER *bb, l_uint8 *src, l_int32 nbytes)
bbufferRead()
Definition: bbuffer.c:265
PIX * pixSeedfillBinary(PIX *pixd, PIX *pixs, PIX *pixm, l_int32 connectivity)
pixSeedfillBinary()
Definition: seedfill.c:247
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1975
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1932
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1402
l_int32 ptaaGetCount(PTAA *ptaa)
ptaaGetCount()
Definition: ptabasic.c:1125
l_ok ptaEmpty(PTA *pta)
ptaEmpty()
Definition: ptabasic.c:321
l_int32 numaaGetCount(NUMAA *naa)
numaaGetCount()
Definition: numabasic.c:1631
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:691
void ccbDestroy(CCBORD **pccb)
ccbDestroy()
Definition: ccbord.c:406
l_int32 h
Definition: pix.h:485
Definition: pix.h:138
static PTA * pixGetOuterBorderPta(PIX *pixs, BOX *box)
pixGetOuterBorderPta()
Definition: ccbord.c:824
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:195
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1815
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:502
l_ok ccbaStepChainsToPixCoords(CCBORDA *ccba, l_int32 coordtype)
ccbaStepChainsToPixCoords()
Definition: ccbord.c:1315
l_int32 nalloc
Definition: ccbord.h:114
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:282
l_uint8 * zlibCompress(const l_uint8 *datain, size_t nin, size_t *pnout)
zlibCompress()
Definition: zlibmem.c:92
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:734
PTA * ptaTransform(PTA *ptas, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
ptaTransform()
Definition: ptafunc1.c:740
l_ok ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:578
l_ok boxPrintStreamInfo(FILE *fp, BOX *box)
boxPrintStreamInfo()
Definition: boxbasic.c:2431
l_ok ptaaAddPta(PTAA *ptaa, PTA *pta, l_int32 copyflag)
ptaaAddPta()
Definition: ptabasic.c:1038
l_ok ccbaGenerateSinglePath(CCBORDA *ccba)
ccbaGenerateSinglePath()
Definition: ccbord.c:1547
PTA * ptaReverse(PTA *ptas, l_int32 type)
ptaReverse()
Definition: ptafunc1.c:257
#define PIX_XOR
Definition: pix.h:340
l_ok ccbaAddCcb(CCBORDA *ccba, CCBORD *ccb)
ccbaAddCcb()
Definition: ccbord.c:455
l_ok pixGetOuterBorder(CCBORD *ccb, PIX *pixs, BOX *box)
pixGetOuterBorder()
Definition: ccbord.c:897
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:313
Definition: pix.h:480
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:172
struct Pix * pix
Definition: ccbord.h:95
PTAA * pixGetOuterBordersPtaa(PIX *pixs)
pixGetOuterBordersPtaa()
Definition: ccbord.c:764
PTAA * ptaaCreate(l_int32 n)
ptaaCreate()
Definition: ptabasic.c:976
l_ok numaaAddNuma(NUMAA *naa, NUMA *na, l_int32 copyflag)
numaaAddNuma()
Definition: numabasic.c:1546
Definition: pix.h:516
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:362