Leptonica  1.77.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 #include "allheaders.h"
135 
136  /* Default input parameters for pixBackgroundNormSimple()
137  * Notes:
138  * (1) mincount must never exceed the tile area (width * height)
139  * (2) bgval must be sufficiently below 255 to avoid accidental
140  * saturation; otherwise it should be large to avoid
141  * shrinking the dynamic range
142  * (3) results should otherwise not be sensitive to these values
143  */
144 static const l_int32 DEFAULT_TILE_WIDTH = 10;
145 static const l_int32 DEFAULT_TILE_HEIGHT = 15;
146 static const l_int32 DEFAULT_FG_THRESHOLD = 60;
147 static const l_int32 DEFAULT_MIN_COUNT = 40;
148 static const l_int32 DEFAULT_BG_VAL = 200;
149 static const l_int32 DEFAULT_X_SMOOTH_SIZE = 2;
150 static const l_int32 DEFAULT_Y_SMOOTH_SIZE = 1;
152 static l_int32 *iaaGetLinearTRC(l_int32 **iaa, l_int32 diff);
153 
154 #ifndef NO_CONSOLE_IO
155 #define DEBUG_GLOBAL 0
156 #endif /* ~NO_CONSOLE_IO */
157 
158 
159 /*------------------------------------------------------------------*
160  * Clean background to white using background normalization *
161  *------------------------------------------------------------------*/
184 PIX *
186  PIX *pixim,
187  PIX *pixg,
188  l_float32 gamma,
189  l_int32 blackval,
190  l_int32 whiteval)
191 {
192 l_int32 d;
193 PIX *pixd;
194 
195  PROCNAME("pixCleanBackgroundToWhite");
196 
197  if (!pixs)
198  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
199  d = pixGetDepth(pixs);
200  if (d != 8 && d != 32)
201  return (PIX *)ERROR_PTR("depth not 8 or 32", procName, NULL);
202 
203  pixd = pixBackgroundNormSimple(pixs, pixim, pixg);
204  if (!pixd)
205  return (PIX *)ERROR_PTR("background norm failedd", procName, NULL);
206  pixGammaTRC(pixd, pixd, gamma, blackval, whiteval);
207  return pixd;
208 }
209 
210 
211 /*------------------------------------------------------------------*
212  * Adaptive background normalization *
213  *------------------------------------------------------------------*/
230 PIX *
232  PIX *pixim,
233  PIX *pixg)
234 {
235  return pixBackgroundNorm(pixs, pixim, pixg,
240 }
241 
242 
301 PIX *
303  PIX *pixim,
304  PIX *pixg,
305  l_int32 sx,
306  l_int32 sy,
307  l_int32 thresh,
308  l_int32 mincount,
309  l_int32 bgval,
310  l_int32 smoothx,
311  l_int32 smoothy)
312 {
313 l_int32 d, allfg;
314 PIX *pixm, *pixmi, *pixd;
315 PIX *pixmr, *pixmg, *pixmb, *pixmri, *pixmgi, *pixmbi;
316 
317  PROCNAME("pixBackgroundNorm");
318 
319  if (!pixs)
320  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
321  d = pixGetDepth(pixs);
322  if (d != 8 && d != 32)
323  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
324  if (sx < 4 || sy < 4)
325  return (PIX *)ERROR_PTR("sx and sy must be >= 4", procName, NULL);
326  if (mincount > sx * sy) {
327  L_WARNING("mincount too large for tile size\n", procName);
328  mincount = (sx * sy) / 3;
329  }
330 
331  /* If pixim exists, verify that it is not all foreground. */
332  if (pixim) {
333  pixInvert(pixim, pixim);
334  pixZero(pixim, &allfg);
335  pixInvert(pixim, pixim);
336  if (allfg)
337  return (PIX *)ERROR_PTR("pixim all foreground", procName, NULL);
338  }
339 
340  pixd = NULL;
341  if (d == 8) {
342  pixm = NULL;
343  pixGetBackgroundGrayMap(pixs, pixim, sx, sy, thresh, mincount, &pixm);
344  if (!pixm) {
345  L_WARNING("map not made; return a copy of the source\n", procName);
346  return pixCopy(NULL, pixs);
347  }
348 
349  pixmi = pixGetInvBackgroundMap(pixm, bgval, smoothx, smoothy);
350  if (!pixmi) {
351  L_WARNING("pixmi not made; return a copy of source\n", procName);
352  pixDestroy(&pixm);
353  return pixCopy(NULL, pixs);
354  } else {
355  pixd = pixApplyInvBackgroundGrayMap(pixs, pixmi, sx, sy);
356  }
357 
358  pixDestroy(&pixm);
359  pixDestroy(&pixmi);
360  }
361  else {
362  pixmr = pixmg = pixmb = NULL;
363  pixGetBackgroundRGBMap(pixs, pixim, pixg, sx, sy, thresh,
364  mincount, &pixmr, &pixmg, &pixmb);
365  if (!pixmr || !pixmg || !pixmb) {
366  pixDestroy(&pixmr);
367  pixDestroy(&pixmg);
368  pixDestroy(&pixmb);
369  L_WARNING("map not made; return a copy of the source\n", procName);
370  return pixCopy(NULL, pixs);
371  }
372 
373  pixmri = pixGetInvBackgroundMap(pixmr, bgval, smoothx, smoothy);
374  pixmgi = pixGetInvBackgroundMap(pixmg, bgval, smoothx, smoothy);
375  pixmbi = pixGetInvBackgroundMap(pixmb, bgval, smoothx, smoothy);
376  if (!pixmri || !pixmgi || !pixmbi) {
377  L_WARNING("not all pixm*i are made; return src copy\n", procName);
378  pixd = pixCopy(NULL, pixs);
379  } else {
380  pixd = pixApplyInvBackgroundRGBMap(pixs, pixmri, pixmgi, pixmbi,
381  sx, sy);
382  }
383 
384  pixDestroy(&pixmr);
385  pixDestroy(&pixmg);
386  pixDestroy(&pixmb);
387  pixDestroy(&pixmri);
388  pixDestroy(&pixmgi);
389  pixDestroy(&pixmbi);
390  }
391 
392  if (!pixd)
393  ERROR_PTR("pixd not made", procName, NULL);
394  pixCopyResolution(pixd, pixs);
395  return pixd;
396 }
397 
398 
438 PIX *
440  PIX *pixim,
441  l_int32 reduction,
442  l_int32 size,
443  l_int32 bgval)
444 {
445 l_int32 d, allfg;
446 PIX *pixm, *pixmi, *pixd;
447 PIX *pixmr, *pixmg, *pixmb, *pixmri, *pixmgi, *pixmbi;
448 
449  PROCNAME("pixBackgroundNormMorph");
450 
451  if (!pixs)
452  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
453  d = pixGetDepth(pixs);
454  if (d != 8 && d != 32)
455  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
456  if (reduction < 2 || reduction > 16)
457  return (PIX *)ERROR_PTR("reduction must be between 2 and 16",
458  procName, NULL);
459 
460  /* If pixim exists, verify that it is not all foreground. */
461  if (pixim) {
462  pixInvert(pixim, pixim);
463  pixZero(pixim, &allfg);
464  pixInvert(pixim, pixim);
465  if (allfg)
466  return (PIX *)ERROR_PTR("pixim all foreground", procName, NULL);
467  }
468 
469  pixd = NULL;
470  if (d == 8) {
471  pixGetBackgroundGrayMapMorph(pixs, pixim, reduction, size, &pixm);
472  if (!pixm)
473  return (PIX *)ERROR_PTR("pixm not made", procName, NULL);
474  pixmi = pixGetInvBackgroundMap(pixm, bgval, 0, 0);
475  if (!pixmi)
476  ERROR_PTR("pixmi not made", procName, NULL);
477  else
478  pixd = pixApplyInvBackgroundGrayMap(pixs, pixmi,
479  reduction, reduction);
480  pixDestroy(&pixm);
481  pixDestroy(&pixmi);
482  }
483  else { /* d == 32 */
484  pixmr = pixmg = pixmb = NULL;
485  pixGetBackgroundRGBMapMorph(pixs, pixim, reduction, size,
486  &pixmr, &pixmg, &pixmb);
487  if (!pixmr || !pixmg || !pixmb) {
488  pixDestroy(&pixmr);
489  pixDestroy(&pixmg);
490  pixDestroy(&pixmb);
491  return (PIX *)ERROR_PTR("not all pixm*", procName, NULL);
492  }
493 
494  pixmri = pixGetInvBackgroundMap(pixmr, bgval, 0, 0);
495  pixmgi = pixGetInvBackgroundMap(pixmg, bgval, 0, 0);
496  pixmbi = pixGetInvBackgroundMap(pixmb, bgval, 0, 0);
497  if (!pixmri || !pixmgi || !pixmbi)
498  ERROR_PTR("not all pixm*i are made", procName, NULL);
499  else
500  pixd = pixApplyInvBackgroundRGBMap(pixs, pixmri, pixmgi, pixmbi,
501  reduction, reduction);
502 
503  pixDestroy(&pixmr);
504  pixDestroy(&pixmg);
505  pixDestroy(&pixmb);
506  pixDestroy(&pixmri);
507  pixDestroy(&pixmgi);
508  pixDestroy(&pixmbi);
509  }
510 
511  if (!pixd)
512  ERROR_PTR("pixd not made", procName, NULL);
513  pixCopyResolution(pixd, pixs);
514  return pixd;
515 }
516 
517 
518 /*-------------------------------------------------------------------------*
519  * Arrays of inverted background values for normalization *
520  *-------------------------------------------------------------------------*
521  * Notes for these four functions: *
522  * (1) They are useful if you need to save the actual mapping array. *
523  * (2) They could be used in the top-level functions but are *
524  * not because their use makes those functions less clear. *
525  * (3) Each component in the input pixs generates a 16 bpp pix array. *
526  *-------------------------------------------------------------------------*/
549 l_ok
551  PIX *pixim,
552  l_int32 sx,
553  l_int32 sy,
554  l_int32 thresh,
555  l_int32 mincount,
556  l_int32 bgval,
557  l_int32 smoothx,
558  l_int32 smoothy,
559  PIX **ppixd)
560 {
561 l_int32 allfg;
562 PIX *pixm;
563 
564  PROCNAME("pixBackgroundNormGrayArray");
565 
566  if (!ppixd)
567  return ERROR_INT("&pixd not defined", procName, 1);
568  *ppixd = NULL;
569  if (!pixs || pixGetDepth(pixs) != 8)
570  return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
571  if (pixGetColormap(pixs))
572  return ERROR_INT("pixs is colormapped", procName, 1);
573  if (pixim && pixGetDepth(pixim) != 1)
574  return ERROR_INT("pixim not 1 bpp", procName, 1);
575  if (sx < 4 || sy < 4)
576  return ERROR_INT("sx and sy must be >= 4", procName, 1);
577  if (mincount > sx * sy) {
578  L_WARNING("mincount too large for tile size\n", procName);
579  mincount = (sx * sy) / 3;
580  }
581 
582  /* If pixim exists, verify that it is not all foreground. */
583  if (pixim) {
584  pixInvert(pixim, pixim);
585  pixZero(pixim, &allfg);
586  pixInvert(pixim, pixim);
587  if (allfg)
588  return ERROR_INT("pixim all foreground", procName, 1);
589  }
590 
591  pixGetBackgroundGrayMap(pixs, pixim, sx, sy, thresh, mincount, &pixm);
592  if (!pixm)
593  return ERROR_INT("pixm not made", procName, 1);
594  *ppixd = pixGetInvBackgroundMap(pixm, bgval, smoothx, smoothy);
595  pixCopyResolution(*ppixd, pixs);
596  pixDestroy(&pixm);
597  return 0;
598 }
599 
600 
626 l_ok
628  PIX *pixim,
629  PIX *pixg,
630  l_int32 sx,
631  l_int32 sy,
632  l_int32 thresh,
633  l_int32 mincount,
634  l_int32 bgval,
635  l_int32 smoothx,
636  l_int32 smoothy,
637  PIX **ppixr,
638  PIX **ppixg,
639  PIX **ppixb)
640 {
641 l_int32 allfg;
642 PIX *pixmr, *pixmg, *pixmb;
643 
644  PROCNAME("pixBackgroundNormRGBArrays");
645 
646  if (!ppixr || !ppixg || !ppixb)
647  return ERROR_INT("&pixr, &pixg, &pixb not all defined", procName, 1);
648  *ppixr = *ppixg = *ppixb = NULL;
649  if (!pixs)
650  return ERROR_INT("pixs not defined", procName, 1);
651  if (pixGetDepth(pixs) != 32)
652  return ERROR_INT("pixs not 32 bpp", procName, 1);
653  if (pixim && pixGetDepth(pixim) != 1)
654  return ERROR_INT("pixim not 1 bpp", procName, 1);
655  if (sx < 4 || sy < 4)
656  return ERROR_INT("sx and sy must be >= 4", procName, 1);
657  if (mincount > sx * sy) {
658  L_WARNING("mincount too large for tile size\n", procName);
659  mincount = (sx * sy) / 3;
660  }
661 
662  /* If pixim exists, verify that it is not all foreground. */
663  if (pixim) {
664  pixInvert(pixim, pixim);
665  pixZero(pixim, &allfg);
666  pixInvert(pixim, pixim);
667  if (allfg)
668  return ERROR_INT("pixim all foreground", procName, 1);
669  }
670 
671  pixGetBackgroundRGBMap(pixs, pixim, pixg, sx, sy, thresh, mincount,
672  &pixmr, &pixmg, &pixmb);
673  if (!pixmr || !pixmg || !pixmb) {
674  pixDestroy(&pixmr);
675  pixDestroy(&pixmg);
676  pixDestroy(&pixmb);
677  return ERROR_INT("not all pixm* made", procName, 1);
678  }
679 
680  *ppixr = pixGetInvBackgroundMap(pixmr, bgval, smoothx, smoothy);
681  *ppixg = pixGetInvBackgroundMap(pixmg, bgval, smoothx, smoothy);
682  *ppixb = pixGetInvBackgroundMap(pixmb, bgval, smoothx, smoothy);
683  pixDestroy(&pixmr);
684  pixDestroy(&pixmg);
685  pixDestroy(&pixmb);
686  return 0;
687 }
688 
689 
709 l_ok
711  PIX *pixim,
712  l_int32 reduction,
713  l_int32 size,
714  l_int32 bgval,
715  PIX **ppixd)
716 {
717 l_int32 allfg;
718 PIX *pixm;
719 
720  PROCNAME("pixBackgroundNormGrayArrayMorph");
721 
722  if (!ppixd)
723  return ERROR_INT("&pixd not defined", procName, 1);
724  *ppixd = NULL;
725  if (!pixs)
726  return ERROR_INT("pixs not defined", procName, 1);
727  if (pixGetDepth(pixs) != 8)
728  return ERROR_INT("pixs not 8 bpp", procName, 1);
729  if (pixim && pixGetDepth(pixim) != 1)
730  return ERROR_INT("pixim not 1 bpp", procName, 1);
731  if (reduction < 2 || reduction > 16)
732  return ERROR_INT("reduction must be between 2 and 16", procName, 1);
733 
734  /* If pixim exists, verify that it is not all foreground. */
735  if (pixim) {
736  pixInvert(pixim, pixim);
737  pixZero(pixim, &allfg);
738  pixInvert(pixim, pixim);
739  if (allfg)
740  return ERROR_INT("pixim all foreground", procName, 1);
741  }
742 
743  pixGetBackgroundGrayMapMorph(pixs, pixim, reduction, size, &pixm);
744  if (!pixm)
745  return ERROR_INT("pixm not made", procName, 1);
746  *ppixd = pixGetInvBackgroundMap(pixm, bgval, 0, 0);
747  pixCopyResolution(*ppixd, pixs);
748  pixDestroy(&pixm);
749  return 0;
750 }
751 
752 
774 l_ok
776  PIX *pixim,
777  l_int32 reduction,
778  l_int32 size,
779  l_int32 bgval,
780  PIX **ppixr,
781  PIX **ppixg,
782  PIX **ppixb)
783 {
784 l_int32 allfg;
785 PIX *pixmr, *pixmg, *pixmb;
786 
787  PROCNAME("pixBackgroundNormRGBArraysMorph");
788 
789  if (!ppixr || !ppixg || !ppixb)
790  return ERROR_INT("&pixr, &pixg, &pixb not all defined", procName, 1);
791  *ppixr = *ppixg = *ppixb = NULL;
792  if (!pixs)
793  return ERROR_INT("pixs not defined", procName, 1);
794  if (pixGetDepth(pixs) != 32)
795  return ERROR_INT("pixs not 32 bpp", procName, 1);
796  if (pixim && pixGetDepth(pixim) != 1)
797  return ERROR_INT("pixim not 1 bpp", procName, 1);
798  if (reduction < 2 || reduction > 16)
799  return ERROR_INT("reduction must be between 2 and 16", procName, 1);
800 
801  /* If pixim exists, verify that it is not all foreground. */
802  if (pixim) {
803  pixInvert(pixim, pixim);
804  pixZero(pixim, &allfg);
805  pixInvert(pixim, pixim);
806  if (allfg)
807  return ERROR_INT("pixim all foreground", procName, 1);
808  }
809 
810  pixGetBackgroundRGBMapMorph(pixs, pixim, reduction, size,
811  &pixmr, &pixmg, &pixmb);
812  if (!pixmr || !pixmg || !pixmb) {
813  pixDestroy(&pixmr);
814  pixDestroy(&pixmg);
815  pixDestroy(&pixmb);
816  return ERROR_INT("not all pixm* made", procName, 1);
817  }
818 
819  *ppixr = pixGetInvBackgroundMap(pixmr, bgval, 0, 0);
820  *ppixg = pixGetInvBackgroundMap(pixmg, bgval, 0, 0);
821  *ppixb = pixGetInvBackgroundMap(pixmb, bgval, 0, 0);
822  pixDestroy(&pixmr);
823  pixDestroy(&pixmg);
824  pixDestroy(&pixmb);
825  return 0;
826 }
827 
828 
829 /*------------------------------------------------------------------*
830  * Measurement of local background *
831  *------------------------------------------------------------------*/
851 l_ok
853  PIX *pixim,
854  l_int32 sx,
855  l_int32 sy,
856  l_int32 thresh,
857  l_int32 mincount,
858  PIX **ppixd)
859 {
860 l_int32 w, h, wd, hd, wim, him, wpls, wplim, wpld, wplf;
861 l_int32 xim, yim, delx, nx, ny, i, j, k, m;
862 l_int32 count, sum, val8;
863 l_int32 empty, fgpixels;
864 l_uint32 *datas, *dataim, *datad, *dataf, *lines, *lineim, *lined, *linef;
865 l_float32 scalex, scaley;
866 PIX *pixd, *piximi, *pixb, *pixf, *pixims;
867 
868  PROCNAME("pixGetBackgroundGrayMap");
869 
870  if (!ppixd)
871  return ERROR_INT("&pixd not defined", procName, 1);
872  *ppixd = NULL;
873  if (!pixs || pixGetDepth(pixs) != 8)
874  return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
875  if (pixGetColormap(pixs))
876  return ERROR_INT("pixs is colormapped", procName, 1);
877  if (pixim && pixGetDepth(pixim) != 1)
878  return ERROR_INT("pixim not 1 bpp", procName, 1);
879  if (sx < 4 || sy < 4)
880  return ERROR_INT("sx and sy must be >= 4", procName, 1);
881  if (mincount > sx * sy) {
882  L_WARNING("mincount too large for tile size\n", procName);
883  mincount = (sx * sy) / 3;
884  }
885 
886  /* Evaluate the 'image' mask, pixim, and make sure
887  * it is not all fg. */
888  fgpixels = 0; /* boolean for existence of fg pixels in the image mask. */
889  if (pixim) {
890  piximi = pixInvert(NULL, pixim); /* set non-'image' pixels to 1 */
891  pixZero(piximi, &empty);
892  pixDestroy(&piximi);
893  if (empty)
894  return ERROR_INT("pixim all fg; no background", procName, 1);
895  pixZero(pixim, &empty);
896  if (!empty) /* there are fg pixels in pixim */
897  fgpixels = 1;
898  }
899 
900  /* Generate the foreground mask, pixf, which is at
901  * full resolution. These pixels will be ignored when
902  * computing the background values. */
903  pixb = pixThresholdToBinary(pixs, thresh);
904  pixf = pixMorphSequence(pixb, "d7.1 + d1.7", 0);
905  pixDestroy(&pixb);
906 
907 
908  /* ------------- Set up the output map pixd --------------- */
909  /* Generate pixd, which is reduced by the factors (sx, sy). */
910  w = pixGetWidth(pixs);
911  h = pixGetHeight(pixs);
912  wd = (w + sx - 1) / sx;
913  hd = (h + sy - 1) / sy;
914  pixd = pixCreate(wd, hd, 8);
915 
916  /* Note: we only compute map values in tiles that are complete.
917  * In general, tiles at right and bottom edges will not be
918  * complete, and we must fill them in later. */
919  nx = w / sx;
920  ny = h / sy;
921  wpls = pixGetWpl(pixs);
922  datas = pixGetData(pixs);
923  wpld = pixGetWpl(pixd);
924  datad = pixGetData(pixd);
925  wplf = pixGetWpl(pixf);
926  dataf = pixGetData(pixf);
927  for (i = 0; i < ny; i++) {
928  lines = datas + sy * i * wpls;
929  linef = dataf + sy * i * wplf;
930  lined = datad + i * wpld;
931  for (j = 0; j < nx; j++) {
932  delx = j * sx;
933  sum = 0;
934  count = 0;
935  for (k = 0; k < sy; k++) {
936  for (m = 0; m < sx; m++) {
937  if (GET_DATA_BIT(linef + k * wplf, delx + m) == 0) {
938  sum += GET_DATA_BYTE(lines + k * wpls, delx + m);
939  count++;
940  }
941  }
942  }
943  if (count >= mincount) {
944  val8 = sum / count;
945  SET_DATA_BYTE(lined, j, val8);
946  }
947  }
948  }
949  pixDestroy(&pixf);
950 
951  /* If there is an optional mask with fg pixels, erase the previous
952  * calculation for the corresponding map pixels, setting the
953  * map values to 0. Then, when all the map holes are filled,
954  * these erased pixels will be set by the surrounding map values.
955  *
956  * The calculation here is relatively efficient: for each pixel
957  * in pixd (which corresponds to a tile of mask pixels in pixim)
958  * we look only at the pixel in pixim that is at the center
959  * of the tile. If the mask pixel is ON, we reset the map
960  * pixel in pixd to 0, so that it can later be filled in. */
961  pixims = NULL;
962  if (pixim && fgpixels) {
963  wim = pixGetWidth(pixim);
964  him = pixGetHeight(pixim);
965  dataim = pixGetData(pixim);
966  wplim = pixGetWpl(pixim);
967  for (i = 0; i < ny; i++) {
968  yim = i * sy + sy / 2;
969  if (yim >= him)
970  break;
971  lineim = dataim + yim * wplim;
972  for (j = 0; j < nx; j++) {
973  xim = j * sx + sx / 2;
974  if (xim >= wim)
975  break;
976  if (GET_DATA_BIT(lineim, xim))
977  pixSetPixel(pixd, j, i, 0);
978  }
979  }
980  }
981 
982  /* Fill all the holes in the map. */
983  if (pixFillMapHoles(pixd, nx, ny, L_FILL_BLACK)) {
984  pixDestroy(&pixd);
985  L_WARNING("can't make the map\n", procName);
986  return 1;
987  }
988 
989  /* Finally, for each connected region corresponding to the
990  * 'image' mask, reset all pixels to their average value.
991  * Each of these components represents an image (or part of one)
992  * in the input, and this smooths the background values
993  * in each of these regions. */
994  if (pixim && fgpixels) {
995  scalex = 1. / (l_float32)sx;
996  scaley = 1. / (l_float32)sy;
997  pixims = pixScaleBySampling(pixim, scalex, scaley);
998  pixSmoothConnectedRegions(pixd, pixims, 2);
999  pixDestroy(&pixims);
1000  }
1001 
1002  *ppixd = pixd;
1003  pixCopyResolution(*ppixd, pixs);
1004  return 0;
1005 }
1006 
1007 
1029 l_ok
1031  PIX *pixim,
1032  PIX *pixg,
1033  l_int32 sx,
1034  l_int32 sy,
1035  l_int32 thresh,
1036  l_int32 mincount,
1037  PIX **ppixmr,
1038  PIX **ppixmg,
1039  PIX **ppixmb)
1040 {
1041 l_int32 w, h, wm, hm, wim, him, wpls, wplim, wplf;
1042 l_int32 xim, yim, delx, nx, ny, i, j, k, m;
1043 l_int32 count, rsum, gsum, bsum, rval, gval, bval;
1044 l_int32 empty, fgpixels;
1045 l_uint32 pixel;
1046 l_uint32 *datas, *dataim, *dataf, *lines, *lineim, *linef;
1047 l_float32 scalex, scaley;
1048 PIX *piximi, *pixgc, *pixb, *pixf, *pixims;
1049 PIX *pixmr, *pixmg, *pixmb;
1050 
1051  PROCNAME("pixGetBackgroundRGBMap");
1052 
1053  if (!ppixmr || !ppixmg || !ppixmb)
1054  return ERROR_INT("&pixm* not all defined", procName, 1);
1055  *ppixmr = *ppixmg = *ppixmb = NULL;
1056  if (!pixs)
1057  return ERROR_INT("pixs not defined", procName, 1);
1058  if (pixGetDepth(pixs) != 32)
1059  return ERROR_INT("pixs not 32 bpp", procName, 1);
1060  if (pixim && pixGetDepth(pixim) != 1)
1061  return ERROR_INT("pixim not 1 bpp", procName, 1);
1062  if (sx < 4 || sy < 4)
1063  return ERROR_INT("sx and sy must be >= 4", procName, 1);
1064  if (mincount > sx * sy) {
1065  L_WARNING("mincount too large for tile size\n", procName);
1066  mincount = (sx * sy) / 3;
1067  }
1068 
1069  /* Evaluate the mask pixim and make sure it is not all foreground */
1070  fgpixels = 0; /* boolean for existence of fg mask pixels */
1071  if (pixim) {
1072  piximi = pixInvert(NULL, pixim); /* set non-'image' pixels to 1 */
1073  pixZero(piximi, &empty);
1074  pixDestroy(&piximi);
1075  if (empty)
1076  return ERROR_INT("pixim all fg; no background", procName, 1);
1077  pixZero(pixim, &empty);
1078  if (!empty) /* there are fg pixels in pixim */
1079  fgpixels = 1;
1080  }
1081 
1082  /* Generate the foreground mask. These pixels will be
1083  * ignored when computing the background values. */
1084  if (pixg) /* use the input grayscale version if it is provided */
1085  pixgc = pixClone(pixg);
1086  else
1087  pixgc = pixConvertRGBToGrayFast(pixs);
1088  pixb = pixThresholdToBinary(pixgc, thresh);
1089  pixf = pixMorphSequence(pixb, "d7.1 + d1.7", 0);
1090  pixDestroy(&pixgc);
1091  pixDestroy(&pixb);
1092 
1093  /* Generate the output mask images */
1094  w = pixGetWidth(pixs);
1095  h = pixGetHeight(pixs);
1096  wm = (w + sx - 1) / sx;
1097  hm = (h + sy - 1) / sy;
1098  pixmr = pixCreate(wm, hm, 8);
1099  pixmg = pixCreate(wm, hm, 8);
1100  pixmb = pixCreate(wm, hm, 8);
1101 
1102  /* ------------- Set up the mapping images --------------- */
1103  /* Note: we only compute map values in tiles that are complete.
1104  * In general, tiles at right and bottom edges will not be
1105  * complete, and we must fill them in later. */
1106  nx = w / sx;
1107  ny = h / sy;
1108  wpls = pixGetWpl(pixs);
1109  datas = pixGetData(pixs);
1110  wplf = pixGetWpl(pixf);
1111  dataf = pixGetData(pixf);
1112  for (i = 0; i < ny; i++) {
1113  lines = datas + sy * i * wpls;
1114  linef = dataf + sy * i * wplf;
1115  for (j = 0; j < nx; j++) {
1116  delx = j * sx;
1117  rsum = gsum = bsum = 0;
1118  count = 0;
1119  for (k = 0; k < sy; k++) {
1120  for (m = 0; m < sx; m++) {
1121  if (GET_DATA_BIT(linef + k * wplf, delx + m) == 0) {
1122  pixel = *(lines + k * wpls + delx + m);
1123  rsum += (pixel >> 24);
1124  gsum += ((pixel >> 16) & 0xff);
1125  bsum += ((pixel >> 8) & 0xff);
1126  count++;
1127  }
1128  }
1129  }
1130  if (count >= mincount) {
1131  rval = rsum / count;
1132  gval = gsum / count;
1133  bval = bsum / count;
1134  pixSetPixel(pixmr, j, i, rval);
1135  pixSetPixel(pixmg, j, i, gval);
1136  pixSetPixel(pixmb, j, i, bval);
1137  }
1138  }
1139  }
1140  pixDestroy(&pixf);
1141 
1142  /* If there is an optional mask with fg pixels, erase the previous
1143  * calculation for the corresponding map pixels, setting the
1144  * map values in each of the 3 color maps to 0. Then, when
1145  * all the map holes are filled, these erased pixels will
1146  * be set by the surrounding map values. */
1147  if (pixim) {
1148  wim = pixGetWidth(pixim);
1149  him = pixGetHeight(pixim);
1150  dataim = pixGetData(pixim);
1151  wplim = pixGetWpl(pixim);
1152  for (i = 0; i < ny; i++) {
1153  yim = i * sy + sy / 2;
1154  if (yim >= him)
1155  break;
1156  lineim = dataim + yim * wplim;
1157  for (j = 0; j < nx; j++) {
1158  xim = j * sx + sx / 2;
1159  if (xim >= wim)
1160  break;
1161  if (GET_DATA_BIT(lineim, xim)) {
1162  pixSetPixel(pixmr, j, i, 0);
1163  pixSetPixel(pixmg, j, i, 0);
1164  pixSetPixel(pixmb, j, i, 0);
1165  }
1166  }
1167  }
1168  }
1169 
1170  /* ----------------- Now fill in the holes ----------------------- */
1171  if (pixFillMapHoles(pixmr, nx, ny, L_FILL_BLACK) ||
1172  pixFillMapHoles(pixmg, nx, ny, L_FILL_BLACK) ||
1173  pixFillMapHoles(pixmb, nx, ny, L_FILL_BLACK)) {
1174  pixDestroy(&pixmr);
1175  pixDestroy(&pixmg);
1176  pixDestroy(&pixmb);
1177  L_WARNING("can't make the maps\n", procName);
1178  return 1;
1179  }
1180 
1181  /* Finally, for each connected region corresponding to the
1182  * fg mask, reset all pixels to their average value. */
1183  if (pixim && fgpixels) {
1184  scalex = 1. / (l_float32)sx;
1185  scaley = 1. / (l_float32)sy;
1186  pixims = pixScaleBySampling(pixim, scalex, scaley);
1187  pixSmoothConnectedRegions(pixmr, pixims, 2);
1188  pixSmoothConnectedRegions(pixmg, pixims, 2);
1189  pixSmoothConnectedRegions(pixmb, pixims, 2);
1190  pixDestroy(&pixims);
1191  }
1192 
1193  *ppixmr = pixmr;
1194  *ppixmg = pixmg;
1195  *ppixmb = pixmb;
1196  pixCopyResolution(*ppixmr, pixs);
1197  pixCopyResolution(*ppixmg, pixs);
1198  pixCopyResolution(*ppixmb, pixs);
1199  return 0;
1200 }
1201 
1202 
1214 l_ok
1216  PIX *pixim,
1217  l_int32 reduction,
1218  l_int32 size,
1219  PIX **ppixm)
1220 {
1221 l_int32 nx, ny, empty, fgpixels;
1222 l_float32 scale;
1223 PIX *pixm, *pix1, *pix2, *pix3, *pixims;
1224 
1225  PROCNAME("pixGetBackgroundGrayMapMorph");
1226 
1227  if (!ppixm)
1228  return ERROR_INT("&pixm not defined", procName, 1);
1229  *ppixm = NULL;
1230  if (!pixs || pixGetDepth(pixs) != 8)
1231  return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
1232  if (pixGetColormap(pixs))
1233  return ERROR_INT("pixs is colormapped", procName, 1);
1234  if (pixim && pixGetDepth(pixim) != 1)
1235  return ERROR_INT("pixim not 1 bpp", procName, 1);
1236 
1237  /* Evaluate the mask pixim and make sure it is not all foreground. */
1238  fgpixels = 0; /* boolean for existence of fg mask pixels */
1239  if (pixim) {
1240  pixInvert(pixim, pixim); /* set background pixels to 1 */
1241  pixZero(pixim, &empty);
1242  if (empty)
1243  return ERROR_INT("pixim all fg; no background", procName, 1);
1244  pixInvert(pixim, pixim); /* revert to original mask */
1245  pixZero(pixim, &empty);
1246  if (!empty) /* there are fg pixels in pixim */
1247  fgpixels = 1;
1248  }
1249 
1250  /* Downscale as requested and do the closing to get the background. */
1251  scale = 1. / (l_float32)reduction;
1252  pix1 = pixScaleBySampling(pixs, scale, scale);
1253  pix2 = pixCloseGray(pix1, size, size);
1254  pix3 = pixExtendByReplication(pix2, 1, 1);
1255  pixDestroy(&pix1);
1256  pixDestroy(&pix2);
1257 
1258  /* Downscale the image mask, if any, and remove it from the
1259  * background. These pixels will be filled in (twice). */
1260  pixims = NULL;
1261  if (pixim) {
1262  pixims = pixScale(pixim, scale, scale);
1263  pixm = pixConvertTo8(pixims, FALSE);
1264  pixAnd(pixm, pixm, pix3);
1265  }
1266  else
1267  pixm = pixClone(pix3);
1268  pixDestroy(&pix3);
1269 
1270  /* Fill all the holes in the map. */
1271  nx = pixGetWidth(pixs) / reduction;
1272  ny = pixGetHeight(pixs) / reduction;
1273  if (pixFillMapHoles(pixm, nx, ny, L_FILL_BLACK)) {
1274  pixDestroy(&pixm);
1275  pixDestroy(&pixims);
1276  L_WARNING("can't make the map\n", procName);
1277  return 1;
1278  }
1279 
1280  /* Finally, for each connected region corresponding to the
1281  * fg mask, reset all pixels to their average value. */
1282  if (pixim && fgpixels)
1283  pixSmoothConnectedRegions(pixm, pixims, 2);
1284  pixDestroy(&pixims);
1285 
1286  *ppixm = pixm;
1287  pixCopyResolution(*ppixm, pixs);
1288  return 0;
1289 }
1290 
1291 
1305 l_ok
1307  PIX *pixim,
1308  l_int32 reduction,
1309  l_int32 size,
1310  PIX **ppixmr,
1311  PIX **ppixmg,
1312  PIX **ppixmb)
1313 {
1314 l_int32 nx, ny, empty, fgpixels;
1315 l_float32 scale;
1316 PIX *pixm, *pixmr, *pixmg, *pixmb, *pix1, *pix2, *pix3, *pixims;
1317 
1318  PROCNAME("pixGetBackgroundRGBMapMorph");
1319 
1320  if (!ppixmr || !ppixmg || !ppixmb)
1321  return ERROR_INT("&pixm* not all defined", procName, 1);
1322  *ppixmr = *ppixmg = *ppixmb = NULL;
1323  if (!pixs)
1324  return ERROR_INT("pixs not defined", procName, 1);
1325  if (pixGetDepth(pixs) != 32)
1326  return ERROR_INT("pixs not 32 bpp", procName, 1);
1327  if (pixim && pixGetDepth(pixim) != 1)
1328  return ERROR_INT("pixim not 1 bpp", procName, 1);
1329 
1330  /* Evaluate the mask pixim and make sure it is not all foreground. */
1331  fgpixels = 0; /* boolean for existence of fg mask pixels */
1332  if (pixim) {
1333  pixInvert(pixim, pixim); /* set background pixels to 1 */
1334  pixZero(pixim, &empty);
1335  if (empty)
1336  return ERROR_INT("pixim all fg; no background", procName, 1);
1337  pixInvert(pixim, pixim); /* revert to original mask */
1338  pixZero(pixim, &empty);
1339  if (!empty) /* there are fg pixels in pixim */
1340  fgpixels = 1;
1341  }
1342 
1343  /* Generate an 8 bpp version of the image mask, if it exists */
1344  scale = 1. / (l_float32)reduction;
1345  pixims = NULL;
1346  pixm = NULL;
1347  if (pixim) {
1348  pixims = pixScale(pixim, scale, scale);
1349  pixm = pixConvertTo8(pixims, FALSE);
1350  }
1351 
1352  /* Downscale as requested and do the closing to get the background.
1353  * Then remove the image mask pixels from the background. They
1354  * will be filled in (twice) later. Do this for all 3 components. */
1355  pix1 = pixScaleRGBToGrayFast(pixs, reduction, COLOR_RED);
1356  pix2 = pixCloseGray(pix1, size, size);
1357  pix3 = pixExtendByReplication(pix2, 1, 1);
1358  if (pixim)
1359  pixmr = pixAnd(NULL, pixm, pix3);
1360  else
1361  pixmr = pixClone(pix3);
1362  pixDestroy(&pix1);
1363  pixDestroy(&pix2);
1364  pixDestroy(&pix3);
1365 
1366  pix1 = pixScaleRGBToGrayFast(pixs, reduction, COLOR_GREEN);
1367  pix2 = pixCloseGray(pix1, size, size);
1368  pix3 = pixExtendByReplication(pix2, 1, 1);
1369  if (pixim)
1370  pixmg = pixAnd(NULL, pixm, pix3);
1371  else
1372  pixmg = pixClone(pix3);
1373  pixDestroy(&pix1);
1374  pixDestroy(&pix2);
1375  pixDestroy(&pix3);
1376 
1377  pix1 = pixScaleRGBToGrayFast(pixs, reduction, COLOR_BLUE);
1378  pix2 = pixCloseGray(pix1, size, size);
1379  pix3 = pixExtendByReplication(pix2, 1, 1);
1380  if (pixim)
1381  pixmb = pixAnd(NULL, pixm, pix3);
1382  else
1383  pixmb = pixClone(pix3);
1384  pixDestroy(&pixm);
1385  pixDestroy(&pix1);
1386  pixDestroy(&pix2);
1387  pixDestroy(&pix3);
1388 
1389  /* Fill all the holes in the three maps. */
1390  nx = pixGetWidth(pixs) / reduction;
1391  ny = pixGetHeight(pixs) / reduction;
1392  if (pixFillMapHoles(pixmr, nx, ny, L_FILL_BLACK) ||
1393  pixFillMapHoles(pixmg, nx, ny, L_FILL_BLACK) ||
1394  pixFillMapHoles(pixmb, nx, ny, L_FILL_BLACK)) {
1395  pixDestroy(&pixmr);
1396  pixDestroy(&pixmg);
1397  pixDestroy(&pixmb);
1398  pixDestroy(&pixims);
1399  L_WARNING("can't make the maps\n", procName);
1400  return 1;
1401  }
1402 
1403  /* Finally, for each connected region corresponding to the
1404  * fg mask in each component, reset all pixels to their
1405  * average value. */
1406  if (pixim && fgpixels) {
1407  pixSmoothConnectedRegions(pixmr, pixims, 2);
1408  pixSmoothConnectedRegions(pixmg, pixims, 2);
1409  pixSmoothConnectedRegions(pixmb, pixims, 2);
1410  pixDestroy(&pixims);
1411  }
1412 
1413  *ppixmr = pixmr;
1414  *ppixmg = pixmg;
1415  *ppixmb = pixmb;
1416  pixCopyResolution(*ppixmr, pixs);
1417  pixCopyResolution(*ppixmg, pixs);
1418  pixCopyResolution(*ppixmb, pixs);
1419  return 0;
1420 }
1421 
1422 
1459 l_ok
1461  l_int32 nx,
1462  l_int32 ny,
1463  l_int32 filltype)
1464 {
1465 l_int32 w, h, y, nmiss, goodcol, i, j, found, ival, valtest;
1466 l_uint32 val, lastval;
1467 NUMA *na; /* indicates if there is any data in the column */
1468 PIX *pixt;
1469 
1470  PROCNAME("pixFillMapHoles");
1471 
1472  if (!pix || pixGetDepth(pix) != 8)
1473  return ERROR_INT("pix not defined or not 8 bpp", procName, 1);
1474  if (pixGetColormap(pix))
1475  return ERROR_INT("pix is colormapped", procName, 1);
1476 
1477  /* ------------- Fill holes in the mapping image columns ----------- */
1478  pixGetDimensions(pix, &w, &h, NULL);
1479  na = numaCreate(0); /* holds flag for which columns have data */
1480  nmiss = 0;
1481  valtest = (filltype == L_FILL_WHITE) ? 255 : 0;
1482  for (j = 0; j < nx; j++) { /* do it by columns */
1483  found = FALSE;
1484  for (i = 0; i < ny; i++) {
1485  pixGetPixel(pix, j, i, &val);
1486  if (val != valtest) {
1487  y = i;
1488  found = TRUE;
1489  break;
1490  }
1491  }
1492  if (found == FALSE) {
1493  numaAddNumber(na, 0); /* no data in the column */
1494  nmiss++;
1495  }
1496  else {
1497  numaAddNumber(na, 1); /* data in the column */
1498  for (i = y - 1; i >= 0; i--) /* replicate upwards to top */
1499  pixSetPixel(pix, j, i, val);
1500  pixGetPixel(pix, j, 0, &lastval);
1501  for (i = 1; i < h; i++) { /* set going down to bottom */
1502  pixGetPixel(pix, j, i, &val);
1503  if (val == valtest)
1504  pixSetPixel(pix, j, i, lastval);
1505  else
1506  lastval = val;
1507  }
1508  }
1509  }
1510  numaAddNumber(na, 0); /* last column */
1511 
1512  if (nmiss == nx) { /* no data in any column! */
1513  numaDestroy(&na);
1514  L_WARNING("no bg found; no data in any column\n", procName);
1515  return 1;
1516  }
1517 
1518  /* ---------- Fill in missing columns by replication ----------- */
1519  if (nmiss > 0) { /* replicate columns */
1520  pixt = pixCopy(NULL, pix);
1521  /* Find the first good column */
1522  goodcol = 0;
1523  for (j = 0; j < w; j++) {
1524  numaGetIValue(na, j, &ival);
1525  if (ival == 1) {
1526  goodcol = j;
1527  break;
1528  }
1529  }
1530  if (goodcol > 0) { /* copy cols backward */
1531  for (j = goodcol - 1; j >= 0; j--) {
1532  pixRasterop(pix, j, 0, 1, h, PIX_SRC, pixt, j + 1, 0);
1533  pixRasterop(pixt, j, 0, 1, h, PIX_SRC, pix, j, 0);
1534  }
1535  }
1536  for (j = goodcol + 1; j < w; j++) { /* copy cols forward */
1537  numaGetIValue(na, j, &ival);
1538  if (ival == 0) {
1539  /* Copy the column to the left of j */
1540  pixRasterop(pix, j, 0, 1, h, PIX_SRC, pixt, j - 1, 0);
1541  pixRasterop(pixt, j, 0, 1, h, PIX_SRC, pix, j, 0);
1542  }
1543  }
1544  pixDestroy(&pixt);
1545  }
1546  if (w > nx) { /* replicate the last column */
1547  for (i = 0; i < h; i++) {
1548  pixGetPixel(pix, w - 2, i, &val);
1549  pixSetPixel(pix, w - 1, i, val);
1550  }
1551  }
1552 
1553  numaDestroy(&na);
1554  return 0;
1555 }
1556 
1557 
1571 PIX *
1573  l_int32 addw,
1574  l_int32 addh)
1575 {
1576 l_int32 w, h, i, j;
1577 l_uint32 val;
1578 PIX *pixd;
1579 
1580  PROCNAME("pixExtendByReplication");
1581 
1582  if (!pixs || pixGetDepth(pixs) != 8)
1583  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
1584 
1585  if (addw == 0 && addh == 0)
1586  return pixCopy(NULL, pixs);
1587 
1588  pixGetDimensions(pixs, &w, &h, NULL);
1589  if ((pixd = pixCreate(w + addw, h + addh, 8)) == NULL)
1590  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1591  pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
1592 
1593  if (addw > 0) {
1594  for (i = 0; i < h; i++) {
1595  pixGetPixel(pixd, w - 1, i, &val);
1596  for (j = 0; j < addw; j++)
1597  pixSetPixel(pixd, w + j, i, val);
1598  }
1599  }
1600 
1601  if (addh > 0) {
1602  for (j = 0; j < w + addw; j++) {
1603  pixGetPixel(pixd, j, h - 1, &val);
1604  for (i = 0; i < addh; i++)
1605  pixSetPixel(pixd, j, h + i, val);
1606  }
1607  }
1608 
1609  pixCopyResolution(pixd, pixs);
1610  return pixd;
1611 }
1612 
1613 
1634 l_ok
1636  PIX *pixm,
1637  l_int32 factor)
1638 {
1639 l_int32 empty, i, n, x, y;
1640 l_float32 aveval;
1641 BOXA *boxa;
1642 PIX *pixmc;
1643 PIXA *pixa;
1644 
1645  PROCNAME("pixSmoothConnectedRegions");
1646 
1647  if (!pixs || pixGetDepth(pixs) != 8)
1648  return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
1649  if (pixGetColormap(pixs))
1650  return ERROR_INT("pixs has colormap", procName, 1);
1651  if (!pixm) {
1652  L_INFO("pixm not defined\n", procName);
1653  return 0;
1654  }
1655  if (pixGetDepth(pixm) != 1)
1656  return ERROR_INT("pixm not 1 bpp", procName, 1);
1657  pixZero(pixm, &empty);
1658  if (empty) {
1659  L_INFO("pixm has no fg pixels; nothing to do\n", procName);
1660  return 0;
1661  }
1662 
1663  boxa = pixConnComp(pixm, &pixa, 8);
1664  n = boxaGetCount(boxa);
1665  for (i = 0; i < n; i++) {
1666  if ((pixmc = pixaGetPix(pixa, i, L_CLONE)) == NULL) {
1667  L_WARNING("missing pixmc!\n", procName);
1668  continue;
1669  }
1670  boxaGetBoxGeometry(boxa, i, &x, &y, NULL, NULL);
1671  pixGetAverageMasked(pixs, pixmc, x, y, factor, L_MEAN_ABSVAL, &aveval);
1672  pixPaintThroughMask(pixs, pixmc, x, y, (l_int32)aveval);
1673  pixDestroy(&pixmc);
1674  }
1675 
1676  boxaDestroy(&boxa);
1677  pixaDestroy(&pixa);
1678  return 0;
1679 }
1680 
1681 
1682 /*------------------------------------------------------------------*
1683  * Measurement of local foreground *
1684  *------------------------------------------------------------------*/
1685 #if 0 /* Not working properly: do not use */
1686 
1723 l_ok
1724 pixGetForegroundGrayMap(PIX *pixs,
1725  PIX *pixim,
1726  l_int32 sx,
1727  l_int32 sy,
1728  l_int32 thresh,
1729  PIX **ppixd)
1730 {
1731 l_int32 w, h, d, wd, hd;
1732 l_int32 empty, fgpixels;
1733 PIX *pixd, *piximi, *pixim2, *pixims, *pixs2, *pixb, *pixt1, *pixt2, *pixt3;
1734 
1735  PROCNAME("pixGetForegroundGrayMap");
1736 
1737  if (!ppixd)
1738  return ERROR_INT("&pixd not defined", procName, 1);
1739  *ppixd = NULL;
1740  if (!pixs)
1741  return ERROR_INT("pixs not defined", procName, 1);
1742  pixGetDimensions(pixs, &w, &h, &d);
1743  if (d != 8)
1744  return ERROR_INT("pixs not 8 bpp", procName, 1);
1745  if (pixim && pixGetDepth(pixim) != 1)
1746  return ERROR_INT("pixim not 1 bpp", procName, 1);
1747  if (sx < 2 || sy < 2)
1748  return ERROR_INT("sx and sy must be >= 2", procName, 1);
1749 
1750  /* Generate pixd, which is reduced by the factors (sx, sy). */
1751  wd = (w + sx - 1) / sx;
1752  hd = (h + sy - 1) / sy;
1753  pixd = pixCreate(wd, hd, 8);
1754  *ppixd = pixd;
1755 
1756  /* Evaluate the 'image' mask, pixim. If it is all fg,
1757  * the output pixd has all pixels with value 0. */
1758  fgpixels = 0; /* boolean for existence of fg pixels in the image mask. */
1759  if (pixim) {
1760  piximi = pixInvert(NULL, pixim); /* set non-image pixels to 1 */
1761  pixZero(piximi, &empty);
1762  pixDestroy(&piximi);
1763  if (empty) /* all 'image'; return with all pixels set to 0 */
1764  return 0;
1765  pixZero(pixim, &empty);
1766  if (!empty) /* there are fg pixels in pixim */
1767  fgpixels = 1;
1768  }
1769 
1770  /* 2x subsampling; paint white through 'image' mask. */
1771  pixs2 = pixScaleBySampling(pixs, 0.5, 0.5);
1772  if (pixim && fgpixels) {
1773  pixim2 = pixReduceBinary2(pixim, NULL);
1774  pixPaintThroughMask(pixs2, pixim2, 0, 0, 255);
1775  pixDestroy(&pixim2);
1776  }
1777 
1778  /* Min (erosion) downscaling; total reduction (4 sx, 4 sy). */
1779  pixt1 = pixScaleGrayMinMax(pixs2, sx, sy, L_CHOOSE_MIN);
1780 
1781 /* pixDisplay(pixt1, 300, 200); */
1782 
1783  /* Threshold to identify fg; paint bg pixels to white. */
1784  pixb = pixThresholdToBinary(pixt1, thresh); /* fg pixels */
1785  pixInvert(pixb, pixb);
1786  pixPaintThroughMask(pixt1, pixb, 0, 0, 255);
1787  pixDestroy(&pixb);
1788 
1789  /* Replicative expansion by 2x to (sx, sy). */
1790  pixt2 = pixExpandReplicate(pixt1, 2);
1791 
1792 /* pixDisplay(pixt2, 500, 200); */
1793 
1794  /* Fill holes in the fg by propagation */
1795  pixFillMapHoles(pixt2, w / sx, h / sy, L_FILL_WHITE);
1796 
1797 /* pixDisplay(pixt2, 700, 200); */
1798 
1799  /* Smooth with 17x17 kernel. */
1800  pixt3 = pixBlockconv(pixt2, 8, 8);
1801  pixRasterop(pixd, 0, 0, wd, hd, PIX_SRC, pixt3, 0, 0);
1802 
1803  /* Paint the image parts black. */
1804  pixims = pixScaleBySampling(pixim, 1. / sx, 1. / sy);
1805  pixPaintThroughMask(pixd, pixims, 0, 0, 0);
1806 
1807  pixDestroy(&pixs2);
1808  pixDestroy(&pixt1);
1809  pixDestroy(&pixt2);
1810  pixDestroy(&pixt3);
1811  return 0;
1812 }
1813 #endif /* Not working properly: do not use */
1814 
1815 
1816 /*------------------------------------------------------------------*
1817  * Generate inverted background map *
1818  *------------------------------------------------------------------*/
1835 PIX *
1837  l_int32 bgval,
1838  l_int32 smoothx,
1839  l_int32 smoothy)
1840 {
1841 l_int32 w, h, wplsm, wpld, i, j;
1842 l_int32 val, val16;
1843 l_uint32 *datasm, *datad, *linesm, *lined;
1844 PIX *pixsm, *pixd;
1845 
1846  PROCNAME("pixGetInvBackgroundMap");
1847 
1848  if (!pixs || pixGetDepth(pixs) != 8)
1849  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
1850  if (pixGetColormap(pixs))
1851  return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
1852  pixGetDimensions(pixs, &w, &h, NULL);
1853  if (w < 5 || h < 5)
1854  return (PIX *)ERROR_PTR("w and h must be >= 5", procName, NULL);
1855 
1856  /* smooth the map image */
1857  pixsm = pixBlockconv(pixs, smoothx, smoothy);
1858  datasm = pixGetData(pixsm);
1859  wplsm = pixGetWpl(pixsm);
1860 
1861  /* invert the map image, scaling up to preserve dynamic range */
1862  pixd = pixCreate(w, h, 16);
1863  datad = pixGetData(pixd);
1864  wpld = pixGetWpl(pixd);
1865  for (i = 0; i < h; i++) {
1866  linesm = datasm + i * wplsm;
1867  lined = datad + i * wpld;
1868  for (j = 0; j < w; j++) {
1869  val = GET_DATA_BYTE(linesm, j);
1870  if (val > 0)
1871  val16 = (256 * bgval) / val;
1872  else { /* shouldn't happen */
1873  L_WARNING("smoothed bg has 0 pixel!\n", procName);
1874  val16 = bgval / 2;
1875  }
1876  SET_DATA_TWO_BYTES(lined, j, val16);
1877  }
1878  }
1879 
1880  pixDestroy(&pixsm);
1881  pixCopyResolution(pixd, pixs);
1882  return pixd;
1883 }
1884 
1885 
1886 /*------------------------------------------------------------------*
1887  * Apply background map to image *
1888  *------------------------------------------------------------------*/
1898 PIX *
1900  PIX *pixm,
1901  l_int32 sx,
1902  l_int32 sy)
1903 {
1904 l_int32 w, h, wm, hm, wpls, wpld, i, j, k, m, xoff, yoff;
1905 l_int32 vals, vald;
1906 l_uint32 val16;
1907 l_uint32 *datas, *datad, *lines, *lined, *flines, *flined;
1908 PIX *pixd;
1909 
1910  PROCNAME("pixApplyInvBackgroundGrayMap");
1911 
1912  if (!pixs || pixGetDepth(pixs) != 8)
1913  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
1914  if (pixGetColormap(pixs))
1915  return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
1916  if (!pixm || pixGetDepth(pixm) != 16)
1917  return (PIX *)ERROR_PTR("pixm undefined or not 16 bpp", procName, NULL);
1918  if (sx == 0 || sy == 0)
1919  return (PIX *)ERROR_PTR("invalid sx and/or sy", procName, NULL);
1920 
1921  datas = pixGetData(pixs);
1922  wpls = pixGetWpl(pixs);
1923  pixGetDimensions(pixs, &w, &h, NULL);
1924  pixGetDimensions(pixm, &wm, &hm, NULL);
1925  if ((pixd = pixCreateTemplate(pixs)) == NULL)
1926  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1927  datad = pixGetData(pixd);
1928  wpld = pixGetWpl(pixd);
1929  for (i = 0; i < hm; i++) {
1930  lines = datas + sy * i * wpls;
1931  lined = datad + sy * i * wpld;
1932  yoff = sy * i;
1933  for (j = 0; j < wm; j++) {
1934  pixGetPixel(pixm, j, i, &val16);
1935  xoff = sx * j;
1936  for (k = 0; k < sy && yoff + k < h; k++) {
1937  flines = lines + k * wpls;
1938  flined = lined + k * wpld;
1939  for (m = 0; m < sx && xoff + m < w; m++) {
1940  vals = GET_DATA_BYTE(flines, xoff + m);
1941  vald = (vals * val16) / 256;
1942  vald = L_MIN(vald, 255);
1943  SET_DATA_BYTE(flined, xoff + m, vald);
1944  }
1945  }
1946  }
1947  }
1948 
1949  return pixd;
1950 }
1951 
1952 
1964 PIX *
1966  PIX *pixmr,
1967  PIX *pixmg,
1968  PIX *pixmb,
1969  l_int32 sx,
1970  l_int32 sy)
1971 {
1972 l_int32 w, h, wm, hm, wpls, wpld, i, j, k, m, xoff, yoff;
1973 l_int32 rvald, gvald, bvald;
1974 l_uint32 vals;
1975 l_uint32 rval16, gval16, bval16;
1976 l_uint32 *datas, *datad, *lines, *lined, *flines, *flined;
1977 PIX *pixd;
1978 
1979  PROCNAME("pixApplyInvBackgroundRGBMap");
1980 
1981  if (!pixs)
1982  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1983  if (pixGetDepth(pixs) != 32)
1984  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1985  if (!pixmr || !pixmg || !pixmb)
1986  return (PIX *)ERROR_PTR("pix maps not all defined", procName, NULL);
1987  if (pixGetDepth(pixmr) != 16 || pixGetDepth(pixmg) != 16 ||
1988  pixGetDepth(pixmb) != 16)
1989  return (PIX *)ERROR_PTR("pix maps not all 16 bpp", procName, NULL);
1990  if (sx == 0 || sy == 0)
1991  return (PIX *)ERROR_PTR("invalid sx and/or sy", procName, NULL);
1992 
1993  datas = pixGetData(pixs);
1994  wpls = pixGetWpl(pixs);
1995  w = pixGetWidth(pixs);
1996  h = pixGetHeight(pixs);
1997  wm = pixGetWidth(pixmr);
1998  hm = pixGetHeight(pixmr);
1999  if ((pixd = pixCreateTemplate(pixs)) == NULL)
2000  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2001  datad = pixGetData(pixd);
2002  wpld = pixGetWpl(pixd);
2003  for (i = 0; i < hm; i++) {
2004  lines = datas + sy * i * wpls;
2005  lined = datad + sy * i * wpld;
2006  yoff = sy * i;
2007  for (j = 0; j < wm; j++) {
2008  pixGetPixel(pixmr, j, i, &rval16);
2009  pixGetPixel(pixmg, j, i, &gval16);
2010  pixGetPixel(pixmb, j, i, &bval16);
2011  xoff = sx * j;
2012  for (k = 0; k < sy && yoff + k < h; k++) {
2013  flines = lines + k * wpls;
2014  flined = lined + k * wpld;
2015  for (m = 0; m < sx && xoff + m < w; m++) {
2016  vals = *(flines + xoff + m);
2017  rvald = ((vals >> 24) * rval16) / 256;
2018  rvald = L_MIN(rvald, 255);
2019  gvald = (((vals >> 16) & 0xff) * gval16) / 256;
2020  gvald = L_MIN(gvald, 255);
2021  bvald = (((vals >> 8) & 0xff) * bval16) / 256;
2022  bvald = L_MIN(bvald, 255);
2023  composeRGBPixel(rvald, gvald, bvald, flined + xoff + m);
2024  }
2025  }
2026  }
2027  }
2028 
2029  return pixd;
2030 }
2031 
2032 
2033 /*------------------------------------------------------------------*
2034  * Apply variable map *
2035  *------------------------------------------------------------------*/
2062 PIX *
2064  PIX *pixg,
2065  l_int32 target)
2066 {
2067 l_int32 i, j, w, h, d, wpls, wplg, wpld, vals, valg, vald;
2068 l_uint8 *lut;
2069 l_uint32 *datas, *datag, *datad, *lines, *lineg, *lined;
2070 l_float32 fval;
2071 PIX *pixd;
2072 
2073  PROCNAME("pixApplyVariableGrayMap");
2074 
2075  if (!pixs)
2076  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2077  if (!pixg)
2078  return (PIX *)ERROR_PTR("pixg not defined", procName, NULL);
2079  if (!pixSizesEqual(pixs, pixg))
2080  return (PIX *)ERROR_PTR("pix sizes not equal", procName, NULL);
2081  pixGetDimensions(pixs, &w, &h, &d);
2082  if (d != 8)
2083  return (PIX *)ERROR_PTR("depth not 8 bpp", procName, NULL);
2084 
2085  /* Generate a LUT for the mapping if the image is large enough
2086  * to warrant the overhead. The LUT is of size 2^16. For the
2087  * index to the table, get the MSB from pixs and the LSB from pixg.
2088  * Note: this LUT is bigger than the typical 32K L1 cache, so
2089  * we expect cache misses. L2 latencies are about 5ns. But
2090  * division is slooooow. For large images, this function is about
2091  * 4x faster when using the LUT. C'est la vie. */
2092  lut = NULL;
2093  if (w * h > 100000) { /* more pixels than 2^16 */
2094  if ((lut = (l_uint8 *)LEPT_CALLOC(0x10000, sizeof(l_uint8))) == NULL)
2095  return (PIX *)ERROR_PTR("lut not made", procName, NULL);
2096  for (i = 0; i < 256; i++) {
2097  for (j = 0; j < 256; j++) {
2098  fval = (l_float32)(i * target) / (j + 0.5);
2099  lut[(i << 8) + j] = L_MIN(255, (l_int32)(fval + 0.5));
2100  }
2101  }
2102  }
2103 
2104  if ((pixd = pixCreateNoInit(w, h, 8)) == NULL) {
2105  LEPT_FREE(lut);
2106  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2107  }
2108  pixCopyResolution(pixd, pixs);
2109  datad = pixGetData(pixd);
2110  wpld = pixGetWpl(pixd);
2111  datas = pixGetData(pixs);
2112  wpls = pixGetWpl(pixs);
2113  datag = pixGetData(pixg);
2114  wplg = pixGetWpl(pixg);
2115  for (i = 0; i < h; i++) {
2116  lines = datas + i * wpls;
2117  lineg = datag + i * wplg;
2118  lined = datad + i * wpld;
2119  if (lut) {
2120  for (j = 0; j < w; j++) {
2121  vals = GET_DATA_BYTE(lines, j);
2122  valg = GET_DATA_BYTE(lineg, j);
2123  vald = lut[(vals << 8) + valg];
2124  SET_DATA_BYTE(lined, j, vald);
2125  }
2126  }
2127  else {
2128  for (j = 0; j < w; j++) {
2129  vals = GET_DATA_BYTE(lines, j);
2130  valg = GET_DATA_BYTE(lineg, j);
2131  fval = (l_float32)(vals * target) / (valg + 0.5);
2132  vald = L_MIN(255, (l_int32)(fval + 0.5));
2133  SET_DATA_BYTE(lined, j, vald);
2134  }
2135  }
2136  }
2137 
2138  LEPT_FREE(lut);
2139  return pixd;
2140 }
2141 
2142 
2143 /*------------------------------------------------------------------*
2144  * Non-adaptive (global) mapping *
2145  *------------------------------------------------------------------*/
2180 PIX *
2182  PIX *pixs,
2183  l_int32 rval,
2184  l_int32 gval,
2185  l_int32 bval,
2186  l_int32 mapval)
2187 {
2188 l_int32 w, h, d, i, j, ncolors, rv, gv, bv, wpl;
2189 l_int32 *rarray, *garray, *barray;
2190 l_uint32 *data, *line;
2191 NUMA *nar, *nag, *nab;
2192 PIXCMAP *cmap;
2193 
2194  PROCNAME("pixGlobalNormRGB");
2195 
2196  if (!pixs)
2197  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2198  cmap = pixGetColormap(pixs);
2199  pixGetDimensions(pixs, &w, &h, &d);
2200  if (!cmap && d != 32)
2201  return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
2202  if (mapval <= 0) {
2203  L_WARNING("mapval must be > 0; setting to 255\n", procName);
2204  mapval = 255;
2205  }
2206 
2207  /* Prepare pixd to be a copy of pixs */
2208  if ((pixd = pixCopy(pixd, pixs)) == NULL)
2209  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2210 
2211  /* Generate the TRC maps for each component. Make sure the
2212  * upper range for each color is greater than zero. */
2213  nar = numaGammaTRC(1.0, 0, L_MAX(1, 255 * rval / mapval));
2214  nag = numaGammaTRC(1.0, 0, L_MAX(1, 255 * gval / mapval));
2215  nab = numaGammaTRC(1.0, 0, L_MAX(1, 255 * bval / mapval));
2216 
2217  /* Extract copies of the internal arrays */
2218  rarray = numaGetIArray(nar);
2219  garray = numaGetIArray(nag);
2220  barray = numaGetIArray(nab);
2221  if (!nar || !nag || !nab || !rarray || !garray || !barray) {
2222  L_ERROR("allocation failure in arrays\n", procName);
2223  goto cleanup_arrays;
2224  }
2225 
2226  if (cmap) {
2227  ncolors = pixcmapGetCount(cmap);
2228  for (i = 0; i < ncolors; i++) {
2229  pixcmapGetColor(cmap, i, &rv, &gv, &bv);
2230  pixcmapResetColor(cmap, i, rarray[rv], garray[gv], barray[bv]);
2231  }
2232  }
2233  else {
2234  data = pixGetData(pixd);
2235  wpl = pixGetWpl(pixd);
2236  for (i = 0; i < h; i++) {
2237  line = data + i * wpl;
2238  for (j = 0; j < w; j++) {
2239  extractRGBValues(line[j], &rv, &gv, &bv);
2240  composeRGBPixel(rarray[rv], garray[gv], barray[bv], line + j);
2241  }
2242  }
2243  }
2244 
2245 cleanup_arrays:
2246  numaDestroy(&nar);
2247  numaDestroy(&nag);
2248  numaDestroy(&nab);
2249  LEPT_FREE(rarray);
2250  LEPT_FREE(garray);
2251  LEPT_FREE(barray);
2252  return pixd;
2253 }
2254 
2255 
2289 PIX *
2291  PIX *pixs,
2292  l_int32 rval,
2293  l_int32 gval,
2294  l_int32 bval,
2295  l_int32 factor,
2296  l_float32 rank)
2297 {
2298 l_int32 mapval;
2299 l_float32 rankrval, rankgval, rankbval;
2300 l_float32 rfract, gfract, bfract, maxfract;
2301 
2302  PROCNAME("pixGlobalNormNoSatRGB");
2303 
2304  if (!pixs)
2305  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2306  if (pixGetDepth(pixs) != 32)
2307  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
2308  if (factor < 1)
2309  return (PIX *)ERROR_PTR("sampling factor < 1", procName, NULL);
2310  if (rank < 0.0 || rank > 1.0)
2311  return (PIX *)ERROR_PTR("rank not in [0.0 ... 1.0]", procName, NULL);
2312  if (rval <= 0 || gval <= 0 || bval <= 0)
2313  return (PIX *)ERROR_PTR("invalid estim. color values", procName, NULL);
2314 
2315  /* The max value for each component may be larger than the
2316  * input estimated background value. In that case, mapping
2317  * for those pixels would saturate. To prevent saturation,
2318  * we compute the fraction for each component by which we
2319  * would oversaturate. Then take the max of these, and
2320  * reduce, uniformly over all components, the output intensity
2321  * by this value. Then no component will saturate.
2322  * In practice, if rank < 1.0, a fraction of pixels
2323  * may have a component saturate. By keeping rank close to 1.0,
2324  * that fraction can be made arbitrarily small. */
2325  pixGetRankValueMaskedRGB(pixs, NULL, 0, 0, factor, rank, &rankrval,
2326  &rankgval, &rankbval);
2327  rfract = rankrval / (l_float32)rval;
2328  gfract = rankgval / (l_float32)gval;
2329  bfract = rankbval / (l_float32)bval;
2330  maxfract = L_MAX(rfract, gfract);
2331  maxfract = L_MAX(maxfract, bfract);
2332 #if DEBUG_GLOBAL
2333  fprintf(stderr, "rankrval = %7.2f, rankgval = %7.2f, rankbval = %7.2f\n",
2334  rankrval, rankgval, rankbval);
2335  fprintf(stderr, "rfract = %7.4f, gfract = %7.4f, bfract = %7.4f\n",
2336  rfract, gfract, bfract);
2337 #endif /* DEBUG_GLOBAL */
2338 
2339  mapval = (l_int32)(255. / maxfract);
2340  pixd = pixGlobalNormRGB(pixd, pixs, rval, gval, bval, mapval);
2341  return pixd;
2342 }
2343 
2344 
2345 /*------------------------------------------------------------------*
2346  * Adaptive threshold spread normalization *
2347  *------------------------------------------------------------------*/
2389 l_ok
2391  l_int32 filtertype,
2392  l_int32 edgethresh,
2393  l_int32 smoothx,
2394  l_int32 smoothy,
2395  l_float32 gamma,
2396  l_int32 minval,
2397  l_int32 maxval,
2398  l_int32 targetthresh,
2399  PIX **ppixth,
2400  PIX **ppixb,
2401  PIX **ppixd)
2402 {
2403 PIX *pixe, *pixet, *pixsd, *pixg1, *pixg2, *pixth;
2404 
2405  PROCNAME("pixThresholdSpreadNorm");
2406 
2407  if (ppixth) *ppixth = NULL;
2408  if (ppixb) *ppixb = NULL;
2409  if (ppixd) *ppixd = NULL;
2410  if (!pixs || pixGetDepth(pixs) != 8)
2411  return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
2412  if (pixGetColormap(pixs))
2413  return ERROR_INT("pixs is colormapped", procName, 1);
2414  if (!ppixth && !ppixb && !ppixd)
2415  return ERROR_INT("no output requested", procName, 1);
2416  if (filtertype != L_SOBEL_EDGE && filtertype != L_TWO_SIDED_EDGE)
2417  return ERROR_INT("invalid filter type", procName, 1);
2418 
2419  /* Get the thresholded edge pixels. These are the ones
2420  * that have values in pixs near the local optimal fg/bg threshold. */
2421  if (filtertype == L_SOBEL_EDGE)
2422  pixe = pixSobelEdgeFilter(pixs, L_VERTICAL_EDGES);
2423  else /* L_TWO_SIDED_EDGE */
2425  pixet = pixThresholdToBinary(pixe, edgethresh);
2426  pixInvert(pixet, pixet);
2427 
2428  /* Build a seed image whose only nonzero values are those
2429  * values of pixs corresponding to pixels in the fg of pixet. */
2430  pixsd = pixCreateTemplate(pixs);
2431  pixCombineMasked(pixsd, pixs, pixet);
2432 
2433  /* Spread the seed and optionally smooth to reduce noise */
2434  pixg1 = pixSeedspread(pixsd, 4);
2435  pixg2 = pixBlockconv(pixg1, smoothx, smoothy);
2436 
2437  /* Optionally do a gamma enhancement */
2438  pixth = pixGammaTRC(NULL, pixg2, gamma, minval, maxval);
2439 
2440  /* Do the mapping and thresholding */
2441  if (ppixd) {
2442  *ppixd = pixApplyVariableGrayMap(pixs, pixth, targetthresh);
2443  if (ppixb)
2444  *ppixb = pixThresholdToBinary(*ppixd, targetthresh);
2445  }
2446  else if (ppixb)
2447  *ppixb = pixVarThresholdToBinary(pixs, pixth);
2448 
2449  if (ppixth)
2450  *ppixth = pixth;
2451  else
2452  pixDestroy(&pixth);
2453 
2454  pixDestroy(&pixe);
2455  pixDestroy(&pixet);
2456  pixDestroy(&pixsd);
2457  pixDestroy(&pixg1);
2458  pixDestroy(&pixg2);
2459  return 0;
2460 }
2461 
2462 
2463 /*------------------------------------------------------------------*
2464  * Adaptive background normalization (flexible adaptaption) *
2465  *------------------------------------------------------------------*/
2495 PIX *
2497  l_int32 sx,
2498  l_int32 sy,
2499  l_int32 smoothx,
2500  l_int32 smoothy,
2501  l_int32 delta)
2502 {
2503 l_float32 scalex, scaley;
2504 PIX *pixt, *pixsd, *pixmin, *pixbg, *pixbgi, *pixd;
2505 
2506  PROCNAME("pixBackgroundNormFlex");
2507 
2508  if (!pixs || pixGetDepth(pixs) != 8)
2509  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
2510  if (pixGetColormap(pixs))
2511  return (PIX *)ERROR_PTR("pixs is colormapped", procName, NULL);
2512  if (sx < 3 || sy < 3)
2513  return (PIX *)ERROR_PTR("sx and/or sy less than 3", procName, NULL);
2514  if (sx > 10 || sy > 10)
2515  return (PIX *)ERROR_PTR("sx and/or sy exceed 10", procName, NULL);
2516  if (smoothx < 1 || smoothy < 1)
2517  return (PIX *)ERROR_PTR("smooth params less than 1", procName, NULL);
2518  if (smoothx > 3 || smoothy > 3)
2519  return (PIX *)ERROR_PTR("smooth params exceed 3", procName, NULL);
2520 
2521  /* Generate the bg estimate using smoothed average with subsampling */
2522  scalex = 1. / (l_float32)sx;
2523  scaley = 1. / (l_float32)sy;
2524  pixt = pixScaleSmooth(pixs, scalex, scaley);
2525 
2526  /* Do basin filling on the bg estimate if requested */
2527  if (delta <= 0)
2528  pixsd = pixClone(pixt);
2529  else {
2530  pixLocalExtrema(pixt, 0, 0, &pixmin, NULL);
2531  pixsd = pixSeedfillGrayBasin(pixmin, pixt, delta, 4);
2532  pixDestroy(&pixmin);
2533  }
2534  pixbg = pixExtendByReplication(pixsd, 1, 1);
2535 
2536  /* Map the bg to 200 */
2537  pixbgi = pixGetInvBackgroundMap(pixbg, 200, smoothx, smoothy);
2538  pixd = pixApplyInvBackgroundGrayMap(pixs, pixbgi, sx, sy);
2539 
2540  pixDestroy(&pixt);
2541  pixDestroy(&pixsd);
2542  pixDestroy(&pixbg);
2543  pixDestroy(&pixbgi);
2544  return pixd;
2545 }
2546 
2547 
2548 /*------------------------------------------------------------------*
2549  * Adaptive contrast normalization *
2550  *------------------------------------------------------------------*/
2590 PIX *
2592  PIX *pixs,
2593  l_int32 sx,
2594  l_int32 sy,
2595  l_int32 mindiff,
2596  l_int32 smoothx,
2597  l_int32 smoothy)
2598 {
2599 PIX *pixmin, *pixmax;
2600 
2601  PROCNAME("pixContrastNorm");
2602 
2603  if (!pixs || pixGetDepth(pixs) != 8)
2604  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, pixd);
2605  if (pixd && pixd != pixs)
2606  return (PIX *)ERROR_PTR("pixd not null or == pixs", procName, pixd);
2607  if (pixGetColormap(pixs))
2608  return (PIX *)ERROR_PTR("pixs is colormapped", procName, pixd);
2609  if (sx < 5 || sy < 5)
2610  return (PIX *)ERROR_PTR("sx and/or sy less than 5", procName, pixd);
2611  if (smoothx < 0 || smoothy < 0)
2612  return (PIX *)ERROR_PTR("smooth params less than 0", procName, pixd);
2613  if (smoothx > 8 || smoothy > 8)
2614  return (PIX *)ERROR_PTR("smooth params exceed 8", procName, pixd);
2615 
2616  /* Get the min and max pixel values in each tile, and represent
2617  * each value as a pixel in pixmin and pixmax, respectively. */
2618  pixMinMaxTiles(pixs, sx, sy, mindiff, smoothx, smoothy, &pixmin, &pixmax);
2619 
2620  /* For each tile, do a linear expansion of the dynamic range
2621  * of pixels so that the min value is mapped to 0 and the
2622  * max value is mapped to 255. */
2623  pixd = pixLinearTRCTiled(pixd, pixs, sx, sy, pixmin, pixmax);
2624 
2625  pixDestroy(&pixmin);
2626  pixDestroy(&pixmax);
2627  return pixd;
2628 }
2629 
2630 
2650 l_ok
2652  l_int32 sx,
2653  l_int32 sy,
2654  l_int32 mindiff,
2655  l_int32 smoothx,
2656  l_int32 smoothy,
2657  PIX **ppixmin,
2658  PIX **ppixmax)
2659 {
2660 l_int32 w, h;
2661 PIX *pixmin1, *pixmax1, *pixmin2, *pixmax2;
2662 
2663  PROCNAME("pixMinMaxTiles");
2664 
2665  if (ppixmin) *ppixmin = NULL;
2666  if (ppixmax) *ppixmax = NULL;
2667  if (!ppixmin || !ppixmax)
2668  return ERROR_INT("&pixmin or &pixmax undefined", procName, 1);
2669  if (!pixs || pixGetDepth(pixs) != 8)
2670  return ERROR_INT("pixs undefined or not 8 bpp", procName, 1);
2671  if (pixGetColormap(pixs))
2672  return ERROR_INT("pixs is colormapped", procName, 1);
2673  if (sx < 5 || sy < 5)
2674  return ERROR_INT("sx and/or sy less than 3", procName, 1);
2675  if (smoothx < 0 || smoothy < 0)
2676  return ERROR_INT("smooth params less than 0", procName, 1);
2677  if (smoothx > 5 || smoothy > 5)
2678  return ERROR_INT("smooth params exceed 5", procName, 1);
2679 
2680  /* Get the min and max values in each tile */
2681  pixmin1 = pixScaleGrayMinMax(pixs, sx, sy, L_CHOOSE_MIN);
2682  pixmax1 = pixScaleGrayMinMax(pixs, sx, sy, L_CHOOSE_MAX);
2683 
2684  pixmin2 = pixExtendByReplication(pixmin1, 1, 1);
2685  pixmax2 = pixExtendByReplication(pixmax1, 1, 1);
2686  pixDestroy(&pixmin1);
2687  pixDestroy(&pixmax1);
2688 
2689  /* Make sure no value is 0 */
2690  pixAddConstantGray(pixmin2, 1);
2691  pixAddConstantGray(pixmax2, 1);
2692 
2693  /* Generate holes where the contrast is too small */
2694  pixSetLowContrast(pixmin2, pixmax2, mindiff);
2695 
2696  /* Fill the holes (0 values) */
2697  pixGetDimensions(pixmin2, &w, &h, NULL);
2698  pixFillMapHoles(pixmin2, w, h, L_FILL_BLACK);
2699  pixFillMapHoles(pixmax2, w, h, L_FILL_BLACK);
2700 
2701  /* Smooth if requested */
2702  if (smoothx > 0 || smoothy > 0) {
2703  smoothx = L_MIN(smoothx, (w - 1) / 2);
2704  smoothy = L_MIN(smoothy, (h - 1) / 2);
2705  *ppixmin = pixBlockconv(pixmin2, smoothx, smoothy);
2706  *ppixmax = pixBlockconv(pixmax2, smoothx, smoothy);
2707  }
2708  else {
2709  *ppixmin = pixClone(pixmin2);
2710  *ppixmax = pixClone(pixmax2);
2711  }
2712  pixCopyResolution(*ppixmin, pixs);
2713  pixCopyResolution(*ppixmax, pixs);
2714  pixDestroy(&pixmin2);
2715  pixDestroy(&pixmax2);
2716 
2717  return 0;
2718 }
2719 
2720 
2741 l_ok
2743  PIX *pixs2,
2744  l_int32 mindiff)
2745 {
2746 l_int32 i, j, w, h, d, wpl, val1, val2, found;
2747 l_uint32 *data1, *data2, *line1, *line2;
2748 
2749  PROCNAME("pixSetLowContrast");
2750 
2751  if (!pixs1 || !pixs2)
2752  return ERROR_INT("pixs1 and pixs2 not both defined", procName, 1);
2753  if (pixSizesEqual(pixs1, pixs2) == 0)
2754  return ERROR_INT("pixs1 and pixs2 not equal size", procName, 1);
2755  pixGetDimensions(pixs1, &w, &h, &d);
2756  if (d != 8)
2757  return ERROR_INT("depth not 8 bpp", procName, 1);
2758  if (mindiff > 254) return 0;
2759 
2760  data1 = pixGetData(pixs1);
2761  data2 = pixGetData(pixs2);
2762  wpl = pixGetWpl(pixs1);
2763  found = 0; /* init to not finding any diffs >= mindiff */
2764  for (i = 0; i < h; i++) {
2765  line1 = data1 + i * wpl;
2766  line2 = data2 + i * wpl;
2767  for (j = 0; j < w; j++) {
2768  val1 = GET_DATA_BYTE(line1, j);
2769  val2 = GET_DATA_BYTE(line2, j);
2770  if (L_ABS(val1 - val2) >= mindiff) {
2771  found = 1;
2772  break;
2773  }
2774  }
2775  if (found) break;
2776  }
2777  if (!found) {
2778  L_WARNING("no pixel pair diffs as large as mindiff\n", procName);
2779  pixClearAll(pixs1);
2780  pixClearAll(pixs2);
2781  return 1;
2782  }
2783 
2784  for (i = 0; i < h; i++) {
2785  line1 = data1 + i * wpl;
2786  line2 = data2 + i * wpl;
2787  for (j = 0; j < w; j++) {
2788  val1 = GET_DATA_BYTE(line1, j);
2789  val2 = GET_DATA_BYTE(line2, j);
2790  if (L_ABS(val1 - val2) < mindiff) {
2791  SET_DATA_BYTE(line1, j, 0);
2792  SET_DATA_BYTE(line2, j, 0);
2793  }
2794  }
2795  }
2796 
2797  return 0;
2798 }
2799 
2800 
2824 PIX *
2826  PIX *pixs,
2827  l_int32 sx,
2828  l_int32 sy,
2829  PIX *pixmin,
2830  PIX *pixmax)
2831 {
2832 l_int32 i, j, k, m, w, h, wt, ht, wpl, wplt, xoff, yoff;
2833 l_int32 minval, maxval, val, sval;
2834 l_int32 *ia;
2835 l_int32 **iaa;
2836 l_uint32 *data, *datamin, *datamax, *line, *tline, *linemin, *linemax;
2837 
2838  PROCNAME("pixLinearTRCTiled");
2839 
2840  if (!pixs || pixGetDepth(pixs) != 8)
2841  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, pixd);
2842  if (pixd && pixd != pixs)
2843  return (PIX *)ERROR_PTR("pixd not null or == pixs", procName, pixd);
2844  if (pixGetColormap(pixs))
2845  return (PIX *)ERROR_PTR("pixs is colormapped", procName, pixd);
2846  if (!pixmin || !pixmax)
2847  return (PIX *)ERROR_PTR("pixmin & pixmax not defined", procName, pixd);
2848  if (sx < 5 || sy < 5)
2849  return (PIX *)ERROR_PTR("sx and/or sy less than 5", procName, pixd);
2850 
2851  if ((iaa = (l_int32 **)LEPT_CALLOC(256, sizeof(l_int32 *))) == NULL)
2852  return (PIX *)ERROR_PTR("iaa not made", procName, NULL);
2853  if ((pixd = pixCopy(pixd, pixs)) == NULL) {
2854  LEPT_FREE(iaa);
2855  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2856  }
2857  pixGetDimensions(pixd, &w, &h, NULL);
2858 
2859  data = pixGetData(pixd);
2860  wpl = pixGetWpl(pixd);
2861  datamin = pixGetData(pixmin);
2862  datamax = pixGetData(pixmax);
2863  wplt = pixGetWpl(pixmin);
2864  pixGetDimensions(pixmin, &wt, &ht, NULL);
2865  for (i = 0; i < ht; i++) {
2866  line = data + sy * i * wpl;
2867  linemin = datamin + i * wplt;
2868  linemax = datamax + i * wplt;
2869  yoff = sy * i;
2870  for (j = 0; j < wt; j++) {
2871  xoff = sx * j;
2872  minval = GET_DATA_BYTE(linemin, j);
2873  maxval = GET_DATA_BYTE(linemax, j);
2874  if (maxval == minval) {
2875  L_ERROR("shouldn't happen! i,j = %d,%d, minval = %d\n",
2876  procName, i, j, minval);
2877  continue;
2878  }
2879  if ((ia = iaaGetLinearTRC(iaa, maxval - minval)) == NULL) {
2880  L_ERROR("failure to make ia for j = %d!\n", procName, j);
2881  continue;
2882  }
2883  for (k = 0; k < sy && yoff + k < h; k++) {
2884  tline = line + k * wpl;
2885  for (m = 0; m < sx && xoff + m < w; m++) {
2886  val = GET_DATA_BYTE(tline, xoff + m);
2887  sval = val - minval;
2888  sval = L_MAX(0, sval);
2889  SET_DATA_BYTE(tline, xoff + m, ia[sval]);
2890  }
2891  }
2892  }
2893  }
2894 
2895  for (i = 0; i < 256; i++)
2896  LEPT_FREE(iaa[i]);
2897  LEPT_FREE(iaa);
2898  return pixd;
2899 }
2900 
2901 
2911 static l_int32 *
2912 iaaGetLinearTRC(l_int32 **iaa,
2913  l_int32 diff)
2914 {
2915 l_int32 i;
2916 l_int32 *ia;
2917 l_float32 factor;
2918 
2919  PROCNAME("iaaGetLinearTRC");
2920 
2921  if (!iaa)
2922  return (l_int32 *)ERROR_PTR("iaa not defined", procName, NULL);
2923 
2924  if (iaa[diff] != NULL) /* already have it */
2925  return iaa[diff];
2926 
2927  if ((ia = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32))) == NULL)
2928  return (l_int32 *)ERROR_PTR("ia not made", procName, NULL);
2929  iaa[diff] = ia;
2930  if (diff == 0) { /* shouldn't happen */
2931  for (i = 0; i < 256; i++)
2932  ia[i] = 128;
2933  }
2934  else {
2935  factor = 255. / (l_float32)diff;
2936  for (i = 0; i < diff + 1; i++)
2937  ia[i] = (l_int32)(factor * i + 0.5);
2938  for (i = diff + 1; i < 256; i++)
2939  ia[i] = 255;
2940  }
2941 
2942  return ia;
2943 }
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:550
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:852
PIX * pixApplyInvBackgroundGrayMap(PIX *pixs, PIX *pixm, l_int32 sx, l_int32 sy)
pixApplyInvBackgroundGrayMap()
Definition: adaptmap.c:1899
static l_int32 * iaaGetLinearTRC(l_int32 **iaa, l_int32 diff)
iaaGetLinearTRC()
Definition: adaptmap.c:2912
l_ok pixGetBackgroundGrayMapMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, PIX **ppixm)
pixGetBackgroundGrayMapMorph()
Definition: adaptmap.c:1215
l_ok pixSmoothConnectedRegions(PIX *pixs, PIX *pixm, l_int32 factor)
pixSmoothConnectedRegions()
Definition: adaptmap.c:1635
PIX * pixSeedspread(PIX *pixs, l_int32 connectivity)
pixSeedspread()
Definition: seedfill.c:2791
static const l_int32 DEFAULT_Y_SMOOTH_SIZE
Definition: adaptmap.c:150
PIX * pixApplyVariableGrayMap(PIX *pixs, PIX *pixg, l_int32 target)
pixApplyVariableGrayMap()
Definition: adaptmap.c:2063
PIX * pixScaleRGBToGrayFast(PIX *pixs, l_int32 factor, l_int32 color)
pixScaleRGBToGrayFast()
Definition: scale1.c:1487
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:473
PIX * pixScaleGrayMinMax(PIX *pixs, l_int32 xfact, l_int32 yfact, l_int32 type)
pixScaleGrayMinMax()
Definition: scale2.c:1014
NUMA * numaGammaTRC(l_float32 gamma, l_int32 minval, l_int32 maxval)
numaGammaTRC()
Definition: enhance.c:366
PIX * pixCloseGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseGray()
Definition: graymorph.c:522
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:193
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3041
l_ok pixLocalExtrema(PIX *pixs, l_int32 maxmin, l_int32 minmax, PIX **ppixmin, PIX **ppixmax)
pixLocalExtrema()
Definition: seedfill.c:3018
static const l_int32 DEFAULT_MIN_COUNT
Definition: adaptmap.c:147
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:302
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1395
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:187
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:580
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1624
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:443
PIX * pixScaleBySampling(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBySampling()
Definition: scale1.c:1338
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
PIX * pixCreateTemplate(PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:367
Definition: pix.h:492
l_ok pixBackgroundNormGrayArrayMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, l_int32 bgval, PIX **ppixd)
pixBackgroundNormGrayArrayMorph()
Definition: adaptmap.c:710
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:618
PIX * pixTwoSidedEdgeFilter(PIX *pixs, l_int32 orientflag)
pixTwoSidedEdgeFilter()
Definition: edge.c:199
l_ok pixCombineMasked(PIX *pixd, PIX *pixs, PIX *pixm)
pixCombineMasked()
Definition: pix3.c:374
l_int32 * numaGetIArray(NUMA *na)
numaGetIArray()
Definition: numabasic.c:820
PIX * pixConvertRGBToGrayFast(PIX *pixs)
pixConvertRGBToGrayFast()
Definition: pixconv.c:831
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:147
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:727
Definition: array.h:59
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:1457
PIX * pixBackgroundNormFlex(PIX *pixs, l_int32 sx, l_int32 sy, l_int32 smoothx, l_int32 smoothy, l_int32 delta)
pixBackgroundNormFlex()
Definition: adaptmap.c:2496
l_ok pixClearAll(PIX *pix)
pixClearAll()
Definition: pix2.c:712
PIX * pixLinearTRCTiled(PIX *pixd, PIX *pixs, l_int32 sx, l_int32 sy, PIX *pixmin, PIX *pixmax)
pixLinearTRCTiled()
Definition: adaptmap.c:2825
PIX * pixGetInvBackgroundMap(PIX *pixs, l_int32 bgval, l_int32 smoothx, l_int32 smoothy)
pixGetInvBackgroundMap()
Definition: adaptmap.c:1836
PIX * pixCleanBackgroundToWhite(PIX *pixs, PIX *pixim, PIX *pixg, l_float32 gamma, l_int32 blackval, l_int32 whiteval)
pixCleanBackgroundToWhite()
Definition: adaptmap.c:185
l_ok boxaGetBoxGeometry(BOXA *boxa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetBoxGeometry()
Definition: boxbasic.c:863
PIX * pixAnd(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixAnd()
Definition: pix3.c:1510
static const l_int32 DEFAULT_TILE_HEIGHT
Definition: adaptmap.c:145
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:253
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:751
PIX * pixMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequence()
Definition: morphseq.c:133
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:2591
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
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:627
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
PIX * pixApplyInvBackgroundRGBMap(PIX *pixs, PIX *pixmr, PIX *pixmg, PIX *pixmb, l_int32 sx, l_int32 sy)
pixApplyInvBackgroundRGBMap()
Definition: adaptmap.c:1965
PIX * pixExtendByReplication(PIX *pixs, l_int32 addw, l_int32 addh)
pixExtendByReplication()
Definition: adaptmap.c:1572
l_ok 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:2651
PIX * pixCreateNoInit(l_int32 width, l_int32 height, l_int32 depth)
pixCreateNoInit()
Definition: pix1.c:331
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:515
static const l_int32 DEFAULT_BG_VAL
Definition: adaptmap.c:148
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
l_ok pixcmapResetColor(PIXCMAP *cmap, l_int32 index, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapResetColor()
Definition: colormap.c:893
Definition: pix.h:454
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:360
l_ok pixSetLowContrast(PIX *pixs1, PIX *pixs2, l_int32 mindiff)
pixSetLowContrast()
Definition: adaptmap.c:2742
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:180
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
static const l_int32 DEFAULT_TILE_WIDTH
Definition: adaptmap.c:144
PIX * pixReduceBinary2(PIX *pixs, l_uint8 *intab)
pixReduceBinary2()
Definition: binreduce.c:71
static const l_int32 DEFAULT_X_SMOOTH_SIZE
Definition: adaptmap.c:149
PIX * pixExpandReplicate(PIX *pixs, l_int32 factor)
pixExpandReplicate()
Definition: scale2.c:867
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:1030
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:775
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:672
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:302
static const l_int32 DEFAULT_FG_THRESHOLD
Definition: adaptmap.c:146
l_int32 pixcmapGetCount(PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:635
PIX * pixBackgroundNormSimple(PIX *pixs, PIX *pixim, PIX *pixg)
pixBackgroundNormSimple()
Definition: adaptmap.c:231
Definition: pix.h:134
Definition: pix.h:719
PIX * pixSobelEdgeFilter(PIX *pixs, l_int32 orientflag)
pixSobelEdgeFilter()
Definition: edge.c:91
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1701
#define PIX_SRC
Definition: pix.h:327
PIX * pixCopy(PIX *pixd, PIX *pixs)
pixCopy()
Definition: pix1.c:628
PIX * pixGammaTRC(PIX *pixd, PIX *pixs, l_float32 gamma, l_int32 minval, l_int32 maxval)
pixGammaTRC()
Definition: enhance.c:174
Definition: pix.h:201
PIX * pixBlockconv(PIX *pix, l_int32 wc, l_int32 hc)
pixBlockconv()
Definition: convolve.c:127
PIX * pixBackgroundNormMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, l_int32 bgval)
pixBackgroundNormMorph()
Definition: adaptmap.c:439
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:718
l_ok pixFillMapHoles(PIX *pix, l_int32 nx, l_int32 ny, l_int32 filltype)
pixFillMapHoles()
Definition: adaptmap.c:1460
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2671
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:1015
l_ok pixGetBackgroundRGBMapMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, PIX **ppixmr, PIX **ppixmg, PIX **ppixmb)
pixGetBackgroundRGBMapMorph()
Definition: adaptmap.c:1306
l_int32 pixSizesEqual(const PIX *pix1, const PIX *pix2)
pixSizesEqual()
Definition: pix1.c:781
PIX * pixScaleSmooth(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleSmooth()
Definition: scale1.c:1711
PIX * pixVarThresholdToBinary(PIX *pixs, PIX *pixg)
pixVarThresholdToBinary()
Definition: grayquant.c:651
PIX * pixGlobalNormRGB(PIX *pixd, PIX *pixs, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 mapval)
pixGlobalNormRGB()
Definition: adaptmap.c:2181
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:244
#define SET_DATA_TWO_BYTES(pdata, n, val)
Definition: arrayaccess.h:222
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:408
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2737
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:2390
PIX * pixSeedfillGrayBasin(PIX *pixb, PIX *pixm, l_int32 delta, l_int32 connectivity)
pixSeedfillGrayBasin()
Definition: seedfill.c:2442
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:2290
l_ok pixAddConstantGray(PIX *pixs, l_int32 val)
pixAddConstantGray()
Definition: pixarith.c:115