Leptonica  1.83.1
Image processing and image analysis suite
pix5.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 
105 #ifdef HAVE_CONFIG_H
106 #include <config_auto.h>
107 #endif /* HAVE_CONFIG_H */
108 
109 #include <string.h>
110 #include <math.h>
111 #include "allheaders.h"
112 
113 static const l_uint32 rmask32[] = {0x0,
114  0x00000001, 0x00000003, 0x00000007, 0x0000000f,
115  0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
116  0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
117  0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
118  0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
119  0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
120  0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
121  0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
122 
123 #ifndef NO_CONSOLE_IO
124 #define DEBUG_EDGES 0
125 #endif /* ~NO_CONSOLE_IO */
126 
127 
128 /*-------------------------------------------------------------*
129  * Measurement of properties *
130  *-------------------------------------------------------------*/
139 l_ok
141  NUMA **pnaw,
142  NUMA **pnah)
143 {
144 l_int32 i, n, w, h;
145 PIX *pixt;
146 
147  if (pnaw) *pnaw = NULL;
148  if (pnah) *pnah = NULL;
149  if (!pnaw && !pnah)
150  return ERROR_INT("no output requested", __func__, 1);
151  if (!pixa)
152  return ERROR_INT("pixa not defined", __func__, 1);
153 
154  n = pixaGetCount(pixa);
155  if (pnaw) *pnaw = numaCreate(n);
156  if (pnah) *pnah = numaCreate(n);
157  for (i = 0; i < n; i++) {
158  pixt = pixaGetPix(pixa, i, L_CLONE);
159  pixGetDimensions(pixt, &w, &h, NULL);
160  if (pnaw)
161  numaAddNumber(*pnaw, w);
162  if (pnah)
163  numaAddNumber(*pnah, h);
164  pixDestroy(&pixt);
165  }
166  return 0;
167 }
168 
169 
187 l_ok
189  l_int32 *tab,
190  l_float32 *pfract)
191 {
192 l_int32 *tab8;
193 l_int32 nfg, nbound;
194 PIX *pixt;
195 
196  if (!pfract)
197  return ERROR_INT("&fract not defined", __func__, 1);
198  *pfract = 0.0;
199  if (!pixs || pixGetDepth(pixs) != 1)
200  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
201 
202  if (!tab)
203  tab8 = makePixelSumTab8();
204  else
205  tab8 = tab;
206 
207  pixt = pixErodeBrick(NULL, pixs, 3, 3);
208  pixCountPixels(pixt, &nfg, tab8);
209  if (nfg == 0) {
210  pixDestroy(&pixt);
211  if (!tab) LEPT_FREE(tab8);
212  return 0;
213  }
214  pixXor(pixt, pixt, pixs);
215  pixCountPixels(pixt, &nbound, tab8);
216  *pfract = (l_float32)nfg / (l_float32)nbound;
217  pixDestroy(&pixt);
218 
219  if (!tab) LEPT_FREE(tab8);
220  return 0;
221 }
222 
223 
236 NUMA *
238 {
239 l_int32 i, n;
240 l_int32 *tab;
241 l_float32 fract;
242 NUMA *na;
243 PIX *pixt;
244 
245  if (!pixa)
246  return (NUMA *)ERROR_PTR("pixa not defined", __func__, NULL);
247 
248  n = pixaGetCount(pixa);
249  na = numaCreate(n);
250  tab = makePixelSumTab8();
251  for (i = 0; i < n; i++) {
252  pixt = pixaGetPix(pixa, i, L_CLONE);
253  pixFindPerimToAreaRatio(pixt, tab, &fract);
254  numaAddNumber(na, fract);
255  pixDestroy(&pixt);
256  }
257  LEPT_FREE(tab);
258  return na;
259 }
260 
261 
284 l_ok
286  l_int32 *tab,
287  l_float32 *pfract)
288 {
289 l_int32 *tab8;
290 l_int32 nfg, nbound;
291 PIX *pixt;
292 
293  if (!pfract)
294  return ERROR_INT("&fract not defined", __func__, 1);
295  *pfract = 0.0;
296  if (!pixs || pixGetDepth(pixs) != 1)
297  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
298 
299  if (!tab)
300  tab8 = makePixelSumTab8();
301  else
302  tab8 = tab;
303 
304  pixCountPixels(pixs, &nfg, tab8);
305  if (nfg == 0) {
306  if (!tab) LEPT_FREE(tab8);
307  return 0;
308  }
309  pixt = pixErodeBrick(NULL, pixs, 3, 3);
310  pixXor(pixt, pixt, pixs);
311  pixCountPixels(pixt, &nbound, tab8);
312  *pfract = (l_float32)nbound / (l_float32)nfg;
313  pixDestroy(&pixt);
314 
315  if (!tab) LEPT_FREE(tab8);
316  return 0;
317 }
318 
319 
336 NUMA *
338 {
339 l_int32 i, n;
340 l_int32 *tab;
341 l_float32 ratio;
342 NUMA *na;
343 PIX *pixt;
344 
345  if (!pixa)
346  return (NUMA *)ERROR_PTR("pixa not defined", __func__, NULL);
347 
348  n = pixaGetCount(pixa);
349  na = numaCreate(n);
350  tab = makePixelSumTab8();
351  for (i = 0; i < n; i++) {
352  pixt = pixaGetPix(pixa, i, L_CLONE);
353  pixFindPerimSizeRatio(pixt, tab, &ratio);
354  numaAddNumber(na, ratio);
355  pixDestroy(&pixt);
356  }
357  LEPT_FREE(tab);
358  return na;
359 }
360 
361 
384 l_ok
386  l_int32 *tab,
387  l_float32 *pratio)
388 {
389 l_int32 *tab8;
390 l_int32 w, h, nbound;
391 PIX *pixt;
392 
393  if (!pratio)
394  return ERROR_INT("&ratio not defined", __func__, 1);
395  *pratio = 0.0;
396  if (!pixs || pixGetDepth(pixs) != 1)
397  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
398 
399  if (!tab)
400  tab8 = makePixelSumTab8();
401  else
402  tab8 = tab;
403 
404  pixt = pixErodeBrick(NULL, pixs, 3, 3);
405  pixXor(pixt, pixt, pixs);
406  pixCountPixels(pixt, &nbound, tab8);
407  pixGetDimensions(pixs, &w, &h, NULL);
408  *pratio = (0.5 * nbound) / (l_float32)(w + h);
409  pixDestroy(&pixt);
410 
411  if (!tab) LEPT_FREE(tab8);
412  return 0;
413 }
414 
415 
428 NUMA *
430 {
431 l_int32 i, n;
432 l_int32 *tab;
433 l_float32 fract;
434 NUMA *na;
435 PIX *pixt;
436 
437  if (!pixa)
438  return (NUMA *)ERROR_PTR("pixa not defined", __func__, NULL);
439 
440  n = pixaGetCount(pixa);
441  na = numaCreate(n);
442  tab = makePixelSumTab8();
443  for (i = 0; i < n; i++) {
444  pixt = pixaGetPix(pixa, i, L_CLONE);
445  pixFindAreaFraction(pixt, tab, &fract);
446  numaAddNumber(na, fract);
447  pixDestroy(&pixt);
448  }
449  LEPT_FREE(tab);
450  return na;
451 }
452 
453 
469 l_ok
471  l_int32 *tab,
472  l_float32 *pfract)
473 {
474 l_int32 w, h, sum;
475 l_int32 *tab8;
476 
477  if (!pfract)
478  return ERROR_INT("&fract not defined", __func__, 1);
479  *pfract = 0.0;
480  if (!pixs || pixGetDepth(pixs) != 1)
481  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
482 
483  if (!tab)
484  tab8 = makePixelSumTab8();
485  else
486  tab8 = tab;
487  pixGetDimensions(pixs, &w, &h, NULL);
488  pixCountPixels(pixs, &sum, tab8);
489  *pfract = (l_float32)sum / (l_float32)(w * h);
490 
491  if (!tab) LEPT_FREE(tab8);
492  return 0;
493 }
494 
495 
515 NUMA *
517  PIX *pixm,
518  l_int32 debug)
519 {
520 l_int32 i, n, full;
521 l_int32 *tab;
522 l_float32 fract;
523 BOX *box;
524 NUMA *na;
525 PIX *pix;
526 
527  if (!pixa)
528  return (NUMA *)ERROR_PTR("pixa not defined", __func__, NULL);
529  if (!pixm || pixGetDepth(pixm) != 1)
530  return (NUMA *)ERROR_PTR("pixm undefined or not 1 bpp", __func__, NULL);
531 
532  n = pixaGetCount(pixa);
533  na = numaCreate(n);
534  tab = makePixelSumTab8();
535  pixaIsFull(pixa, NULL, &full); /* check boxa */
536  box = NULL;
537  for (i = 0; i < n; i++) {
538  pix = pixaGetPix(pixa, i, L_CLONE);
539  if (full)
540  box = pixaGetBox(pixa, i, L_CLONE);
541  pixFindAreaFractionMasked(pix, box, pixm, tab, &fract);
542  numaAddNumber(na, fract);
543  boxDestroy(&box);
544  pixDestroy(&pix);
545  }
546  LEPT_FREE(tab);
547 
548  if (debug) {
549  l_int32 w, h;
550  PIX *pix1, *pix2;
551  pixGetDimensions(pixm, &w, &h, NULL);
552  pix1 = pixaDisplay(pixa, w, h); /* recover original image */
553  pix2 = pixCreate(w, h, 8); /* make an 8 bpp white image ... */
554  pixSetColormap(pix2, pixcmapCreate(8)); /* that's cmapped ... */
555  pixSetBlackOrWhite(pix2, L_SET_WHITE); /* and init to white */
556  pixSetMaskedCmap(pix2, pix1, 0, 0, 255, 0, 0); /* color all fg red */
557  pixRasterop(pix1, 0, 0, w, h, PIX_MASK, pixm, 0, 0);
558  pixSetMaskedCmap(pix2, pix1, 0, 0, 0, 255, 0); /* turn masked green */
559  pixDisplay(pix2, 100, 100);
560  pixDestroy(&pix1);
561  pixDestroy(&pix2);
562  }
563 
564  return na;
565 }
566 
567 
592 l_ok
594  BOX *box,
595  PIX *pixm,
596  l_int32 *tab,
597  l_float32 *pfract)
598 {
599 l_int32 x, y, w, h, sum, masksum;
600 l_int32 *tab8;
601 PIX *pix1;
602 
603  if (!pfract)
604  return ERROR_INT("&fract not defined", __func__, 1);
605  *pfract = 0.0;
606  if (!pixs || pixGetDepth(pixs) != 1)
607  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
608  if (!pixm || pixGetDepth(pixm) != 1)
609  return ERROR_INT("pixm not defined or not 1 bpp", __func__, 1);
610 
611  if (!tab)
612  tab8 = makePixelSumTab8();
613  else
614  tab8 = tab;
615  x = y = 0;
616  if (box)
617  boxGetGeometry(box, &x, &y, NULL, NULL);
618  pixGetDimensions(pixs, &w, &h, NULL);
619 
620  pix1 = pixCopy(NULL, pixs);
621  pixRasterop(pix1, 0, 0, w, h, PIX_MASK, pixm, x, y);
622  pixCountPixels(pixs, &sum, tab8);
623  if (sum == 0) {
624  pixDestroy(&pix1);
625  if (!tab) LEPT_FREE(tab8);
626  return 0;
627  }
628  pixCountPixels(pix1, &masksum, tab8);
629  *pfract = (l_float32)masksum / (l_float32)sum;
630 
631  if (!tab) LEPT_FREE(tab8);
632  pixDestroy(&pix1);
633  return 0;
634 }
635 
636 
649 NUMA *
651 {
652 l_int32 i, n, w, h;
653 NUMA *na;
654 PIX *pixt;
655 
656  if (!pixa)
657  return (NUMA *)ERROR_PTR("pixa not defined", __func__, NULL);
658 
659  n = pixaGetCount(pixa);
660  na = numaCreate(n);
661  for (i = 0; i < n; i++) {
662  pixt = pixaGetPix(pixa, i, L_CLONE);
663  pixGetDimensions(pixt, &w, &h, NULL);
664  numaAddNumber(na, (l_float32)w / (l_float32)h);
665  pixDestroy(&pixt);
666  }
667  return na;
668 }
669 
670 
683 NUMA *
685 {
686 l_int32 i, n, w, h;
687 NUMA *na;
688 PIX *pixt;
689 
690  if (!pixa)
691  return (NUMA *)ERROR_PTR("pixa not defined", __func__, NULL);
692 
693  n = pixaGetCount(pixa);
694  na = numaCreate(n);
695  for (i = 0; i < n; i++) {
696  pixt = pixaGetPix(pixa, i, L_CLONE);
697  pixGetDimensions(pixt, &w, &h, NULL);
698  numaAddNumber(na, w * h);
699  pixDestroy(&pixt);
700  }
701  return na;
702 }
703 
704 
721 l_ok
723  PIX *pixs2,
724  l_int32 x2,
725  l_int32 y2,
726  l_int32 *tab,
727  l_float32 *pratio,
728  l_int32 *pnoverlap)
729 {
730 l_int32 *tab8;
731 l_int32 w, h, nintersect, nunion;
732 PIX *pixt;
733 
734  if (pnoverlap) *pnoverlap = 0;
735  if (!pratio)
736  return ERROR_INT("&ratio not defined", __func__, 1);
737  *pratio = 0.0;
738  if (!pixs1 || pixGetDepth(pixs1) != 1)
739  return ERROR_INT("pixs1 not defined or not 1 bpp", __func__, 1);
740  if (!pixs2 || pixGetDepth(pixs2) != 1)
741  return ERROR_INT("pixs2 not defined or not 1 bpp", __func__, 1);
742 
743  if (!tab)
744  tab8 = makePixelSumTab8();
745  else
746  tab8 = tab;
747 
748  pixGetDimensions(pixs2, &w, &h, NULL);
749  pixt = pixCopy(NULL, pixs1);
750  pixRasterop(pixt, x2, y2, w, h, PIX_MASK, pixs2, 0, 0); /* AND */
751  pixCountPixels(pixt, &nintersect, tab8);
752  if (pnoverlap)
753  *pnoverlap = nintersect;
754  pixCopy(pixt, pixs1);
755  pixRasterop(pixt, x2, y2, w, h, PIX_PAINT, pixs2, 0, 0); /* OR */
756  pixCountPixels(pixt, &nunion, tab8);
757  if (!tab) LEPT_FREE(tab8);
758  pixDestroy(&pixt);
759 
760  if (nunion > 0)
761  *pratio = (l_float32)nintersect / (l_float32)nunion;
762  return 0;
763 }
764 
765 
786 BOXA *
788  l_int32 dist,
789  l_int32 minw,
790  l_int32 minh)
791 {
792 l_int32 w, h, i, n, conforms;
793 BOX *box;
794 BOXA *boxa, *boxad;
795 PIX *pix;
796 PIXA *pixa;
797 
798  if (!pixs || pixGetDepth(pixs) != 1)
799  return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
800  if (dist < 0)
801  return (BOXA *)ERROR_PTR("dist must be >= 0", __func__, NULL);
802  if (minw <= 2 * dist && minh <= 2 * dist)
803  return (BOXA *)ERROR_PTR("invalid parameters", __func__, NULL);
804 
805  boxa = pixConnComp(pixs, &pixa, 8);
806  boxad = boxaCreate(0);
807  n = pixaGetCount(pixa);
808  for (i = 0; i < n; i++) {
809  pix = pixaGetPix(pixa, i, L_CLONE);
810  pixGetDimensions(pix, &w, &h, NULL);
811  if (w < minw || h < minh) {
812  pixDestroy(&pix);
813  continue;
814  }
815  pixConformsToRectangle(pix, NULL, dist, &conforms);
816  if (conforms) {
817  box = boxaGetBox(boxa, i, L_COPY);
818  boxaAddBox(boxad, box, L_INSERT);
819  }
820  pixDestroy(&pix);
821  }
822  boxaDestroy(&boxa);
823  pixaDestroy(&pixa);
824  return boxad;
825 }
826 
827 
864 l_ok
866  BOX *box,
867  l_int32 dist,
868  l_int32 *pconforms)
869 {
870 l_int32 w, h, empty;
871 PIX *pix1, *pix2;
872 
873  if (!pconforms)
874  return ERROR_INT("&conforms not defined", __func__, 1);
875  *pconforms = 0;
876  if (!pixs || pixGetDepth(pixs) != 1)
877  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
878  if (dist < 0)
879  return ERROR_INT("dist must be >= 0", __func__, 1);
880  pixGetDimensions(pixs, &w, &h, NULL);
881  if (w <= 2 * dist || h <= 2 * dist) {
882  L_WARNING("automatic conformation: distance too large\n", __func__);
883  *pconforms = 1;
884  return 0;
885  }
886 
887  /* Extract the region, if necessary */
888  if (box)
889  pix1 = pixClipRectangle(pixs, box, NULL);
890  else
891  pix1 = pixCopy(NULL, pixs);
892 
893  /* Invert and fill from the boundary into the interior.
894  * Because we're considering the connected component in an
895  * 8-connected sense, we do the background filling as 4 c.c. */
896  pixInvert(pix1, pix1);
897  pix2 = pixExtractBorderConnComps(pix1, 4);
898 
899  /* Mask out all pixels within a distance %dist from the box
900  * boundary. Any remaining pixels are from filling that goes
901  * more than %dist from the boundary. If no pixels remain,
902  * the component conforms to the bounding rectangle within
903  * a distance %dist. */
904  pixSetOrClearBorder(pix2, dist, dist, dist, dist, PIX_CLR);
905  pixZero(pix2, &empty);
906  pixDestroy(&pix1);
907  pixDestroy(&pix2);
908  *pconforms = (empty) ? 1 : 0;
909  return 0;
910 }
911 
912 
913 /*-----------------------------------------------------------------------*
914  * Extract rectangular region *
915  *-----------------------------------------------------------------------*/
929 PIXA *
931  BOXA *boxa)
932 {
933 l_int32 i, n;
934 BOX *box, *boxc;
935 PIX *pix;
936 PIXA *pixa;
937 
938  if (!pixs)
939  return (PIXA *)ERROR_PTR("pixs not defined", __func__, NULL);
940  if (!boxa)
941  return (PIXA *)ERROR_PTR("boxa not defined", __func__, NULL);
942 
943  n = boxaGetCount(boxa);
944  pixa = pixaCreate(n);
945  for (i = 0; i < n; i++) {
946  box = boxaGetBox(boxa, i, L_CLONE);
947  pix = pixClipRectangle(pixs, box, &boxc);
948  pixaAddPix(pixa, pix, L_INSERT);
949  pixaAddBox(pixa, boxc, L_INSERT);
950  boxDestroy(&box);
951  }
952 
953  return pixa;
954 }
955 
956 
993 PIX *
995  BOX *box,
996  BOX **pboxc)
997 {
998 l_int32 w, h, d, bx, by, bw, bh;
999 BOX *boxc;
1000 PIX *pixd;
1001 
1002  if (pboxc) *pboxc = NULL;
1003  if (!pixs)
1004  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1005  if (!box)
1006  return (PIX *)ERROR_PTR("box not defined", __func__, NULL);
1007 
1008  /* Clip the input box to the pix */
1009  pixGetDimensions(pixs, &w, &h, &d);
1010  if ((boxc = boxClipToRectangle(box, w, h)) == NULL) {
1011  L_WARNING("box doesn't overlap pix\n", __func__);
1012  return NULL;
1013  }
1014  boxGetGeometry(boxc, &bx, &by, &bw, &bh);
1015 
1016  /* Extract the block */
1017  if ((pixd = pixCreate(bw, bh, d)) == NULL) {
1018  boxDestroy(&boxc);
1019  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1020  }
1021  pixCopyResolution(pixd, pixs);
1022  pixCopyColormap(pixd, pixs);
1023  pixCopyText(pixd, pixs);
1024  pixRasterop(pixd, 0, 0, bw, bh, PIX_SRC, pixs, bx, by);
1025 
1026  if (pboxc)
1027  *pboxc = boxc;
1028  else
1029  boxDestroy(&boxc);
1030 
1031  return pixd;
1032 }
1033 
1034 
1054 PIX *
1056  BOX *box,
1057  l_int32 maxbord,
1058  BOX **pboxn)
1059 {
1060 l_int32 w, h, bx, by, bw, bh, bord;
1061 BOX *box1;
1062 PIX *pix1;
1063 
1064  if (!pboxn)
1065  return (PIX *)ERROR_PTR("&boxn not defined", __func__, NULL);
1066  *pboxn = NULL;
1067  if (!pixs)
1068  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1069  if (!box)
1070  return (PIX *)ERROR_PTR("box not defined", __func__, NULL);
1071 
1072  /* Determine the border width */
1073  pixGetDimensions(pixs, &w, &h, NULL);
1074  boxGetGeometry(box, &bx, &by, &bw, &bh);
1075  bord = L_MIN(bx, by);
1076  bord = L_MIN(bord, w - bx - bw);
1077  bord = L_MIN(bord, h - by - bh);
1078  bord = L_MIN(bord, maxbord);
1079 
1080  if (bord <= 0) { /* standard clipping */
1081  pix1 = pixClipRectangle(pixs, box, NULL);
1082  pixGetDimensions(pix1, &w, &h, NULL);
1083  *pboxn = boxCreate(0, 0, w, h);
1084  return pix1;
1085  }
1086 
1087  /* There is a positive border */
1088  box1 = boxAdjustSides(NULL, box, -bord, bord, -bord, bord);
1089  pix1 = pixClipRectangle(pixs, box1, NULL);
1090  boxDestroy(&box1);
1091  *pboxn = boxCreate(bord, bord, bw, bh);
1092  return pix1;
1093 }
1094 
1095 
1125 PIX *
1127  PIX *pixm,
1128  l_int32 x,
1129  l_int32 y,
1130  l_uint32 outval)
1131 {
1132 l_int32 wm, hm, index, rval, gval, bval;
1133 l_uint32 pixel;
1134 BOX *box;
1135 PIX *pixmi, *pixd;
1136 PIXCMAP *cmap;
1137 
1138  if (!pixs)
1139  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1140  if (!pixm || pixGetDepth(pixm) != 1)
1141  return (PIX *)ERROR_PTR("pixm undefined or not 1 bpp", __func__, NULL);
1142 
1143  /* Clip out the region specified by pixm and (x,y) */
1144  pixGetDimensions(pixm, &wm, &hm, NULL);
1145  box = boxCreate(x, y, wm, hm);
1146  pixd = pixClipRectangle(pixs, box, NULL);
1147 
1148  /* Paint 'outval' (or something close to it if cmapped) through
1149  * the pixels not masked by pixm */
1150  cmap = pixGetColormap(pixd);
1151  pixmi = pixInvert(NULL, pixm);
1152  if (cmap) {
1153  extractRGBValues(outval, &rval, &gval, &bval);
1154  pixcmapGetNearestIndex(cmap, rval, gval, bval, &index);
1155  pixcmapGetColor(cmap, index, &rval, &gval, &bval);
1156  composeRGBPixel(rval, gval, bval, &pixel);
1157  pixPaintThroughMask(pixd, pixmi, 0, 0, pixel);
1158  } else {
1159  pixPaintThroughMask(pixd, pixmi, 0, 0, outval);
1160  }
1161 
1162  boxDestroy(&box);
1163  pixDestroy(&pixmi);
1164  return pixd;
1165 }
1166 
1167 
1185 l_ok
1187  PIX *pixs2,
1188  PIX **ppixd1,
1189  PIX **ppixd2)
1190 {
1191 l_int32 w1, h1, w2, h2, w, h;
1192 
1193  if (!ppixd1 || !ppixd2)
1194  return ERROR_INT("&pixd1 and &pixd2 not both defined", __func__, 1);
1195  *ppixd1 = *ppixd2 = NULL;
1196  if (!pixs1 || !pixs2)
1197  return ERROR_INT("pixs1 and pixs2 not defined", __func__, 1);
1198 
1199  pixGetDimensions(pixs1, &w1, &h1, NULL);
1200  pixGetDimensions(pixs2, &w2, &h2, NULL);
1201  w = L_MIN(w1, w2);
1202  h = L_MIN(h1, h2);
1203 
1204  *ppixd1 = pixCropToSize(pixs1, w, h);
1205  *ppixd2 = pixCropToSize(pixs2, w, h);
1206  if (*ppixd1 == NULL || *ppixd2 == NULL)
1207  return ERROR_INT("cropped image failure", __func__, 1);
1208  return 0;
1209 }
1210 
1211 
1226 PIX *
1228  l_int32 w,
1229  l_int32 h)
1230 {
1231 l_int32 ws, hs, wd, hd, d;
1232 PIX *pixd;
1233 
1234  if (!pixs)
1235  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1236 
1237  pixGetDimensions(pixs, &ws, &hs, &d);
1238  if (ws <= w && hs <= h) /* no cropping necessary */
1239  return pixClone(pixs);
1240 
1241  wd = L_MIN(ws, w);
1242  hd = L_MIN(hs, h);
1243  if ((pixd = pixCreate(wd, hd, d)) == NULL)
1244  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1245  pixCopyResolution(pixd, pixs);
1246  pixCopyColormap(pixd, pixs);
1247  pixCopyText(pixd, pixs);
1248  pixCopyInputFormat(pixd, pixs);
1249  pixRasterop(pixd, 0, 0, wd, hd, PIX_SRC, pixs, 0, 0);
1250  return pixd;
1251 }
1252 
1253 
1278 PIX *
1280  PIX *pixt,
1281  l_int32 w,
1282  l_int32 h)
1283 {
1284 l_int32 i, j, ws, hs, d;
1285 PIX *pixd;
1286 
1287  if (!pixs)
1288  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1289  if (!pixt && (w <= 0 || h <= 0))
1290  return (PIX *)ERROR_PTR("both w and h not > 0", __func__, NULL);
1291 
1292  if (pixt) /* redefine w, h */
1293  pixGetDimensions(pixt, &w, &h, NULL);
1294  pixGetDimensions(pixs, &ws, &hs, &d);
1295  if (ws == w && hs == h)
1296  return pixCopy(NULL, pixs);
1297 
1298  if ((pixd = pixCreate(w, h, d)) == NULL)
1299  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1300  pixCopyResolution(pixd, pixs);
1301  pixCopyColormap(pixd, pixs);
1302  pixCopyText(pixd, pixs);
1303  pixCopyInputFormat(pixd, pixs);
1304  pixRasterop(pixd, 0, 0, ws, hs, PIX_SRC, pixs, 0, 0);
1305  if (ws >= w && hs >= h)
1306  return pixd;
1307 
1308  /* Replicate the last column and then the last row */
1309  if (ws < w) {
1310  for (j = ws; j < w; j++)
1311  pixRasterop(pixd, j, 0, 1, h, PIX_SRC, pixd, ws - 1, 0);
1312  }
1313  if (hs < h) {
1314  for (i = hs; i < h; i++)
1315  pixRasterop(pixd, 0, i, w, 1, PIX_SRC, pixd, 0, hs - 1);
1316  }
1317 
1318  return pixd;
1319 }
1320 
1321 
1322 /*---------------------------------------------------------------------*
1323  * Select a connected component by size *
1324  *---------------------------------------------------------------------*/
1345 PIX *
1346 pixSelectComponentBySize(PIX *pixs,
1347  l_int32 rankorder,
1348  l_int32 type,
1349  l_int32 connectivity,
1350  BOX **pbox)
1351 {
1352 l_int32 n, empty, sorttype, index;
1353 BOXA *boxa1;
1354 NUMA *naindex;
1355 PIX *pixd;
1356 PIXA *pixa1, *pixa2;
1357 
1358  if (pbox) *pbox = NULL;
1359  if (!pixs || pixGetDepth(pixs) != 1)
1360  return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
1361  if (type == L_SELECT_BY_WIDTH)
1362  sorttype = L_SORT_BY_WIDTH;
1363  else if (type == L_SELECT_BY_HEIGHT)
1364  sorttype = L_SORT_BY_HEIGHT;
1365  else if (type == L_SELECT_BY_MAX_DIMENSION)
1366  sorttype = L_SORT_BY_MAX_DIMENSION;
1367  else if (type == L_SELECT_BY_AREA)
1368  sorttype = L_SORT_BY_AREA;
1369  else if (type == L_SELECT_BY_PERIMETER)
1370  sorttype = L_SORT_BY_PERIMETER;
1371  else
1372  return (PIX *)ERROR_PTR("invalid selection type", __func__, NULL);
1373  if (connectivity != 4 && connectivity != 8)
1374  return (PIX *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
1375  pixZero(pixs, &empty);
1376  if (empty)
1377  return (PIX *)ERROR_PTR("no foreground pixels", __func__, NULL);
1378 
1379  boxa1 = pixConnComp(pixs, &pixa1, connectivity);
1380  n = boxaGetCount(boxa1);
1381  if (rankorder < 0 || rankorder >= n)
1382  rankorder = n - 1; /* smallest */
1383  pixa2 = pixaSort(pixa1, sorttype, L_SORT_DECREASING, &naindex, L_CLONE);
1384  pixd = pixaGetPix(pixa2, rankorder, L_COPY);
1385  if (pbox) {
1386  numaGetIValue(naindex, rankorder, &index);
1387  *pbox = boxaGetBox(boxa1, index, L_COPY);
1388  }
1389 
1390  numaDestroy(&naindex);
1391  boxaDestroy(&boxa1);
1392  pixaDestroy(&pixa1);
1393  pixaDestroy(&pixa2);
1394  return pixd;
1395 }
1396 
1397 
1416 PIX *
1417 pixFilterComponentBySize(PIX *pixs,
1418  l_int32 rankorder,
1419  l_int32 type,
1420  l_int32 connectivity,
1421  BOX **pbox)
1422 {
1423 l_int32 x, y, w, h;
1424 BOX *box;
1425 PIX *pix1, *pix2;
1426 
1427  if (!pixs || pixGetDepth(pixs) != 1)
1428  return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
1429 
1430  pix1 = pixSelectComponentBySize(pixs, rankorder, type, connectivity, &box);
1431  if (!pix1) {
1432  boxDestroy(&box);
1433  return (PIX *)ERROR_PTR("pix1 not made", __func__, NULL);
1434  }
1435 
1436  /* Put the selected component in a new pix at the same
1437  * location as it had in %pixs */
1438  boxGetGeometry(box, &x, &y, &w, &h);
1439  pix2 = pixCreateTemplate(pixs);
1440  pixRasterop(pix2, x, y, w, h, PIX_SRC, pix1, 0, 0);
1441  if (pbox)
1442  *pbox = box;
1443  else
1444  boxDestroy(&box);
1445  pixDestroy(&pix1);
1446  return pix2;
1447 }
1448 
1449 
1450 /*---------------------------------------------------------------------*
1451  * Make special masks *
1452  *---------------------------------------------------------------------*/
1483 PIX *
1485  l_int32 h,
1486  l_float32 hf,
1487  l_float32 vf,
1488  l_int32 type)
1489 {
1490  if (w <= 0 || h <= 0)
1491  return (PIX *)ERROR_PTR("mask size 0", __func__, NULL);
1492  if (hf < 0.0 || hf > 1.0)
1493  return (PIX *)ERROR_PTR("invalid horiz fractions", __func__, NULL);
1494  if (vf < 0.0 || vf > 1.0)
1495  return (PIX *)ERROR_PTR("invalid vert fractions", __func__, NULL);
1496 
1497  if (type == L_USE_INNER)
1498  return pixMakeFrameMask(w, h, hf, 1.0, vf, 1.0);
1499  else if (type == L_USE_OUTER)
1500  return pixMakeFrameMask(w, h, 0.0, hf, 0.0, vf);
1501  else
1502  return (PIX *)ERROR_PTR("invalid type", __func__, NULL);
1503 }
1504 
1505 
1538 PIX *
1540  l_int32 h,
1541  l_float32 hf1,
1542  l_float32 hf2,
1543  l_float32 vf1,
1544  l_float32 vf2)
1545 {
1546 l_int32 h1, h2, v1, v2;
1547 PIX *pixd;
1548 
1549  if (w <= 0 || h <= 0)
1550  return (PIX *)ERROR_PTR("mask size 0", __func__, NULL);
1551  if (hf1 < 0.0 || hf1 > 1.0 || hf2 < 0.0 || hf2 > 1.0)
1552  return (PIX *)ERROR_PTR("invalid horiz fractions", __func__, NULL);
1553  if (vf1 < 0.0 || vf1 > 1.0 || vf2 < 0.0 || vf2 > 1.0)
1554  return (PIX *)ERROR_PTR("invalid vert fractions", __func__, NULL);
1555  if (hf1 > hf2 || vf1 > vf2)
1556  return (PIX *)ERROR_PTR("invalid relative sizes", __func__, NULL);
1557 
1558  pixd = pixCreate(w, h, 1);
1559 
1560  /* Special cases */
1561  if (hf1 == 0.0 && vf1 == 0.0 && hf2 == 1.0 && vf2 == 1.0) { /* full */
1562  pixSetAll(pixd);
1563  return pixd;
1564  }
1565  if (hf1 == hf2 && vf1 == vf2) { /* empty */
1566  return pixd;
1567  }
1568 
1569  /* General case */
1570  h1 = 0.5 * hf1 * w;
1571  h2 = 0.5 * hf2 * w;
1572  v1 = 0.5 * vf1 * h;
1573  v2 = 0.5 * vf2 * h;
1574  pixRasterop(pixd, h1, v1, w - 2 * h1, h - 2 * v1, PIX_SET, NULL, 0, 0);
1575  if (hf2 < 1.0 && vf2 < 1.0)
1576  pixRasterop(pixd, h2, v2, w - 2 * h2, h - 2 * v2, PIX_CLR, NULL, 0, 0);
1577  return pixd;
1578 }
1579 
1580 
1581 /*---------------------------------------------------------------------*
1582  * Generate a covering of rectangles over connected components *
1583  *---------------------------------------------------------------------*/
1602 PIX *
1604  l_int32 maxiters)
1605 {
1606 l_int32 empty, same, niters;
1607 BOXA *boxa;
1608 PIX *pix1, *pix2;
1609 
1610  if (!pixs || pixGetDepth(pixs) != 1)
1611  return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
1612  if (maxiters < 0)
1613  return (PIX *)ERROR_PTR("maxiters must be >= 0", __func__, NULL);
1614  if (maxiters == 0) maxiters = 50; /* ridiculously large number */
1615 
1616  pixZero(pixs, &empty);
1617  pix1 = pixCreateTemplate(pixs);
1618  if (empty) return pix1;
1619 
1620  /* Do first iteration */
1621  boxa = pixConnCompBB(pixs, 8);
1622  pixMaskBoxa(pix1, pix1, boxa, L_SET_PIXELS);
1623  boxaDestroy(&boxa);
1624  if (maxiters == 1) return pix1;
1625 
1626  niters = 1;
1627  while (niters < maxiters) { /* continue to add pixels to pix1 */
1628  niters++;
1629  boxa = pixConnCompBB(pix1, 8);
1630  pix2 = pixCopy(NULL, pix1);
1631  pixMaskBoxa(pix1, pix1, boxa, L_SET_PIXELS);
1632  boxaDestroy(&boxa);
1633  pixEqual(pix1, pix2, &same);
1634  pixDestroy(&pix2);
1635  if (same) {
1636  L_INFO("%d iterations\n", __func__, niters - 1);
1637  return pix1;
1638  }
1639  }
1640  L_INFO("maxiters = %d reached\n", __func__, niters);
1641  return pix1;
1642 }
1643 
1644 
1645 /*---------------------------------------------------------------------*
1646  * Fraction of Fg pixels under a mask *
1647  *---------------------------------------------------------------------*/
1673 l_ok
1675  PIX *pix2,
1676  l_float32 *pfract)
1677 {
1678 l_int32 w1, h1, w2, h2, empty, count1, count3;
1679 PIX *pix3;
1680 
1681  if (!pfract)
1682  return ERROR_INT("&fract not defined", __func__, 1);
1683  *pfract = 0.0;
1684  if (!pix1 || pixGetDepth(pix1) != 1)
1685  return ERROR_INT("pix1 not defined or not 1 bpp", __func__, 1);
1686  if (!pix2 || pixGetDepth(pix2) != 1)
1687  return ERROR_INT("pix2 not defined or not 1 bpp", __func__, 1);
1688 
1689  pixGetDimensions(pix1, &w1, &h1, NULL);
1690  pixGetDimensions(pix2, &w2, &h2, NULL);
1691  if (w1 != w2 || h1 != h2) {
1692  L_INFO("sizes unequal: (w1,w2) = (%d,%d), (h1,h2) = (%d,%d)\n",
1693  __func__, w1, w2, h1, h2);
1694  }
1695  pixZero(pix1, &empty);
1696  if (empty) return 0;
1697  pixZero(pix2, &empty);
1698  if (empty) return 0;
1699 
1700  pix3 = pixCopy(NULL, pix1);
1701  pixAnd(pix3, pix3, pix2);
1702  pixCountPixels(pix1, &count1, NULL); /* |1| */
1703  pixCountPixels(pix3, &count3, NULL); /* |1 & 2| */
1704  *pfract = (l_float32)count3 / (l_float32)count1;
1705  pixDestroy(&pix3);
1706  return 0;
1707 }
1708 
1709 
1710 /*---------------------------------------------------------------------*
1711  * Clip to Foreground *
1712  *---------------------------------------------------------------------*/
1727 l_ok
1729  PIX **ppixd,
1730  BOX **pbox)
1731 {
1732 l_int32 w, h, wpl, nfullwords, extra, i, j;
1733 l_int32 minx, miny, maxx, maxy;
1734 l_uint32 result, mask;
1735 l_uint32 *data, *line;
1736 BOX *box;
1737 
1738  if (ppixd) *ppixd = NULL;
1739  if (pbox) *pbox = NULL;
1740  if (!ppixd && !pbox)
1741  return ERROR_INT("no output requested", __func__, 1);
1742  if (!pixs || (pixGetDepth(pixs) != 1))
1743  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
1744 
1745  pixGetDimensions(pixs, &w, &h, NULL);
1746  nfullwords = w / 32;
1747  extra = w & 31;
1748  mask = ~rmask32[32 - extra];
1749  wpl = pixGetWpl(pixs);
1750  data = pixGetData(pixs);
1751 
1752  result = 0;
1753  for (i = 0, miny = 0; i < h; i++, miny++) {
1754  line = data + i * wpl;
1755  for (j = 0; j < nfullwords; j++)
1756  result |= line[j];
1757  if (extra)
1758  result |= (line[j] & mask);
1759  if (result)
1760  break;
1761  }
1762  if (miny == h) /* no ON pixels */
1763  return 1;
1764 
1765  result = 0;
1766  for (i = h - 1, maxy = h - 1; i >= 0; i--, maxy--) {
1767  line = data + i * wpl;
1768  for (j = 0; j < nfullwords; j++)
1769  result |= line[j];
1770  if (extra)
1771  result |= (line[j] & mask);
1772  if (result)
1773  break;
1774  }
1775 
1776  minx = 0;
1777  for (j = 0, minx = 0; j < w; j++, minx++) {
1778  for (i = 0; i < h; i++) {
1779  line = data + i * wpl;
1780  if (GET_DATA_BIT(line, j))
1781  goto minx_found;
1782  }
1783  }
1784 
1785 minx_found:
1786  for (j = w - 1, maxx = w - 1; j >= 0; j--, maxx--) {
1787  for (i = 0; i < h; i++) {
1788  line = data + i * wpl;
1789  if (GET_DATA_BIT(line, j))
1790  goto maxx_found;
1791  }
1792  }
1793 
1794 maxx_found:
1795  box = boxCreate(minx, miny, maxx - minx + 1, maxy - miny + 1);
1796 
1797  if (ppixd)
1798  *ppixd = pixClipRectangle(pixs, box, NULL);
1799  if (pbox)
1800  *pbox = box;
1801  else
1802  boxDestroy(&box);
1803 
1804  return 0;
1805 }
1806 
1807 
1825 l_ok
1827  l_int32 *pcanclip)
1828 {
1829 l_int32 i, j, w, h, wpl, found;
1830 l_uint32 *data, *line;
1831 
1832  if (!pcanclip)
1833  return ERROR_INT("&canclip not defined", __func__, 1);
1834  *pcanclip = 0;
1835  if (!pixs || (pixGetDepth(pixs) != 1))
1836  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
1837 
1838  /* Check top and bottom raster lines */
1839  pixGetDimensions(pixs, &w, &h, NULL);
1840  data = pixGetData(pixs);
1841  wpl = pixGetWpl(pixs);
1842  found = FALSE;
1843  for (j = 0; found == FALSE && j < w; j++)
1844  found = GET_DATA_BIT(data, j);
1845  if (!found) {
1846  *pcanclip = 1;
1847  return 0;
1848  }
1849 
1850  line = data + (h - 1) * wpl;
1851  found = FALSE;
1852  for (j = 0; found == FALSE && j < w; j++)
1853  found = GET_DATA_BIT(data, j);
1854  if (!found) {
1855  *pcanclip = 1;
1856  return 0;
1857  }
1858 
1859  /* Check left and right edges */
1860  found = FALSE;
1861  for (i = 0, line = data; found == FALSE && i < h; line += wpl, i++)
1862  found = GET_DATA_BIT(line, 0);
1863  if (!found) {
1864  *pcanclip = 1;
1865  return 0;
1866  }
1867 
1868  found = FALSE;
1869  for (i = 0, line = data; found == FALSE && i < h; line += wpl, i++)
1870  found = GET_DATA_BIT(line, w - 1);
1871  if (!found)
1872  *pcanclip = 1;
1873 
1874  return 0; /* fg pixels found on all edges */
1875 }
1876 
1877 
1895 l_ok
1897  BOX *boxs,
1898  PIX **ppixd,
1899  BOX **pboxd)
1900 {
1901 l_int32 w, h, bx, by, bw, bh, cbw, cbh, left, right, top, bottom;
1902 BOX *boxt, *boxd;
1903 
1904  if (ppixd) *ppixd = NULL;
1905  if (pboxd) *pboxd = NULL;
1906  if (!ppixd && !pboxd)
1907  return ERROR_INT("no output requested", __func__, 1);
1908  if (!pixs || (pixGetDepth(pixs) != 1))
1909  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
1910 
1911  if (!boxs)
1912  return pixClipToForeground(pixs, ppixd, pboxd);
1913 
1914  pixGetDimensions(pixs, &w, &h, NULL);
1915  boxGetGeometry(boxs, &bx, &by, &bw, &bh);
1916  cbw = L_MIN(bw, w - bx);
1917  cbh = L_MIN(bh, h - by);
1918  if (cbw < 0 || cbh < 0)
1919  return ERROR_INT("box not within image", __func__, 1);
1920  boxt = boxCreate(bx, by, cbw, cbh);
1921 
1922  if (pixScanForForeground(pixs, boxt, L_FROM_LEFT, &left)) {
1923  boxDestroy(&boxt);
1924  return 1;
1925  }
1926  pixScanForForeground(pixs, boxt, L_FROM_RIGHT, &right);
1927  pixScanForForeground(pixs, boxt, L_FROM_TOP, &top);
1928  pixScanForForeground(pixs, boxt, L_FROM_BOT, &bottom);
1929 
1930  boxd = boxCreate(left, top, right - left + 1, bottom - top + 1);
1931  if (ppixd)
1932  *ppixd = pixClipRectangle(pixs, boxd, NULL);
1933  if (pboxd)
1934  *pboxd = boxd;
1935  else
1936  boxDestroy(&boxd);
1937 
1938  boxDestroy(&boxt);
1939  return 0;
1940 }
1941 
1942 
1959 l_ok
1961  BOX *box,
1962  l_int32 scanflag,
1963  l_int32 *ploc)
1964 {
1965 l_int32 bx, by, bw, bh, x, xstart, xend, y, ystart, yend, wpl;
1966 l_uint32 *data, *line;
1967 BOX *boxt;
1968 
1969  if (!ploc)
1970  return ERROR_INT("&loc not defined", __func__, 1);
1971  *ploc = 0;
1972  if (!pixs || (pixGetDepth(pixs) != 1))
1973  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
1974 
1975  /* Clip box to pixs if it exists */
1976  pixGetDimensions(pixs, &bw, &bh, NULL);
1977  if (box) {
1978  if ((boxt = boxClipToRectangle(box, bw, bh)) == NULL)
1979  return ERROR_INT("invalid box", __func__, 1);
1980  boxGetGeometry(boxt, &bx, &by, &bw, &bh);
1981  boxDestroy(&boxt);
1982  } else {
1983  bx = by = 0;
1984  }
1985  xstart = bx;
1986  ystart = by;
1987  xend = bx + bw - 1;
1988  yend = by + bh - 1;
1989 
1990  data = pixGetData(pixs);
1991  wpl = pixGetWpl(pixs);
1992  if (scanflag == L_FROM_LEFT) {
1993  for (x = xstart; x <= xend; x++) {
1994  for (y = ystart; y <= yend; y++) {
1995  line = data + y * wpl;
1996  if (GET_DATA_BIT(line, x)) {
1997  *ploc = x;
1998  return 0;
1999  }
2000  }
2001  }
2002  } else if (scanflag == L_FROM_RIGHT) {
2003  for (x = xend; x >= xstart; x--) {
2004  for (y = ystart; y <= yend; y++) {
2005  line = data + y * wpl;
2006  if (GET_DATA_BIT(line, x)) {
2007  *ploc = x;
2008  return 0;
2009  }
2010  }
2011  }
2012  } else if (scanflag == L_FROM_TOP) {
2013  for (y = ystart; y <= yend; y++) {
2014  line = data + y * wpl;
2015  for (x = xstart; x <= xend; x++) {
2016  if (GET_DATA_BIT(line, x)) {
2017  *ploc = y;
2018  return 0;
2019  }
2020  }
2021  }
2022  } else if (scanflag == L_FROM_BOT) {
2023  for (y = yend; y >= ystart; y--) {
2024  line = data + y * wpl;
2025  for (x = xstart; x <= xend; x++) {
2026  if (GET_DATA_BIT(line, x)) {
2027  *ploc = y;
2028  return 0;
2029  }
2030  }
2031  }
2032  } else {
2033  return ERROR_INT("invalid scanflag", __func__, 1);
2034  }
2035 
2036  return 1; /* no fg found */
2037 }
2038 
2039 
2073 l_ok
2075  BOX *boxs,
2076  l_int32 lowthresh,
2077  l_int32 highthresh,
2078  l_int32 maxwidth,
2079  l_int32 factor,
2080  PIX **ppixd,
2081  BOX **pboxd)
2082 {
2083 l_int32 w, h, bx, by, bw, bh, cbw, cbh, left, right, top, bottom;
2084 l_int32 lfound, rfound, tfound, bfound, change;
2085 BOX *boxt, *boxd;
2086 
2087  if (ppixd) *ppixd = NULL;
2088  if (pboxd) *pboxd = NULL;
2089  if (!ppixd && !pboxd)
2090  return ERROR_INT("no output requested", __func__, 1);
2091  if (!pixs || (pixGetDepth(pixs) != 1))
2092  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
2093  if (lowthresh < 1 || highthresh < 1 ||
2094  lowthresh > highthresh || maxwidth < 1)
2095  return ERROR_INT("invalid thresholds", __func__, 1);
2096  factor = L_MIN(1, factor);
2097 
2098  if (lowthresh == 1 && highthresh == 1)
2099  return pixClipBoxToForeground(pixs, boxs, ppixd, pboxd);
2100 
2101  pixGetDimensions(pixs, &w, &h, NULL);
2102  if (boxs) {
2103  boxGetGeometry(boxs, &bx, &by, &bw, &bh);
2104  cbw = L_MIN(bw, w - bx);
2105  cbh = L_MIN(bh, h - by);
2106  if (cbw < 0 || cbh < 0)
2107  return ERROR_INT("box not within image", __func__, 1);
2108  boxt = boxCreate(bx, by, cbw, cbh);
2109  } else {
2110  boxt = boxCreate(0, 0, w, h);
2111  }
2112 
2113  lfound = rfound = tfound = bfound = 0;
2114  while (!lfound || !rfound || !tfound || !bfound) {
2115  change = 0;
2116  if (!lfound) {
2117  if (!pixScanForEdge(pixs, boxt, lowthresh, highthresh, maxwidth,
2118  factor, L_FROM_LEFT, &left)) {
2119  lfound = 1;
2120  change = 1;
2121  boxRelocateOneSide(boxt, boxt, left, L_FROM_LEFT);
2122  }
2123  }
2124  if (!rfound) {
2125  if (!pixScanForEdge(pixs, boxt, lowthresh, highthresh, maxwidth,
2126  factor, L_FROM_RIGHT, &right)) {
2127  rfound = 1;
2128  change = 1;
2129  boxRelocateOneSide(boxt, boxt, right, L_FROM_RIGHT);
2130  }
2131  }
2132  if (!tfound) {
2133  if (!pixScanForEdge(pixs, boxt, lowthresh, highthresh, maxwidth,
2134  factor, L_FROM_TOP, &top)) {
2135  tfound = 1;
2136  change = 1;
2137  boxRelocateOneSide(boxt, boxt, top, L_FROM_TOP);
2138  }
2139  }
2140  if (!bfound) {
2141  if (!pixScanForEdge(pixs, boxt, lowthresh, highthresh, maxwidth,
2142  factor, L_FROM_BOT, &bottom)) {
2143  bfound = 1;
2144  change = 1;
2145  boxRelocateOneSide(boxt, boxt, bottom, L_FROM_BOT);
2146  }
2147  }
2148 
2149 #if DEBUG_EDGES
2150  lept_stderr("iter: %d %d %d %d\n", lfound, rfound, tfound, bfound);
2151 #endif /* DEBUG_EDGES */
2152 
2153  if (change == 0) break;
2154  }
2155  boxDestroy(&boxt);
2156 
2157  if (change == 0)
2158  return ERROR_INT("not all edges found", __func__, 1);
2159 
2160  boxd = boxCreate(left, top, right - left + 1, bottom - top + 1);
2161  if (ppixd)
2162  *ppixd = pixClipRectangle(pixs, boxd, NULL);
2163  if (pboxd)
2164  *pboxd = boxd;
2165  else
2166  boxDestroy(&boxd);
2167 
2168  return 0;
2169 }
2170 
2171 
2201 l_ok
2203  BOX *box,
2204  l_int32 lowthresh,
2205  l_int32 highthresh,
2206  l_int32 maxwidth,
2207  l_int32 factor,
2208  l_int32 scanflag,
2209  l_int32 *ploc)
2210 {
2211 l_int32 bx, by, bw, bh, foundmin, loc, sum, wpl;
2212 l_int32 x, xstart, xend, y, ystart, yend;
2213 l_uint32 *data, *line;
2214 BOX *boxt;
2215 
2216  if (!ploc)
2217  return ERROR_INT("&ploc not defined", __func__, 1);
2218  *ploc = 0;
2219  if (!pixs || (pixGetDepth(pixs) != 1))
2220  return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
2221  if (lowthresh < 1 || highthresh < 1 ||
2222  lowthresh > highthresh || maxwidth < 1)
2223  return ERROR_INT("invalid thresholds", __func__, 1);
2224  factor = L_MIN(1, factor);
2225 
2226  /* Clip box to pixs if it exists */
2227  pixGetDimensions(pixs, &bw, &bh, NULL);
2228  if (box) {
2229  if ((boxt = boxClipToRectangle(box, bw, bh)) == NULL)
2230  return ERROR_INT("invalid box", __func__, 1);
2231  boxGetGeometry(boxt, &bx, &by, &bw, &bh);
2232  boxDestroy(&boxt);
2233  } else {
2234  bx = by = 0;
2235  }
2236  xstart = bx;
2237  ystart = by;
2238  xend = bx + bw - 1;
2239  yend = by + bh - 1;
2240 
2241  data = pixGetData(pixs);
2242  wpl = pixGetWpl(pixs);
2243  foundmin = 0;
2244  if (scanflag == L_FROM_LEFT) {
2245  for (x = xstart; x <= xend; x++) {
2246  sum = 0;
2247  for (y = ystart; y <= yend; y += factor) {
2248  line = data + y * wpl;
2249  if (GET_DATA_BIT(line, x))
2250  sum++;
2251  }
2252  if (!foundmin && sum < lowthresh)
2253  continue;
2254  if (!foundmin) { /* save the loc of the beginning of the edge */
2255  foundmin = 1;
2256  loc = x;
2257  }
2258  if (sum >= highthresh) {
2259 #if DEBUG_EDGES
2260  lept_stderr("Left: x = %d, loc = %d\n", x, loc);
2261 #endif /* DEBUG_EDGES */
2262  if (x - loc < maxwidth) {
2263  *ploc = loc;
2264  return 0;
2265  } else {
2266  return 1;
2267  }
2268  }
2269  }
2270  } else if (scanflag == L_FROM_RIGHT) {
2271  for (x = xend; x >= xstart; x--) {
2272  sum = 0;
2273  for (y = ystart; y <= yend; y += factor) {
2274  line = data + y * wpl;
2275  if (GET_DATA_BIT(line, x))
2276  sum++;
2277  }
2278  if (!foundmin && sum < lowthresh)
2279  continue;
2280  if (!foundmin) {
2281  foundmin = 1;
2282  loc = x;
2283  }
2284  if (sum >= highthresh) {
2285 #if DEBUG_EDGES
2286  lept_stderr("Right: x = %d, loc = %d\n", x, loc);
2287 #endif /* DEBUG_EDGES */
2288  if (loc - x < maxwidth) {
2289  *ploc = loc;
2290  return 0;
2291  } else {
2292  return 1;
2293  }
2294  }
2295  }
2296  } else if (scanflag == L_FROM_TOP) {
2297  for (y = ystart; y <= yend; y++) {
2298  sum = 0;
2299  line = data + y * wpl;
2300  for (x = xstart; x <= xend; x += factor) {
2301  if (GET_DATA_BIT(line, x))
2302  sum++;
2303  }
2304  if (!foundmin && sum < lowthresh)
2305  continue;
2306  if (!foundmin) {
2307  foundmin = 1;
2308  loc = y;
2309  }
2310  if (sum >= highthresh) {
2311 #if DEBUG_EDGES
2312  lept_stderr("Top: y = %d, loc = %d\n", y, loc);
2313 #endif /* DEBUG_EDGES */
2314  if (y - loc < maxwidth) {
2315  *ploc = loc;
2316  return 0;
2317  } else {
2318  return 1;
2319  }
2320  }
2321  }
2322  } else if (scanflag == L_FROM_BOT) {
2323  for (y = yend; y >= ystart; y--) {
2324  sum = 0;
2325  line = data + y * wpl;
2326  for (x = xstart; x <= xend; x += factor) {
2327  if (GET_DATA_BIT(line, x))
2328  sum++;
2329  }
2330  if (!foundmin && sum < lowthresh)
2331  continue;
2332  if (!foundmin) {
2333  foundmin = 1;
2334  loc = y;
2335  }
2336  if (sum >= highthresh) {
2337 #if DEBUG_EDGES
2338  lept_stderr("Bottom: y = %d, loc = %d\n", y, loc);
2339 #endif /* DEBUG_EDGES */
2340  if (loc - y < maxwidth) {
2341  *ploc = loc;
2342  return 0;
2343  } else {
2344  return 1;
2345  }
2346  }
2347  }
2348  } else {
2349  return ERROR_INT("invalid scanflag", __func__, 1);
2350  }
2351 
2352  return 1; /* edge not found */
2353 }
2354 
2355 
2356 /*---------------------------------------------------------------------*
2357  * Extract pixel averages and reversals along lines *
2358  *---------------------------------------------------------------------*/
2380 NUMA *
2382  l_int32 x1,
2383  l_int32 y1,
2384  l_int32 x2,
2385  l_int32 y2,
2386  l_int32 factor)
2387 {
2388 l_int32 i, w, h, d, xmin, ymin, xmax, ymax, npts, direction;
2389 l_uint32 val;
2390 l_float32 x, y;
2391 l_float64 slope;
2392 NUMA *na;
2393 PTA *pta;
2394 
2395  if (!pixs)
2396  return (NUMA *)ERROR_PTR("pixs not defined", __func__, NULL);
2397  pixGetDimensions(pixs, &w, &h, &d);
2398  if (d != 1 && d != 8)
2399  return (NUMA *)ERROR_PTR("d not 1 or 8 bpp", __func__, NULL);
2400  if (pixGetColormap(pixs))
2401  return (NUMA *)ERROR_PTR("pixs has a colormap", __func__, NULL);
2402  if (factor < 1) {
2403  L_WARNING("factor must be >= 1; setting to 1\n", __func__);
2404  factor = 1;
2405  }
2406 
2407  /* Clip line to the image */
2408  x1 = L_MAX(0, L_MIN(x1, w - 1));
2409  x2 = L_MAX(0, L_MIN(x2, w - 1));
2410  y1 = L_MAX(0, L_MIN(y1, h - 1));
2411  y2 = L_MAX(0, L_MIN(y2, h - 1));
2412 
2413  if (x1 == x2 && y1 == y2) {
2414  pixGetPixel(pixs, x1, y1, &val);
2415  na = numaCreate(1);
2416  numaAddNumber(na, val);
2417  return na;
2418  }
2419 
2420  if (y1 == y2)
2421  direction = L_HORIZONTAL_LINE;
2422  else if (x1 == x2)
2423  direction = L_VERTICAL_LINE;
2424  else
2425  direction = L_OBLIQUE_LINE;
2426 
2427  na = numaCreate(0);
2428  if (direction == L_HORIZONTAL_LINE) { /* plot against x */
2429  xmin = L_MIN(x1, x2);
2430  xmax = L_MAX(x1, x2);
2431  numaSetParameters(na, xmin, factor);
2432  for (i = xmin; i <= xmax; i += factor) {
2433  pixGetPixel(pixs, i, y1, &val);
2434  numaAddNumber(na, val);
2435  }
2436  } else if (direction == L_VERTICAL_LINE) { /* plot against y */
2437  ymin = L_MIN(y1, y2);
2438  ymax = L_MAX(y1, y2);
2439  numaSetParameters(na, ymin, factor);
2440  for (i = ymin; i <= ymax; i += factor) {
2441  pixGetPixel(pixs, x1, i, &val);
2442  numaAddNumber(na, val);
2443  }
2444  } else { /* direction == L_OBLIQUE_LINE */
2445  slope = (l_float64)((y2 - y1) / (x2 - x1));
2446  if (L_ABS(slope) < 1.0) { /* quasi-horizontal */
2447  xmin = L_MIN(x1, x2);
2448  xmax = L_MAX(x1, x2);
2449  ymin = (xmin == x1) ? y1 : y2; /* pt that goes with xmin */
2450  ymax = (ymin == y1) ? y2 : y1; /* pt that goes with xmax */
2451  pta = generatePtaLine(xmin, ymin, xmax, ymax);
2452  numaSetParameters(na, xmin, (l_float32)factor);
2453  } else { /* quasi-vertical */
2454  ymin = L_MIN(y1, y2);
2455  ymax = L_MAX(y1, y2);
2456  xmin = (ymin == y1) ? x1 : x2; /* pt that goes with ymin */
2457  xmax = (xmin == x1) ? x2 : x1; /* pt that goes with ymax */
2458  pta = generatePtaLine(xmin, ymin, xmax, ymax);
2459  numaSetParameters(na, ymin, (l_float32)factor);
2460  }
2461  npts = ptaGetCount(pta);
2462  for (i = 0; i < npts; i += factor) {
2463  ptaGetPt(pta, i, &x, &y);
2464  pixGetPixel(pixs, (l_int32)x, (l_int32)y, &val);
2465  numaAddNumber(na, val);
2466  }
2467 
2468 #if 0 /* debugging */
2469  pixPlotAlongPta(pixs, pta, GPLOT_PNG, NULL);
2470 #endif
2471 
2472  ptaDestroy(&pta);
2473  }
2474 
2475  return na;
2476 }
2477 
2478 
2498 l_float32
2500  l_int32 x1,
2501  l_int32 y1,
2502  l_int32 x2,
2503  l_int32 y2,
2504  l_int32 factor)
2505 {
2506 l_int32 i, j, w, h, d, direction, count, wpl;
2507 l_uint32 *data, *line;
2508 l_float32 sum;
2509 
2510  if (!pixs)
2511  return ERROR_INT("pixs not defined", __func__, 1);
2512  pixGetDimensions(pixs, &w, &h, &d);
2513  if (d != 1 && d != 8)
2514  return ERROR_INT("d not 1 or 8 bpp", __func__, 1);
2515  if (pixGetColormap(pixs))
2516  return ERROR_INT("pixs has a colormap", __func__, 1);
2517  if (x1 > x2 || y1 > y2)
2518  return ERROR_INT("x1 > x2 or y1 > y2", __func__, 1);
2519 
2520  if (y1 == y2) {
2521  x1 = L_MAX(0, x1);
2522  x2 = L_MIN(w - 1, x2);
2523  y1 = L_MAX(0, L_MIN(y1, h - 1));
2524  direction = L_HORIZONTAL_LINE;
2525  } else if (x1 == x2) {
2526  y1 = L_MAX(0, y1);
2527  y2 = L_MIN(h - 1, y2);
2528  x1 = L_MAX(0, L_MIN(x1, w - 1));
2529  direction = L_VERTICAL_LINE;
2530  } else {
2531  return ERROR_INT("line neither horiz nor vert", __func__, 1);
2532  }
2533 
2534  if (factor < 1) {
2535  L_WARNING("factor must be >= 1; setting to 1\n", __func__);
2536  factor = 1;
2537  }
2538 
2539  data = pixGetData(pixs);
2540  wpl = pixGetWpl(pixs);
2541  sum = 0;
2542  count = 0;
2543  if (direction == L_HORIZONTAL_LINE) {
2544  line = data + y1 * wpl;
2545  for (j = x1, count = 0; j <= x2; count++, j += factor) {
2546  if (d == 1)
2547  sum += GET_DATA_BIT(line, j);
2548  else /* d == 8 */
2549  sum += GET_DATA_BYTE(line, j);
2550  }
2551  } else if (direction == L_VERTICAL_LINE) {
2552  for (i = y1, count = 0; i <= y2; count++, i += factor) {
2553  line = data + i * wpl;
2554  if (d == 1)
2555  sum += GET_DATA_BIT(line, x1);
2556  else /* d == 8 */
2557  sum += GET_DATA_BYTE(line, x1);
2558  }
2559  }
2560 
2561  return sum / (l_float32)count;
2562 }
2563 
2564 
2595 NUMA *
2597  l_float32 fract,
2598  l_int32 dir,
2599  l_int32 first,
2600  l_int32 last,
2601  l_int32 factor1,
2602  l_int32 factor2)
2603 {
2604 l_int32 i, j, w, h, d, start, end;
2605 l_float32 ave;
2606 NUMA *nad;
2607 PIX *pixr, *pixg;
2608 
2609  if (!pixs)
2610  return (NUMA *)ERROR_PTR("pixs not defined", __func__, NULL);
2611  if (fract < 0.0 || fract > 1.0)
2612  return (NUMA *)ERROR_PTR("fract < 0.0 or > 1.0", __func__, NULL);
2613  if (dir != L_HORIZONTAL_LINE && dir != L_VERTICAL_LINE)
2614  return (NUMA *)ERROR_PTR("invalid direction", __func__, NULL);
2615  if (first < 0) first = 0;
2616  if (last < first)
2617  return (NUMA *)ERROR_PTR("last must be >= first", __func__, NULL);
2618  if (factor1 < 1) {
2619  L_WARNING("factor1 must be >= 1; setting to 1\n", __func__);
2620  factor1 = 1;
2621  }
2622  if (factor2 < 1) {
2623  L_WARNING("factor2 must be >= 1; setting to 1\n", __func__);
2624  factor2 = 1;
2625  }
2626 
2627  /* Use 1 or 8 bpp, without colormap */
2628  if (pixGetColormap(pixs))
2630  else
2631  pixr = pixClone(pixs);
2632  pixGetDimensions(pixr, &w, &h, &d);
2633  if (d == 1)
2634  pixg = pixClone(pixr);
2635  else
2636  pixg = pixConvertTo8(pixr, 0);
2637 
2638  nad = numaCreate(0); /* output: samples in slow scan direction */
2639  numaSetParameters(nad, 0, factor2);
2640  if (dir == L_HORIZONTAL_LINE) {
2641  start = (l_int32)(0.5 * (1.0 - fract) * (l_float32)w);
2642  end = w - start;
2643  if (last > h - 1) {
2644  L_WARNING("last > h - 1; clipping\n", __func__);
2645  last = h - 1;
2646  }
2647  for (i = first; i <= last; i += factor2) {
2648  ave = pixAverageOnLine(pixg, start, i, end, i, factor1);
2649  numaAddNumber(nad, ave);
2650  }
2651  } else if (dir == L_VERTICAL_LINE) {
2652  start = (l_int32)(0.5 * (1.0 - fract) * (l_float32)h);
2653  end = h - start;
2654  if (last > w - 1) {
2655  L_WARNING("last > w - 1; clipping\n", __func__);
2656  last = w - 1;
2657  }
2658  for (j = first; j <= last; j += factor2) {
2659  ave = pixAverageOnLine(pixg, j, start, j, end, factor1);
2660  numaAddNumber(nad, ave);
2661  }
2662  }
2663 
2664  pixDestroy(&pixr);
2665  pixDestroy(&pixg);
2666  return nad;
2667 }
2668 
2669 
2708 NUMA *
2710  l_float32 fract,
2711  l_int32 dir,
2712  l_int32 first,
2713  l_int32 last,
2714  l_int32 minreversal,
2715  l_int32 factor1,
2716  l_int32 factor2)
2717 {
2718 l_int32 i, j, w, h, d, start, end, nr;
2719 NUMA *naline, *nad;
2720 PIX *pixr, *pixg;
2721 
2722  if (!pixs)
2723  return (NUMA *)ERROR_PTR("pixs not defined", __func__, NULL);
2724  if (fract < 0.0 || fract > 1.0)
2725  return (NUMA *)ERROR_PTR("fract < 0.0 or > 1.0", __func__, NULL);
2726  if (dir != L_HORIZONTAL_LINE && dir != L_VERTICAL_LINE)
2727  return (NUMA *)ERROR_PTR("invalid direction", __func__, NULL);
2728  if (first < 0) first = 0;
2729  if (last < first)
2730  return (NUMA *)ERROR_PTR("last must be >= first", __func__, NULL);
2731  if (factor1 < 1) {
2732  L_WARNING("factor1 must be >= 1; setting to 1\n", __func__);
2733  factor1 = 1;
2734  }
2735  if (factor2 < 1) {
2736  L_WARNING("factor2 must be >= 1; setting to 1\n", __func__);
2737  factor2 = 1;
2738  }
2739 
2740  /* Use 1 or 8 bpp, without colormap */
2741  if (pixGetColormap(pixs))
2743  else
2744  pixr = pixClone(pixs);
2745  pixGetDimensions(pixr, &w, &h, &d);
2746  if (d == 1) {
2747  pixg = pixClone(pixr);
2748  minreversal = 1; /* enforce this */
2749  } else {
2750  pixg = pixConvertTo8(pixr, 0);
2751  }
2752 
2753  nad = numaCreate(0); /* output: samples in slow scan direction */
2754  numaSetParameters(nad, 0, factor2);
2755  if (dir == L_HORIZONTAL_LINE) {
2756  start = (l_int32)(0.5 * (1.0 - fract) * (l_float32)w);
2757  end = w - start;
2758  if (last > h - 1) {
2759  L_WARNING("last > h - 1; clipping\n", __func__);
2760  last = h - 1;
2761  }
2762  for (i = first; i <= last; i += factor2) {
2763  naline = pixExtractOnLine(pixg, start, i, end, i, factor1);
2764  numaCountReversals(naline, minreversal, &nr, NULL);
2765  numaAddNumber(nad, nr);
2766  numaDestroy(&naline);
2767  }
2768  } else if (dir == L_VERTICAL_LINE) {
2769  start = (l_int32)(0.5 * (1.0 - fract) * (l_float32)h);
2770  end = h - start;
2771  if (last > w - 1) {
2772  L_WARNING("last > w - 1; clipping\n", __func__);
2773  last = w - 1;
2774  }
2775  for (j = first; j <= last; j += factor2) {
2776  naline = pixExtractOnLine(pixg, j, start, j, end, factor1);
2777  numaCountReversals(naline, minreversal, &nr, NULL);
2778  numaAddNumber(nad, nr);
2779  numaDestroy(&naline);
2780  }
2781  }
2782 
2783  pixDestroy(&pixr);
2784  pixDestroy(&pixg);
2785  return nad;
2786 }
2787 
2788 
2789 /*---------------------------------------------------------------------*
2790  * Extract windowed variance along a line *
2791  *---------------------------------------------------------------------*/
2815 l_ok
2817  l_int32 dir,
2818  l_int32 loc,
2819  l_int32 c1,
2820  l_int32 c2,
2821  l_int32 size,
2822  NUMA **pnad)
2823 {
2824 l_int32 i, j, w, h, cmin, cmax, maxloc, n, x, y;
2825 l_uint32 val;
2826 l_float32 norm, rootvar;
2827 l_float32 *array;
2828 l_float64 sum1, sum2, ave, var;
2829 NUMA *na1, *nad;
2830 PTA *pta;
2831 
2832  if (!pnad)
2833  return ERROR_INT("&nad not defined", __func__, 1);
2834  *pnad = NULL;
2835  if (!pixs || pixGetDepth(pixs) != 8)
2836  return ERROR_INT("pixs not defined or not 8bpp", __func__, 1);
2837  if (size < 2)
2838  return ERROR_INT("window size must be > 1", __func__, 1);
2839  if (dir != L_HORIZONTAL_LINE && dir != L_VERTICAL_LINE)
2840  return ERROR_INT("invalid direction", __func__, 1);
2841  pixGetDimensions(pixs, &w, &h, NULL);
2842  maxloc = (dir == L_HORIZONTAL_LINE) ? h - 1 : w - 1;
2843  if (loc < 0 || loc > maxloc)
2844  return ERROR_INT("invalid line position", __func__, 1);
2845 
2846  /* Clip line to the image */
2847  cmin = L_MIN(c1, c2);
2848  cmax = L_MAX(c1, c2);
2849  maxloc = (dir == L_HORIZONTAL_LINE) ? w - 1 : h - 1;
2850  cmin = L_MAX(0, L_MIN(cmin, maxloc));
2851  cmax = L_MAX(0, L_MIN(cmax, maxloc));
2852  n = cmax - cmin + 1;
2853 
2854  /* Generate pta along the line */
2855  pta = ptaCreate(n);
2856  if (dir == L_HORIZONTAL_LINE) {
2857  for (i = cmin; i <= cmax; i++)
2858  ptaAddPt(pta, i, loc);
2859  } else { /* vertical line */
2860  for (i = cmin; i <= cmax; i++)
2861  ptaAddPt(pta, loc, i);
2862  }
2863 
2864  /* Get numa of pixel values on the line */
2865  na1 = numaCreate(n);
2866  numaSetParameters(na1, cmin, 1);
2867  for (i = 0; i < n; i++) {
2868  ptaGetIPt(pta, i, &x, &y);
2869  pixGetPixel(pixs, x, y, &val);
2870  numaAddNumber(na1, val);
2871  }
2872  array = numaGetFArray(na1, L_NOCOPY);
2873  ptaDestroy(&pta);
2874 
2875  /* Compute root variance on overlapping windows */
2876  nad = numaCreate(n);
2877  *pnad = nad;
2878  numaSetParameters(nad, cmin + size / 2, 1);
2879  norm = 1.0 / (l_float32)size;
2880  for (i = 0; i < n - size; i++) { /* along the line */
2881  sum1 = sum2 = 0;
2882  for (j = 0; j < size; j++) { /* over the window */
2883  val = array[i + j];
2884  sum1 += val;
2885  sum2 += (l_float64)(val) * val;
2886  }
2887  ave = norm * sum1;
2888  var = norm * sum2 - ave * ave;
2889  if (var < 0) /* avoid small negative values from rounding effects */
2890  var = 0.0;
2891  rootvar = (l_float32)sqrt(var);
2892  numaAddNumber(nad, rootvar);
2893  }
2894 
2895  numaDestroy(&na1);
2896  return 0;
2897 }
2898 
2899 
2900 /*---------------------------------------------------------------------*
2901  * Extract min/max of pixel values near lines *
2902  *---------------------------------------------------------------------*/
2933 l_ok
2935  l_int32 x1,
2936  l_int32 y1,
2937  l_int32 x2,
2938  l_int32 y2,
2939  l_int32 dist,
2940  l_int32 direction,
2941  NUMA **pnamin,
2942  NUMA **pnamax,
2943  l_float32 *pminave,
2944  l_float32 *pmaxave)
2945 {
2946 l_int32 i, j, w, h, d, x, y, n, dir, found, minval, maxval, negloc, posloc;
2947 l_uint32 val;
2948 l_float32 sum;
2949 NUMA *namin, *namax;
2950 PTA *pta;
2951 
2952  if (pnamin) *pnamin = NULL;
2953  if (pnamax) *pnamax = NULL;
2954  if (pminave) *pminave = UNDEF;
2955  if (pmaxave) *pmaxave = UNDEF;
2956  if (!pnamin && !pnamax && !pminave && !pmaxave)
2957  return ERROR_INT("no output requested", __func__, 1);
2958  if (!pixs)
2959  return ERROR_INT("pixs not defined", __func__, 1);
2960  pixGetDimensions(pixs, &w, &h, &d);
2961  if (d != 8 || pixGetColormap(pixs))
2962  return ERROR_INT("pixs not 8 bpp or has colormap", __func__, 1);
2963  dist = L_ABS(dist);
2964  if (direction != L_SCAN_NEGATIVE && direction != L_SCAN_POSITIVE &&
2965  direction != L_SCAN_BOTH)
2966  return ERROR_INT("invalid direction", __func__, 1);
2967 
2968  pta = generatePtaLine(x1, y1, x2, y2);
2969  n = ptaGetCount(pta);
2970  dir = (L_ABS(x1 - x2) == n - 1) ? L_HORIZ : L_VERT;
2971  namin = numaCreate(n);
2972  namax = numaCreate(n);
2973  negloc = -dist;
2974  posloc = dist;
2975  if (direction == L_SCAN_NEGATIVE)
2976  posloc = 0;
2977  else if (direction == L_SCAN_POSITIVE)
2978  negloc = 0;
2979  for (i = 0; i < n; i++) {
2980  ptaGetIPt(pta, i, &x, &y);
2981  minval = 255;
2982  maxval = 0;
2983  found = FALSE;
2984  if (dir == L_HORIZ) {
2985  if (x < 0 || x >= w) continue;
2986  for (j = negloc; j <= posloc; j++) {
2987  if (y + j < 0 || y + j >= h) continue;
2988  pixGetPixel(pixs, x, y + j, &val);
2989  found = TRUE;
2990  if (val < minval) minval = val;
2991  if (val > maxval) maxval = val;
2992  }
2993  } else { /* dir == L_VERT */
2994  if (y < 0 || y >= h) continue;
2995  for (j = negloc; j <= posloc; j++) {
2996  if (x + j < 0 || x + j >= w) continue;
2997  pixGetPixel(pixs, x + j, y, &val);
2998  found = TRUE;
2999  if (val < minval) minval = val;
3000  if (val > maxval) maxval = val;
3001  }
3002  }
3003  if (found) {
3004  numaAddNumber(namin, minval);
3005  numaAddNumber(namax, maxval);
3006  }
3007  }
3008 
3009  n = numaGetCount(namin);
3010  if (n == 0) {
3011  numaDestroy(&namin);
3012  numaDestroy(&namax);
3013  ptaDestroy(&pta);
3014  return ERROR_INT("no output from this line", __func__, 1);
3015  }
3016 
3017  if (pminave) {
3018  numaGetSum(namin, &sum);
3019  *pminave = sum / n;
3020  }
3021  if (pmaxave) {
3022  numaGetSum(namax, &sum);
3023  *pmaxave = sum / n;
3024  }
3025  if (pnamin)
3026  *pnamin = namin;
3027  else
3028  numaDestroy(&namin);
3029  if (pnamax)
3030  *pnamax = namax;
3031  else
3032  numaDestroy(&namax);
3033  ptaDestroy(&pta);
3034  return 0;
3035 }
3036 
3037 
3038 /*---------------------------------------------------------------------*
3039  * Rank row and column transforms *
3040  *---------------------------------------------------------------------*/
3054 PIX *
3056 {
3057 l_int32 i, j, k, m, w, h, wpl, val;
3058 l_int32 histo[256];
3059 l_uint32 *datas, *datad, *lines, *lined;
3060 PIX *pixd;
3061 
3062  if (!pixs)
3063  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
3064  if (pixGetDepth(pixs) != 8)
3065  return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
3066  if (pixGetColormap(pixs))
3067  return (PIX *)ERROR_PTR("pixs has a colormap", __func__, NULL);
3068 
3069  pixGetDimensions(pixs, &w, &h, NULL);
3070  pixd = pixCreateTemplate(pixs);
3071  datas = pixGetData(pixs);
3072  datad = pixGetData(pixd);
3073  wpl = pixGetWpl(pixs);
3074  for (i = 0; i < h; i++) {
3075  memset(histo, 0, 1024);
3076  lines = datas + i * wpl;
3077  lined = datad + i * wpl;
3078  for (j = 0; j < w; j++) {
3079  val = GET_DATA_BYTE(lines, j);
3080  histo[val]++;
3081  }
3082  for (m = 0, j = 0; m < 256; m++) {
3083  for (k = 0; k < histo[m]; k++, j++)
3084  SET_DATA_BYTE(lined, j, m);
3085  }
3086  }
3087 
3088  return pixd;
3089 }
3090 
3091 
3105 PIX *
3107 {
3108 l_int32 i, j, k, m, w, h, val;
3109 l_int32 histo[256];
3110 void **lines8, **lined8;
3111 PIX *pixd;
3112 
3113  if (!pixs)
3114  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
3115  if (pixGetDepth(pixs) != 8)
3116  return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
3117  if (pixGetColormap(pixs))
3118  return (PIX *)ERROR_PTR("pixs has a colormap", __func__, NULL);
3119 
3120  pixGetDimensions(pixs, &w, &h, NULL);
3121  pixd = pixCreateTemplate(pixs);
3122  lines8 = pixGetLinePtrs(pixs, NULL);
3123  lined8 = pixGetLinePtrs(pixd, NULL);
3124  for (j = 0; j < w; j++) {
3125  memset(histo, 0, 1024);
3126  for (i = 0; i < h; i++) {
3127  val = GET_DATA_BYTE(lines8[i], j);
3128  histo[val]++;
3129  }
3130  for (m = 0, i = 0; m < 256; m++) {
3131  for (k = 0; k < histo[m]; k++, i++)
3132  SET_DATA_BYTE(lined8[i], j, m);
3133  }
3134  }
3135 
3136  LEPT_FREE(lines8);
3137  LEPT_FREE(lined8);
3138  return pixd;
3139 }
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
l_ok boxGetGeometry(const BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:301
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:273
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:553
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:519
l_int32 boxaGetCount(const BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:661
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:702
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:171
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:442
BOX * boxRelocateOneSide(BOX *boxd, BOX *boxs, l_int32 loc, l_int32 sideflag)
boxRelocateOneSide()
Definition: boxfunc1.c:1794
BOX * boxClipToRectangle(BOX *box, l_int32 wi, l_int32 hi)
boxClipToRectangle()
Definition: boxfunc1.c:1679
BOX * boxAdjustSides(BOX *boxd, BOX *boxs, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxAdjustSides()
Definition: boxfunc1.c:1932
PIX * pixMaskBoxa(PIX *pixd, PIX *pixs, BOXA *boxa, l_int32 op)
pixMaskBoxa()
Definition: boxfunc3.c:149
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:126
l_ok pixcmapGetNearestIndex(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapGetNearestIndex()
Definition: colormap.c:1292
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:789
l_ok pixEqual(PIX *pix1, PIX *pix2, l_int32 *psame)
pixEqual()
Definition: compare.c:156
BOXA * pixConnCompBB(PIX *pixs, l_int32 connectivity)
pixConnCompBB()
Definition: conncomp.c:307
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:152
PTA * generatePtaLine(l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2)
generatePtaLine()
Definition: graphics.c:141
PIX * pixErodeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeBrick()
Definition: morph.c:740
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:460
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:193
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:720
l_ok numaSetParameters(NUMA *na, l_float32 startx, l_float32 delx)
numaSetParameters()
Definition: numabasic.c:910
l_float32 * numaGetFArray(NUMA *na, l_int32 copyflag)
numaGetFArray()
Definition: numabasic.c:850
l_ok numaGetSum(NUMA *na, l_float32 *psum)
numaGetSum()
Definition: numafunc1.c:525
l_ok numaCountReversals(NUMA *nas, l_float32 minreversal, l_int32 *pnr, l_float32 *prd)
numaCountReversals()
Definition: numafunc2.c:2701
l_ok pixSetMaskedCmap(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_int32 rval, l_int32 gval, l_int32 bval)
pixSetMaskedCmap()
Definition: paintcmap.c:686
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1642
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1582
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:689
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:380
l_ok pixCopyColormap(PIX *pixd, const PIX *pixs)
pixCopyColormap()
Definition: pix1.c:795
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
void ** pixGetLinePtrs(PIX *pix, l_int32 *psize)
pixGetLinePtrs()
Definition: pix1.c:1844
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:192
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:799
l_ok pixSetOrClearBorder(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_int32 op)
pixSetOrClearBorder()
Definition: pix2.c:1474
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2728
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2793
l_ok pixSetBlackOrWhite(PIX *pixs, l_int32 op)
pixSetBlackOrWhite()
Definition: pix2.c:997
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1777
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1481
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:618
l_ok pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition: pix3.c:1893
PIX * pixAnd(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixAnd()
Definition: pix3.c:1592
l_int32 * makePixelSumTab8(void)
makePixelSumTab8()
Definition: pix3.c:2354
PIX * pixXor(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixXor()
Definition: pix3.c:1654
PIX * pixResizeToMatch(PIX *pixs, PIX *pixt, l_int32 w, l_int32 h)
pixResizeToMatch()
Definition: pix5.c:1279
l_ok pixWindowedVarianceOnLine(PIX *pixs, l_int32 dir, l_int32 loc, l_int32 c1, l_int32 c2, l_int32 size, NUMA **pnad)
pixWindowedVarianceOnLine()
Definition: pix5.c:2816
l_ok pixFractionFgInMask(PIX *pix1, PIX *pix2, l_float32 *pfract)
pixFractionFgInMask()
Definition: pix5.c:1674
l_ok pixFindAreaPerimRatio(PIX *pixs, l_int32 *tab, l_float32 *pfract)
pixFindAreaPerimRatio()
Definition: pix5.c:188
NUMA * pixAverageIntensityProfile(PIX *pixs, l_float32 fract, l_int32 dir, l_int32 first, l_int32 last, l_int32 factor1, l_int32 factor2)
pixAverageIntensityProfile()
Definition: pix5.c:2596
l_ok pixFindPerimToAreaRatio(PIX *pixs, l_int32 *tab, l_float32 *pfract)
pixFindPerimToAreaRatio()
Definition: pix5.c:285
NUMA * pixaFindAreaFraction(PIXA *pixa)
pixaFindAreaFraction()
Definition: pix5.c:429
PIX * pixCropToSize(PIX *pixs, l_int32 w, l_int32 h)
pixCropToSize()
Definition: pix5.c:1227
NUMA * pixaFindPerimSizeRatio(PIXA *pixa)
pixaFindPerimSizeRatio()
Definition: pix5.c:337
PIX * pixMakeSymmetricMask(l_int32 w, l_int32 h, l_float32 hf, l_float32 vf, l_int32 type)
pixSelectComponentBySize()
Definition: pix5.c:1484
NUMA * pixaFindPerimToAreaRatio(PIXA *pixa)
pixaFindPerimToAreaRatio()
Definition: pix5.c:237
PIX * pixRankRowTransform(PIX *pixs)
pixRankRowTransform()
Definition: pix5.c:3055
l_ok pixFindPerimSizeRatio(PIX *pixs, l_int32 *tab, l_float32 *pratio)
pixFindPerimSizeRatio()
Definition: pix5.c:385
NUMA * pixaFindWidthHeightProduct(PIXA *pixa)
pixaFindWidthHeightProduct()
Definition: pix5.c:684
l_ok pixFindAreaFraction(PIX *pixs, l_int32 *tab, l_float32 *pfract)
pixFindAreaFraction()
Definition: pix5.c:470
l_ok pixScanForForeground(PIX *pixs, BOX *box, l_int32 scanflag, l_int32 *ploc)
pixScanForForeground()
Definition: pix5.c:1960
BOXA * pixFindRectangleComps(PIX *pixs, l_int32 dist, l_int32 minw, l_int32 minh)
pixFindRectangleComps()
Definition: pix5.c:787
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:994
l_ok pixClipBoxToEdges(PIX *pixs, BOX *boxs, l_int32 lowthresh, l_int32 highthresh, l_int32 maxwidth, l_int32 factor, PIX **ppixd, BOX **pboxd)
pixClipBoxToEdges()
Definition: pix5.c:2074
l_float32 pixAverageOnLine(PIX *pixs, l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2, l_int32 factor)
pixAverageOnLine()
Definition: pix5.c:2499
PIX * pixClipRectangleWithBorder(PIX *pixs, BOX *box, l_int32 maxbord, BOX **pboxn)
pixClipRectangleWithBorder()
Definition: pix5.c:1055
l_ok pixTestClipToForeground(PIX *pixs, l_int32 *pcanclip)
pixTestClipToForeground()
Definition: pix5.c:1826
PIX * pixRankColumnTransform(PIX *pixs)
pixRankColumnTransform()
Definition: pix5.c:3106
l_ok pixClipBoxToForeground(PIX *pixs, BOX *boxs, PIX **ppixd, BOX **pboxd)
pixClipBoxToForeground()
Definition: pix5.c:1896
l_ok pixFindAreaFractionMasked(PIX *pixs, BOX *box, PIX *pixm, l_int32 *tab, l_float32 *pfract)
pixFindAreaFractionMasked()
Definition: pix5.c:593
NUMA * pixExtractOnLine(PIX *pixs, l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2, l_int32 factor)
pixExtractOnLine()
Definition: pix5.c:2381
l_ok pixScanForEdge(PIX *pixs, BOX *box, l_int32 lowthresh, l_int32 highthresh, l_int32 maxwidth, l_int32 factor, l_int32 scanflag, l_int32 *ploc)
pixScanForEdge()
Definition: pix5.c:2202
l_ok pixMinMaxNearLine(PIX *pixs, l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2, l_int32 dist, l_int32 direction, NUMA **pnamin, NUMA **pnamax, l_float32 *pminave, l_float32 *pmaxave)
pixMinMaxNearLine()
Definition: pix5.c:2934
PIX * pixMakeCoveringOfRectangles(PIX *pixs, l_int32 maxiters)
pixMakeCoveringOfRectangles()
Definition: pix5.c:1603
NUMA * pixaFindWidthHeightRatio(PIXA *pixa)
pixaFindWidthHeightRatio()
Definition: pix5.c:650
l_ok pixClipToForeground(PIX *pixs, PIX **ppixd, BOX **pbox)
pixClipToForeground()
Definition: pix5.c:1728
l_ok pixaFindDimensions(PIXA *pixa, NUMA **pnaw, NUMA **pnah)
pixaFindDimensions()
Definition: pix5.c:140
l_ok pixConformsToRectangle(PIX *pixs, BOX *box, l_int32 dist, l_int32 *pconforms)
pixConformsToRectangle()
Definition: pix5.c:865
NUMA * pixaFindAreaFractionMasked(PIXA *pixa, PIX *pixm, l_int32 debug)
pixaFindAreaFractionMasked()
Definition: pix5.c:516
PIX * pixClipMasked(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_uint32 outval)
pixClipMasked()
Definition: pix5.c:1126
l_ok pixFindOverlapFraction(PIX *pixs1, PIX *pixs2, l_int32 x2, l_int32 y2, l_int32 *tab, l_float32 *pratio, l_int32 *pnoverlap)
pixFindOverlapFraction()
Definition: pix5.c:722
l_ok pixCropToMatch(PIX *pixs1, PIX *pixs2, PIX **ppixd1, PIX **ppixd2)
pixCropToMatch()
Definition: pix5.c:1186
NUMA * pixReversalProfile(PIX *pixs, l_float32 fract, l_int32 dir, l_int32 first, l_int32 last, l_int32 minreversal, l_int32 factor1, l_int32 factor2)
pixReversalProfile()
Definition: pix5.c:2709
PIXA * pixClipRectangles(PIX *pixs, BOXA *boxa)
pixClipRectangles()
Definition: pix5.c:930
PIX * pixMakeFrameMask(l_int32 w, l_int32 h, l_float32 hf1, l_float32 hf2, l_float32 vf1, l_float32 vf2)
pixMakeFrameMask()
Definition: pix5.c:1539
#define PIX_MASK
Definition: pix.h:451
@ L_SET_PIXELS
Definition: pix.h:565
@ L_HORIZONTAL_LINE
Definition: pix.h:806
@ L_OBLIQUE_LINE
Definition: pix.h:810
@ L_VERTICAL_LINE
Definition: pix.h:808
@ L_USE_INNER
Definition: pix.h:1030
@ L_USE_OUTER
Definition: pix.h:1031
@ L_SORT_BY_AREA
Definition: pix.h:537
@ L_SORT_BY_PERIMETER
Definition: pix.h:536
@ L_SORT_BY_WIDTH
Definition: pix.h:532
@ L_SORT_BY_HEIGHT
Definition: pix.h:533
@ L_SORT_BY_MAX_DIMENSION
Definition: pix.h:535
@ REMOVE_CMAP_TO_GRAYSCALE
Definition: pix.h:381
@ L_COPY
Definition: pix.h:505
@ L_CLONE
Definition: pix.h:506
@ L_NOCOPY
Definition: pix.h:503
@ L_INSERT
Definition: pix.h:504
#define PIX_PAINT
Definition: pix.h:450
@ L_SET_WHITE
Definition: pix.h:699
@ L_FROM_BOT
Definition: pix.h:830
@ L_FROM_LEFT
Definition: pix.h:827
@ L_SCAN_NEGATIVE
Definition: pix.h:831
@ L_SCAN_BOTH
Definition: pix.h:833
@ L_FROM_RIGHT
Definition: pix.h:828
@ L_SCAN_POSITIVE
Definition: pix.h:832
@ L_FROM_TOP
Definition: pix.h:829
#define PIX_SRC
Definition: pix.h:444
#define PIX_CLR
Definition: pix.h:447
@ L_SORT_DECREASING
Definition: pix.h:523
#define PIX_SET
Definition: pix.h:448
@ L_SELECT_BY_HEIGHT
Definition: pix.h:584
@ L_SELECT_BY_AREA
Definition: pix.h:587
@ L_SELECT_BY_PERIMETER
Definition: pix.h:588
@ L_SELECT_BY_WIDTH
Definition: pix.h:583
@ L_SELECT_BY_MAX_DIMENSION
Definition: pix.h:585
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:404
BOX * pixaGetBox(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetBox()
Definition: pixabasic.c:764
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:629
l_ok pixaAddBox(PIXA *pixa, BOX *box, l_int32 copyflag)
pixaAddBox()
Definition: pixabasic.c:540
l_ok pixaIsFull(PIXA *pixa, l_int32 *pfullpa, l_int32 *pfullba)
pixaIsFull()
Definition: pixabasic.c:993
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:647
PIXA * pixaSort(PIXA *pixas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex, l_int32 copyflag)
pixaSort()
Definition: pixafunc1.c:1438
PIX * pixaDisplay(PIXA *pixa, l_int32 w, l_int32 h)
pixaDisplay()
Definition: pixafunc2.c:191
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:324
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3055
l_ok ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:527
l_ok ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:328
l_ok ptaGetPt(PTA *pta, l_int32 index, l_float32 *px, l_float32 *py)
ptaGetPt()
Definition: ptabasic.c:499
l_int32 ptaGetCount(PTA *pta)
ptaGetCount()
Definition: ptabasic.c:480
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:120
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:191
l_ok pixPlotAlongPta(PIX *pixs, PTA *pta, l_int32 outformat, const char *title)
pixPlotAlongPta()
Definition: ptafunc1.c:1812
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
PIX * pixExtractBorderConnComps(PIX *pixs, l_int32 connectivity)
pixExtractBorderConnComps()
Definition: seedfill.c:688
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306