Leptonica  1.73
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 
96 #include <string.h>
97 #include <math.h>
98 #include "allheaders.h"
99 
100 static const l_uint32 rmask32[] = {0x0,
101  0x00000001, 0x00000003, 0x00000007, 0x0000000f,
102  0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
103  0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
104  0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
105  0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
106  0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
107  0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
108  0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
109 
110 #ifndef NO_CONSOLE_IO
111 #define DEBUG_EDGES 0
112 #endif /* ~NO_CONSOLE_IO */
113 
114 
115 /*-------------------------------------------------------------*
116  * Measurement of properties *
117  *-------------------------------------------------------------*/
126 l_int32
128  NUMA **pnaw,
129  NUMA **pnah)
130 {
131 l_int32 i, n, w, h;
132 PIX *pixt;
133 
134  PROCNAME("pixaFindDimensions");
135 
136  if (pnaw) *pnaw = NULL;
137  if (pnah) *pnah = NULL;
138  if (!pnaw && !pnah)
139  return ERROR_INT("no output requested", procName, 1);
140  if (!pixa)
141  return ERROR_INT("pixa not defined", procName, 1);
142 
143  n = pixaGetCount(pixa);
144  if (pnaw) *pnaw = numaCreate(n);
145  if (pnah) *pnah = numaCreate(n);
146  for (i = 0; i < n; i++) {
147  pixt = pixaGetPix(pixa, i, L_CLONE);
148  pixGetDimensions(pixt, &w, &h, NULL);
149  if (pnaw)
150  numaAddNumber(*pnaw, w);
151  if (pnah)
152  numaAddNumber(*pnah, h);
153  pixDestroy(&pixt);
154  }
155  return 0;
156 }
157 
158 
176 l_int32
178  l_int32 *tab,
179  l_float32 *pfract)
180 {
181 l_int32 *tab8;
182 l_int32 nfg, nbound;
183 PIX *pixt;
184 
185  PROCNAME("pixFindAreaPerimRatio");
186 
187  if (!pfract)
188  return ERROR_INT("&fract not defined", procName, 1);
189  *pfract = 0.0;
190  if (!pixs || pixGetDepth(pixs) != 1)
191  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
192 
193  if (!tab)
194  tab8 = makePixelSumTab8();
195  else
196  tab8 = tab;
197 
198  pixt = pixErodeBrick(NULL, pixs, 3, 3);
199  pixCountPixels(pixt, &nfg, tab8);
200  if (nfg == 0) {
201  pixDestroy(&pixt);
202  if (!tab) LEPT_FREE(tab8);
203  return 0;
204  }
205  pixXor(pixt, pixt, pixs);
206  pixCountPixels(pixt, &nbound, tab8);
207  *pfract = (l_float32)nfg / (l_float32)nbound;
208  pixDestroy(&pixt);
209 
210  if (!tab) LEPT_FREE(tab8);
211  return 0;
212 }
213 
214 
227 NUMA *
229 {
230 l_int32 i, n;
231 l_int32 *tab;
232 l_float32 fract;
233 NUMA *na;
234 PIX *pixt;
235 
236  PROCNAME("pixaFindPerimToAreaRatio");
237 
238  if (!pixa)
239  return (NUMA *)ERROR_PTR("pixa not defined", procName, NULL);
240 
241  n = pixaGetCount(pixa);
242  na = numaCreate(n);
243  tab = makePixelSumTab8();
244  for (i = 0; i < n; i++) {
245  pixt = pixaGetPix(pixa, i, L_CLONE);
246  pixFindPerimToAreaRatio(pixt, tab, &fract);
247  numaAddNumber(na, fract);
248  pixDestroy(&pixt);
249  }
250  LEPT_FREE(tab);
251  return na;
252 }
253 
254 
277 l_int32
279  l_int32 *tab,
280  l_float32 *pfract)
281 {
282 l_int32 *tab8;
283 l_int32 nfg, nbound;
284 PIX *pixt;
285 
286  PROCNAME("pixFindPerimToAreaRatio");
287 
288  if (!pfract)
289  return ERROR_INT("&fract not defined", procName, 1);
290  *pfract = 0.0;
291  if (!pixs || pixGetDepth(pixs) != 1)
292  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
293 
294  if (!tab)
295  tab8 = makePixelSumTab8();
296  else
297  tab8 = tab;
298 
299  pixCountPixels(pixs, &nfg, tab8);
300  if (nfg == 0) {
301  if (!tab) LEPT_FREE(tab8);
302  return 0;
303  }
304  pixt = pixErodeBrick(NULL, pixs, 3, 3);
305  pixXor(pixt, pixt, pixs);
306  pixCountPixels(pixt, &nbound, tab8);
307  *pfract = (l_float32)nbound / (l_float32)nfg;
308  pixDestroy(&pixt);
309 
310  if (!tab) LEPT_FREE(tab8);
311  return 0;
312 }
313 
314 
331 NUMA *
333 {
334 l_int32 i, n;
335 l_int32 *tab;
336 l_float32 ratio;
337 NUMA *na;
338 PIX *pixt;
339 
340  PROCNAME("pixaFindPerimSizeRatio");
341 
342  if (!pixa)
343  return (NUMA *)ERROR_PTR("pixa not defined", procName, NULL);
344 
345  n = pixaGetCount(pixa);
346  na = numaCreate(n);
347  tab = makePixelSumTab8();
348  for (i = 0; i < n; i++) {
349  pixt = pixaGetPix(pixa, i, L_CLONE);
350  pixFindPerimSizeRatio(pixt, tab, &ratio);
351  numaAddNumber(na, ratio);
352  pixDestroy(&pixt);
353  }
354  LEPT_FREE(tab);
355  return na;
356 }
357 
358 
381 l_int32
383  l_int32 *tab,
384  l_float32 *pratio)
385 {
386 l_int32 *tab8;
387 l_int32 w, h, nbound;
388 PIX *pixt;
389 
390  PROCNAME("pixFindPerimSizeRatio");
391 
392  if (!pratio)
393  return ERROR_INT("&ratio not defined", procName, 1);
394  *pratio = 0.0;
395  if (!pixs || pixGetDepth(pixs) != 1)
396  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
397 
398  if (!tab)
399  tab8 = makePixelSumTab8();
400  else
401  tab8 = tab;
402 
403  pixt = pixErodeBrick(NULL, pixs, 3, 3);
404  pixXor(pixt, pixt, pixs);
405  pixCountPixels(pixt, &nbound, tab8);
406  pixGetDimensions(pixs, &w, &h, NULL);
407  *pratio = (0.5 * nbound) / (l_float32)(w + h);
408  pixDestroy(&pixt);
409 
410  if (!tab) LEPT_FREE(tab8);
411  return 0;
412 }
413 
414 
427 NUMA *
429 {
430 l_int32 i, n;
431 l_int32 *tab;
432 l_float32 fract;
433 NUMA *na;
434 PIX *pixt;
435 
436  PROCNAME("pixaFindAreaFraction");
437 
438  if (!pixa)
439  return (NUMA *)ERROR_PTR("pixa not defined", procName, NULL);
440 
441  n = pixaGetCount(pixa);
442  na = numaCreate(n);
443  tab = makePixelSumTab8();
444  for (i = 0; i < n; i++) {
445  pixt = pixaGetPix(pixa, i, L_CLONE);
446  pixFindAreaFraction(pixt, tab, &fract);
447  numaAddNumber(na, fract);
448  pixDestroy(&pixt);
449  }
450  LEPT_FREE(tab);
451  return na;
452 }
453 
454 
470 l_int32
472  l_int32 *tab,
473  l_float32 *pfract)
474 {
475 l_int32 w, h, sum;
476 l_int32 *tab8;
477 
478  PROCNAME("pixFindAreaFraction");
479 
480  if (!pfract)
481  return ERROR_INT("&fract not defined", procName, 1);
482  *pfract = 0.0;
483  if (!pixs || pixGetDepth(pixs) != 1)
484  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
485 
486  if (!tab)
487  tab8 = makePixelSumTab8();
488  else
489  tab8 = tab;
490  pixGetDimensions(pixs, &w, &h, NULL);
491  pixCountPixels(pixs, &sum, tab8);
492  *pfract = (l_float32)sum / (l_float32)(w * h);
493 
494  if (!tab) LEPT_FREE(tab8);
495  return 0;
496 }
497 
498 
518 NUMA *
520  PIX *pixm,
521  l_int32 debug)
522 {
523 l_int32 i, n, full;
524 l_int32 *tab;
525 l_float32 fract;
526 BOX *box;
527 NUMA *na;
528 PIX *pix;
529 
530  PROCNAME("pixaFindAreaFractionMasked");
531 
532  if (!pixa)
533  return (NUMA *)ERROR_PTR("pixa not defined", procName, NULL);
534  if (!pixm || pixGetDepth(pixm) != 1)
535  return (NUMA *)ERROR_PTR("pixm undefined or not 1 bpp", procName, NULL);
536 
537  n = pixaGetCount(pixa);
538  na = numaCreate(n);
539  tab = makePixelSumTab8();
540  pixaIsFull(pixa, NULL, &full); /* check boxa */
541  box = NULL;
542  for (i = 0; i < n; i++) {
543  pix = pixaGetPix(pixa, i, L_CLONE);
544  if (full)
545  box = pixaGetBox(pixa, i, L_CLONE);
546  pixFindAreaFractionMasked(pix, box, pixm, tab, &fract);
547  numaAddNumber(na, fract);
548  boxDestroy(&box);
549  pixDestroy(&pix);
550  }
551  LEPT_FREE(tab);
552 
553  if (debug) {
554  l_int32 w, h;
555  PIX *pix1, *pix2;
556  pixGetDimensions(pixm, &w, &h, NULL);
557  pix1 = pixaDisplay(pixa, w, h); /* recover original image */
558  pix2 = pixCreate(w, h, 8); /* make an 8 bpp white image ... */
559  pixSetColormap(pix2, pixcmapCreate(8)); /* that's cmapped ... */
560  pixSetBlackOrWhite(pix2, L_SET_WHITE); /* and init to white */
561  pixSetMaskedCmap(pix2, pix1, 0, 0, 255, 0, 0); /* color all fg red */
562  pixRasterop(pix1, 0, 0, w, h, PIX_MASK, pixm, 0, 0);
563  pixSetMaskedCmap(pix2, pix1, 0, 0, 0, 255, 0); /* turn masked green */
564  pixDisplay(pix2, 100, 100);
565  pixDestroy(&pix1);
566  pixDestroy(&pix2);
567  }
568 
569  return na;
570 }
571 
572 
597 l_int32
599  BOX *box,
600  PIX *pixm,
601  l_int32 *tab,
602  l_float32 *pfract)
603 {
604 l_int32 x, y, w, h, sum, masksum;
605 l_int32 *tab8;
606 PIX *pix1;
607 
608  PROCNAME("pixFindAreaFractionMasked");
609 
610  if (!pfract)
611  return ERROR_INT("&fract not defined", procName, 1);
612  *pfract = 0.0;
613  if (!pixs || pixGetDepth(pixs) != 1)
614  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
615  if (!pixm || pixGetDepth(pixm) != 1)
616  return ERROR_INT("pixm not defined or not 1 bpp", procName, 1);
617 
618  if (!tab)
619  tab8 = makePixelSumTab8();
620  else
621  tab8 = tab;
622  x = y = 0;
623  if (box)
624  boxGetGeometry(box, &x, &y, NULL, NULL);
625  pixGetDimensions(pixs, &w, &h, NULL);
626 
627  pix1 = pixCopy(NULL, pixs);
628  pixRasterop(pix1, 0, 0, w, h, PIX_MASK, pixm, x, y);
629  pixCountPixels(pixs, &sum, tab8);
630  if (sum == 0) {
631  pixDestroy(&pix1);
632  if (!tab) LEPT_FREE(tab8);
633  return 0;
634  }
635  pixCountPixels(pix1, &masksum, tab8);
636  *pfract = (l_float32)masksum / (l_float32)sum;
637 
638  if (!tab) LEPT_FREE(tab8);
639  pixDestroy(&pix1);
640  return 0;
641 }
642 
643 
656 NUMA *
658 {
659 l_int32 i, n, w, h;
660 NUMA *na;
661 PIX *pixt;
662 
663  PROCNAME("pixaFindWidthHeightRatio");
664 
665  if (!pixa)
666  return (NUMA *)ERROR_PTR("pixa not defined", procName, NULL);
667 
668  n = pixaGetCount(pixa);
669  na = numaCreate(n);
670  for (i = 0; i < n; i++) {
671  pixt = pixaGetPix(pixa, i, L_CLONE);
672  pixGetDimensions(pixt, &w, &h, NULL);
673  numaAddNumber(na, (l_float32)w / (l_float32)h);
674  pixDestroy(&pixt);
675  }
676  return na;
677 }
678 
679 
692 NUMA *
694 {
695 l_int32 i, n, w, h;
696 NUMA *na;
697 PIX *pixt;
698 
699  PROCNAME("pixaFindWidthHeightProduct");
700 
701  if (!pixa)
702  return (NUMA *)ERROR_PTR("pixa not defined", procName, NULL);
703 
704  n = pixaGetCount(pixa);
705  na = numaCreate(n);
706  for (i = 0; i < n; i++) {
707  pixt = pixaGetPix(pixa, i, L_CLONE);
708  pixGetDimensions(pixt, &w, &h, NULL);
709  numaAddNumber(na, w * h);
710  pixDestroy(&pixt);
711  }
712  return na;
713 }
714 
715 
732 l_int32
734  PIX *pixs2,
735  l_int32 x2,
736  l_int32 y2,
737  l_int32 *tab,
738  l_float32 *pratio,
739  l_int32 *pnoverlap)
740 {
741 l_int32 *tab8;
742 l_int32 w, h, nintersect, nunion;
743 PIX *pixt;
744 
745  PROCNAME("pixFindOverlapFraction");
746 
747  if (pnoverlap) *pnoverlap = 0;
748  if (!pratio)
749  return ERROR_INT("&ratio not defined", procName, 1);
750  *pratio = 0.0;
751  if (!pixs1 || pixGetDepth(pixs1) != 1)
752  return ERROR_INT("pixs1 not defined or not 1 bpp", procName, 1);
753  if (!pixs2 || pixGetDepth(pixs2) != 1)
754  return ERROR_INT("pixs2 not defined or not 1 bpp", procName, 1);
755 
756  if (!tab)
757  tab8 = makePixelSumTab8();
758  else
759  tab8 = tab;
760 
761  pixGetDimensions(pixs2, &w, &h, NULL);
762  pixt = pixCopy(NULL, pixs1);
763  pixRasterop(pixt, x2, y2, w, h, PIX_MASK, pixs2, 0, 0); /* AND */
764  pixCountPixels(pixt, &nintersect, tab8);
765  if (pnoverlap)
766  *pnoverlap = nintersect;
767  pixCopy(pixt, pixs1);
768  pixRasterop(pixt, x2, y2, w, h, PIX_PAINT, pixs2, 0, 0); /* OR */
769  pixCountPixels(pixt, &nunion, tab8);
770  if (!tab) LEPT_FREE(tab8);
771  pixDestroy(&pixt);
772 
773  if (nunion > 0)
774  *pratio = (l_float32)nintersect / (l_float32)nunion;
775  return 0;
776 }
777 
778 
799 BOXA *
801  l_int32 dist,
802  l_int32 minw,
803  l_int32 minh)
804 {
805 l_int32 w, h, i, n, conforms;
806 BOX *box;
807 BOXA *boxa, *boxad;
808 PIX *pix;
809 PIXA *pixa;
810 
811  PROCNAME("pixFindRectangleComps");
812 
813  if (!pixs || pixGetDepth(pixs) != 1)
814  return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
815  if (dist < 0)
816  return (BOXA *)ERROR_PTR("dist must be >= 0", procName, NULL);
817  if (minw <= 2 * dist && minh <= 2 * dist)
818  return (BOXA *)ERROR_PTR("invalid parameters", procName, NULL);
819 
820  boxa = pixConnComp(pixs, &pixa, 8);
821  boxad = boxaCreate(0);
822  n = pixaGetCount(pixa);
823  for (i = 0; i < n; i++) {
824  pix = pixaGetPix(pixa, i, L_CLONE);
825  pixGetDimensions(pix, &w, &h, NULL);
826  if (w < minw || h < minh) {
827  pixDestroy(&pix);
828  continue;
829  }
830  pixConformsToRectangle(pix, NULL, dist, &conforms);
831  if (conforms) {
832  box = boxaGetBox(boxa, i, L_COPY);
833  boxaAddBox(boxad, box, L_INSERT);
834  }
835  pixDestroy(&pix);
836  }
837  boxaDestroy(&boxa);
838  pixaDestroy(&pixa);
839  return boxad;
840 }
841 
842 
879 l_int32
881  BOX *box,
882  l_int32 dist,
883  l_int32 *pconforms)
884 {
885 l_int32 w, h, empty;
886 PIX *pix1, *pix2;
887 
888  PROCNAME("pixConformsToRectangle");
889 
890  if (!pconforms)
891  return ERROR_INT("&conforms not defined", procName, 1);
892  *pconforms = 0;
893  if (!pixs || pixGetDepth(pixs) != 1)
894  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
895  if (dist < 0)
896  return ERROR_INT("dist must be >= 0", procName, 1);
897  pixGetDimensions(pixs, &w, &h, NULL);
898  if (w <= 2 * dist || h <= 2 * dist) {
899  L_WARNING("automatic conformation: distance too large\n", procName);
900  *pconforms = 1;
901  return 0;
902  }
903 
904  /* Extract the region, if necessary */
905  if (box)
906  pix1 = pixClipRectangle(pixs, box, NULL);
907  else
908  pix1 = pixCopy(NULL, pixs);
909 
910  /* Invert and fill from the boundary into the interior.
911  * Because we're considering the connected component in an
912  * 8-connected sense, we do the background filling as 4 c.c. */
913  pixInvert(pix1, pix1);
914  pix2 = pixExtractBorderConnComps(pix1, 4);
915 
916  /* Mask out all pixels within a distance %dist from the box
917  * boundary. Any remaining pixels are from filling that goes
918  * more than %dist from the boundary. If no pixels remain,
919  * the component conforms to the bounding rectangle within
920  * a distance %dist. */
921  pixSetOrClearBorder(pix2, dist, dist, dist, dist, PIX_CLR);
922  pixZero(pix2, &empty);
923  pixDestroy(&pix1);
924  pixDestroy(&pix2);
925  *pconforms = (empty) ? 1 : 0;
926  return 0;
927 }
928 
929 
930 /*-----------------------------------------------------------------------*
931  * Extract rectangular region *
932  *-----------------------------------------------------------------------*/
946 PIXA *
948  BOXA *boxa)
949 {
950 l_int32 i, n;
951 BOX *box, *boxc;
952 PIX *pix;
953 PIXA *pixa;
954 
955  PROCNAME("pixClipRectangles");
956 
957  if (!pixs)
958  return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL);
959  if (!boxa)
960  return (PIXA *)ERROR_PTR("boxa not defined", procName, NULL);
961 
962  n = boxaGetCount(boxa);
963  pixa = pixaCreate(n);
964  for (i = 0; i < n; i++) {
965  box = boxaGetBox(boxa, i, L_CLONE);
966  pix = pixClipRectangle(pixs, box, &boxc);
967  pixaAddPix(pixa, pix, L_INSERT);
968  pixaAddBox(pixa, boxc, L_INSERT);
969  boxDestroy(&box);
970  }
971 
972  return pixa;
973 }
974 
975 
1012 PIX *
1014  BOX *box,
1015  BOX **pboxc)
1016 {
1017 l_int32 w, h, d, bx, by, bw, bh;
1018 BOX *boxc;
1019 PIX *pixd;
1020 
1021  PROCNAME("pixClipRectangle");
1022 
1023  if (pboxc) *pboxc = NULL;
1024  if (!pixs)
1025  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1026  if (!box)
1027  return (PIX *)ERROR_PTR("box not defined", procName, NULL);
1028 
1029  /* Clip the input box to the pix */
1030  pixGetDimensions(pixs, &w, &h, &d);
1031  if ((boxc = boxClipToRectangle(box, w, h)) == NULL) {
1032  L_WARNING("box doesn't overlap pix\n", procName);
1033  return NULL;
1034  }
1035  boxGetGeometry(boxc, &bx, &by, &bw, &bh);
1036 
1037  /* Extract the block */
1038  if ((pixd = pixCreate(bw, bh, d)) == NULL) {
1039  boxDestroy(&boxc);
1040  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1041  }
1042  pixCopyResolution(pixd, pixs);
1043  pixCopyColormap(pixd, pixs);
1044  pixCopyText(pixd, pixs);
1045  pixRasterop(pixd, 0, 0, bw, bh, PIX_SRC, pixs, bx, by);
1046 
1047  if (pboxc)
1048  *pboxc = boxc;
1049  else
1050  boxDestroy(&boxc);
1051 
1052  return pixd;
1053 }
1054 
1055 
1085 PIX *
1087  PIX *pixm,
1088  l_int32 x,
1089  l_int32 y,
1090  l_uint32 outval)
1091 {
1092 l_int32 wm, hm, index, rval, gval, bval;
1093 l_uint32 pixel;
1094 BOX *box;
1095 PIX *pixmi, *pixd;
1096 PIXCMAP *cmap;
1097 
1098  PROCNAME("pixClipMasked");
1099 
1100  if (!pixs)
1101  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1102  if (!pixm || pixGetDepth(pixm) != 1)
1103  return (PIX *)ERROR_PTR("pixm undefined or not 1 bpp", procName, NULL);
1104 
1105  /* Clip out the region specified by pixm and (x,y) */
1106  pixGetDimensions(pixm, &wm, &hm, NULL);
1107  box = boxCreate(x, y, wm, hm);
1108  pixd = pixClipRectangle(pixs, box, NULL);
1109 
1110  /* Paint 'outval' (or something close to it if cmapped) through
1111  * the pixels not masked by pixm */
1112  cmap = pixGetColormap(pixd);
1113  pixmi = pixInvert(NULL, pixm);
1114  if (cmap) {
1115  extractRGBValues(outval, &rval, &gval, &bval);
1116  pixcmapGetNearestIndex(cmap, rval, gval, bval, &index);
1117  pixcmapGetColor(cmap, index, &rval, &gval, &bval);
1118  composeRGBPixel(rval, gval, bval, &pixel);
1119  pixPaintThroughMask(pixd, pixmi, 0, 0, pixel);
1120  } else {
1121  pixPaintThroughMask(pixd, pixmi, 0, 0, outval);
1122  }
1123 
1124  boxDestroy(&box);
1125  pixDestroy(&pixmi);
1126  return pixd;
1127 }
1128 
1129 
1147 l_int32
1149  PIX *pixs2,
1150  PIX **ppixd1,
1151  PIX **ppixd2)
1152 {
1153 l_int32 w1, h1, w2, h2, w, h;
1154 
1155  PROCNAME("pixCropToMatch");
1156 
1157  if (!ppixd1 || !ppixd2)
1158  return ERROR_INT("&pixd1 and &pixd2 not both defined", procName, 1);
1159  *ppixd1 = *ppixd2 = NULL;
1160  if (!pixs1 || !pixs2)
1161  return ERROR_INT("pixs1 and pixs2 not defined", procName, 1);
1162 
1163  pixGetDimensions(pixs1, &w1, &h1, NULL);
1164  pixGetDimensions(pixs2, &w2, &h2, NULL);
1165  w = L_MIN(w1, w2);
1166  h = L_MIN(h1, h2);
1167 
1168  *ppixd1 = pixCropToSize(pixs1, w, h);
1169  *ppixd2 = pixCropToSize(pixs2, w, h);
1170  if (*ppixd1 == NULL || *ppixd2 == NULL)
1171  return ERROR_INT("cropped image failure", procName, 1);
1172  return 0;
1173 }
1174 
1175 
1190 PIX *
1192  l_int32 w,
1193  l_int32 h)
1194 {
1195 l_int32 ws, hs, wd, hd, d;
1196 PIX *pixd;
1197 
1198  PROCNAME("pixCropToSize");
1199 
1200  if (!pixs)
1201  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1202 
1203  pixGetDimensions(pixs, &ws, &hs, &d);
1204  if (ws <= w && hs <= h) /* no cropping necessary */
1205  return pixClone(pixs);
1206 
1207  wd = L_MIN(ws, w);
1208  hd = L_MIN(hs, h);
1209  if ((pixd = pixCreate(wd, hd, d)) == NULL)
1210  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1211  pixCopyResolution(pixd, pixs);
1212  pixCopyColormap(pixd, pixs);
1213  pixCopyText(pixd, pixs);
1214  pixCopyInputFormat(pixd, pixs);
1215  pixRasterop(pixd, 0, 0, wd, hd, PIX_SRC, pixs, 0, 0);
1216  return pixd;
1217 }
1218 
1219 
1244 PIX *
1246  PIX *pixt,
1247  l_int32 w,
1248  l_int32 h)
1249 {
1250 l_int32 i, j, ws, hs, d;
1251 PIX *pixd;
1252 
1253  PROCNAME("pixResizeToMatch");
1254 
1255  if (!pixs)
1256  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1257  if (!pixt && (w <= 0 || h <= 0))
1258  return (PIX *)ERROR_PTR("both w and h not > 0", procName, NULL);
1259 
1260  if (pixt) /* redefine w, h */
1261  pixGetDimensions(pixt, &w, &h, NULL);
1262  pixGetDimensions(pixs, &ws, &hs, &d);
1263  if (ws == w && hs == h)
1264  return pixCopy(NULL, pixs);
1265 
1266  if ((pixd = pixCreate(w, h, d)) == NULL)
1267  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1268  pixCopyResolution(pixd, pixs);
1269  pixCopyColormap(pixd, pixs);
1270  pixCopyText(pixd, pixs);
1271  pixCopyInputFormat(pixd, pixs);
1272  pixRasterop(pixd, 0, 0, ws, hs, PIX_SRC, pixs, 0, 0);
1273  if (ws >= w && hs >= h)
1274  return pixd;
1275 
1276  /* Replicate the last column and then the last row */
1277  if (ws < w) {
1278  for (j = ws; j < w; j++)
1279  pixRasterop(pixd, j, 0, 1, h, PIX_SRC, pixd, ws - 1, 0);
1280  }
1281  if (hs < h) {
1282  for (i = hs; i < h; i++)
1283  pixRasterop(pixd, 0, i, w, 1, PIX_SRC, pixd, 0, hs - 1);
1284  }
1285 
1286  return pixd;
1287 }
1288 
1289 
1290 /*---------------------------------------------------------------------*
1291  * Make a frame mask *
1292  *---------------------------------------------------------------------*/
1325 PIX *
1327  l_int32 h,
1328  l_float32 hf1,
1329  l_float32 hf2,
1330  l_float32 vf1,
1331  l_float32 vf2)
1332 {
1333 l_int32 h1, h2, v1, v2;
1334 PIX *pixd;
1335 
1336  PROCNAME("pixMakeFrameMask");
1337 
1338  if (w <= 0 || h <= 0)
1339  return (PIX *)ERROR_PTR("mask size 0", procName, NULL);
1340  if (hf1 < 0.0 || hf1 > 1.0 || hf2 < 0.0 || hf2 > 1.0)
1341  return (PIX *)ERROR_PTR("invalid horiz fractions", procName, NULL);
1342  if (vf1 < 0.0 || vf1 > 1.0 || vf2 < 0.0 || vf2 > 1.0)
1343  return (PIX *)ERROR_PTR("invalid vert fractions", procName, NULL);
1344  if (hf1 > hf2 || vf1 > vf2)
1345  return (PIX *)ERROR_PTR("invalid relative sizes", procName, NULL);
1346 
1347  pixd = pixCreate(w, h, 1);
1348 
1349  /* Special cases */
1350  if (hf1 == 0.0 && vf1 == 0.0 && hf2 == 1.0 && vf2 == 1.0) { /* full */
1351  pixSetAll(pixd);
1352  return pixd;
1353  }
1354  if (hf1 == hf2 && vf1 == vf2) { /* empty */
1355  return pixd;
1356  }
1357 
1358  /* General case */
1359  h1 = 0.5 * hf1 * w;
1360  h2 = 0.5 * hf2 * w;
1361  v1 = 0.5 * vf1 * h;
1362  v2 = 0.5 * vf2 * h;
1363  pixRasterop(pixd, h1, v1, w - 2 * h1, h - 2 * v1, PIX_SET, NULL, 0, 0);
1364  if (hf2 < 1.0 && vf2 < 1.0)
1365  pixRasterop(pixd, h2, v2, w - 2 * h2, h - 2 * v2, PIX_CLR, NULL, 0, 0);
1366  return pixd;
1367 }
1368 
1369 
1370 /*---------------------------------------------------------------------*
1371  * Fraction of Fg pixels under a mask *
1372  *---------------------------------------------------------------------*/
1398 l_int32
1400  PIX *pix2,
1401  l_float32 *pfract)
1402 {
1403 l_int32 w1, h1, w2, h2, empty, count1, count3;
1404 PIX *pix3;
1405 
1406  PROCNAME("pixFractionFgInMask");
1407 
1408  if (!pfract)
1409  return ERROR_INT("&fract not defined", procName, 1);
1410  *pfract = 0.0;
1411  if (!pix1 || pixGetDepth(pix1) != 1)
1412  return ERROR_INT("pix1 not defined or not 1 bpp", procName, 1);
1413  if (!pix2 || pixGetDepth(pix2) != 1)
1414  return ERROR_INT("pix2 not defined or not 1 bpp", procName, 1);
1415 
1416  pixGetDimensions(pix1, &w1, &h1, NULL);
1417  pixGetDimensions(pix2, &w2, &h2, NULL);
1418  if (w1 != w2 || h1 != h2) {
1419  L_INFO("sizes unequal: (w1,w2) = (%d,%d), (h1,h2) = (%d,%d)\n",
1420  procName, w1, w2, h1, h2);
1421  }
1422  pixZero(pix1, &empty);
1423  if (empty) return 0;
1424  pixZero(pix2, &empty);
1425  if (empty) return 0;
1426 
1427  pix3 = pixCopy(NULL, pix1);
1428  pixAnd(pix3, pix3, pix2);
1429  pixCountPixels(pix1, &count1, NULL); /* |1| */
1430  pixCountPixels(pix3, &count3, NULL); /* |1 & 2| */
1431  *pfract = (l_float32)count3 / (l_float32)count1;
1432  pixDestroy(&pix3);
1433  return 0;
1434 }
1435 
1436 
1437 /*---------------------------------------------------------------------*
1438  * Clip to Foreground *
1439  *---------------------------------------------------------------------*/
1454 l_int32
1456  PIX **ppixd,
1457  BOX **pbox)
1458 {
1459 l_int32 w, h, wpl, nfullwords, extra, i, j;
1460 l_int32 minx, miny, maxx, maxy;
1461 l_uint32 result, mask;
1462 l_uint32 *data, *line;
1463 BOX *box;
1464 
1465  PROCNAME("pixClipToForeground");
1466 
1467  if (ppixd) *ppixd = NULL;
1468  if (pbox) *pbox = NULL;
1469  if (!ppixd && !pbox)
1470  return ERROR_INT("no output requested", procName, 1);
1471  if (!pixs || (pixGetDepth(pixs) != 1))
1472  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
1473 
1474  pixGetDimensions(pixs, &w, &h, NULL);
1475  nfullwords = w / 32;
1476  extra = w & 31;
1477  mask = ~rmask32[32 - extra];
1478  wpl = pixGetWpl(pixs);
1479  data = pixGetData(pixs);
1480 
1481  result = 0;
1482  for (i = 0, miny = 0; i < h; i++, miny++) {
1483  line = data + i * wpl;
1484  for (j = 0; j < nfullwords; j++)
1485  result |= line[j];
1486  if (extra)
1487  result |= (line[j] & mask);
1488  if (result)
1489  break;
1490  }
1491  if (miny == h) /* no ON pixels */
1492  return 1;
1493 
1494  result = 0;
1495  for (i = h - 1, maxy = h - 1; i >= 0; i--, maxy--) {
1496  line = data + i * wpl;
1497  for (j = 0; j < nfullwords; j++)
1498  result |= line[j];
1499  if (extra)
1500  result |= (line[j] & mask);
1501  if (result)
1502  break;
1503  }
1504 
1505  minx = 0;
1506  for (j = 0, minx = 0; j < w; j++, minx++) {
1507  for (i = 0; i < h; i++) {
1508  line = data + i * wpl;
1509  if (GET_DATA_BIT(line, j))
1510  goto minx_found;
1511  }
1512  }
1513 
1514 minx_found:
1515  for (j = w - 1, maxx = w - 1; j >= 0; j--, maxx--) {
1516  for (i = 0; i < h; i++) {
1517  line = data + i * wpl;
1518  if (GET_DATA_BIT(line, j))
1519  goto maxx_found;
1520  }
1521  }
1522 
1523 maxx_found:
1524  box = boxCreate(minx, miny, maxx - minx + 1, maxy - miny + 1);
1525 
1526  if (ppixd)
1527  *ppixd = pixClipRectangle(pixs, box, NULL);
1528  if (pbox)
1529  *pbox = box;
1530  else
1531  boxDestroy(&box);
1532 
1533  return 0;
1534 }
1535 
1536 
1554 l_int32
1556  l_int32 *pcanclip)
1557 {
1558 l_int32 i, j, w, h, wpl, found;
1559 l_uint32 *data, *line;
1560 
1561  PROCNAME("pixTestClipToForeground");
1562 
1563  if (!pcanclip)
1564  return ERROR_INT("&canclip not defined", procName, 1);
1565  *pcanclip = 0;
1566  if (!pixs || (pixGetDepth(pixs) != 1))
1567  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
1568 
1569  /* Check top and bottom raster lines */
1570  pixGetDimensions(pixs, &w, &h, NULL);
1571  data = pixGetData(pixs);
1572  wpl = pixGetWpl(pixs);
1573  found = FALSE;
1574  for (j = 0; found == FALSE && j < w; j++)
1575  found = GET_DATA_BIT(data, j);
1576  if (!found) {
1577  *pcanclip = 1;
1578  return 0;
1579  }
1580 
1581  line = data + (h - 1) * wpl;
1582  found = FALSE;
1583  for (j = 0; found == FALSE && j < w; j++)
1584  found = GET_DATA_BIT(data, j);
1585  if (!found) {
1586  *pcanclip = 1;
1587  return 0;
1588  }
1589 
1590  /* Check left and right edges */
1591  found = FALSE;
1592  for (i = 0, line = data; found == FALSE && i < h; line += wpl, i++)
1593  found = GET_DATA_BIT(line, 0);
1594  if (!found) {
1595  *pcanclip = 1;
1596  return 0;
1597  }
1598 
1599  found = FALSE;
1600  for (i = 0, line = data; found == FALSE && i < h; line += wpl, i++)
1601  found = GET_DATA_BIT(line, w - 1);
1602  if (!found)
1603  *pcanclip = 1;
1604 
1605  return 0; /* fg pixels found on all edges */
1606 }
1607 
1608 
1626 l_int32
1628  BOX *boxs,
1629  PIX **ppixd,
1630  BOX **pboxd)
1631 {
1632 l_int32 w, h, bx, by, bw, bh, cbw, cbh, left, right, top, bottom;
1633 BOX *boxt, *boxd;
1634 
1635  PROCNAME("pixClipBoxToForeground");
1636 
1637  if (ppixd) *ppixd = NULL;
1638  if (pboxd) *pboxd = NULL;
1639  if (!ppixd && !pboxd)
1640  return ERROR_INT("no output requested", procName, 1);
1641  if (!pixs || (pixGetDepth(pixs) != 1))
1642  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
1643 
1644  if (!boxs)
1645  return pixClipToForeground(pixs, ppixd, pboxd);
1646 
1647  pixGetDimensions(pixs, &w, &h, NULL);
1648  boxGetGeometry(boxs, &bx, &by, &bw, &bh);
1649  cbw = L_MIN(bw, w - bx);
1650  cbh = L_MIN(bh, h - by);
1651  if (cbw < 0 || cbh < 0)
1652  return ERROR_INT("box not within image", procName, 1);
1653  boxt = boxCreate(bx, by, cbw, cbh);
1654 
1655  if (pixScanForForeground(pixs, boxt, L_FROM_LEFT, &left)) {
1656  boxDestroy(&boxt);
1657  return 1;
1658  }
1659  pixScanForForeground(pixs, boxt, L_FROM_RIGHT, &right);
1660  pixScanForForeground(pixs, boxt, L_FROM_TOP, &top);
1661  pixScanForForeground(pixs, boxt, L_FROM_BOT, &bottom);
1662 
1663  boxd = boxCreate(left, top, right - left + 1, bottom - top + 1);
1664  if (ppixd)
1665  *ppixd = pixClipRectangle(pixs, boxd, NULL);
1666  if (pboxd)
1667  *pboxd = boxd;
1668  else
1669  boxDestroy(&boxd);
1670 
1671  boxDestroy(&boxt);
1672  return 0;
1673 }
1674 
1675 
1692 l_int32
1694  BOX *box,
1695  l_int32 scanflag,
1696  l_int32 *ploc)
1697 {
1698 l_int32 bx, by, bw, bh, x, xstart, xend, y, ystart, yend, wpl;
1699 l_uint32 *data, *line;
1700 BOX *boxt;
1701 
1702  PROCNAME("pixScanForForeground");
1703 
1704  if (!ploc)
1705  return ERROR_INT("&loc not defined", procName, 1);
1706  *ploc = 0;
1707  if (!pixs || (pixGetDepth(pixs) != 1))
1708  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
1709 
1710  /* Clip box to pixs if it exists */
1711  pixGetDimensions(pixs, &bw, &bh, NULL);
1712  if (box) {
1713  if ((boxt = boxClipToRectangle(box, bw, bh)) == NULL)
1714  return ERROR_INT("invalid box", procName, 1);
1715  boxGetGeometry(boxt, &bx, &by, &bw, &bh);
1716  boxDestroy(&boxt);
1717  } else {
1718  bx = by = 0;
1719  }
1720  xstart = bx;
1721  ystart = by;
1722  xend = bx + bw - 1;
1723  yend = by + bh - 1;
1724 
1725  data = pixGetData(pixs);
1726  wpl = pixGetWpl(pixs);
1727  if (scanflag == L_FROM_LEFT) {
1728  for (x = xstart; x <= xend; x++) {
1729  for (y = ystart; y <= yend; y++) {
1730  line = data + y * wpl;
1731  if (GET_DATA_BIT(line, x)) {
1732  *ploc = x;
1733  return 0;
1734  }
1735  }
1736  }
1737  } else if (scanflag == L_FROM_RIGHT) {
1738  for (x = xend; x >= xstart; x--) {
1739  for (y = ystart; y <= yend; y++) {
1740  line = data + y * wpl;
1741  if (GET_DATA_BIT(line, x)) {
1742  *ploc = x;
1743  return 0;
1744  }
1745  }
1746  }
1747  } else if (scanflag == L_FROM_TOP) {
1748  for (y = ystart; y <= yend; y++) {
1749  line = data + y * wpl;
1750  for (x = xstart; x <= xend; x++) {
1751  if (GET_DATA_BIT(line, x)) {
1752  *ploc = y;
1753  return 0;
1754  }
1755  }
1756  }
1757  } else if (scanflag == L_FROM_BOT) {
1758  for (y = yend; y >= ystart; y--) {
1759  line = data + y * wpl;
1760  for (x = xstart; x <= xend; x++) {
1761  if (GET_DATA_BIT(line, x)) {
1762  *ploc = y;
1763  return 0;
1764  }
1765  }
1766  }
1767  } else {
1768  return ERROR_INT("invalid scanflag", procName, 1);
1769  }
1770 
1771  return 1; /* no fg found */
1772 }
1773 
1774 
1808 l_int32
1810  BOX *boxs,
1811  l_int32 lowthresh,
1812  l_int32 highthresh,
1813  l_int32 maxwidth,
1814  l_int32 factor,
1815  PIX **ppixd,
1816  BOX **pboxd)
1817 {
1818 l_int32 w, h, bx, by, bw, bh, cbw, cbh, left, right, top, bottom;
1819 l_int32 lfound, rfound, tfound, bfound, change;
1820 BOX *boxt, *boxd;
1821 
1822  PROCNAME("pixClipBoxToEdges");
1823 
1824  if (ppixd) *ppixd = NULL;
1825  if (pboxd) *pboxd = NULL;
1826  if (!ppixd && !pboxd)
1827  return ERROR_INT("no output requested", procName, 1);
1828  if (!pixs || (pixGetDepth(pixs) != 1))
1829  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
1830  if (lowthresh < 1 || highthresh < 1 ||
1831  lowthresh > highthresh || maxwidth < 1)
1832  return ERROR_INT("invalid thresholds", procName, 1);
1833  factor = L_MIN(1, factor);
1834 
1835  if (lowthresh == 1 && highthresh == 1)
1836  return pixClipBoxToForeground(pixs, boxs, ppixd, pboxd);
1837 
1838  pixGetDimensions(pixs, &w, &h, NULL);
1839  if (boxs) {
1840  boxGetGeometry(boxs, &bx, &by, &bw, &bh);
1841  cbw = L_MIN(bw, w - bx);
1842  cbh = L_MIN(bh, h - by);
1843  if (cbw < 0 || cbh < 0)
1844  return ERROR_INT("box not within image", procName, 1);
1845  boxt = boxCreate(bx, by, cbw, cbh);
1846  } else {
1847  boxt = boxCreate(0, 0, w, h);
1848  }
1849 
1850  lfound = rfound = tfound = bfound = 0;
1851  while (!lfound || !rfound || !tfound || !bfound) {
1852  change = 0;
1853  if (!lfound) {
1854  if (!pixScanForEdge(pixs, boxt, lowthresh, highthresh, maxwidth,
1855  factor, L_FROM_LEFT, &left)) {
1856  lfound = 1;
1857  change = 1;
1858  boxRelocateOneSide(boxt, boxt, left, L_FROM_LEFT);
1859  }
1860  }
1861  if (!rfound) {
1862  if (!pixScanForEdge(pixs, boxt, lowthresh, highthresh, maxwidth,
1863  factor, L_FROM_RIGHT, &right)) {
1864  rfound = 1;
1865  change = 1;
1866  boxRelocateOneSide(boxt, boxt, right, L_FROM_RIGHT);
1867  }
1868  }
1869  if (!tfound) {
1870  if (!pixScanForEdge(pixs, boxt, lowthresh, highthresh, maxwidth,
1871  factor, L_FROM_TOP, &top)) {
1872  tfound = 1;
1873  change = 1;
1874  boxRelocateOneSide(boxt, boxt, top, L_FROM_TOP);
1875  }
1876  }
1877  if (!bfound) {
1878  if (!pixScanForEdge(pixs, boxt, lowthresh, highthresh, maxwidth,
1879  factor, L_FROM_BOT, &bottom)) {
1880  bfound = 1;
1881  change = 1;
1882  boxRelocateOneSide(boxt, boxt, bottom, L_FROM_BOT);
1883  }
1884  }
1885 
1886 #if DEBUG_EDGES
1887  fprintf(stderr, "iter: %d %d %d %d\n", lfound, rfound, tfound, bfound);
1888 #endif /* DEBUG_EDGES */
1889 
1890  if (change == 0) break;
1891  }
1892  boxDestroy(&boxt);
1893 
1894  if (change == 0)
1895  return ERROR_INT("not all edges found", procName, 1);
1896 
1897  boxd = boxCreate(left, top, right - left + 1, bottom - top + 1);
1898  if (ppixd)
1899  *ppixd = pixClipRectangle(pixs, boxd, NULL);
1900  if (pboxd)
1901  *pboxd = boxd;
1902  else
1903  boxDestroy(&boxd);
1904 
1905  return 0;
1906 }
1907 
1908 
1938 l_int32
1940  BOX *box,
1941  l_int32 lowthresh,
1942  l_int32 highthresh,
1943  l_int32 maxwidth,
1944  l_int32 factor,
1945  l_int32 scanflag,
1946  l_int32 *ploc)
1947 {
1948 l_int32 bx, by, bw, bh, foundmin, loc, sum, wpl;
1949 l_int32 x, xstart, xend, y, ystart, yend;
1950 l_uint32 *data, *line;
1951 BOX *boxt;
1952 
1953  PROCNAME("pixScanForEdge");
1954 
1955  if (!ploc)
1956  return ERROR_INT("&ploc not defined", procName, 1);
1957  *ploc = 0;
1958  if (!pixs || (pixGetDepth(pixs) != 1))
1959  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
1960  if (lowthresh < 1 || highthresh < 1 ||
1961  lowthresh > highthresh || maxwidth < 1)
1962  return ERROR_INT("invalid thresholds", procName, 1);
1963  factor = L_MIN(1, factor);
1964 
1965  /* Clip box to pixs if it exists */
1966  pixGetDimensions(pixs, &bw, &bh, NULL);
1967  if (box) {
1968  if ((boxt = boxClipToRectangle(box, bw, bh)) == NULL)
1969  return ERROR_INT("invalid box", procName, 1);
1970  boxGetGeometry(boxt, &bx, &by, &bw, &bh);
1971  boxDestroy(&boxt);
1972  } else {
1973  bx = by = 0;
1974  }
1975  xstart = bx;
1976  ystart = by;
1977  xend = bx + bw - 1;
1978  yend = by + bh - 1;
1979 
1980  data = pixGetData(pixs);
1981  wpl = pixGetWpl(pixs);
1982  foundmin = 0;
1983  if (scanflag == L_FROM_LEFT) {
1984  for (x = xstart; x <= xend; x++) {
1985  sum = 0;
1986  for (y = ystart; y <= yend; y += factor) {
1987  line = data + y * wpl;
1988  if (GET_DATA_BIT(line, x))
1989  sum++;
1990  }
1991  if (!foundmin && sum < lowthresh)
1992  continue;
1993  if (!foundmin) { /* save the loc of the beginning of the edge */
1994  foundmin = 1;
1995  loc = x;
1996  }
1997  if (sum >= highthresh) {
1998 #if DEBUG_EDGES
1999  fprintf(stderr, "Left: x = %d, loc = %d\n", x, loc);
2000 #endif /* DEBUG_EDGES */
2001  if (x - loc < maxwidth) {
2002  *ploc = loc;
2003  return 0;
2004  } else {
2005  return 1;
2006  }
2007  }
2008  }
2009  } else if (scanflag == L_FROM_RIGHT) {
2010  for (x = xend; x >= xstart; x--) {
2011  sum = 0;
2012  for (y = ystart; y <= yend; y += factor) {
2013  line = data + y * wpl;
2014  if (GET_DATA_BIT(line, x))
2015  sum++;
2016  }
2017  if (!foundmin && sum < lowthresh)
2018  continue;
2019  if (!foundmin) {
2020  foundmin = 1;
2021  loc = x;
2022  }
2023  if (sum >= highthresh) {
2024 #if DEBUG_EDGES
2025  fprintf(stderr, "Right: x = %d, loc = %d\n", x, loc);
2026 #endif /* DEBUG_EDGES */
2027  if (loc - x < maxwidth) {
2028  *ploc = loc;
2029  return 0;
2030  } else {
2031  return 1;
2032  }
2033  }
2034  }
2035  } else if (scanflag == L_FROM_TOP) {
2036  for (y = ystart; y <= yend; y++) {
2037  sum = 0;
2038  line = data + y * wpl;
2039  for (x = xstart; x <= xend; x += factor) {
2040  if (GET_DATA_BIT(line, x))
2041  sum++;
2042  }
2043  if (!foundmin && sum < lowthresh)
2044  continue;
2045  if (!foundmin) {
2046  foundmin = 1;
2047  loc = y;
2048  }
2049  if (sum >= highthresh) {
2050 #if DEBUG_EDGES
2051  fprintf(stderr, "Top: y = %d, loc = %d\n", y, loc);
2052 #endif /* DEBUG_EDGES */
2053  if (y - loc < maxwidth) {
2054  *ploc = loc;
2055  return 0;
2056  } else {
2057  return 1;
2058  }
2059  }
2060  }
2061  } else if (scanflag == L_FROM_BOT) {
2062  for (y = yend; y >= ystart; y--) {
2063  sum = 0;
2064  line = data + y * wpl;
2065  for (x = xstart; x <= xend; x += factor) {
2066  if (GET_DATA_BIT(line, x))
2067  sum++;
2068  }
2069  if (!foundmin && sum < lowthresh)
2070  continue;
2071  if (!foundmin) {
2072  foundmin = 1;
2073  loc = y;
2074  }
2075  if (sum >= highthresh) {
2076 #if DEBUG_EDGES
2077  fprintf(stderr, "Bottom: y = %d, loc = %d\n", y, loc);
2078 #endif /* DEBUG_EDGES */
2079  if (loc - y < maxwidth) {
2080  *ploc = loc;
2081  return 0;
2082  } else {
2083  return 1;
2084  }
2085  }
2086  }
2087  } else {
2088  return ERROR_INT("invalid scanflag", procName, 1);
2089  }
2090 
2091  return 1; /* edge not found */
2092 }
2093 
2094 
2095 /*---------------------------------------------------------------------*
2096  * Extract pixel averages and reversals along lines *
2097  *---------------------------------------------------------------------*/
2119 NUMA *
2121  l_int32 x1,
2122  l_int32 y1,
2123  l_int32 x2,
2124  l_int32 y2,
2125  l_int32 factor)
2126 {
2127 l_int32 i, w, h, d, xmin, ymin, xmax, ymax, npts, direction;
2128 l_uint32 val;
2129 l_float32 x, y;
2130 l_float64 slope;
2131 NUMA *na;
2132 PTA *pta;
2133 
2134  PROCNAME("pixExtractOnLine");
2135 
2136  if (!pixs)
2137  return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
2138  pixGetDimensions(pixs, &w, &h, &d);
2139  if (d != 1 && d != 8)
2140  return (NUMA *)ERROR_PTR("d not 1 or 8 bpp", procName, NULL);
2141  if (pixGetColormap(pixs))
2142  return (NUMA *)ERROR_PTR("pixs has a colormap", procName, NULL);
2143  if (factor < 1) {
2144  L_WARNING("factor must be >= 1; setting to 1\n", procName);
2145  factor = 1;
2146  }
2147 
2148  /* Clip line to the image */
2149  x1 = L_MAX(0, L_MIN(x1, w - 1));
2150  x2 = L_MAX(0, L_MIN(x2, w - 1));
2151  y1 = L_MAX(0, L_MIN(y1, h - 1));
2152  y2 = L_MAX(0, L_MIN(y2, h - 1));
2153 
2154  if (x1 == x2 && y1 == y2) {
2155  pixGetPixel(pixs, x1, y1, &val);
2156  na = numaCreate(1);
2157  numaAddNumber(na, val);
2158  return na;
2159  }
2160 
2161  if (y1 == y2)
2162  direction = L_HORIZONTAL_LINE;
2163  else if (x1 == x2)
2164  direction = L_VERTICAL_LINE;
2165  else
2166  direction = L_OBLIQUE_LINE;
2167 
2168  na = numaCreate(0);
2169  if (direction == L_HORIZONTAL_LINE) { /* plot against x */
2170  xmin = L_MIN(x1, x2);
2171  xmax = L_MAX(x1, x2);
2172  numaSetParameters(na, xmin, factor);
2173  for (i = xmin; i <= xmax; i += factor) {
2174  pixGetPixel(pixs, i, y1, &val);
2175  numaAddNumber(na, val);
2176  }
2177  } else if (direction == L_VERTICAL_LINE) { /* plot against y */
2178  ymin = L_MIN(y1, y2);
2179  ymax = L_MAX(y1, y2);
2180  numaSetParameters(na, ymin, factor);
2181  for (i = ymin; i <= ymax; i += factor) {
2182  pixGetPixel(pixs, x1, i, &val);
2183  numaAddNumber(na, val);
2184  }
2185  } else { /* direction == L_OBLIQUE_LINE */
2186  slope = (l_float64)((y2 - y1) / (x2 - x1));
2187  if (L_ABS(slope) < 1.0) { /* quasi-horizontal */
2188  xmin = L_MIN(x1, x2);
2189  xmax = L_MAX(x1, x2);
2190  ymin = (xmin == x1) ? y1 : y2; /* pt that goes with xmin */
2191  ymax = (ymin == y1) ? y2 : y1; /* pt that goes with xmax */
2192  pta = generatePtaLine(xmin, ymin, xmax, ymax);
2193  numaSetParameters(na, xmin, (l_float32)factor);
2194  } else { /* quasi-vertical */
2195  ymin = L_MIN(y1, y2);
2196  ymax = L_MAX(y1, y2);
2197  xmin = (ymin == y1) ? x1 : x2; /* pt that goes with ymin */
2198  xmax = (xmin == x1) ? x2 : x1; /* pt that goes with ymax */
2199  pta = generatePtaLine(xmin, ymin, xmax, ymax);
2200  numaSetParameters(na, ymin, (l_float32)factor);
2201  }
2202  npts = ptaGetCount(pta);
2203  for (i = 0; i < npts; i += factor) {
2204  ptaGetPt(pta, i, &x, &y);
2205  pixGetPixel(pixs, (l_int32)x, (l_int32)y, &val);
2206  numaAddNumber(na, val);
2207  }
2208 
2209 #if 0 /* debugging */
2210  pixPlotAlongPta(pixs, pta, GPLOT_PNG, NULL);
2211 #endif
2212 
2213  ptaDestroy(&pta);
2214  }
2215 
2216  return na;
2217 }
2218 
2219 
2239 l_float32
2241  l_int32 x1,
2242  l_int32 y1,
2243  l_int32 x2,
2244  l_int32 y2,
2245  l_int32 factor)
2246 {
2247 l_int32 i, j, w, h, d, direction, count, wpl;
2248 l_uint32 *data, *line;
2249 l_float32 sum;
2250 
2251  PROCNAME("pixAverageOnLine");
2252 
2253  if (!pixs)
2254  return ERROR_INT("pixs not defined", procName, 1);
2255  pixGetDimensions(pixs, &w, &h, &d);
2256  if (d != 1 && d != 8)
2257  return ERROR_INT("d not 1 or 8 bpp", procName, 1);
2258  if (pixGetColormap(pixs))
2259  return ERROR_INT("pixs has a colormap", procName, 1);
2260  if (x1 > x2 || y1 > y2)
2261  return ERROR_INT("x1 > x2 or y1 > y2", procName, 1);
2262 
2263  if (y1 == y2) {
2264  x1 = L_MAX(0, x1);
2265  x2 = L_MIN(w - 1, x2);
2266  y1 = L_MAX(0, L_MIN(y1, h - 1));
2267  direction = L_HORIZONTAL_LINE;
2268  } else if (x1 == x2) {
2269  y1 = L_MAX(0, y1);
2270  y2 = L_MIN(h - 1, y2);
2271  x1 = L_MAX(0, L_MIN(x1, w - 1));
2272  direction = L_VERTICAL_LINE;
2273  } else {
2274  return ERROR_INT("line neither horiz nor vert", procName, 1);
2275  }
2276 
2277  if (factor < 1) {
2278  L_WARNING("factor must be >= 1; setting to 1\n", procName);
2279  factor = 1;
2280  }
2281 
2282  data = pixGetData(pixs);
2283  wpl = pixGetWpl(pixs);
2284  sum = 0;
2285  count = 0;
2286  if (direction == L_HORIZONTAL_LINE) {
2287  line = data + y1 * wpl;
2288  for (j = x1, count = 0; j <= x2; count++, j += factor) {
2289  if (d == 1)
2290  sum += GET_DATA_BIT(line, j);
2291  else /* d == 8 */
2292  sum += GET_DATA_BYTE(line, j);
2293  }
2294  } else if (direction == L_VERTICAL_LINE) {
2295  for (i = y1, count = 0; i <= y2; count++, i += factor) {
2296  line = data + i * wpl;
2297  if (d == 1)
2298  sum += GET_DATA_BIT(line, x1);
2299  else /* d == 8 */
2300  sum += GET_DATA_BYTE(line, x1);
2301  }
2302  }
2303 
2304  return sum / (l_float32)count;
2305 }
2306 
2307 
2337 NUMA *
2339  l_float32 fract,
2340  l_int32 dir,
2341  l_int32 first,
2342  l_int32 last,
2343  l_int32 factor1,
2344  l_int32 factor2)
2345 {
2346 l_int32 i, j, w, h, d, start, end;
2347 l_float32 ave;
2348 NUMA *nad;
2349 PIX *pixr, *pixg;
2350 
2351  PROCNAME("pixAverageIntensityProfile");
2352 
2353  if (!pixs)
2354  return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
2355  if (fract < 0.0 || fract > 1.0)
2356  return (NUMA *)ERROR_PTR("fract < 0.0 or > 1.0", procName, NULL);
2357  if (dir != L_HORIZONTAL_LINE && dir != L_VERTICAL_LINE)
2358  return (NUMA *)ERROR_PTR("invalid direction", procName, NULL);
2359  if (first < 0) first = 0;
2360  if (last < first)
2361  return (NUMA *)ERROR_PTR("last must be >= first", procName, NULL);
2362  if (factor1 < 1) {
2363  L_WARNING("factor1 must be >= 1; setting to 1\n", procName);
2364  factor1 = 1;
2365  }
2366  if (factor2 < 1) {
2367  L_WARNING("factor2 must be >= 1; setting to 1\n", procName);
2368  factor2 = 1;
2369  }
2370 
2371  /* Use 1 or 8 bpp, without colormap */
2372  if (pixGetColormap(pixs))
2374  else
2375  pixr = pixClone(pixs);
2376  pixGetDimensions(pixr, &w, &h, &d);
2377  if (d == 1)
2378  pixg = pixClone(pixr);
2379  else
2380  pixg = pixConvertTo8(pixr, 0);
2381 
2382  nad = numaCreate(0); /* output: samples in slow scan direction */
2383  numaSetParameters(nad, 0, factor2);
2384  if (dir == L_HORIZONTAL_LINE) {
2385  start = (l_int32)(0.5 * (1.0 - fract) * (l_float32)w);
2386  end = w - start;
2387  if (last > h - 1) {
2388  L_WARNING("last > h - 1; clipping\n", procName);
2389  last = h - 1;
2390  }
2391  for (i = first; i <= last; i += factor2) {
2392  ave = pixAverageOnLine(pixg, start, i, end, i, factor1);
2393  numaAddNumber(nad, ave);
2394  }
2395  } else if (dir == L_VERTICAL_LINE) {
2396  start = (l_int32)(0.5 * (1.0 - fract) * (l_float32)h);
2397  end = h - start;
2398  if (last > w - 1) {
2399  L_WARNING("last > w - 1; clipping\n", procName);
2400  last = w - 1;
2401  }
2402  for (j = first; j <= last; j += factor2) {
2403  ave = pixAverageOnLine(pixg, j, start, j, end, factor1);
2404  numaAddNumber(nad, ave);
2405  }
2406  }
2407 
2408  pixDestroy(&pixr);
2409  pixDestroy(&pixg);
2410  return nad;
2411 }
2412 
2413 
2451 NUMA *
2453  l_float32 fract,
2454  l_int32 dir,
2455  l_int32 first,
2456  l_int32 last,
2457  l_int32 minreversal,
2458  l_int32 factor1,
2459  l_int32 factor2)
2460 {
2461 l_int32 i, j, w, h, d, start, end, nr;
2462 NUMA *naline, *nad;
2463 PIX *pixr, *pixg;
2464 
2465  PROCNAME("pixReversalProfile");
2466 
2467  if (!pixs)
2468  return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
2469  if (fract < 0.0 || fract > 1.0)
2470  return (NUMA *)ERROR_PTR("fract < 0.0 or > 1.0", procName, NULL);
2471  if (dir != L_HORIZONTAL_LINE && dir != L_VERTICAL_LINE)
2472  return (NUMA *)ERROR_PTR("invalid direction", procName, NULL);
2473  if (first < 0) first = 0;
2474  if (last < first)
2475  return (NUMA *)ERROR_PTR("last must be >= first", procName, NULL);
2476  if (factor1 < 1) {
2477  L_WARNING("factor1 must be >= 1; setting to 1\n", procName);
2478  factor1 = 1;
2479  }
2480  if (factor2 < 1) {
2481  L_WARNING("factor2 must be >= 1; setting to 1\n", procName);
2482  factor2 = 1;
2483  }
2484 
2485  /* Use 1 or 8 bpp, without colormap */
2486  if (pixGetColormap(pixs))
2488  else
2489  pixr = pixClone(pixs);
2490  pixGetDimensions(pixr, &w, &h, &d);
2491  if (d == 1) {
2492  pixg = pixClone(pixr);
2493  minreversal = 1; /* enforce this */
2494  } else {
2495  pixg = pixConvertTo8(pixr, 0);
2496  }
2497 
2498  nad = numaCreate(0); /* output: samples in slow scan direction */
2499  numaSetParameters(nad, 0, factor2);
2500  if (dir == L_HORIZONTAL_LINE) {
2501  start = (l_int32)(0.5 * (1.0 - fract) * (l_float32)w);
2502  end = w - start;
2503  if (last > h - 1) {
2504  L_WARNING("last > h - 1; clipping\n", procName);
2505  last = h - 1;
2506  }
2507  for (i = first; i <= last; i += factor2) {
2508  naline = pixExtractOnLine(pixg, start, i, end, i, factor1);
2509  numaCountReversals(naline, minreversal, &nr, NULL);
2510  numaAddNumber(nad, nr);
2511  numaDestroy(&naline);
2512  }
2513  } else if (dir == L_VERTICAL_LINE) {
2514  start = (l_int32)(0.5 * (1.0 - fract) * (l_float32)h);
2515  end = h - start;
2516  if (last > w - 1) {
2517  L_WARNING("last > w - 1; clipping\n", procName);
2518  last = w - 1;
2519  }
2520  for (j = first; j <= last; j += factor2) {
2521  naline = pixExtractOnLine(pixg, j, start, j, end, factor1);
2522  numaCountReversals(naline, minreversal, &nr, NULL);
2523  numaAddNumber(nad, nr);
2524  numaDestroy(&naline);
2525  }
2526  }
2527 
2528  pixDestroy(&pixr);
2529  pixDestroy(&pixg);
2530  return nad;
2531 }
2532 
2533 
2534 /*---------------------------------------------------------------------*
2535  * Extract windowed variance along a line *
2536  *---------------------------------------------------------------------*/
2560 l_int32
2562  l_int32 dir,
2563  l_int32 loc,
2564  l_int32 c1,
2565  l_int32 c2,
2566  l_int32 size,
2567  NUMA **pnad)
2568 {
2569 l_int32 i, j, w, h, cmin, cmax, maxloc, n, x, y;
2570 l_uint32 val;
2571 l_float32 norm, rootvar;
2572 l_float32 *array;
2573 l_float64 sum1, sum2, ave, var;
2574 NUMA *na1, *nad;
2575 PTA *pta;
2576 
2577  PROCNAME("pixWindowedVarianceOnLine");
2578 
2579  if (!pnad)
2580  return ERROR_INT("&nad not defined", procName, 1);
2581  *pnad = NULL;
2582  if (!pixs || pixGetDepth(pixs) != 8)
2583  return ERROR_INT("pixs not defined or not 8bpp", procName, 1);
2584  if (size < 2)
2585  return ERROR_INT("window size must be > 1", procName, 1);
2586  if (dir != L_HORIZONTAL_LINE && dir != L_VERTICAL_LINE)
2587  return ERROR_INT("invalid direction", procName, 1);
2588  pixGetDimensions(pixs, &w, &h, NULL);
2589  maxloc = (dir == L_HORIZONTAL_LINE) ? h - 1 : w - 1;
2590  if (loc < 0 || loc > maxloc)
2591  return ERROR_INT("invalid line position", procName, 1);
2592 
2593  /* Clip line to the image */
2594  cmin = L_MIN(c1, c2);
2595  cmax = L_MAX(c1, c2);
2596  maxloc = (dir == L_HORIZONTAL_LINE) ? w - 1 : h - 1;
2597  cmin = L_MAX(0, L_MIN(cmin, maxloc));
2598  cmax = L_MAX(0, L_MIN(cmax, maxloc));
2599  n = cmax - cmin + 1;
2600 
2601  /* Generate pta along the line */
2602  pta = ptaCreate(n);
2603  if (dir == L_HORIZONTAL_LINE) {
2604  for (i = cmin; i <= cmax; i++)
2605  ptaAddPt(pta, i, loc);
2606  } else { /* vertical line */
2607  for (i = cmin; i <= cmax; i++)
2608  ptaAddPt(pta, loc, i);
2609  }
2610 
2611  /* Get numa of pixel values on the line */
2612  na1 = numaCreate(n);
2613  numaSetParameters(na1, cmin, 1);
2614  for (i = 0; i < n; i++) {
2615  ptaGetIPt(pta, i, &x, &y);
2616  pixGetPixel(pixs, x, y, &val);
2617  numaAddNumber(na1, val);
2618  }
2619  array = numaGetFArray(na1, L_NOCOPY);
2620  ptaDestroy(&pta);
2621 
2622  /* Compute root variance on overlapping windows */
2623  nad = numaCreate(n);
2624  *pnad = nad;
2625  numaSetParameters(nad, cmin + size / 2, 1);
2626  norm = 1.0 / (l_float32)size;
2627  for (i = 0; i < n - size; i++) { /* along the line */
2628  sum1 = sum2 = 0;
2629  for (j = 0; j < size; j++) { /* over the window */
2630  val = array[i + j];
2631  sum1 += val;
2632  sum2 += (l_float64)(val) * val;
2633  }
2634  ave = norm * sum1;
2635  var = norm * sum2 - ave * ave;
2636  rootvar = (l_float32)sqrt(var);
2637  numaAddNumber(nad, rootvar);
2638  }
2639 
2640  numaDestroy(&na1);
2641  return 0;
2642 }
2643 
2644 
2645 /*---------------------------------------------------------------------*
2646  * Extract min/max of pixel values near lines *
2647  *---------------------------------------------------------------------*/
2678 l_int32
2680  l_int32 x1,
2681  l_int32 y1,
2682  l_int32 x2,
2683  l_int32 y2,
2684  l_int32 dist,
2685  l_int32 direction,
2686  NUMA **pnamin,
2687  NUMA **pnamax,
2688  l_float32 *pminave,
2689  l_float32 *pmaxave)
2690 {
2691 l_int32 i, j, w, h, d, x, y, n, dir, found, minval, maxval, negloc, posloc;
2692 l_uint32 val;
2693 l_float32 sum;
2694 NUMA *namin, *namax;
2695 PTA *pta;
2696 
2697  PROCNAME("pixMinMaxNearLine");
2698 
2699  if (pnamin) *pnamin = NULL;
2700  if (pnamax) *pnamax = NULL;
2701  if (pminave) *pminave = UNDEF;
2702  if (pmaxave) *pmaxave = UNDEF;
2703  if (!pnamin && !pnamax && !pminave && !pmaxave)
2704  return ERROR_INT("no output requested", procName, 1);
2705  if (!pixs)
2706  return ERROR_INT("pixs not defined", procName, 1);
2707  pixGetDimensions(pixs, &w, &h, &d);
2708  if (d != 8 || pixGetColormap(pixs))
2709  return ERROR_INT("pixs not 8 bpp or has colormap", procName, 1);
2710  dist = L_ABS(dist);
2711  if (direction != L_SCAN_NEGATIVE && direction != L_SCAN_POSITIVE &&
2712  direction != L_SCAN_BOTH)
2713  return ERROR_INT("invalid direction", procName, 1);
2714 
2715  pta = generatePtaLine(x1, y1, x2, y2);
2716  n = ptaGetCount(pta);
2717  dir = (L_ABS(x1 - x2) == n - 1) ? L_HORIZ : L_VERT;
2718  namin = numaCreate(n);
2719  namax = numaCreate(n);
2720  negloc = -dist;
2721  posloc = dist;
2722  if (direction == L_SCAN_NEGATIVE)
2723  posloc = 0;
2724  else if (direction == L_SCAN_POSITIVE)
2725  negloc = 0;
2726  for (i = 0; i < n; i++) {
2727  ptaGetIPt(pta, i, &x, &y);
2728  minval = 255;
2729  maxval = 0;
2730  found = FALSE;
2731  if (dir == L_HORIZ) {
2732  if (x < 0 || x >= w) continue;
2733  for (j = negloc; j <= posloc; j++) {
2734  if (y + j < 0 || y + j >= h) continue;
2735  pixGetPixel(pixs, x, y + j, &val);
2736  found = TRUE;
2737  if (val < minval) minval = val;
2738  if (val > maxval) maxval = val;
2739  }
2740  } else { /* dir == L_VERT */
2741  if (y < 0 || y >= h) continue;
2742  for (j = negloc; j <= posloc; j++) {
2743  if (x + j < 0 || x + j >= w) continue;
2744  pixGetPixel(pixs, x + j, y, &val);
2745  found = TRUE;
2746  if (val < minval) minval = val;
2747  if (val > maxval) maxval = val;
2748  }
2749  }
2750  if (found) {
2751  numaAddNumber(namin, minval);
2752  numaAddNumber(namax, maxval);
2753  }
2754  }
2755 
2756  n = numaGetCount(namin);
2757  if (n == 0) {
2758  numaDestroy(&namin);
2759  numaDestroy(&namax);
2760  ptaDestroy(&pta);
2761  return ERROR_INT("no output from this line", procName, 1);
2762  }
2763 
2764  if (pminave) {
2765  numaGetSum(namin, &sum);
2766  *pminave = sum / n;
2767  }
2768  if (pmaxave) {
2769  numaGetSum(namax, &sum);
2770  *pmaxave = sum / n;
2771  }
2772  if (pnamin)
2773  *pnamin = namin;
2774  else
2775  numaDestroy(&namin);
2776  if (pnamax)
2777  *pnamax = namax;
2778  else
2779  numaDestroy(&namax);
2780  ptaDestroy(&pta);
2781  return 0;
2782 }
2783 
2784 
2785 /*---------------------------------------------------------------------*
2786  * Rank row and column transforms *
2787  *---------------------------------------------------------------------*/
2801 PIX *
2803 {
2804 l_int32 i, j, k, m, w, h, wpl, val;
2805 l_int32 histo[256];
2806 l_uint32 *datas, *datad, *lines, *lined;
2807 PIX *pixd;
2808 
2809  PROCNAME("pixRankRowTransform");
2810 
2811  if (!pixs)
2812  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2813  if (pixGetDepth(pixs) != 8)
2814  return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
2815  if (pixGetColormap(pixs))
2816  return (PIX *)ERROR_PTR("pixs has a colormap", procName, NULL);
2817 
2818  pixGetDimensions(pixs, &w, &h, NULL);
2819  pixd = pixCreateTemplate(pixs);
2820  datas = pixGetData(pixs);
2821  datad = pixGetData(pixd);
2822  wpl = pixGetWpl(pixs);
2823  for (i = 0; i < h; i++) {
2824  memset(histo, 0, 1024);
2825  lines = datas + i * wpl;
2826  lined = datad + i * wpl;
2827  for (j = 0; j < w; j++) {
2828  val = GET_DATA_BYTE(lines, j);
2829  histo[val]++;
2830  }
2831  for (m = 0, j = 0; m < 256; m++) {
2832  for (k = 0; k < histo[m]; k++, j++)
2833  SET_DATA_BYTE(lined, j, m);
2834  }
2835  }
2836 
2837  return pixd;
2838 }
2839 
2840 
2854 PIX *
2856 {
2857 l_int32 i, j, k, m, w, h, val;
2858 l_int32 histo[256];
2859 void **lines8, **lined8;
2860 PIX *pixd;
2861 
2862  PROCNAME("pixRankColumnTransform");
2863 
2864  if (!pixs)
2865  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2866  if (pixGetDepth(pixs) != 8)
2867  return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
2868  if (pixGetColormap(pixs))
2869  return (PIX *)ERROR_PTR("pixs has a colormap", procName, NULL);
2870 
2871  pixGetDimensions(pixs, &w, &h, NULL);
2872  pixd = pixCreateTemplate(pixs);
2873  lines8 = pixGetLinePtrs(pixs, NULL);
2874  lined8 = pixGetLinePtrs(pixd, NULL);
2875  for (j = 0; j < w; j++) {
2876  memset(histo, 0, 1024);
2877  for (i = 0; i < h; i++) {
2878  val = GET_DATA_BYTE(lines8[i], j);
2879  histo[val]++;
2880  }
2881  for (m = 0, i = 0; m < 256; m++) {
2882  for (k = 0; k < histo[m]; k++, i++)
2883  SET_DATA_BYTE(lined8[i], j, m);
2884  }
2885  }
2886 
2887  LEPT_FREE(lines8);
2888  LEPT_FREE(lined8);
2889  return pixd;
2890 }
l_int32 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:2679
l_int32 pixCopyColormap(PIX *pixd, PIX *pixs)
pixCopyColormap()
Definition: pix1.c:735
l_int32 pixcmapGetNearestIndex(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapGetNearestIndex()
Definition: colormap.c:1167
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:322
l_int32 pixaIsFull(PIXA *pixa, l_int32 *pfullpa, l_int32 *pfullba)
pixaIsFull()
Definition: pixabasic.c:1026
l_int32 numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:472
NUMA * pixaFindAreaFraction(PIXA *pixa)
pixaFindAreaFraction()
Definition: pix5.c:428
#define PIX_CLR
Definition: pix.h:330
NUMA * pixExtractOnLine(PIX *pixs, l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2, l_int32 factor)
pixExtractOnLine()
Definition: pix5.c:2120
l_int32 pixWindowedVarianceOnLine(PIX *pixs, l_int32 dir, l_int32 loc, l_int32 c1, l_int32 c2, l_int32 size, NUMA **pnad)
pixWindowedVarianceOnLine()
Definition: pix5.c:2561
BOXA * pixFindRectangleComps(PIX *pixs, l_int32 dist, l_int32 minw, l_int32 minh)
pixFindRectangleComps()
Definition: pix5.c:800
l_int32 ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:341
l_int32 pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:180
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:161
l_int32 ptaGetPt(PTA *pta, l_int32 index, l_float32 *px, l_float32 *py)
ptaGetPt()
Definition: ptabasic.c:524
l_int32 pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1702
l_int32 pixScanForForeground(PIX *pixs, BOX *box, l_int32 scanflag, l_int32 *ploc)
pixScanForForeground()
Definition: pix5.c:1693
Definition: pix.h:704
PIX * pixExtractBorderConnComps(PIX *pixs, l_int32 connectivity)
pixExtractBorderConnComps()
Definition: seedfill.c:694
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:115
PIX * pixMakeFrameMask(l_int32 w, l_int32 h, l_float32 hf1, l_float32 hf2, l_float32 vf1, l_float32 vf2)
pixMakeFrameMask()
Definition: pix5.c:1326
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3041
void ** pixGetLinePtrs(PIX *pix, l_int32 *psize)
pixGetLinePtrs()
Definition: pix1.c:1772
l_int32 boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:615
NUMA * pixaFindAreaFractionMasked(PIXA *pixa, PIX *pixm, l_int32 debug)
pixaFindAreaFractionMasked()
Definition: pix5.c:519
l_float32 pixAverageOnLine(PIX *pixs, l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2, l_int32 factor)
pixAverageOnLine()
Definition: pix5.c:2240
BOX * boxClipToRectangle(BOX *box, l_int32 wi, l_int32 hi)
boxClipToRectangle()
Definition: boxfunc1.c:1587
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:302
l_int32 pixSetOrClearBorder(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot, l_int32 op)
pixSetOrClearBorder()
Definition: pix2.c:1427
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1395
NUMA * pixaFindWidthHeightRatio(PIXA *pixa)
pixaFindWidthHeightRatio()
Definition: pix5.c:657
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:186
l_int32 ptaGetCount(PTA *pta)
ptaGetCount()
Definition: ptabasic.c:503
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:577
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1602
BOX * pixaGetBox(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetBox()
Definition: pixabasic.c:785
l_int32 numaGetSum(NUMA *na, l_float32 *psum)
numaGetSum()
Definition: numafunc1.c:514
NUMA * pixaFindPerimSizeRatio(PIXA *pixa)
pixaFindPerimSizeRatio()
Definition: pix5.c:332
l_int32 pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:709
PIX * pixaDisplay(PIXA *pixa, l_int32 w, l_int32 h)
pixaDisplay()
Definition: pixafunc2.c:179
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:117
l_int32 pixClipBoxToForeground(PIX *pixs, BOX *boxs, PIX **ppixd, BOX **pboxd)
pixClipBoxToForeground()
Definition: pix5.c:1627
PIX * pixCreateTemplate(PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:367
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:1013
Definition: pix.h:492
NUMA * pixaFindPerimToAreaRatio(PIXA *pixa)
pixaFindPerimToAreaRatio()
Definition: pix5.c:228
PIX * pixClipMasked(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_uint32 outval)
pixClipMasked()
Definition: pix5.c:1086
l_int32 pixaFindDimensions(PIXA *pixa, NUMA **pnaw, NUMA **pnah)
pixaFindDimensions()
Definition: pix5.c:127
NUMA * pixaFindWidthHeightProduct(PIXA *pixa)
pixaFindWidthHeightProduct()
Definition: pix5.c:693
l_int32 pixFindAreaPerimRatio(PIX *pixs, l_int32 *tab, l_float32 *pfract)
pixFindAreaPerimRatio()
Definition: pix5.c:177
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:110
#define PIX_MASK
Definition: pix.h:334
l_int32 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:193
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:144
Definition: array.h:59
static const l_int32 L_INSERT
Definition: pix.h:710
PIX * pixXor(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixXor()
Definition: pix3.c:1574
PTA * generatePtaLine(l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2)
generatePtaLine()
Definition: graphics.c:138
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_int32 pixFindOverlapFraction(PIX *pixs1, PIX *pixs2, l_int32 x2, l_int32 y2, l_int32 *tab, l_float32 *pratio, l_int32 *pnoverlap)
pixFindOverlapFraction()
Definition: pix5.c:733
l_int32 pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
#define PIX_SET
Definition: pix.h:331
PIX * pixAnd(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixAnd()
Definition: pix3.c:1510
PIX * pixCropToSize(PIX *pixs, l_int32 w, l_int32 h)
pixCropToSize()
Definition: pix5.c:1191
l_int32 * makePixelSumTab8(void)
makePixelSumTab8()
Definition: pix3.c:2298
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:192
PIXA * pixClipRectangles(PIX *pixs, BOXA *boxa)
pixClipRectangles()
Definition: pix5.c:947
l_int32 pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1556
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:2338
l_int32 boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:309
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:182
#define PIX_PAINT
Definition: pix.h:333
l_int32 pixFindPerimSizeRatio(PIX *pixs, l_int32 *tab, l_float32 *pratio)
pixFindPerimSizeRatio()
Definition: pix5.c:382
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:517
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:545
l_int32 pixFindAreaFractionMasked(PIX *pixs, BOX *box, PIX *pixm, l_int32 *tab, l_float32 *pfract)
pixFindAreaFractionMasked()
Definition: pix5.c:598
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:760
l_int32 pixPlotAlongPta(PIX *pixs, PTA *pta, l_int32 outformat, const char *title)
pixPlotAlongPta()
Definition: ptafunc1.c:1792
l_int32 numaSetParameters(NUMA *na, l_float32 startx, l_float32 delx)
numaSetParameters()
Definition: numabasic.c:965
Definition: pix.h:454
PIX * pixRankColumnTransform(PIX *pixs)
pixRankColumnTransform()
Definition: pix5.c:2855
l_int32 pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:618
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:359
BOX * boxRelocateOneSide(BOX *boxd, BOX *boxs, l_int32 loc, l_int32 sideflag)
boxRelocateOneSide()
Definition: boxfunc1.c:1706
l_int32 ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:554
l_int32 pixSetBlackOrWhite(PIX *pixs, l_int32 op)
pixSetBlackOrWhite()
Definition: pix2.c:934
l_int32 pixFindPerimToAreaRatio(PIX *pixs, l_int32 *tab, l_float32 *pfract)
pixFindPerimToAreaRatio()
Definition: pix5.c:278
l_int32 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:1809
l_float32 * numaGetFArray(NUMA *na, l_int32 copyflag)
numaGetFArray()
Definition: numabasic.c:864
l_int32 pixFractionFgInMask(PIX *pix1, PIX *pix2, l_float32 *pfract)
pixFractionFgInMask()
Definition: pix5.c:1399
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:660
Definition: pix.h:705
l_int32 composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2659
l_int32 pixClipToForeground(PIX *pixs, PIX **ppixd, BOX **pbox)
pixClipToForeground()
Definition: pix5.c:1455
l_int32 pixCropToMatch(PIX *pixs1, PIX *pixs2, PIX **ppixd1, PIX **ppixd2)
pixCropToMatch()
Definition: pix5.c:1148
Definition: pix.h:134
l_int32 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:1939
Definition: pix.h:706
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:191
l_int32 pixaAddBox(PIXA *pixa, BOX *box, l_int32 copyflag)
pixaAddBox()
Definition: pixabasic.c:537
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:496
l_int32 numaCountReversals(NUMA *nas, l_float32 minreversal, l_int32 *pnr, l_float32 *pnrpl)
numaCountReversals()
Definition: numafunc2.c:2544
#define PIX_SRC
Definition: pix.h:327
PIX * pixCopy(PIX *pixd, PIX *pixs)
pixCopy()
Definition: pix1.c:630
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:277
PIX * pixResizeToMatch(PIX *pixs, PIX *pixt, l_int32 w, l_int32 h)
pixResizeToMatch()
Definition: pix5.c:1245
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:715
l_int32 pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:729
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:2452
l_int32 pixGetDimensions(PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1052
l_int32 pixFindAreaFraction(PIX *pixs, l_int32 *tab, l_float32 *pfract)
pixFindAreaFraction()
Definition: pix5.c:471
l_int32 pixConformsToRectangle(PIX *pixs, BOX *box, l_int32 dist, l_int32 *pconforms)
pixConformsToRectangle()
Definition: pix5.c:880
PIX * pixRankRowTransform(PIX *pixs)
pixRankRowTransform()
Definition: pix5.c:2802
PIX * pixErodeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeBrick()
Definition: morph.c:748
l_int32 pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition: pix3.c:1824
Definition: pix.h:480
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:398
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2725
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:164
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:620
l_int32 pixTestClipToForeground(PIX *pixs, l_int32 *pcanclip)
pixTestClipToForeground()
Definition: pix5.c:1555
Definition: pix.h:517
l_int32 pixSetMaskedCmap(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_int32 rval, l_int32 gval, l_int32 bval)
pixSetMaskedCmap()
Definition: paintcmap.c:693