Leptonica  1.82.0
Image processing and image analysis suite
adaptmap.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 
134 #ifdef HAVE_CONFIG_H
135 #include <config_auto.h>
136 #endif /* HAVE_CONFIG_H */
137 
138 #include "allheaders.h"
139 
140  /* Default input parameters for pixBackgroundNormSimple()
141  * Notes:
142  * (1) mincount must never exceed the tile area (width * height)
143  * (2) bgval must be sufficiently below 255 to avoid accidental
144  * saturation; otherwise it should be large to avoid
145  * shrinking the dynamic range
146  * (3) results should otherwise not be sensitive to these values
147  */
148 static const l_int32 DefaultTileWidth = 10;
149 static const l_int32 DefaultTileHeight = 15;
150 static const l_int32 DefaultFgThreshold = 60;
151 static const l_int32 DefaultMinCount = 40;
152 static const l_int32 DefaultBgVal = 200;
153 static const l_int32 DefaultXSmoothSize = 2;
154 static const l_int32 DefaultYSmoothSize = 1;
156 static l_int32 pixMinMaxTiles(PIX *pixs, l_int32 sx, l_int32 sy,
157  l_int32 mindiff, l_int32 smoothx, l_int32 smoothy,
158  PIX **ppixmin, PIX **ppixmax);
159 static l_int32 pixSetLowContrast(PIX *pixs1, PIX *pixs2, l_int32 mindiff);
160 static PIX *pixLinearTRCTiled(PIX *pixd, PIX *pixs, l_int32 sx, l_int32 sy,
161  PIX *pixmin, PIX *pixmax);
162 static l_int32 *iaaGetLinearTRC(l_int32 **iaa, l_int32 diff);
163 
164 #ifndef NO_CONSOLE_IO
165 #define DEBUG_GLOBAL 0
166 #endif /* ~NO_CONSOLE_IO */
167 
168 /*------------------------------------------------------------------*
169  * Clean background to white using background normalization *
170  *------------------------------------------------------------------*/
195 PIX *
197  PIX *pixim,
198  PIX *pixg,
199  l_float32 gamma,
200  l_int32 blackval,
201  l_int32 whiteval)
202 {
203 l_int32 d;
204 PIX *pixd;
205 
206  PROCNAME("pixCleanBackgroundToWhite");
207 
208  if (!pixs)
209  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
210  d = pixGetDepth(pixs);
211  if (d != 8 && d != 32)
212  return (PIX *)ERROR_PTR("depth not 8 or 32", procName, NULL);
213  if (whiteval > 200) {
214  L_WARNING("white value %d must not exceed 200; reset to 190",
215  procName, whiteval);
216  whiteval = 190;
217  }
218 
219  pixd = pixBackgroundNormSimple(pixs, pixim, pixg);
220  if (!pixd)
221  return (PIX *)ERROR_PTR("background norm failedd", procName, NULL);
222  pixGammaTRC(pixd, pixd, gamma, blackval, whiteval);
223  return pixd;
224 }
225 
226 
227 /*------------------------------------------------------------------*
228  * Adaptive background normalization *
229  *------------------------------------------------------------------*/
246 PIX *
248  PIX *pixim,
249  PIX *pixg)
250 {
251  return pixBackgroundNorm(pixs, pixim, pixg,
256 }
257 
258 
321 PIX *
323  PIX *pixim,
324  PIX *pixg,
325  l_int32 sx,
326  l_int32 sy,
327  l_int32 thresh,
328  l_int32 mincount,
329  l_int32 bgval,
330  l_int32 smoothx,
331  l_int32 smoothy)
332 {
333 l_int32 d, allfg;
334 PIX *pixm, *pixmi, *pixd;
335 PIX *pixmr, *pixmg, *pixmb, *pixmri, *pixmgi, *pixmbi;
336 
337  PROCNAME("pixBackgroundNorm");
338 
339  if (!pixs)
340  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
341  d = pixGetDepth(pixs);
342  if (d != 8 && d != 32)
343  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
344  if (sx < 4 || sy < 4)
345  return (PIX *)ERROR_PTR("sx and sy must be >= 4", procName, NULL);
346  if (mincount > sx * sy) {
347  L_WARNING("mincount too large for tile size\n", procName);
348  mincount = (sx * sy) / 3;
349  }
350 
351  /* If pixim exists, verify that it is not all foreground. */
352  if (pixim) {
353  pixInvert(pixim, pixim);
354  pixZero(pixim, &allfg);
355  pixInvert(pixim, pixim);
356  if (allfg)
357  return (PIX *)ERROR_PTR("pixim all foreground", procName, NULL);
358  }
359 
360  pixd = NULL;
361  if (d == 8) {
362  pixm = NULL;
363  pixGetBackgroundGrayMap(pixs, pixim, sx, sy, thresh, mincount, &pixm);
364  if (!pixm) {
365  L_WARNING("map not made; return a copy of the source\n", procName);
366  return pixCopy(NULL, pixs);
367  }
368 
369  pixmi = pixGetInvBackgroundMap(pixm, bgval, smoothx, smoothy);
370  if (!pixmi) {
371  L_WARNING("pixmi not made; return a copy of source\n", procName);
372  pixDestroy(&pixm);
373  return pixCopy(NULL, pixs);
374  } else {
375  pixd = pixApplyInvBackgroundGrayMap(pixs, pixmi, sx, sy);
376  }
377 
378  pixDestroy(&pixm);
379  pixDestroy(&pixmi);
380  }
381  else {
382  pixmr = pixmg = pixmb = NULL;
383  pixGetBackgroundRGBMap(pixs, pixim, pixg, sx, sy, thresh,
384  mincount, &pixmr, &pixmg, &pixmb);
385  if (!pixmr || !pixmg || !pixmb) {
386  pixDestroy(&pixmr);
387  pixDestroy(&pixmg);
388  pixDestroy(&pixmb);
389  L_WARNING("map not made; return a copy of the source\n", procName);
390  return pixCopy(NULL, pixs);
391  }
392 
393  pixmri = pixGetInvBackgroundMap(pixmr, bgval, smoothx, smoothy);
394  pixmgi = pixGetInvBackgroundMap(pixmg, bgval, smoothx, smoothy);
395  pixmbi = pixGetInvBackgroundMap(pixmb, bgval, smoothx, smoothy);
396  if (!pixmri || !pixmgi || !pixmbi) {
397  L_WARNING("not all pixm*i are made; return src copy\n", procName);
398  pixd = pixCopy(NULL, pixs);
399  } else {
400  pixd = pixApplyInvBackgroundRGBMap(pixs, pixmri, pixmgi, pixmbi,
401  sx, sy);
402  }
403 
404  pixDestroy(&pixmr);
405  pixDestroy(&pixmg);
406  pixDestroy(&pixmb);
407  pixDestroy(&pixmri);
408  pixDestroy(&pixmgi);
409  pixDestroy(&pixmbi);
410  }
411 
412  if (!pixd)
413  ERROR_PTR("pixd not made", procName, NULL);
414  pixCopyResolution(pixd, pixs);
415  return pixd;
416 }
417 
418 
458 PIX *
460  PIX *pixim,
461  l_int32 reduction,
462  l_int32 size,
463  l_int32 bgval)
464 {
465 l_int32 d, allfg;
466 PIX *pixm, *pixmi, *pixd;
467 PIX *pixmr, *pixmg, *pixmb, *pixmri, *pixmgi, *pixmbi;
468 
469  PROCNAME("pixBackgroundNormMorph");
470 
471  if (!pixs)
472  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
473  d = pixGetDepth(pixs);
474  if (d != 8 && d != 32)
475  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
476  if (reduction < 2 || reduction > 16)
477  return (PIX *)ERROR_PTR("reduction must be between 2 and 16",
478  procName, NULL);
479 
480  /* If pixim exists, verify that it is not all foreground. */
481  if (pixim) {
482  pixInvert(pixim, pixim);
483  pixZero(pixim, &allfg);
484  pixInvert(pixim, pixim);
485  if (allfg)
486  return (PIX *)ERROR_PTR("pixim all foreground", procName, NULL);
487  }
488 
489  pixd = NULL;
490  if (d == 8) {
491  pixGetBackgroundGrayMapMorph(pixs, pixim, reduction, size, &pixm);
492  if (!pixm)
493  return (PIX *)ERROR_PTR("pixm not made", procName, NULL);
494  pixmi = pixGetInvBackgroundMap(pixm, bgval, 0, 0);
495  if (!pixmi)
496  ERROR_PTR("pixmi not made", procName, NULL);
497  else
498  pixd = pixApplyInvBackgroundGrayMap(pixs, pixmi,
499  reduction, reduction);
500  pixDestroy(&pixm);
501  pixDestroy(&pixmi);
502  }
503  else { /* d == 32 */
504  pixmr = pixmg = pixmb = NULL;
505  pixGetBackgroundRGBMapMorph(pixs, pixim, reduction, size,
506  &pixmr, &pixmg, &pixmb);
507  if (!pixmr || !pixmg || !pixmb) {
508  pixDestroy(&pixmr);
509  pixDestroy(&pixmg);
510  pixDestroy(&pixmb);
511  return (PIX *)ERROR_PTR("not all pixm*", procName, NULL);
512  }
513 
514  pixmri = pixGetInvBackgroundMap(pixmr, bgval, 0, 0);
515  pixmgi = pixGetInvBackgroundMap(pixmg, bgval, 0, 0);
516  pixmbi = pixGetInvBackgroundMap(pixmb, bgval, 0, 0);
517  if (!pixmri || !pixmgi || !pixmbi)
518  ERROR_PTR("not all pixm*i are made", procName, NULL);
519  else
520  pixd = pixApplyInvBackgroundRGBMap(pixs, pixmri, pixmgi, pixmbi,
521  reduction, reduction);
522 
523  pixDestroy(&pixmr);
524  pixDestroy(&pixmg);
525  pixDestroy(&pixmb);
526  pixDestroy(&pixmri);
527  pixDestroy(&pixmgi);
528  pixDestroy(&pixmbi);
529  }
530 
531  if (!pixd)
532  ERROR_PTR("pixd not made", procName, NULL);
533  pixCopyResolution(pixd, pixs);
534  return pixd;
535 }
536 
537 
538 /*-------------------------------------------------------------------------*
539  * Arrays of inverted background values for normalization *
540  *-------------------------------------------------------------------------*
541  * Notes for these four functions: *
542  * (1) They are useful if you need to save the actual mapping array. *
543  * (2) They could be used in the top-level functions but are *
544  * not because their use makes those functions less clear. *
545  * (3) Each component in the input pixs generates a 16 bpp pix array. *
546  *-------------------------------------------------------------------------*/
569 l_ok
571  PIX *pixim,
572  l_int32 sx,
573  l_int32 sy,
574  l_int32 thresh,
575  l_int32 mincount,
576  l_int32 bgval,
577  l_int32 smoothx,
578  l_int32 smoothy,
579  PIX **ppixd)
580 {
581 l_int32 allfg;
582 PIX *pixm;
583 
584  PROCNAME("pixBackgroundNormGrayArray");
585 
586  if (!ppixd)
587  return ERROR_INT("&pixd not defined", procName, 1);
588  *ppixd = NULL;
589  if (!pixs || pixGetDepth(pixs) != 8)
590  return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
591  if (pixGetColormap(pixs))
592  return ERROR_INT("pixs is colormapped", procName, 1);
593  if (pixim && pixGetDepth(pixim) != 1)
594  return ERROR_INT("pixim not 1 bpp", procName, 1);
595  if (sx < 4 || sy < 4)
596  return ERROR_INT("sx and sy must be >= 4", procName, 1);
597  if (mincount > sx * sy) {
598  L_WARNING("mincount too large for tile size\n", procName);
599  mincount = (sx * sy) / 3;
600  }
601 
602  /* If pixim exists, verify that it is not all foreground. */
603  if (pixim) {
604  pixInvert(pixim, pixim);
605  pixZero(pixim, &allfg);
606  pixInvert(pixim, pixim);
607  if (allfg)
608  return ERROR_INT("pixim all foreground", procName, 1);
609  }
610 
611  pixGetBackgroundGrayMap(pixs, pixim, sx, sy, thresh, mincount, &pixm);
612  if (!pixm)
613  return ERROR_INT("pixm not made", procName, 1);
614  *ppixd = pixGetInvBackgroundMap(pixm, bgval, smoothx, smoothy);
615  pixCopyResolution(*ppixd, pixs);
616  pixDestroy(&pixm);
617  return 0;
618 }
619 
620 
646 l_ok
648  PIX *pixim,
649  PIX *pixg,
650  l_int32 sx,
651  l_int32 sy,
652  l_int32 thresh,
653  l_int32 mincount,
654  l_int32 bgval,
655  l_int32 smoothx,
656  l_int32 smoothy,
657  PIX **ppixr,
658  PIX **ppixg,
659  PIX **ppixb)
660 {
661 l_int32 allfg;
662 PIX *pixmr, *pixmg, *pixmb;
663 
664  PROCNAME("pixBackgroundNormRGBArrays");
665 
666  if (!ppixr || !ppixg || !ppixb)
667  return ERROR_INT("&pixr, &pixg, &pixb not all defined", procName, 1);
668  *ppixr = *ppixg = *ppixb = NULL;
669  if (!pixs)
670  return ERROR_INT("pixs not defined", procName, 1);
671  if (pixGetDepth(pixs) != 32)
672  return ERROR_INT("pixs not 32 bpp", procName, 1);
673  if (pixim && pixGetDepth(pixim) != 1)
674  return ERROR_INT("pixim not 1 bpp", procName, 1);
675  if (sx < 4 || sy < 4)
676  return ERROR_INT("sx and sy must be >= 4", procName, 1);
677  if (mincount > sx * sy) {
678  L_WARNING("mincount too large for tile size\n", procName);
679  mincount = (sx * sy) / 3;
680  }
681 
682  /* If pixim exists, verify that it is not all foreground. */
683  if (pixim) {
684  pixInvert(pixim, pixim);
685  pixZero(pixim, &allfg);
686  pixInvert(pixim, pixim);
687  if (allfg)
688  return ERROR_INT("pixim all foreground", procName, 1);
689  }
690 
691  pixGetBackgroundRGBMap(pixs, pixim, pixg, sx, sy, thresh, mincount,
692  &pixmr, &pixmg, &pixmb);
693  if (!pixmr || !pixmg || !pixmb) {
694  pixDestroy(&pixmr);
695  pixDestroy(&pixmg);
696  pixDestroy(&pixmb);
697  return ERROR_INT("not all pixm* made", procName, 1);
698  }
699 
700  *ppixr = pixGetInvBackgroundMap(pixmr, bgval, smoothx, smoothy);
701  *ppixg = pixGetInvBackgroundMap(pixmg, bgval, smoothx, smoothy);
702  *ppixb = pixGetInvBackgroundMap(pixmb, bgval, smoothx, smoothy);
703  pixDestroy(&pixmr);
704  pixDestroy(&pixmg);
705  pixDestroy(&pixmb);
706  return 0;
707 }
708 
709 
729 l_ok
731  PIX *pixim,
732  l_int32 reduction,
733  l_int32 size,
734  l_int32 bgval,
735  PIX **ppixd)
736 {
737 l_int32 allfg;
738 PIX *pixm;
739 
740  PROCNAME("pixBackgroundNormGrayArrayMorph");
741 
742  if (!ppixd)
743  return ERROR_INT("&pixd not defined", procName, 1);
744  *ppixd = NULL;
745  if (!pixs)
746  return ERROR_INT("pixs not defined", procName, 1);
747  if (pixGetDepth(pixs) != 8)
748  return ERROR_INT("pixs not 8 bpp", procName, 1);
749  if (pixim && pixGetDepth(pixim) != 1)
750  return ERROR_INT("pixim not 1 bpp", procName, 1);
751  if (reduction < 2 || reduction > 16)
752  return ERROR_INT("reduction must be between 2 and 16", procName, 1);
753 
754  /* If pixim exists, verify that it is not all foreground. */
755  if (pixim) {
756  pixInvert(pixim, pixim);
757  pixZero(pixim, &allfg);
758  pixInvert(pixim, pixim);
759  if (allfg)
760  return ERROR_INT("pixim all foreground", procName, 1);
761  }
762 
763  pixGetBackgroundGrayMapMorph(pixs, pixim, reduction, size, &pixm);
764  if (!pixm)
765  return ERROR_INT("pixm not made", procName, 1);
766  *ppixd = pixGetInvBackgroundMap(pixm, bgval, 0, 0);
767  pixCopyResolution(*ppixd, pixs);
768  pixDestroy(&pixm);
769  return 0;
770 }
771 
772 
794 l_ok
796  PIX *pixim,
797  l_int32 reduction,
798  l_int32 size,
799  l_int32 bgval,
800  PIX **ppixr,
801  PIX **ppixg,
802  PIX **ppixb)
803 {
804 l_int32 allfg;
805 PIX *pixmr, *pixmg, *pixmb;
806 
807  PROCNAME("pixBackgroundNormRGBArraysMorph");
808 
809  if (!ppixr || !ppixg || !ppixb)
810  return ERROR_INT("&pixr, &pixg, &pixb not all defined", procName, 1);
811  *ppixr = *ppixg = *ppixb = NULL;
812  if (!pixs)
813  return ERROR_INT("pixs not defined", procName, 1);
814  if (pixGetDepth(pixs) != 32)
815  return ERROR_INT("pixs not 32 bpp", procName, 1);
816  if (pixim && pixGetDepth(pixim) != 1)
817  return ERROR_INT("pixim not 1 bpp", procName, 1);
818  if (reduction < 2 || reduction > 16)
819  return ERROR_INT("reduction must be between 2 and 16", procName, 1);
820 
821  /* If pixim exists, verify that it is not all foreground. */
822  if (pixim) {
823  pixInvert(pixim, pixim);
824  pixZero(pixim, &allfg);
825  pixInvert(pixim, pixim);
826  if (allfg)
827  return ERROR_INT("pixim all foreground", procName, 1);
828  }
829 
830  pixGetBackgroundRGBMapMorph(pixs, pixim, reduction, size,
831  &pixmr, &pixmg, &pixmb);
832  if (!pixmr || !pixmg || !pixmb) {
833  pixDestroy(&pixmr);
834  pixDestroy(&pixmg);
835  pixDestroy(&pixmb);
836  return ERROR_INT("not all pixm* made", procName, 1);
837  }
838 
839  *ppixr = pixGetInvBackgroundMap(pixmr, bgval, 0, 0);
840  *ppixg = pixGetInvBackgroundMap(pixmg, bgval, 0, 0);
841  *ppixb = pixGetInvBackgroundMap(pixmb, bgval, 0, 0);
842  pixDestroy(&pixmr);
843  pixDestroy(&pixmg);
844  pixDestroy(&pixmb);
845  return 0;
846 }
847 
848 
849 /*------------------------------------------------------------------*
850  * Measurement of local background *
851  *------------------------------------------------------------------*/
871 l_ok
873  PIX *pixim,
874  l_int32 sx,
875  l_int32 sy,
876  l_int32 thresh,
877  l_int32 mincount,
878  PIX **ppixd)
879 {
880 l_int32 w, h, wd, hd, wim, him, wpls, wplim, wpld, wplf;
881 l_int32 xim, yim, delx, nx, ny, i, j, k, m;
882 l_int32 count, sum, val8;
883 l_int32 empty, fgpixels;
884 l_uint32 *datas, *dataim, *datad, *dataf, *lines, *lineim, *lined, *linef;
885 l_float32 scalex, scaley;
886 PIX *pixd, *piximi, *pixb, *pixf, *pixims;
887 
888  PROCNAME("pixGetBackgroundGrayMap");
889 
890  if (!ppixd)
891  return ERROR_INT("&pixd not defined", procName, 1);
892  *ppixd = NULL;
893  if (!pixs || pixGetDepth(pixs) != 8)
894  return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
895  if (pixGetColormap(pixs))
896  return ERROR_INT("pixs is colormapped", procName, 1);
897  if (pixim && pixGetDepth(pixim) != 1)
898  return ERROR_INT("pixim not 1 bpp", procName, 1);
899  if (sx < 4 || sy < 4)
900  return ERROR_INT("sx and sy must be >= 4", procName, 1);
901  if (mincount > sx * sy) {
902  L_WARNING("mincount too large for tile size\n", procName);
903  mincount = (sx * sy) / 3;
904  }
905 
906  /* Evaluate the 'image' mask, pixim, and make sure
907  * it is not all fg. */
908  fgpixels = 0; /* boolean for existence of fg pixels in the image mask. */
909  if (pixim) {
910  piximi = pixInvert(NULL, pixim); /* set non-'image' pixels to 1 */
911  pixZero(piximi, &empty);
912  pixDestroy(&piximi);
913  if (empty)
914  return ERROR_INT("pixim all fg; no background", procName, 1);
915  pixZero(pixim, &empty);
916  if (!empty) /* there are fg pixels in pixim */
917  fgpixels = 1;
918  }
919 
920  /* Generate the foreground mask, pixf, which is at
921  * full resolution. These pixels will be ignored when
922  * computing the background values. */
923  pixb = pixThresholdToBinary(pixs, thresh);
924  pixf = pixMorphSequence(pixb, "d7.1 + d1.7", 0);
925  pixDestroy(&pixb);
926  if (!pixf)
927  return ERROR_INT("pixf not made", procName, 1);
928 
929 
930  /* ------------- Set up the output map pixd --------------- */
931  /* Generate pixd, which is reduced by the factors (sx, sy). */
932  w = pixGetWidth(pixs);
933  h = pixGetHeight(pixs);
934  wd = (w + sx - 1) / sx;
935  hd = (h + sy - 1) / sy;
936  pixd = pixCreate(wd, hd, 8);
937 
938  /* Note: we only compute map values in tiles that are complete.
939  * In general, tiles at right and bottom edges will not be
940  * complete, and we must fill them in later. */
941  nx = w / sx;
942  ny = h / sy;
943  wpls = pixGetWpl(pixs);
944  datas = pixGetData(pixs);
945  wpld = pixGetWpl(pixd);
946  datad = pixGetData(pixd);
947  wplf = pixGetWpl(pixf);
948  dataf = pixGetData(pixf);
949  for (i = 0; i < ny; i++) {
950  lines = datas + sy * i * wpls;
951  linef = dataf + sy * i * wplf;
952  lined = datad + i * wpld;
953  for (j = 0; j < nx; j++) {
954  delx = j * sx;
955  sum = 0;
956  count = 0;
957  for (k = 0; k < sy; k++) {
958  for (m = 0; m < sx; m++) {
959  if (GET_DATA_BIT(linef + k * wplf, delx + m) == 0) {
960  sum += GET_DATA_BYTE(lines + k * wpls, delx + m);
961  count++;
962  }
963  }
964  }
965  if (count >= mincount) {
966  val8 = sum / count;
967  SET_DATA_BYTE(lined, j, val8);
968  }
969  }
970  }
971  pixDestroy(&pixf);
972 
973  /* If there is an optional mask with fg pixels, erase the previous
974  * calculation for the corresponding map pixels, setting the
975  * map values to 0. Then, when all the map holes are filled,
976  * these erased pixels will be set by the surrounding map values.
977  *
978  * The calculation here is relatively efficient: for each pixel
979  * in pixd (which corresponds to a tile of mask pixels in pixim)
980  * we look only at the pixel in pixim that is at the center
981  * of the tile. If the mask pixel is ON, we reset the map
982  * pixel in pixd to 0, so that it can later be filled in. */
983  pixims = NULL;
984  if (pixim && fgpixels) {
985  wim = pixGetWidth(pixim);
986  him = pixGetHeight(pixim);
987  dataim = pixGetData(pixim);
988  wplim = pixGetWpl(pixim);
989  for (i = 0; i < ny; i++) {
990  yim = i * sy + sy / 2;
991  if (yim >= him)
992  break;
993  lineim = dataim + yim * wplim;
994  for (j = 0; j < nx; j++) {
995  xim = j * sx + sx / 2;
996  if (xim >= wim)
997  break;
998  if (GET_DATA_BIT(lineim, xim))
999  pixSetPixel(pixd, j, i, 0);
1000  }
1001  }
1002  }
1003 
1004  /* Fill all the holes in the map. */
1005  if (pixFillMapHoles(pixd, nx, ny, L_FILL_BLACK)) {
1006  pixDestroy(&pixd);
1007  L_WARNING("can't make the map\n", procName);
1008  return 1;
1009  }
1010 
1011  /* Finally, for each connected region corresponding to the
1012  * 'image' mask, reset all pixels to their average value.
1013  * Each of these components represents an image (or part of one)
1014  * in the input, and this smooths the background values
1015  * in each of these regions. */
1016  if (pixim && fgpixels) {
1017  scalex = 1. / (l_float32)sx;
1018  scaley = 1. / (l_float32)sy;
1019  pixims = pixScaleBySampling(pixim, scalex, scaley);
1020  pixSmoothConnectedRegions(pixd, pixims, 2);
1021  pixDestroy(&pixims);
1022  }
1023 
1024  *ppixd = pixd;
1025  pixCopyResolution(*ppixd, pixs);
1026  return 0;
1027 }
1028 
1029 
1053 l_ok
1055  PIX *pixim,
1056  PIX *pixg,
1057  l_int32 sx,
1058  l_int32 sy,
1059  l_int32 thresh,
1060  l_int32 mincount,
1061  PIX **ppixmr,
1062  PIX **ppixmg,
1063  PIX **ppixmb)
1064 {
1065 l_int32 w, h, wm, hm, wim, him, wpls, wplim, wplf;
1066 l_int32 xim, yim, delx, nx, ny, i, j, k, m;
1067 l_int32 count, rsum, gsum, bsum, rval, gval, bval;
1068 l_int32 empty, fgpixels;
1069 l_uint32 pixel;
1070 l_uint32 *datas, *dataim, *dataf, *lines, *lineim, *linef;
1071 l_float32 scalex, scaley;
1072 PIX *piximi, *pixgc, *pixb, *pixf, *pixims;
1073 PIX *pixmr, *pixmg, *pixmb;
1074 
1075  PROCNAME("pixGetBackgroundRGBMap");
1076 
1077  if (!ppixmr || !ppixmg || !ppixmb)
1078  return ERROR_INT("&pixm* not all defined", procName, 1);
1079  *ppixmr = *ppixmg = *ppixmb = NULL;
1080  if (!pixs)
1081  return ERROR_INT("pixs not defined", procName, 1);
1082  if (pixGetDepth(pixs) != 32)
1083  return ERROR_INT("pixs not 32 bpp", procName, 1);
1084  if (pixim && pixGetDepth(pixim) != 1)
1085  return ERROR_INT("pixim not 1 bpp", procName, 1);
1086  if (sx < 4 || sy < 4)
1087  return ERROR_INT("sx and sy must be >= 4", procName, 1);
1088  if (mincount > sx * sy) {
1089  L_WARNING("mincount too large for tile size\n", procName);
1090  mincount = (sx * sy) / 3;
1091  }
1092 
1093  /* Evaluate the mask pixim and make sure it is not all foreground */
1094  fgpixels = 0; /* boolean for existence of fg mask pixels */
1095  if (pixim) {
1096  piximi = pixInvert(NULL, pixim); /* set non-'image' pixels to 1 */
1097  pixZero(piximi, &empty);
1098  pixDestroy(&piximi);
1099  if (empty)
1100  return ERROR_INT("pixim all fg; no background", procName, 1);
1101  pixZero(pixim, &empty);
1102  if (!empty) /* there are fg pixels in pixim */
1103  fgpixels = 1;
1104  }
1105 
1106  /* Generate the foreground mask. These pixels will be
1107  * ignored when computing the background values. */
1108  if (pixg) /* use the input grayscale version if it is provided */
1109  pixgc = pixClone(pixg);
1110  else
1111  pixgc = pixConvertRGBToGrayFast(pixs);
1112  pixb = pixThresholdToBinary(pixgc, thresh);
1113  pixf = pixMorphSequence(pixb, "d7.1 + d1.7", 0);
1114  pixDestroy(&pixgc);
1115  pixDestroy(&pixb);
1116 
1117  /* Generate the output mask images */
1118  w = pixGetWidth(pixs);
1119  h = pixGetHeight(pixs);
1120  wm = (w + sx - 1) / sx;
1121  hm = (h + sy - 1) / sy;
1122  pixmr = pixCreate(wm, hm, 8);
1123  pixmg = pixCreate(wm, hm, 8);
1124  pixmb = pixCreate(wm, hm, 8);
1125 
1126  /* ------------- Set up the mapping images --------------- */
1127  /* Note: we only compute map values in tiles that are complete.
1128  * In general, tiles at right and bottom edges will not be
1129  * complete, and we must fill them in later. */
1130  nx = w / sx;
1131  ny = h / sy;
1132  wpls = pixGetWpl(pixs);
1133  datas = pixGetData(pixs);
1134  wplf = pixGetWpl(pixf);
1135  dataf = pixGetData(pixf);
1136  for (i = 0; i < ny; i++) {
1137  lines = datas + sy * i * wpls;
1138  linef = dataf + sy * i * wplf;
1139  for (j = 0; j < nx; j++) {
1140  delx = j * sx;
1141  rsum = gsum = bsum = 0;
1142  count = 0;
1143  for (k = 0; k < sy; k++) {
1144  for (m = 0; m < sx; m++) {
1145  if (GET_DATA_BIT(linef + k * wplf, delx + m) == 0) {
1146  pixel = *(lines + k * wpls + delx + m);
1147  rsum += (pixel >> 24);
1148  gsum += ((pixel >> 16) & 0xff);
1149  bsum += ((pixel >> 8) & 0xff);
1150  count++;
1151  }
1152  }
1153  }
1154  if (count >= mincount) {
1155  rval = rsum / count;
1156  gval = gsum / count;
1157  bval = bsum / count;
1158  pixSetPixel(pixmr, j, i, rval);
1159  pixSetPixel(pixmg, j, i, gval);
1160  pixSetPixel(pixmb, j, i, bval);
1161  }
1162  }
1163  }
1164  pixDestroy(&pixf);
1165 
1166  /* If there is an optional mask with fg pixels, erase the previous
1167  * calculation for the corresponding map pixels, setting the
1168  * map values in each of the 3 color maps to 0. Then, when
1169  * all the map holes are filled, these erased pixels will
1170  * be set by the surrounding map values. */
1171  if (pixim) {
1172  wim = pixGetWidth(pixim);
1173  him = pixGetHeight(pixim);
1174  dataim = pixGetData(pixim);
1175  wplim = pixGetWpl(pixim);
1176  for (i = 0; i < ny; i++) {
1177  yim = i * sy + sy / 2;
1178  if (yim >= him)
1179  break;
1180  lineim = dataim + yim * wplim;
1181  for (j = 0; j < nx; j++) {
1182  xim = j * sx + sx / 2;
1183  if (xim >= wim)
1184  break;
1185  if (GET_DATA_BIT(lineim, xim)) {
1186  pixSetPixel(pixmr, j, i, 0);
1187  pixSetPixel(pixmg, j, i, 0);
1188  pixSetPixel(pixmb, j, i, 0);
1189  }
1190  }
1191  }
1192  }
1193 
1194  /* ----------------- Now fill in the holes ----------------------- */
1195  if (pixFillMapHoles(pixmr, nx, ny, L_FILL_BLACK) ||
1196  pixFillMapHoles(pixmg, nx, ny, L_FILL_BLACK) ||
1197  pixFillMapHoles(pixmb, nx, ny, L_FILL_BLACK)) {
1198  pixDestroy(&pixmr);
1199  pixDestroy(&pixmg);
1200  pixDestroy(&pixmb);
1201  L_WARNING("can't make the maps\n", procName);
1202  return 1;
1203  }
1204 
1205  /* Finally, for each connected region corresponding to the
1206  * fg mask, reset all pixels to their average value. */
1207  if (pixim && fgpixels) {
1208  scalex = 1. / (l_float32)sx;
1209  scaley = 1. / (l_float32)sy;
1210  pixims = pixScaleBySampling(pixim, scalex, scaley);
1211  pixSmoothConnectedRegions(pixmr, pixims, 2);
1212  pixSmoothConnectedRegions(pixmg, pixims, 2);
1213  pixSmoothConnectedRegions(pixmb, pixims, 2);
1214  pixDestroy(&pixims);
1215  }
1216 
1217  *ppixmr = pixmr;
1218  *ppixmg = pixmg;
1219  *ppixmb = pixmb;
1220  pixCopyResolution(*ppixmr, pixs);
1221  pixCopyResolution(*ppixmg, pixs);
1222  pixCopyResolution(*ppixmb, pixs);
1223  return 0;
1224 }
1225 
1226 
1238 l_ok
1240  PIX *pixim,
1241  l_int32 reduction,
1242  l_int32 size,
1243  PIX **ppixm)
1244 {
1245 l_int32 nx, ny, empty, fgpixels;
1246 l_float32 scale;
1247 PIX *pixm, *pix1, *pix2, *pix3, *pixims;
1248 
1249  PROCNAME("pixGetBackgroundGrayMapMorph");
1250 
1251  if (!ppixm)
1252  return ERROR_INT("&pixm not defined", procName, 1);
1253  *ppixm = NULL;
1254  if (!pixs || pixGetDepth(pixs) != 8)
1255  return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
1256  if (pixGetColormap(pixs))
1257  return ERROR_INT("pixs is colormapped", procName, 1);
1258  if (pixim && pixGetDepth(pixim) != 1)
1259  return ERROR_INT("pixim not 1 bpp", procName, 1);
1260 
1261  /* Evaluate the mask pixim and make sure it is not all foreground. */
1262  fgpixels = 0; /* boolean for existence of fg mask pixels */
1263  if (pixim) {
1264  pixInvert(pixim, pixim); /* set background pixels to 1 */
1265  pixZero(pixim, &empty);
1266  if (empty)
1267  return ERROR_INT("pixim all fg; no background", procName, 1);
1268  pixInvert(pixim, pixim); /* revert to original mask */
1269  pixZero(pixim, &empty);
1270  if (!empty) /* there are fg pixels in pixim */
1271  fgpixels = 1;
1272  }
1273 
1274  /* Downscale as requested and do the closing to get the background. */
1275  scale = 1. / (l_float32)reduction;
1276  pix1 = pixScaleBySampling(pixs, scale, scale);
1277  pix2 = pixCloseGray(pix1, size, size);
1278  pix3 = pixExtendByReplication(pix2, 1, 1);
1279  pixDestroy(&pix1);
1280  pixDestroy(&pix2);
1281 
1282  /* Downscale the image mask, if any, and remove it from the
1283  * background. These pixels will be filled in (twice). */
1284  pixims = NULL;
1285  if (pixim) {
1286  pixims = pixScale(pixim, scale, scale);
1287  pixm = pixConvertTo8(pixims, FALSE);
1288  pixAnd(pixm, pixm, pix3);
1289  }
1290  else
1291  pixm = pixClone(pix3);
1292  pixDestroy(&pix3);
1293 
1294  /* Fill all the holes in the map. */
1295  nx = pixGetWidth(pixs) / reduction;
1296  ny = pixGetHeight(pixs) / reduction;
1297  if (pixFillMapHoles(pixm, nx, ny, L_FILL_BLACK)) {
1298  pixDestroy(&pixm);
1299  pixDestroy(&pixims);
1300  L_WARNING("can't make the map\n", procName);
1301  return 1;
1302  }
1303 
1304  /* Finally, for each connected region corresponding to the
1305  * fg mask, reset all pixels to their average value. */
1306  if (pixim && fgpixels)
1307  pixSmoothConnectedRegions(pixm, pixims, 2);
1308  pixDestroy(&pixims);
1309 
1310  *ppixm = pixm;
1311  pixCopyResolution(*ppixm, pixs);
1312  return 0;
1313 }
1314 
1315 
1329 l_ok
1331  PIX *pixim,
1332  l_int32 reduction,
1333  l_int32 size,
1334  PIX **ppixmr,
1335  PIX **ppixmg,
1336  PIX **ppixmb)
1337 {
1338 l_int32 nx, ny, empty, fgpixels;
1339 l_float32 scale;
1340 PIX *pixm, *pixmr, *pixmg, *pixmb, *pix1, *pix2, *pix3, *pixims;
1341 
1342  PROCNAME("pixGetBackgroundRGBMapMorph");
1343 
1344  if (!ppixmr || !ppixmg || !ppixmb)
1345  return ERROR_INT("&pixm* not all defined", procName, 1);
1346  *ppixmr = *ppixmg = *ppixmb = NULL;
1347  if (!pixs)
1348  return ERROR_INT("pixs not defined", procName, 1);
1349  if (pixGetDepth(pixs) != 32)
1350  return ERROR_INT("pixs not 32 bpp", procName, 1);
1351  if (pixim && pixGetDepth(pixim) != 1)
1352  return ERROR_INT("pixim not 1 bpp", procName, 1);
1353 
1354  /* Evaluate the mask pixim and make sure it is not all foreground. */
1355  fgpixels = 0; /* boolean for existence of fg mask pixels */
1356  if (pixim) {
1357  pixInvert(pixim, pixim); /* set background pixels to 1 */
1358  pixZero(pixim, &empty);
1359  if (empty)
1360  return ERROR_INT("pixim all fg; no background", procName, 1);
1361  pixInvert(pixim, pixim); /* revert to original mask */
1362  pixZero(pixim, &empty);
1363  if (!empty) /* there are fg pixels in pixim */
1364  fgpixels = 1;
1365  }
1366 
1367  /* Generate an 8 bpp version of the image mask, if it exists */
1368  scale = 1. / (l_float32)reduction;
1369  pixims = NULL;
1370  pixm = NULL;
1371  if (pixim) {
1372  pixims = pixScale(pixim, scale, scale);
1373  pixm = pixConvertTo8(pixims, FALSE);
1374  }
1375 
1376  /* Downscale as requested and do the closing to get the background.
1377  * Then remove the image mask pixels from the background. They
1378  * will be filled in (twice) later. Do this for all 3 components. */
1379  pix1 = pixScaleRGBToGrayFast(pixs, reduction, COLOR_RED);
1380  pix2 = pixCloseGray(pix1, size, size);
1381  pix3 = pixExtendByReplication(pix2, 1, 1);
1382  if (pixim)
1383  pixmr = pixAnd(NULL, pixm, pix3);
1384  else
1385  pixmr = pixClone(pix3);
1386  pixDestroy(&pix1);
1387  pixDestroy(&pix2);
1388  pixDestroy(&pix3);
1389 
1390  pix1 = pixScaleRGBToGrayFast(pixs, reduction, COLOR_GREEN);
1391  pix2 = pixCloseGray(pix1, size, size);
1392  pix3 = pixExtendByReplication(pix2, 1, 1);
1393  if (pixim)
1394  pixmg = pixAnd(NULL, pixm, pix3);
1395  else
1396  pixmg = pixClone(pix3);
1397  pixDestroy(&pix1);
1398  pixDestroy(&pix2);
1399  pixDestroy(&pix3);
1400 
1401  pix1 = pixScaleRGBToGrayFast(pixs, reduction, COLOR_BLUE);
1402  pix2 = pixCloseGray(pix1, size, size);
1403  pix3 = pixExtendByReplication(pix2, 1, 1);
1404  if (pixim)
1405  pixmb = pixAnd(NULL, pixm, pix3);
1406  else
1407  pixmb = pixClone(pix3);
1408  pixDestroy(&pixm);
1409  pixDestroy(&pix1);
1410  pixDestroy(&pix2);
1411  pixDestroy(&pix3);
1412 
1413  /* Fill all the holes in the three maps. */
1414  nx = pixGetWidth(pixs) / reduction;
1415  ny = pixGetHeight(pixs) / reduction;
1416  if (pixFillMapHoles(pixmr, nx, ny, L_FILL_BLACK) ||
1417  pixFillMapHoles(pixmg, nx, ny, L_FILL_BLACK) ||
1418  pixFillMapHoles(pixmb, nx, ny, L_FILL_BLACK)) {
1419  pixDestroy(&pixmr);
1420  pixDestroy(&pixmg);
1421  pixDestroy(&pixmb);
1422  pixDestroy(&pixims);
1423  L_WARNING("can't make the maps\n", procName);
1424  return 1;
1425  }
1426 
1427  /* Finally, for each connected region corresponding to the
1428  * fg mask in each component, reset all pixels to their
1429  * average value. */
1430  if (pixim && fgpixels) {
1431  pixSmoothConnectedRegions(pixmr, pixims, 2);
1432  pixSmoothConnectedRegions(pixmg, pixims, 2);
1433  pixSmoothConnectedRegions(pixmb, pixims, 2);
1434  pixDestroy(&pixims);
1435  }
1436 
1437  *ppixmr = pixmr;
1438  *ppixmg = pixmg;
1439  *ppixmb = pixmb;
1440  pixCopyResolution(*ppixmr, pixs);
1441  pixCopyResolution(*ppixmg, pixs);
1442  pixCopyResolution(*ppixmb, pixs);
1443  return 0;
1444 }
1445 
1446 
1483 l_ok
1485  l_int32 nx,
1486  l_int32 ny,
1487  l_int32 filltype)
1488 {
1489 l_int32 w, h, y, nmiss, goodcol, i, j, found, ival, valtest;
1490 l_uint32 val, lastval;
1491 NUMA *na; /* indicates if there is any data in the column */
1492 
1493  PROCNAME("pixFillMapHoles");
1494 
1495  if (!pix || pixGetDepth(pix) != 8)
1496  return ERROR_INT("pix not defined or not 8 bpp", procName, 1);
1497  if (pixGetColormap(pix))
1498  return ERROR_INT("pix is colormapped", procName, 1);
1499 
1500  /* ------------- Fill holes in the mapping image columns ----------- */
1501  pixGetDimensions(pix, &w, &h, NULL);
1502  na = numaCreate(0); /* holds flag for which columns have data */
1503  nmiss = 0;
1504  valtest = (filltype == L_FILL_WHITE) ? 255 : 0;
1505  for (j = 0; j < nx; j++) { /* do it by columns */
1506  found = FALSE;
1507  for (i = 0; i < ny; i++) {
1508  pixGetPixel(pix, j, i, &val);
1509  if (val != valtest) {
1510  y = i;
1511  found = TRUE;
1512  break;
1513  }
1514  }
1515  if (found == FALSE) {
1516  numaAddNumber(na, 0); /* no data in the column */
1517  nmiss++;
1518  }
1519  else {
1520  numaAddNumber(na, 1); /* data in the column */
1521  for (i = y - 1; i >= 0; i--) /* replicate upwards to top */
1522  pixSetPixel(pix, j, i, val);
1523  pixGetPixel(pix, j, 0, &lastval);
1524  for (i = 1; i < h; i++) { /* set going down to bottom */
1525  pixGetPixel(pix, j, i, &val);
1526  if (val == valtest)
1527  pixSetPixel(pix, j, i, lastval);
1528  else
1529  lastval = val;
1530  }
1531  }
1532  }
1533 
1534  if (nmiss == nx) { /* no data in any column! */
1535  numaDestroy(&na);
1536  L_WARNING("no bg found; no data in any column\n", procName);
1537  return 1;
1538  }
1539 
1540  /* ---------- Fill in missing columns by replication ----------- */
1541  if (nmiss > 0) { /* replicate columns */
1542  /* Find the first good column */
1543  goodcol = 0;
1544  for (j = 0; j < w; j++) {
1545  numaGetIValue(na, j, &ival);
1546  if (ival == 1) {
1547  goodcol = j;
1548  break;
1549  }
1550  }
1551  if (goodcol > 0) { /* copy cols backward */
1552  for (j = goodcol - 1; j >= 0; j--)
1553  pixRasterop(pix, j, 0, 1, h, PIX_SRC, pix, j + 1, 0);
1554  }
1555  for (j = goodcol + 1; j < w; j++) { /* copy cols forward */
1556  numaGetIValue(na, j, &ival);
1557  if (ival == 0) {
1558  /* Copy the column to the left of j */
1559  pixRasterop(pix, j, 0, 1, h, PIX_SRC, pix, j - 1, 0);
1560  }
1561  }
1562  }
1563  if (w > nx) { /* replicate the last column */
1564  pixRasterop(pix, w - 1, 0, 1, h, PIX_SRC, pix, w - 2, 0);
1565  }
1566 
1567  numaDestroy(&na);
1568  return 0;
1569 }
1570 
1571 
1585 PIX *
1587  l_int32 addw,
1588  l_int32 addh)
1589 {
1590 l_int32 w, h, i, j;
1591 l_uint32 val;
1592 PIX *pixd;
1593 
1594  PROCNAME("pixExtendByReplication");
1595 
1596  if (!pixs || pixGetDepth(pixs) != 8)
1597  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
1598 
1599  if (addw == 0 && addh == 0)
1600  return pixCopy(NULL, pixs);
1601 
1602  pixGetDimensions(pixs, &w, &h, NULL);
1603  if ((pixd = pixCreate(w + addw, h + addh, 8)) == NULL)
1604  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1605  pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
1606 
1607  if (addw > 0) {
1608  for (i = 0; i < h; i++) {
1609  pixGetPixel(pixd, w - 1, i, &val);
1610  for (j = 0; j < addw; j++)
1611  pixSetPixel(pixd, w + j, i, val);
1612  }
1613  }
1614 
1615  if (addh > 0) {
1616  for (j = 0; j < w + addw; j++) {
1617  pixGetPixel(pixd, j, h - 1, &val);
1618  for (i = 0; i < addh; i++)
1619  pixSetPixel(pixd, j, h + i, val);
1620  }
1621  }
1622 
1623  pixCopyResolution(pixd, pixs);
1624  return pixd;
1625 }
1626 
1627 
1648 l_ok
1650  PIX *pixm,
1651  l_int32 factor)
1652 {
1653 l_int32 empty, i, n, x, y;
1654 l_float32 aveval;
1655 BOXA *boxa;
1656 PIX *pixmc;
1657 PIXA *pixa;
1658 
1659  PROCNAME("pixSmoothConnectedRegions");
1660 
1661  if (!pixs || pixGetDepth(pixs) != 8)
1662  return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
1663  if (pixGetColormap(pixs))
1664  return ERROR_INT("pixs has colormap", procName, 1);
1665  if (!pixm) {
1666  L_INFO("pixm not defined\n", procName);
1667  return 0;
1668  }
1669  if (pixGetDepth(pixm) != 1)
1670  return ERROR_INT("pixm not 1 bpp", procName, 1);
1671  pixZero(pixm, &empty);
1672  if (empty) {
1673  L_INFO("pixm has no fg pixels; nothing to do\n", procName);
1674  return 0;
1675  }
1676 
1677  boxa = pixConnComp(pixm, &pixa, 8);
1678  n = boxaGetCount(boxa);
1679  for (i = 0; i < n; i++) {
1680  if ((pixmc = pixaGetPix(pixa, i, L_CLONE)) == NULL) {
1681  L_WARNING("missing pixmc!\n", procName);
1682  continue;
1683  }
1684  boxaGetBoxGeometry(boxa, i, &x, &y, NULL, NULL);
1685  pixGetAverageMasked(pixs, pixmc, x, y, factor, L_MEAN_ABSVAL, &aveval);
1686  pixPaintThroughMask(pixs, pixmc, x, y, (l_int32)aveval);
1687  pixDestroy(&pixmc);
1688  }
1689 
1690  boxaDestroy(&boxa);
1691  pixaDestroy(&pixa);
1692  return 0;
1693 }
1694 
1695 
1696 /*------------------------------------------------------------------*
1697  * Measurement of local foreground *
1698  *------------------------------------------------------------------*/
1699 #if 0 /* Not working properly: do not use */
1700 
1737 l_ok
1738 pixGetForegroundGrayMap(PIX *pixs,
1739  PIX *pixim,
1740  l_int32 sx,
1741  l_int32 sy,
1742  l_int32 thresh,
1743  PIX **ppixd)
1744 {
1745 l_int32 w, h, d, wd, hd;
1746 l_int32 empty, fgpixels;
1747 PIX *pixd, *piximi, *pixim2, *pixims, *pixs2, *pixb, *pixt1, *pixt2, *pixt3;
1748 
1749  PROCNAME("pixGetForegroundGrayMap");
1750 
1751  if (!ppixd)
1752  return ERROR_INT("&pixd not defined", procName, 1);
1753  *ppixd = NULL;
1754  if (!pixs)
1755  return ERROR_INT("pixs not defined", procName, 1);
1756  pixGetDimensions(pixs, &w, &h, &d);
1757  if (d != 8)
1758  return ERROR_INT("pixs not 8 bpp", procName, 1);
1759  if (pixim && pixGetDepth(pixim) != 1)
1760  return ERROR_INT("pixim not 1 bpp", procName, 1);
1761  if (sx < 2 || sy < 2)
1762  return ERROR_INT("sx and sy must be >= 2", procName, 1);
1763 
1764  /* Generate pixd, which is reduced by the factors (sx, sy). */
1765  wd = (w + sx - 1) / sx;
1766  hd = (h + sy - 1) / sy;
1767  pixd = pixCreate(wd, hd, 8);
1768  *ppixd = pixd;
1769 
1770  /* Evaluate the 'image' mask, pixim. If it is all fg,
1771  * the output pixd has all pixels with value 0. */
1772  fgpixels = 0; /* boolean for existence of fg pixels in the image mask. */
1773  if (pixim) {
1774  piximi = pixInvert(NULL, pixim); /* set non-image pixels to 1 */
1775  pixZero(piximi, &empty);
1776  pixDestroy(&piximi);
1777  if (empty) /* all 'image'; return with all pixels set to 0 */
1778  return 0;
1779  pixZero(pixim, &empty);
1780  if (!empty) /* there are fg pixels in pixim */
1781  fgpixels = 1;
1782  }
1783 
1784  /* 2x subsampling; paint white through 'image' mask. */
1785  pixs2 = pixScaleBySampling(pixs, 0.5, 0.5);
1786  if (pixim && fgpixels) {
1787  pixim2 = pixReduceBinary2(pixim, NULL);
1788  pixPaintThroughMask(pixs2, pixim2, 0, 0, 255);
1789  pixDestroy(&pixim2);
1790  }
1791 
1792  /* Min (erosion) downscaling; total reduction (4 sx, 4 sy). */
1793  pixt1 = pixScaleGrayMinMax(pixs2, sx, sy, L_CHOOSE_MIN);
1794 
1795 /* pixDisplay(pixt1, 300, 200); */
1796 
1797  /* Threshold to identify fg; paint bg pixels to white. */
1798  pixb = pixThresholdToBinary(pixt1, thresh); /* fg pixels */
1799  pixInvert(pixb, pixb);
1800  pixPaintThroughMask(pixt1, pixb, 0, 0, 255);
1801  pixDestroy(&pixb);
1802 
1803  /* Replicative expansion by 2x to (sx, sy). */
1804  pixt2 = pixExpandReplicate(pixt1, 2);
1805 
1806 /* pixDisplay(pixt2, 500, 200); */
1807 
1808  /* Fill holes in the fg by propagation */
1809  pixFillMapHoles(pixt2, w / sx, h / sy, L_FILL_WHITE);
1810 
1811 /* pixDisplay(pixt2, 700, 200); */
1812 
1813  /* Smooth with 17x17 kernel. */
1814  pixt3 = pixBlockconv(pixt2, 8, 8);
1815  pixRasterop(pixd, 0, 0, wd, hd, PIX_SRC, pixt3, 0, 0);
1816 
1817  /* Paint the image parts black. */
1818  pixims = pixScaleBySampling(pixim, 1. / sx, 1. / sy);
1819  pixPaintThroughMask(pixd, pixims, 0, 0, 0);
1820 
1821  pixDestroy(&pixs2);
1822  pixDestroy(&pixt1);
1823  pixDestroy(&pixt2);
1824  pixDestroy(&pixt3);
1825  return 0;
1826 }
1827 #endif /* Not working properly: do not use */
1828 
1829 
1830 /*------------------------------------------------------------------*
1831  * Generate inverted background map *
1832  *------------------------------------------------------------------*/
1849 PIX *
1851  l_int32 bgval,
1852  l_int32 smoothx,
1853  l_int32 smoothy)
1854 {
1855 l_int32 w, h, wplsm, wpld, i, j;
1856 l_int32 val, val16;
1857 l_uint32 *datasm, *datad, *linesm, *lined;
1858 PIX *pixsm, *pixd;
1859 
1860  PROCNAME("pixGetInvBackgroundMap");
1861 
1862  if (!pixs || pixGetDepth(pixs) != 8)
1863  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
1864  if (pixGetColormap(pixs))
1865  return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
1866  pixGetDimensions(pixs, &w, &h, NULL);
1867  if (w < 5 || h < 5)
1868  return (PIX *)ERROR_PTR("w and h must be >= 5", procName, NULL);
1869 
1870  /* smooth the map image */
1871  pixsm = pixBlockconv(pixs, smoothx, smoothy);
1872  datasm = pixGetData(pixsm);
1873  wplsm = pixGetWpl(pixsm);
1874 
1875  /* invert the map image, scaling up to preserve dynamic range */
1876  pixd = pixCreate(w, h, 16);
1877  datad = pixGetData(pixd);
1878  wpld = pixGetWpl(pixd);
1879  for (i = 0; i < h; i++) {
1880  linesm = datasm + i * wplsm;
1881  lined = datad + i * wpld;
1882  for (j = 0; j < w; j++) {
1883  val = GET_DATA_BYTE(linesm, j);
1884  if (val > 0)
1885  val16 = (256 * bgval) / val;
1886  else { /* shouldn't happen */
1887  L_WARNING("smoothed bg has 0 pixel!\n", procName);
1888  val16 = bgval / 2;
1889  }
1890  SET_DATA_TWO_BYTES(lined, j, val16);
1891  }
1892  }
1893 
1894  pixDestroy(&pixsm);
1895  pixCopyResolution(pixd, pixs);
1896  return pixd;
1897 }
1898 
1899 
1900 /*------------------------------------------------------------------*
1901  * Apply background map to image *
1902  *------------------------------------------------------------------*/
1912 PIX *
1914  PIX *pixm,
1915  l_int32 sx,
1916  l_int32 sy)
1917 {
1918 l_int32 w, h, wm, hm, wpls, wpld, i, j, k, m, xoff, yoff;
1919 l_int32 vals, vald;
1920 l_uint32 val16;
1921 l_uint32 *datas, *datad, *lines, *lined, *flines, *flined;
1922 PIX *pixd;
1923 
1924  PROCNAME("pixApplyInvBackgroundGrayMap");
1925 
1926  if (!pixs || pixGetDepth(pixs) != 8)
1927  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
1928  if (pixGetColormap(pixs))
1929  return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
1930  if (!pixm || pixGetDepth(pixm) != 16)
1931  return (PIX *)ERROR_PTR("pixm undefined or not 16 bpp", procName, NULL);
1932  if (sx == 0 || sy == 0)
1933  return (PIX *)ERROR_PTR("invalid sx and/or sy", procName, NULL);
1934 
1935  datas = pixGetData(pixs);
1936  wpls = pixGetWpl(pixs);
1937  pixGetDimensions(pixs, &w, &h, NULL);
1938  pixGetDimensions(pixm, &wm, &hm, NULL);
1939  if ((pixd = pixCreateTemplate(pixs)) == NULL)
1940  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1941  datad = pixGetData(pixd);
1942  wpld = pixGetWpl(pixd);
1943  for (i = 0; i < hm; i++) {
1944  lines = datas + sy * i * wpls;
1945  lined = datad + sy * i * wpld;
1946  yoff = sy * i;
1947  for (j = 0; j < wm; j++) {
1948  pixGetPixel(pixm, j, i, &val16);
1949  xoff = sx * j;
1950  for (k = 0; k < sy && yoff + k < h; k++) {
1951  flines = lines + k * wpls;
1952  flined = lined + k * wpld;
1953  for (m = 0; m < sx && xoff + m < w; m++) {
1954  vals = GET_DATA_BYTE(flines, xoff + m);
1955  vald = (vals * val16) / 256;
1956  vald = L_MIN(vald, 255);
1957  SET_DATA_BYTE(flined, xoff + m, vald);
1958  }
1959  }
1960  }
1961  }
1962 
1963  return pixd;
1964 }
1965 
1966 
1978 PIX *
1980  PIX *pixmr,
1981  PIX *pixmg,
1982  PIX *pixmb,
1983  l_int32 sx,
1984  l_int32 sy)
1985 {
1986 l_int32 w, h, wm, hm, wpls, wpld, i, j, k, m, xoff, yoff;
1987 l_int32 rvald, gvald, bvald;
1988 l_uint32 vals;
1989 l_uint32 rval16, gval16, bval16;
1990 l_uint32 *datas, *datad, *lines, *lined, *flines, *flined;
1991 PIX *pixd;
1992 
1993  PROCNAME("pixApplyInvBackgroundRGBMap");
1994 
1995  if (!pixs)
1996  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1997  if (pixGetDepth(pixs) != 32)
1998  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1999  if (!pixmr || !pixmg || !pixmb)
2000  return (PIX *)ERROR_PTR("pix maps not all defined", procName, NULL);
2001  if (pixGetDepth(pixmr) != 16 || pixGetDepth(pixmg) != 16 ||
2002  pixGetDepth(pixmb) != 16)
2003  return (PIX *)ERROR_PTR("pix maps not all 16 bpp", procName, NULL);
2004  if (sx == 0 || sy == 0)
2005  return (PIX *)ERROR_PTR("invalid sx and/or sy", procName, NULL);
2006 
2007  datas = pixGetData(pixs);
2008  wpls = pixGetWpl(pixs);
2009  w = pixGetWidth(pixs);
2010  h = pixGetHeight(pixs);
2011  wm = pixGetWidth(pixmr);
2012  hm = pixGetHeight(pixmr);
2013  if ((pixd = pixCreateTemplate(pixs)) == NULL)
2014  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2015  datad = pixGetData(pixd);
2016  wpld = pixGetWpl(pixd);
2017  for (i = 0; i < hm; i++) {
2018  lines = datas + sy * i * wpls;
2019  lined = datad + sy * i * wpld;
2020  yoff = sy * i;
2021  for (j = 0; j < wm; j++) {
2022  pixGetPixel(pixmr, j, i, &rval16);
2023  pixGetPixel(pixmg, j, i, &gval16);
2024  pixGetPixel(pixmb, j, i, &bval16);
2025  xoff = sx * j;
2026  for (k = 0; k < sy && yoff + k < h; k++) {
2027  flines = lines + k * wpls;
2028  flined = lined + k * wpld;
2029  for (m = 0; m < sx && xoff + m < w; m++) {
2030  vals = *(flines + xoff + m);
2031  rvald = ((vals >> 24) * rval16) / 256;
2032  rvald = L_MIN(rvald, 255);
2033  gvald = (((vals >> 16) & 0xff) * gval16) / 256;
2034  gvald = L_MIN(gvald, 255);
2035  bvald = (((vals >> 8) & 0xff) * bval16) / 256;
2036  bvald = L_MIN(bvald, 255);
2037  composeRGBPixel(rvald, gvald, bvald, flined + xoff + m);
2038  }
2039  }
2040  }
2041  }
2042 
2043  return pixd;
2044 }
2045 
2046 
2047 /*------------------------------------------------------------------*
2048  * Apply variable map *
2049  *------------------------------------------------------------------*/
2076 PIX *
2078  PIX *pixg,
2079  l_int32 target)
2080 {
2081 l_int32 i, j, w, h, d, wpls, wplg, wpld, vals, valg, vald;
2082 l_uint8 *lut;
2083 l_uint32 *datas, *datag, *datad, *lines, *lineg, *lined;
2084 l_float32 fval;
2085 PIX *pixd;
2086 
2087  PROCNAME("pixApplyVariableGrayMap");
2088 
2089  if (!pixs)
2090  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2091  if (!pixg)
2092  return (PIX *)ERROR_PTR("pixg not defined", procName, NULL);
2093  if (!pixSizesEqual(pixs, pixg))
2094  return (PIX *)ERROR_PTR("pix sizes not equal", procName, NULL);
2095  pixGetDimensions(pixs, &w, &h, &d);
2096  if (d != 8)
2097  return (PIX *)ERROR_PTR("depth not 8 bpp", procName, NULL);
2098 
2099  /* Generate a LUT for the mapping if the image is large enough
2100  * to warrant the overhead. The LUT is of size 2^16. For the
2101  * index to the table, get the MSB from pixs and the LSB from pixg.
2102  * Note: this LUT is bigger than the typical 32K L1 cache, so
2103  * we expect cache misses. L2 latencies are about 5ns. But
2104  * division is slooooow. For large images, this function is about
2105  * 4x faster when using the LUT. C'est la vie. */
2106  lut = NULL;
2107  if (w * h > 100000) { /* more pixels than 2^16 */
2108  lut = (l_uint8 *)LEPT_CALLOC(0x10000, sizeof(l_uint8));
2109  for (i = 0; i < 256; i++) {
2110  for (j = 0; j < 256; j++) {
2111  fval = (l_float32)(i * target) / (j + 0.5);
2112  lut[(i << 8) + j] = L_MIN(255, (l_int32)(fval + 0.5));
2113  }
2114  }
2115  }
2116 
2117  if ((pixd = pixCreate(w, h, 8)) == NULL) {
2118  LEPT_FREE(lut);
2119  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2120  }
2121  pixCopyResolution(pixd, pixs);
2122  datad = pixGetData(pixd);
2123  wpld = pixGetWpl(pixd);
2124  datas = pixGetData(pixs);
2125  wpls = pixGetWpl(pixs);
2126  datag = pixGetData(pixg);
2127  wplg = pixGetWpl(pixg);
2128  for (i = 0; i < h; i++) {
2129  lines = datas + i * wpls;
2130  lineg = datag + i * wplg;
2131  lined = datad + i * wpld;
2132  if (lut) {
2133  for (j = 0; j < w; j++) {
2134  vals = GET_DATA_BYTE(lines, j);
2135  valg = GET_DATA_BYTE(lineg, j);
2136  vald = lut[(vals << 8) + valg];
2137  SET_DATA_BYTE(lined, j, vald);
2138  }
2139  }
2140  else {
2141  for (j = 0; j < w; j++) {
2142  vals = GET_DATA_BYTE(lines, j);
2143  valg = GET_DATA_BYTE(lineg, j);
2144  fval = (l_float32)(vals * target) / (valg + 0.5);
2145  vald = L_MIN(255, (l_int32)(fval + 0.5));
2146  SET_DATA_BYTE(lined, j, vald);
2147  }
2148  }
2149  }
2150 
2151  LEPT_FREE(lut);
2152  return pixd;
2153 }
2154 
2155 
2156 /*------------------------------------------------------------------*
2157  * Non-adaptive (global) mapping *
2158  *------------------------------------------------------------------*/
2193 PIX *
2195  PIX *pixs,
2196  l_int32 rval,
2197  l_int32 gval,
2198  l_int32 bval,
2199  l_int32 mapval)
2200 {
2201 l_int32 w, h, d, i, j, ncolors, rv, gv, bv, wpl;
2202 l_int32 *rarray, *garray, *barray;
2203 l_uint32 *data, *line;
2204 NUMA *nar, *nag, *nab;
2205 PIXCMAP *cmap;
2206 
2207  PROCNAME("pixGlobalNormRGB");
2208 
2209  if (!pixs)
2210  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2211  cmap = pixGetColormap(pixs);
2212  pixGetDimensions(pixs, &w, &h, &d);
2213  if (!cmap && d != 32)
2214  return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
2215  if (mapval <= 0) {
2216  L_WARNING("mapval must be > 0; setting to 255\n", procName);
2217  mapval = 255;
2218  }
2219 
2220  /* Prepare pixd to be a copy of pixs */
2221  if ((pixd = pixCopy(pixd, pixs)) == NULL)
2222  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2223 
2224  /* Generate the TRC maps for each component. Make sure the
2225  * upper range for each color is greater than zero. */
2226  nar = numaGammaTRC(1.0, 0, L_MAX(1, 255 * rval / mapval));
2227  nag = numaGammaTRC(1.0, 0, L_MAX(1, 255 * gval / mapval));
2228  nab = numaGammaTRC(1.0, 0, L_MAX(1, 255 * bval / mapval));
2229 
2230  /* Extract copies of the internal arrays */
2231  rarray = numaGetIArray(nar);
2232  garray = numaGetIArray(nag);
2233  barray = numaGetIArray(nab);
2234  if (!nar || !nag || !nab || !rarray || !garray || !barray) {
2235  L_ERROR("allocation failure in arrays\n", procName);
2236  goto cleanup_arrays;
2237  }
2238 
2239  if (cmap) {
2240  ncolors = pixcmapGetCount(cmap);
2241  for (i = 0; i < ncolors; i++) {
2242  pixcmapGetColor(cmap, i, &rv, &gv, &bv);
2243  pixcmapResetColor(cmap, i, rarray[rv], garray[gv], barray[bv]);
2244  }
2245  }
2246  else {
2247  data = pixGetData(pixd);
2248  wpl = pixGetWpl(pixd);
2249  for (i = 0; i < h; i++) {
2250  line = data + i * wpl;
2251  for (j = 0; j < w; j++) {
2252  extractRGBValues(line[j], &rv, &gv, &bv);
2253  composeRGBPixel(rarray[rv], garray[gv], barray[bv], line + j);
2254  }
2255  }
2256  }
2257 
2258 cleanup_arrays:
2259  numaDestroy(&nar);
2260  numaDestroy(&nag);
2261  numaDestroy(&nab);
2262  LEPT_FREE(rarray);
2263  LEPT_FREE(garray);
2264  LEPT_FREE(barray);
2265  return pixd;
2266 }
2267 
2268 
2302 PIX *
2304  PIX *pixs,
2305  l_int32 rval,
2306  l_int32 gval,
2307  l_int32 bval,
2308  l_int32 factor,
2309  l_float32 rank)
2310 {
2311 l_int32 mapval;
2312 l_float32 rankrval, rankgval, rankbval;
2313 l_float32 rfract, gfract, bfract, maxfract;
2314 
2315  PROCNAME("pixGlobalNormNoSatRGB");
2316 
2317  if (!pixs)
2318  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2319  if (pixGetDepth(pixs) != 32)
2320  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
2321  if (factor < 1)
2322  return (PIX *)ERROR_PTR("sampling factor < 1", procName, NULL);
2323  if (rank < 0.0 || rank > 1.0)
2324  return (PIX *)ERROR_PTR("rank not in [0.0 ... 1.0]", procName, NULL);
2325  if (rval <= 0 || gval <= 0 || bval <= 0)
2326  return (PIX *)ERROR_PTR("invalid estim. color values", procName, NULL);
2327 
2328  /* The max value for each component may be larger than the
2329  * input estimated background value. In that case, mapping
2330  * for those pixels would saturate. To prevent saturation,
2331  * we compute the fraction for each component by which we
2332  * would oversaturate. Then take the max of these, and
2333  * reduce, uniformly over all components, the output intensity
2334  * by this value. Then no component will saturate.
2335  * In practice, if rank < 1.0, a fraction of pixels
2336  * may have a component saturate. By keeping rank close to 1.0,
2337  * that fraction can be made arbitrarily small. */
2338  pixGetRankValueMaskedRGB(pixs, NULL, 0, 0, factor, rank, &rankrval,
2339  &rankgval, &rankbval);
2340  rfract = rankrval / (l_float32)rval;
2341  gfract = rankgval / (l_float32)gval;
2342  bfract = rankbval / (l_float32)bval;
2343  maxfract = L_MAX(rfract, gfract);
2344  maxfract = L_MAX(maxfract, bfract);
2345 #if DEBUG_GLOBAL
2346  lept_stderr("rankrval = %7.2f, rankgval = %7.2f, rankbval = %7.2f\n",
2347  rankrval, rankgval, rankbval);
2348  lept_stderr("rfract = %7.4f, gfract = %7.4f, bfract = %7.4f\n",
2349  rfract, gfract, bfract);
2350 #endif /* DEBUG_GLOBAL */
2351 
2352  mapval = (l_int32)(255. / maxfract);
2353  pixd = pixGlobalNormRGB(pixd, pixs, rval, gval, bval, mapval);
2354  return pixd;
2355 }
2356 
2357 
2358 /*------------------------------------------------------------------*
2359  * Adaptive threshold spread normalization *
2360  *------------------------------------------------------------------*/
2404 l_ok
2406  l_int32 filtertype,
2407  l_int32 edgethresh,
2408  l_int32 smoothx,
2409  l_int32 smoothy,
2410  l_float32 gamma,
2411  l_int32 minval,
2412  l_int32 maxval,
2413  l_int32 targetthresh,
2414  PIX **ppixth,
2415  PIX **ppixb,
2416  PIX **ppixd)
2417 {
2418 PIX *pixe, *pixet, *pixsd, *pixg1, *pixg2, *pixth;
2419 
2420  PROCNAME("pixThresholdSpreadNorm");
2421 
2422  if (ppixth) *ppixth = NULL;
2423  if (ppixb) *ppixb = NULL;
2424  if (ppixd) *ppixd = NULL;
2425  if (!pixs || pixGetDepth(pixs) != 8)
2426  return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
2427  if (pixGetColormap(pixs))
2428  return ERROR_INT("pixs is colormapped", procName, 1);
2429  if (!ppixth && !ppixb && !ppixd)
2430  return ERROR_INT("no output requested", procName, 1);
2431  if (filtertype != L_SOBEL_EDGE && filtertype != L_TWO_SIDED_EDGE)
2432  return ERROR_INT("invalid filter type", procName, 1);
2433 
2434  /* Get the thresholded edge pixels. These are the ones
2435  * that have values in pixs near the local optimal fg/bg threshold. */
2436  if (filtertype == L_SOBEL_EDGE)
2437  pixe = pixSobelEdgeFilter(pixs, L_VERTICAL_EDGES);
2438  else /* L_TWO_SIDED_EDGE */
2440  pixet = pixThresholdToBinary(pixe, edgethresh);
2441  pixInvert(pixet, pixet);
2442 
2443  /* Build a seed image whose only nonzero values are those
2444  * values of pixs corresponding to pixels in the fg of pixet. */
2445  pixsd = pixCreateTemplate(pixs);
2446  pixCombineMasked(pixsd, pixs, pixet);
2447 
2448  /* Spread the seed and optionally smooth to reduce noise */
2449  pixg1 = pixSeedspread(pixsd, 4);
2450  pixg2 = pixBlockconv(pixg1, smoothx, smoothy);
2451 
2452  /* Optionally do a gamma enhancement */
2453  pixth = pixGammaTRC(NULL, pixg2, gamma, minval, maxval);
2454 
2455  /* Do the mapping and thresholding */
2456  if (ppixd) {
2457  *ppixd = pixApplyVariableGrayMap(pixs, pixth, targetthresh);
2458  if (ppixb)
2459  *ppixb = pixThresholdToBinary(*ppixd, targetthresh);
2460  }
2461  else if (ppixb)
2462  *ppixb = pixVarThresholdToBinary(pixs, pixth);
2463 
2464  if (ppixth)
2465  *ppixth = pixth;
2466  else
2467  pixDestroy(&pixth);
2468 
2469  pixDestroy(&pixe);
2470  pixDestroy(&pixet);
2471  pixDestroy(&pixsd);
2472  pixDestroy(&pixg1);
2473  pixDestroy(&pixg2);
2474  return 0;
2475 }
2476 
2477 
2478 /*------------------------------------------------------------------*
2479  * Adaptive background normalization (flexible adaptaption) *
2480  *------------------------------------------------------------------*/
2510 PIX *
2512  l_int32 sx,
2513  l_int32 sy,
2514  l_int32 smoothx,
2515  l_int32 smoothy,
2516  l_int32 delta)
2517 {
2518 l_float32 scalex, scaley;
2519 PIX *pixt, *pixsd, *pixmin, *pixbg, *pixbgi, *pixd;
2520 
2521  PROCNAME("pixBackgroundNormFlex");
2522 
2523  if (!pixs || pixGetDepth(pixs) != 8)
2524  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
2525  if (pixGetColormap(pixs))
2526  return (PIX *)ERROR_PTR("pixs is colormapped", procName, NULL);
2527  if (sx < 3 || sy < 3)
2528  return (PIX *)ERROR_PTR("sx and/or sy less than 3", procName, NULL);
2529  if (sx > 10 || sy > 10)
2530  return (PIX *)ERROR_PTR("sx and/or sy exceed 10", procName, NULL);
2531  if (smoothx < 1 || smoothy < 1)
2532  return (PIX *)ERROR_PTR("smooth params less than 1", procName, NULL);
2533  if (smoothx > 3 || smoothy > 3)
2534  return (PIX *)ERROR_PTR("smooth params exceed 3", procName, NULL);
2535 
2536  /* Generate the bg estimate using smoothed average with subsampling */
2537  scalex = 1. / (l_float32)sx;
2538  scaley = 1. / (l_float32)sy;
2539  pixt = pixScaleSmooth(pixs, scalex, scaley);
2540 
2541  /* Do basin filling on the bg estimate if requested */
2542  if (delta <= 0)
2543  pixsd = pixClone(pixt);
2544  else {
2545  pixLocalExtrema(pixt, 0, 0, &pixmin, NULL);
2546  pixsd = pixSeedfillGrayBasin(pixmin, pixt, delta, 4);
2547  pixDestroy(&pixmin);
2548  }
2549  pixbg = pixExtendByReplication(pixsd, 1, 1);
2550 
2551  /* Map the bg to 200 */
2552  pixbgi = pixGetInvBackgroundMap(pixbg, 200, smoothx, smoothy);
2553  pixd = pixApplyInvBackgroundGrayMap(pixs, pixbgi, sx, sy);
2554 
2555  pixDestroy(&pixt);
2556  pixDestroy(&pixsd);
2557  pixDestroy(&pixbg);
2558  pixDestroy(&pixbgi);
2559  return pixd;
2560 }
2561 
2562 
2563 /*------------------------------------------------------------------*
2564  * Adaptive contrast normalization *
2565  *------------------------------------------------------------------*/
2605 PIX *
2607  PIX *pixs,
2608  l_int32 sx,
2609  l_int32 sy,
2610  l_int32 mindiff,
2611  l_int32 smoothx,
2612  l_int32 smoothy)
2613 {
2614 PIX *pixmin, *pixmax;
2615 
2616  PROCNAME("pixContrastNorm");
2617 
2618  if (!pixs || pixGetDepth(pixs) != 8)
2619  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, pixd);
2620  if (pixd && pixd != pixs)
2621  return (PIX *)ERROR_PTR("pixd not null or == pixs", procName, pixd);
2622  if (pixGetColormap(pixs))
2623  return (PIX *)ERROR_PTR("pixs is colormapped", procName, pixd);
2624  if (sx < 5 || sy < 5)
2625  return (PIX *)ERROR_PTR("sx and/or sy less than 5", procName, pixd);
2626  if (smoothx < 0 || smoothy < 0)
2627  return (PIX *)ERROR_PTR("smooth params less than 0", procName, pixd);
2628  if (smoothx > 8 || smoothy > 8)
2629  return (PIX *)ERROR_PTR("smooth params exceed 8", procName, pixd);
2630 
2631  /* Get the min and max pixel values in each tile, and represent
2632  * each value as a pixel in pixmin and pixmax, respectively. */
2633  pixMinMaxTiles(pixs, sx, sy, mindiff, smoothx, smoothy, &pixmin, &pixmax);
2634 
2635  /* For each tile, do a linear expansion of the dynamic range
2636  * of pixels so that the min value is mapped to 0 and the
2637  * max value is mapped to 255. */
2638  pixd = pixLinearTRCTiled(pixd, pixs, sx, sy, pixmin, pixmax);
2639 
2640  pixDestroy(&pixmin);
2641  pixDestroy(&pixmax);
2642  return pixd;
2643 }
2644 
2645 
2665 static l_ok
2667  l_int32 sx,
2668  l_int32 sy,
2669  l_int32 mindiff,
2670  l_int32 smoothx,
2671  l_int32 smoothy,
2672  PIX **ppixmin,
2673  PIX **ppixmax)
2674 {
2675 l_int32 w, h;
2676 PIX *pixmin1, *pixmax1, *pixmin2, *pixmax2;
2677 
2678  PROCNAME("pixMinMaxTiles");
2679 
2680  if (ppixmin) *ppixmin = NULL;
2681  if (ppixmax) *ppixmax = NULL;
2682  if (!ppixmin || !ppixmax)
2683  return ERROR_INT("&pixmin or &pixmax undefined", procName, 1);
2684  if (!pixs || pixGetDepth(pixs) != 8)
2685  return ERROR_INT("pixs undefined or not 8 bpp", procName, 1);
2686  if (pixGetColormap(pixs))
2687  return ERROR_INT("pixs is colormapped", procName, 1);
2688  if (sx < 5 || sy < 5)
2689  return ERROR_INT("sx and/or sy less than 3", procName, 1);
2690  if (smoothx < 0 || smoothy < 0)
2691  return ERROR_INT("smooth params less than 0", procName, 1);
2692  if (smoothx > 5 || smoothy > 5)
2693  return ERROR_INT("smooth params exceed 5", procName, 1);
2694 
2695  /* Get the min and max values in each tile */
2696  pixmin1 = pixScaleGrayMinMax(pixs, sx, sy, L_CHOOSE_MIN);
2697  pixmax1 = pixScaleGrayMinMax(pixs, sx, sy, L_CHOOSE_MAX);
2698 
2699  pixmin2 = pixExtendByReplication(pixmin1, 1, 1);
2700  pixmax2 = pixExtendByReplication(pixmax1, 1, 1);
2701  pixDestroy(&pixmin1);
2702  pixDestroy(&pixmax1);
2703 
2704  /* Make sure no value is 0 */
2705  pixAddConstantGray(pixmin2, 1);
2706  pixAddConstantGray(pixmax2, 1);
2707 
2708  /* Generate holes where the contrast is too small */
2709  pixSetLowContrast(pixmin2, pixmax2, mindiff);
2710 
2711  /* Fill the holes (0 values) */
2712  pixGetDimensions(pixmin2, &w, &h, NULL);
2713  pixFillMapHoles(pixmin2, w, h, L_FILL_BLACK);
2714  pixFillMapHoles(pixmax2, w, h, L_FILL_BLACK);
2715 
2716  /* Smooth if requested */
2717  if (smoothx > 0 || smoothy > 0) {
2718  smoothx = L_MIN(smoothx, (w - 1) / 2);
2719  smoothy = L_MIN(smoothy, (h - 1) / 2);
2720  *ppixmin = pixBlockconv(pixmin2, smoothx, smoothy);
2721  *ppixmax = pixBlockconv(pixmax2, smoothx, smoothy);
2722  }
2723  else {
2724  *ppixmin = pixClone(pixmin2);
2725  *ppixmax = pixClone(pixmax2);
2726  }
2727  pixCopyResolution(*ppixmin, pixs);
2728  pixCopyResolution(*ppixmax, pixs);
2729  pixDestroy(&pixmin2);
2730  pixDestroy(&pixmax2);
2731 
2732  return 0;
2733 }
2734 
2735 
2756 static l_ok
2758  PIX *pixs2,
2759  l_int32 mindiff)
2760 {
2761 l_int32 i, j, w, h, d, wpl, val1, val2, found;
2762 l_uint32 *data1, *data2, *line1, *line2;
2763 
2764  PROCNAME("pixSetLowContrast");
2765 
2766  if (!pixs1 || !pixs2)
2767  return ERROR_INT("pixs1 and pixs2 not both defined", procName, 1);
2768  if (pixSizesEqual(pixs1, pixs2) == 0)
2769  return ERROR_INT("pixs1 and pixs2 not equal size", procName, 1);
2770  pixGetDimensions(pixs1, &w, &h, &d);
2771  if (d != 8)
2772  return ERROR_INT("depth not 8 bpp", procName, 1);
2773  if (mindiff > 254) return 0;
2774 
2775  data1 = pixGetData(pixs1);
2776  data2 = pixGetData(pixs2);
2777  wpl = pixGetWpl(pixs1);
2778  found = 0; /* init to not finding any diffs >= mindiff */
2779  for (i = 0; i < h; i++) {
2780  line1 = data1 + i * wpl;
2781  line2 = data2 + i * wpl;
2782  for (j = 0; j < w; j++) {
2783  val1 = GET_DATA_BYTE(line1, j);
2784  val2 = GET_DATA_BYTE(line2, j);
2785  if (L_ABS(val1 - val2) >= mindiff) {
2786  found = 1;
2787  break;
2788  }
2789  }
2790  if (found) break;
2791  }
2792  if (!found) {
2793  L_WARNING("no pixel pair diffs as large as mindiff\n", procName);
2794  pixClearAll(pixs1);
2795  pixClearAll(pixs2);
2796  return 1;
2797  }
2798 
2799  for (i = 0; i < h; i++) {
2800  line1 = data1 + i * wpl;
2801  line2 = data2 + i * wpl;
2802  for (j = 0; j < w; j++) {
2803  val1 = GET_DATA_BYTE(line1, j);
2804  val2 = GET_DATA_BYTE(line2, j);
2805  if (L_ABS(val1 - val2) < mindiff) {
2806  SET_DATA_BYTE(line1, j, 0);
2807  SET_DATA_BYTE(line2, j, 0);
2808  }
2809  }
2810  }
2811 
2812  return 0;
2813 }
2814 
2815 
2839 static PIX *
2841  PIX *pixs,
2842  l_int32 sx,
2843  l_int32 sy,
2844  PIX *pixmin,
2845  PIX *pixmax)
2846 {
2847 l_int32 i, j, k, m, w, h, wt, ht, wpl, wplt, xoff, yoff;
2848 l_int32 minval, maxval, val, sval;
2849 l_int32 *ia;
2850 l_int32 **iaa;
2851 l_uint32 *data, *datamin, *datamax, *line, *tline, *linemin, *linemax;
2852 
2853  PROCNAME("pixLinearTRCTiled");
2854 
2855  if (!pixs || pixGetDepth(pixs) != 8)
2856  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, pixd);
2857  if (pixd && pixd != pixs)
2858  return (PIX *)ERROR_PTR("pixd not null or == pixs", procName, pixd);
2859  if (pixGetColormap(pixs))
2860  return (PIX *)ERROR_PTR("pixs is colormapped", procName, pixd);
2861  if (!pixmin || !pixmax)
2862  return (PIX *)ERROR_PTR("pixmin & pixmax not defined", procName, pixd);
2863  if (sx < 5 || sy < 5)
2864  return (PIX *)ERROR_PTR("sx and/or sy less than 5", procName, pixd);
2865 
2866  iaa = (l_int32 **)LEPT_CALLOC(256, sizeof(l_int32 *));
2867  if ((pixd = pixCopy(pixd, pixs)) == NULL) {
2868  LEPT_FREE(iaa);
2869  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2870  }
2871  pixGetDimensions(pixd, &w, &h, NULL);
2872 
2873  data = pixGetData(pixd);
2874  wpl = pixGetWpl(pixd);
2875  datamin = pixGetData(pixmin);
2876  datamax = pixGetData(pixmax);
2877  wplt = pixGetWpl(pixmin);
2878  pixGetDimensions(pixmin, &wt, &ht, NULL);
2879  for (i = 0; i < ht; i++) {
2880  line = data + sy * i * wpl;
2881  linemin = datamin + i * wplt;
2882  linemax = datamax + i * wplt;
2883  yoff = sy * i;
2884  for (j = 0; j < wt; j++) {
2885  xoff = sx * j;
2886  minval = GET_DATA_BYTE(linemin, j);
2887  maxval = GET_DATA_BYTE(linemax, j);
2888  if (maxval == minval) {
2889  L_ERROR("shouldn't happen! i,j = %d,%d, minval = %d\n",
2890  procName, i, j, minval);
2891  continue;
2892  }
2893  if ((ia = iaaGetLinearTRC(iaa, maxval - minval)) == NULL) {
2894  L_ERROR("failure to make ia for j = %d!\n", procName, j);
2895  continue;
2896  }
2897  for (k = 0; k < sy && yoff + k < h; k++) {
2898  tline = line + k * wpl;
2899  for (m = 0; m < sx && xoff + m < w; m++) {
2900  val = GET_DATA_BYTE(tline, xoff + m);
2901  sval = val - minval;
2902  sval = L_MAX(0, sval);
2903  SET_DATA_BYTE(tline, xoff + m, ia[sval]);
2904  }
2905  }
2906  }
2907  }
2908 
2909  for (i = 0; i < 256; i++)
2910  LEPT_FREE(iaa[i]);
2911  LEPT_FREE(iaa);
2912  return pixd;
2913 }
2914 
2915 
2925 static l_int32 *
2926 iaaGetLinearTRC(l_int32 **iaa,
2927  l_int32 diff)
2928 {
2929 l_int32 i;
2930 l_int32 *ia;
2931 l_float32 factor;
2932 
2933  PROCNAME("iaaGetLinearTRC");
2934 
2935  if (!iaa)
2936  return (l_int32 *)ERROR_PTR("iaa not defined", procName, NULL);
2937 
2938  if (iaa[diff] != NULL) /* already have it */
2939  return iaa[diff];
2940 
2941  ia = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2942  iaa[diff] = ia;
2943  if (diff == 0) { /* shouldn't happen */
2944  for (i = 0; i < 256; i++)
2945  ia[i] = 128;
2946  }
2947  else {
2948  factor = 255. / (l_float32)diff;
2949  for (i = 0; i < diff + 1; i++)
2950  ia[i] = (l_int32)(factor * i + 0.5);
2951  for (i = diff + 1; i < 256; i++)
2952  ia[i] = 255;
2953  }
2954 
2955  return ia;
2956 }
l_ok pixGetBackgroundRGBMap(PIX *pixs, PIX *pixim, PIX *pixg, l_int32 sx, l_int32 sy, l_int32 thresh, l_int32 mincount, PIX **ppixmr, PIX **ppixmg, PIX **ppixmb)
pixGetBackgroundRGBMap()
Definition: adaptmap.c:1054
l_ok pixBackgroundNormRGBArraysMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, l_int32 bgval, PIX **ppixr, PIX **ppixg, PIX **ppixb)
pixBackgroundNormRGBArraysMorph()
Definition: adaptmap.c:795
static const l_int32 DefaultFgThreshold
Definition: adaptmap.c:150
static const l_int32 DefaultTileHeight
Definition: adaptmap.c:149
PIX * pixBackgroundNormSimple(PIX *pixs, PIX *pixim, PIX *pixg)
pixBackgroundNormSimple()
Definition: adaptmap.c:247
static l_int32 * iaaGetLinearTRC(l_int32 **iaa, l_int32 diff)
iaaGetLinearTRC()
Definition: adaptmap.c:2926
l_ok pixBackgroundNormRGBArrays(PIX *pixs, PIX *pixim, PIX *pixg, l_int32 sx, l_int32 sy, l_int32 thresh, l_int32 mincount, l_int32 bgval, l_int32 smoothx, l_int32 smoothy, PIX **ppixr, PIX **ppixg, PIX **ppixb)
pixBackgroundNormRGBArrays()
Definition: adaptmap.c:647
l_ok pixSmoothConnectedRegions(PIX *pixs, PIX *pixm, l_int32 factor)
pixSmoothConnectedRegions()
Definition: adaptmap.c:1649
PIX * pixGlobalNormRGB(PIX *pixd, PIX *pixs, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 mapval)
pixGlobalNormRGB()
Definition: adaptmap.c:2194
PIX * pixCleanBackgroundToWhite(PIX *pixs, PIX *pixim, PIX *pixg, l_float32 gamma, l_int32 blackval, l_int32 whiteval)
pixCleanBackgroundToWhite()
Definition: adaptmap.c:196
PIX * pixContrastNorm(PIX *pixd, PIX *pixs, l_int32 sx, l_int32 sy, l_int32 mindiff, l_int32 smoothx, l_int32 smoothy)
pixContrastNorm()
Definition: adaptmap.c:2606
l_ok pixBackgroundNormGrayArrayMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, l_int32 bgval, PIX **ppixd)
pixBackgroundNormGrayArrayMorph()
Definition: adaptmap.c:730
l_ok pixGetBackgroundGrayMap(PIX *pixs, PIX *pixim, l_int32 sx, l_int32 sy, l_int32 thresh, l_int32 mincount, PIX **ppixd)
pixGetBackgroundGrayMap()
Definition: adaptmap.c:872
PIX * pixGetInvBackgroundMap(PIX *pixs, l_int32 bgval, l_int32 smoothx, l_int32 smoothy)
pixGetInvBackgroundMap()
Definition: adaptmap.c:1850
PIX * pixApplyInvBackgroundGrayMap(PIX *pixs, PIX *pixm, l_int32 sx, l_int32 sy)
pixApplyInvBackgroundGrayMap()
Definition: adaptmap.c:1913
l_ok pixGetBackgroundRGBMapMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, PIX **ppixmr, PIX **ppixmg, PIX **ppixmb)
pixGetBackgroundRGBMapMorph()
Definition: adaptmap.c:1330
static l_int32 pixSetLowContrast(PIX *pixs1, PIX *pixs2, l_int32 mindiff)
pixSetLowContrast()
Definition: adaptmap.c:2757
static const l_int32 DefaultBgVal
Definition: adaptmap.c:152
PIX * pixGlobalNormNoSatRGB(PIX *pixd, PIX *pixs, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 factor, l_float32 rank)
pixGlobalNormNoSatRGB()
Definition: adaptmap.c:2303
l_ok pixBackgroundNormGrayArray(PIX *pixs, PIX *pixim, l_int32 sx, l_int32 sy, l_int32 thresh, l_int32 mincount, l_int32 bgval, l_int32 smoothx, l_int32 smoothy, PIX **ppixd)
pixBackgroundNormGrayArray()
Definition: adaptmap.c:570
static const l_int32 DefaultTileWidth
Definition: adaptmap.c:148
PIX * pixBackgroundNorm(PIX *pixs, PIX *pixim, PIX *pixg, l_int32 sx, l_int32 sy, l_int32 thresh, l_int32 mincount, l_int32 bgval, l_int32 smoothx, l_int32 smoothy)
pixBackgroundNorm()
Definition: adaptmap.c:322
static const l_int32 DefaultMinCount
Definition: adaptmap.c:151
PIX * pixApplyVariableGrayMap(PIX *pixs, PIX *pixg, l_int32 target)
pixApplyVariableGrayMap()
Definition: adaptmap.c:2077
PIX * pixBackgroundNormFlex(PIX *pixs, l_int32 sx, l_int32 sy, l_int32 smoothx, l_int32 smoothy, l_int32 delta)
pixBackgroundNormFlex()
Definition: adaptmap.c:2511
PIX * pixApplyInvBackgroundRGBMap(PIX *pixs, PIX *pixmr, PIX *pixmg, PIX *pixmb, l_int32 sx, l_int32 sy)
pixApplyInvBackgroundRGBMap()
Definition: adaptmap.c:1979
l_ok pixFillMapHoles(PIX *pix, l_int32 nx, l_int32 ny, l_int32 filltype)
pixFillMapHoles()
Definition: adaptmap.c:1484
l_ok pixGetBackgroundGrayMapMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, PIX **ppixm)
pixGetBackgroundGrayMapMorph()
Definition: adaptmap.c:1239
PIX * pixExtendByReplication(PIX *pixs, l_int32 addw, l_int32 addh)
pixExtendByReplication()
Definition: adaptmap.c:1586
static l_int32 pixMinMaxTiles(PIX *pixs, l_int32 sx, l_int32 sy, l_int32 mindiff, l_int32 smoothx, l_int32 smoothy, PIX **ppixmin, PIX **ppixmax)
pixMinMaxTiles()
Definition: adaptmap.c:2666
static const l_int32 DefaultXSmoothSize
Definition: adaptmap.c:153
static PIX * pixLinearTRCTiled(PIX *pixd, PIX *pixs, l_int32 sx, l_int32 sy, PIX *pixmin, PIX *pixmax)
pixLinearTRCTiled()
Definition: adaptmap.c:2840
static const l_int32 DefaultYSmoothSize
Definition: adaptmap.c:154
l_ok pixThresholdSpreadNorm(PIX *pixs, l_int32 filtertype, l_int32 edgethresh, l_int32 smoothx, l_int32 smoothy, l_float32 gamma, l_int32 minval, l_int32 maxval, l_int32 targetthresh, PIX **ppixth, PIX **ppixb, PIX **ppixd)
pixThresholdSpreadNorm()
Definition: adaptmap.c:2405
PIX * pixBackgroundNormMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, l_int32 bgval)
pixBackgroundNormMorph()
Definition: adaptmap.c:459
#define SET_DATA_TWO_BYTES(pdata, n, val)
Definition: arrayaccess.h:222
#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
PIX * pixReduceBinary2(PIX *pixs, l_uint8 *intab)
pixReduceBinary2()
Definition: binreduce.c:74
l_ok boxaGetBoxGeometry(BOXA *boxa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetBoxGeometry()
Definition: boxbasic.c:879
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:734
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:583
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:708
l_ok pixcmapResetColor(PIXCMAP *cmap, l_int32 index, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapResetColor()
Definition: colormap.c:966
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:824
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:151
PIX * pixBlockconv(PIX *pix, l_int32 wc, l_int32 hc)
pixBlockconv()
Definition: convolve.c:132
PIX * pixTwoSidedEdgeFilter(PIX *pixs, l_int32 orientflag)
pixTwoSidedEdgeFilter()
Definition: edge.c:202
PIX * pixSobelEdgeFilter(PIX *pixs, l_int32 orientflag)
pixSobelEdgeFilter()
Definition: edge.c:94
NUMA * numaGammaTRC(l_float32 gamma, l_int32 minval, l_int32 maxval)
numaGammaTRC()
Definition: enhance.c:369
PIX * pixGammaTRC(PIX *pixd, PIX *pixs, l_float32 gamma, l_int32 minval, l_int32 maxval)
pixGammaTRC()
Definition: enhance.c:176
PIX * pixCloseGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseGray()
Definition: graymorph.c:526
PIX * pixVarThresholdToBinary(PIX *pixs, PIX *pixg)
pixVarThresholdToBinary()
Definition: grayquant.c:655
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:447
PIX * pixMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequence()
Definition: morphseq.c:137
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:754
l_int32 * numaGetIArray(NUMA *na)
numaGetIArray()
Definition: numabasic.c:847
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
l_int32 pixSizesEqual(const PIX *pix1, const PIX *pix2)
pixSizesEqual()
Definition: pix1.c:1985
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:383
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:263
l_ok pixClearAll(PIX *pix)
pixClearAll()
Definition: pix2.c:789
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:190
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2751
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2820
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1815
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1509
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:626
PIX * pixAnd(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixAnd()
Definition: pix3.c:1624
l_ok pixCombineMasked(PIX *pixd, PIX *pixs, PIX *pixm)
pixCombineMasked()
Definition: pix3.c:382
l_ok pixGetAverageMasked(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_int32 factor, l_int32 type, l_float32 *pval)
pixGetAverageMasked()
Definition: pix4.c:1526
l_ok pixGetRankValueMaskedRGB(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_int32 factor, l_float32 rank, l_float32 *prval, l_float32 *pgval, l_float32 *pbval)
pixGetRankValueMaskedRGB()
Definition: pix4.c:1076
@ COLOR_BLUE
Definition: pix.h:206
@ COLOR_RED
Definition: pix.h:204
@ COLOR_GREEN
Definition: pix.h:205
@ L_CLONE
Definition: pix.h:713
@ L_TWO_SIDED_EDGE
Definition: pix.h:1171
@ L_SOBEL_EDGE
Definition: pix.h:1170
#define PIX_SRC
Definition: pix.h:330
@ L_MEAN_ABSVAL
Definition: pix.h:968
@ L_VERTICAL_EDGES
Definition: pix.h:1004
@ L_FILL_WHITE
Definition: pix.h:897
@ L_FILL_BLACK
Definition: pix.h:898
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:691
l_ok pixAddConstantGray(PIX *pixs, l_int32 val)
pixAddConstantGray()
Definition: pixarith.c:119
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3133
PIX * pixConvertRGBToGrayFast(PIX *pixs)
pixConvertRGBToGrayFast()
Definition: pixconv.c:905
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 * pixScaleRGBToGrayFast(PIX *pixs, l_int32 factor, l_int32 color)
pixScaleRGBToGrayFast()
Definition: scale1.c:1486
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:250
PIX * pixScaleSmooth(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleSmooth()
Definition: scale1.c:1709
PIX * pixScaleBySampling(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBySampling()
Definition: scale1.c:1338
PIX * pixExpandReplicate(PIX *pixs, l_int32 factor)
pixExpandReplicate()
Definition: scale2.c:872
PIX * pixScaleGrayMinMax(PIX *pixs, l_int32 xfact, l_int32 yfact, l_int32 type)
pixScaleGrayMinMax()
Definition: scale2.c:1019
PIX * pixSeedspread(PIX *pixs, l_int32 connectivity)
pixSeedspread()
Definition: seedfill.c:2792
PIX * pixSeedfillGrayBasin(PIX *pixb, PIX *pixm, l_int32 delta, l_int32 connectivity)
pixSeedfillGrayBasin()
Definition: seedfill.c:2444
l_ok pixLocalExtrema(PIX *pixs, l_int32 maxmin, l_int32 minmax, PIX **ppixmin, PIX **ppixmax)
pixLocalExtrema()
Definition: seedfill.c:3019
Definition: pix.h:492
Definition: array.h:71
Definition: pix.h:139
Definition: pix.h:456
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306