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