Leptonica  1.83.1
Image processing and image analysis suite
adaptmap.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
134 #ifdef HAVE_CONFIG_H
135 #include <config_auto.h>
136 #endif /* HAVE_CONFIG_H */
137 
138 #include "allheaders.h"
139 
140  /* Default input parameters for pixBackgroundNormSimple()
141  * Notes:
142  * (1) mincount must never exceed the tile area (width * height)
143  * (2) bgval must be sufficiently below 255 to avoid accidental
144  * saturation; otherwise it should be large to avoid
145  * shrinking the dynamic range
146  * (3) results should otherwise not be sensitive to these values
147  */
148 static const l_int32 DefaultTileWidth = 10;
149 static const l_int32 DefaultTileHeight = 15;
150 static const l_int32 DefaultFgThreshold = 60;
151 static const l_int32 DefaultMinCount = 40;
152 static const l_int32 DefaultBgVal = 200;
153 static const l_int32 DefaultXSmoothSize = 2;
154 static const l_int32 DefaultYSmoothSize = 1;
156 static l_int32 pixMinMaxTiles(PIX *pixs, l_int32 sx, l_int32 sy,
157  l_int32 mindiff, l_int32 smoothx, l_int32 smoothy,
158  PIX **ppixmin, PIX **ppixmax);
159 static l_int32 pixSetLowContrast(PIX *pixs1, PIX *pixs2, l_int32 mindiff);
160 static PIX *pixLinearTRCTiled(PIX *pixd, PIX *pixs, l_int32 sx, l_int32 sy,
161  PIX *pixmin, PIX *pixmax);
162 static l_int32 *iaaGetLinearTRC(l_int32 **iaa, l_int32 diff);
163 
164 #ifndef NO_CONSOLE_IO
165 #define DEBUG_GLOBAL 0
166 #endif /* ~NO_CONSOLE_IO */
167 
168 /*------------------------------------------------------------------*
169  * Clean background to white using background normalization *
170  *------------------------------------------------------------------*/
195 PIX *
197  PIX *pixim,
198  PIX *pixg,
199  l_float32 gamma,
200  l_int32 blackval,
201  l_int32 whiteval)
202 {
203 l_int32 d;
204 PIX *pixd;
205 
206  if (!pixs)
207  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
208  d = pixGetDepth(pixs);
209  if (d != 8 && d != 32)
210  return (PIX *)ERROR_PTR("depth not 8 or 32", __func__, NULL);
211  if (whiteval > 200) {
212  L_WARNING("white value %d must not exceed 200; reset to 190",
213  __func__, whiteval);
214  whiteval = 190;
215  }
216 
217  pixd = pixBackgroundNormSimple(pixs, pixim, pixg);
218  if (!pixd)
219  return (PIX *)ERROR_PTR("background norm failedd", __func__, NULL);
220  pixGammaTRC(pixd, pixd, gamma, blackval, whiteval);
221  return pixd;
222 }
223 
224 
225 /*------------------------------------------------------------------*
226  * Adaptive background normalization *
227  *------------------------------------------------------------------*/
244 PIX *
246  PIX *pixim,
247  PIX *pixg)
248 {
249  return pixBackgroundNorm(pixs, pixim, pixg,
254 }
255 
256 
319 PIX *
321  PIX *pixim,
322  PIX *pixg,
323  l_int32 sx,
324  l_int32 sy,
325  l_int32 thresh,
326  l_int32 mincount,
327  l_int32 bgval,
328  l_int32 smoothx,
329  l_int32 smoothy)
330 {
331 l_int32 d, allfg;
332 PIX *pixm, *pixmi, *pixd;
333 PIX *pixmr, *pixmg, *pixmb, *pixmri, *pixmgi, *pixmbi;
334 
335  if (!pixs)
336  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
337  d = pixGetDepth(pixs);
338  if (d != 8 && d != 32)
339  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", __func__, NULL);
340  if (sx < 4 || sy < 4)
341  return (PIX *)ERROR_PTR("sx and sy must be >= 4", __func__, NULL);
342  if (mincount > sx * sy) {
343  L_WARNING("mincount too large for tile size\n", __func__);
344  mincount = (sx * sy) / 3;
345  }
346 
347  /* If pixim exists, verify that it is not all foreground. */
348  if (pixim) {
349  pixInvert(pixim, pixim);
350  pixZero(pixim, &allfg);
351  pixInvert(pixim, pixim);
352  if (allfg)
353  return (PIX *)ERROR_PTR("pixim all foreground", __func__, NULL);
354  }
355 
356  pixd = NULL;
357  if (d == 8) {
358  pixm = NULL;
359  pixGetBackgroundGrayMap(pixs, pixim, sx, sy, thresh, mincount, &pixm);
360  if (!pixm) {
361  L_WARNING("map not made; return a copy of the source\n", __func__);
362  return pixCopy(NULL, pixs);
363  }
364 
365  pixmi = pixGetInvBackgroundMap(pixm, bgval, smoothx, smoothy);
366  if (!pixmi) {
367  L_WARNING("pixmi not made; return a copy of source\n", __func__);
368  pixDestroy(&pixm);
369  return pixCopy(NULL, pixs);
370  } else {
371  pixd = pixApplyInvBackgroundGrayMap(pixs, pixmi, sx, sy);
372  }
373 
374  pixDestroy(&pixm);
375  pixDestroy(&pixmi);
376  }
377  else {
378  pixmr = pixmg = pixmb = NULL;
379  pixGetBackgroundRGBMap(pixs, pixim, pixg, sx, sy, thresh,
380  mincount, &pixmr, &pixmg, &pixmb);
381  if (!pixmr || !pixmg || !pixmb) {
382  pixDestroy(&pixmr);
383  pixDestroy(&pixmg);
384  pixDestroy(&pixmb);
385  L_WARNING("map not made; return a copy of the source\n", __func__);
386  return pixCopy(NULL, pixs);
387  }
388 
389  pixmri = pixGetInvBackgroundMap(pixmr, bgval, smoothx, smoothy);
390  pixmgi = pixGetInvBackgroundMap(pixmg, bgval, smoothx, smoothy);
391  pixmbi = pixGetInvBackgroundMap(pixmb, bgval, smoothx, smoothy);
392  if (!pixmri || !pixmgi || !pixmbi) {
393  L_WARNING("not all pixm*i are made; return src copy\n", __func__);
394  pixd = pixCopy(NULL, pixs);
395  } else {
396  pixd = pixApplyInvBackgroundRGBMap(pixs, pixmri, pixmgi, pixmbi,
397  sx, sy);
398  }
399 
400  pixDestroy(&pixmr);
401  pixDestroy(&pixmg);
402  pixDestroy(&pixmb);
403  pixDestroy(&pixmri);
404  pixDestroy(&pixmgi);
405  pixDestroy(&pixmbi);
406  }
407 
408  if (!pixd)
409  ERROR_PTR("pixd not made", __func__, NULL);
410  pixCopyResolution(pixd, pixs);
411  return pixd;
412 }
413 
414 
454 PIX *
456  PIX *pixim,
457  l_int32 reduction,
458  l_int32 size,
459  l_int32 bgval)
460 {
461 l_int32 d, allfg;
462 PIX *pixm, *pixmi, *pixd;
463 PIX *pixmr, *pixmg, *pixmb, *pixmri, *pixmgi, *pixmbi;
464 
465  if (!pixs)
466  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
467  d = pixGetDepth(pixs);
468  if (d != 8 && d != 32)
469  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", __func__, NULL);
470  if (reduction < 2 || reduction > 16)
471  return (PIX *)ERROR_PTR("reduction must be between 2 and 16",
472  __func__, NULL);
473 
474  /* If pixim exists, verify that it is not all foreground. */
475  if (pixim) {
476  pixInvert(pixim, pixim);
477  pixZero(pixim, &allfg);
478  pixInvert(pixim, pixim);
479  if (allfg)
480  return (PIX *)ERROR_PTR("pixim all foreground", __func__, NULL);
481  }
482 
483  pixd = NULL;
484  if (d == 8) {
485  pixGetBackgroundGrayMapMorph(pixs, pixim, reduction, size, &pixm);
486  if (!pixm)
487  return (PIX *)ERROR_PTR("pixm not made", __func__, NULL);
488  pixmi = pixGetInvBackgroundMap(pixm, bgval, 0, 0);
489  if (!pixmi)
490  ERROR_PTR("pixmi not made", __func__, NULL);
491  else
492  pixd = pixApplyInvBackgroundGrayMap(pixs, pixmi,
493  reduction, reduction);
494  pixDestroy(&pixm);
495  pixDestroy(&pixmi);
496  }
497  else { /* d == 32 */
498  pixmr = pixmg = pixmb = NULL;
499  pixGetBackgroundRGBMapMorph(pixs, pixim, reduction, size,
500  &pixmr, &pixmg, &pixmb);
501  if (!pixmr || !pixmg || !pixmb) {
502  pixDestroy(&pixmr);
503  pixDestroy(&pixmg);
504  pixDestroy(&pixmb);
505  return (PIX *)ERROR_PTR("not all pixm*", __func__, NULL);
506  }
507 
508  pixmri = pixGetInvBackgroundMap(pixmr, bgval, 0, 0);
509  pixmgi = pixGetInvBackgroundMap(pixmg, bgval, 0, 0);
510  pixmbi = pixGetInvBackgroundMap(pixmb, bgval, 0, 0);
511  if (!pixmri || !pixmgi || !pixmbi)
512  ERROR_PTR("not all pixm*i are made", __func__, NULL);
513  else
514  pixd = pixApplyInvBackgroundRGBMap(pixs, pixmri, pixmgi, pixmbi,
515  reduction, reduction);
516 
517  pixDestroy(&pixmr);
518  pixDestroy(&pixmg);
519  pixDestroy(&pixmb);
520  pixDestroy(&pixmri);
521  pixDestroy(&pixmgi);
522  pixDestroy(&pixmbi);
523  }
524 
525  if (!pixd)
526  ERROR_PTR("pixd not made", __func__, NULL);
527  pixCopyResolution(pixd, pixs);
528  return pixd;
529 }
530 
531 
532 /*-------------------------------------------------------------------------*
533  * Arrays of inverted background values for normalization *
534  *-------------------------------------------------------------------------*
535  * Notes for these four functions: *
536  * (1) They are useful if you need to save the actual mapping array. *
537  * (2) They could be used in the top-level functions but are *
538  * not because their use makes those functions less clear. *
539  * (3) Each component in the input pixs generates a 16 bpp pix array. *
540  *-------------------------------------------------------------------------*/
563 l_ok
565  PIX *pixim,
566  l_int32 sx,
567  l_int32 sy,
568  l_int32 thresh,
569  l_int32 mincount,
570  l_int32 bgval,
571  l_int32 smoothx,
572  l_int32 smoothy,
573  PIX **ppixd)
574 {
575 l_int32 allfg;
576 PIX *pixm;
577 
578  if (!ppixd)
579  return ERROR_INT("&pixd not defined", __func__, 1);
580  *ppixd = NULL;
581  if (!pixs || pixGetDepth(pixs) != 8)
582  return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
583  if (pixGetColormap(pixs))
584  return ERROR_INT("pixs is colormapped", __func__, 1);
585  if (pixim && pixGetDepth(pixim) != 1)
586  return ERROR_INT("pixim not 1 bpp", __func__, 1);
587  if (sx < 4 || sy < 4)
588  return ERROR_INT("sx and sy must be >= 4", __func__, 1);
589  if (mincount > sx * sy) {
590  L_WARNING("mincount too large for tile size\n", __func__);
591  mincount = (sx * sy) / 3;
592  }
593 
594  /* If pixim exists, verify that it is not all foreground. */
595  if (pixim) {
596  pixInvert(pixim, pixim);
597  pixZero(pixim, &allfg);
598  pixInvert(pixim, pixim);
599  if (allfg)
600  return ERROR_INT("pixim all foreground", __func__, 1);
601  }
602 
603  pixGetBackgroundGrayMap(pixs, pixim, sx, sy, thresh, mincount, &pixm);
604  if (!pixm)
605  return ERROR_INT("pixm not made", __func__, 1);
606  *ppixd = pixGetInvBackgroundMap(pixm, bgval, smoothx, smoothy);
607  pixCopyResolution(*ppixd, pixs);
608  pixDestroy(&pixm);
609  return 0;
610 }
611 
612 
638 l_ok
640  PIX *pixim,
641  PIX *pixg,
642  l_int32 sx,
643  l_int32 sy,
644  l_int32 thresh,
645  l_int32 mincount,
646  l_int32 bgval,
647  l_int32 smoothx,
648  l_int32 smoothy,
649  PIX **ppixr,
650  PIX **ppixg,
651  PIX **ppixb)
652 {
653 l_int32 allfg;
654 PIX *pixmr, *pixmg, *pixmb;
655 
656  if (!ppixr || !ppixg || !ppixb)
657  return ERROR_INT("&pixr, &pixg, &pixb not all defined", __func__, 1);
658  *ppixr = *ppixg = *ppixb = NULL;
659  if (!pixs)
660  return ERROR_INT("pixs not defined", __func__, 1);
661  if (pixGetDepth(pixs) != 32)
662  return ERROR_INT("pixs not 32 bpp", __func__, 1);
663  if (pixim && pixGetDepth(pixim) != 1)
664  return ERROR_INT("pixim not 1 bpp", __func__, 1);
665  if (sx < 4 || sy < 4)
666  return ERROR_INT("sx and sy must be >= 4", __func__, 1);
667  if (mincount > sx * sy) {
668  L_WARNING("mincount too large for tile size\n", __func__);
669  mincount = (sx * sy) / 3;
670  }
671 
672  /* If pixim exists, verify that it is not all foreground. */
673  if (pixim) {
674  pixInvert(pixim, pixim);
675  pixZero(pixim, &allfg);
676  pixInvert(pixim, pixim);
677  if (allfg)
678  return ERROR_INT("pixim all foreground", __func__, 1);
679  }
680 
681  pixGetBackgroundRGBMap(pixs, pixim, pixg, sx, sy, thresh, mincount,
682  &pixmr, &pixmg, &pixmb);
683  if (!pixmr || !pixmg || !pixmb) {
684  pixDestroy(&pixmr);
685  pixDestroy(&pixmg);
686  pixDestroy(&pixmb);
687  return ERROR_INT("not all pixm* made", __func__, 1);
688  }
689 
690  *ppixr = pixGetInvBackgroundMap(pixmr, bgval, smoothx, smoothy);
691  *ppixg = pixGetInvBackgroundMap(pixmg, bgval, smoothx, smoothy);
692  *ppixb = pixGetInvBackgroundMap(pixmb, bgval, smoothx, smoothy);
693  pixDestroy(&pixmr);
694  pixDestroy(&pixmg);
695  pixDestroy(&pixmb);
696  return 0;
697 }
698 
699 
719 l_ok
721  PIX *pixim,
722  l_int32 reduction,
723  l_int32 size,
724  l_int32 bgval,
725  PIX **ppixd)
726 {
727 l_int32 allfg;
728 PIX *pixm;
729 
730  if (!ppixd)
731  return ERROR_INT("&pixd not defined", __func__, 1);
732  *ppixd = NULL;
733  if (!pixs)
734  return ERROR_INT("pixs not defined", __func__, 1);
735  if (pixGetDepth(pixs) != 8)
736  return ERROR_INT("pixs not 8 bpp", __func__, 1);
737  if (pixim && pixGetDepth(pixim) != 1)
738  return ERROR_INT("pixim not 1 bpp", __func__, 1);
739  if (reduction < 2 || reduction > 16)
740  return ERROR_INT("reduction must be between 2 and 16", __func__, 1);
741 
742  /* If pixim exists, verify that it is not all foreground. */
743  if (pixim) {
744  pixInvert(pixim, pixim);
745  pixZero(pixim, &allfg);
746  pixInvert(pixim, pixim);
747  if (allfg)
748  return ERROR_INT("pixim all foreground", __func__, 1);
749  }
750 
751  pixGetBackgroundGrayMapMorph(pixs, pixim, reduction, size, &pixm);
752  if (!pixm)
753  return ERROR_INT("pixm not made", __func__, 1);
754  *ppixd = pixGetInvBackgroundMap(pixm, bgval, 0, 0);
755  pixCopyResolution(*ppixd, pixs);
756  pixDestroy(&pixm);
757  return 0;
758 }
759 
760 
782 l_ok
784  PIX *pixim,
785  l_int32 reduction,
786  l_int32 size,
787  l_int32 bgval,
788  PIX **ppixr,
789  PIX **ppixg,
790  PIX **ppixb)
791 {
792 l_int32 allfg;
793 PIX *pixmr, *pixmg, *pixmb;
794 
795  if (!ppixr || !ppixg || !ppixb)
796  return ERROR_INT("&pixr, &pixg, &pixb not all defined", __func__, 1);
797  *ppixr = *ppixg = *ppixb = NULL;
798  if (!pixs)
799  return ERROR_INT("pixs not defined", __func__, 1);
800  if (pixGetDepth(pixs) != 32)
801  return ERROR_INT("pixs not 32 bpp", __func__, 1);
802  if (pixim && pixGetDepth(pixim) != 1)
803  return ERROR_INT("pixim not 1 bpp", __func__, 1);
804  if (reduction < 2 || reduction > 16)
805  return ERROR_INT("reduction must be between 2 and 16", __func__, 1);
806 
807  /* If pixim exists, verify that it is not all foreground. */
808  if (pixim) {
809  pixInvert(pixim, pixim);
810  pixZero(pixim, &allfg);
811  pixInvert(pixim, pixim);
812  if (allfg)
813  return ERROR_INT("pixim all foreground", __func__, 1);
814  }
815 
816  pixGetBackgroundRGBMapMorph(pixs, pixim, reduction, size,
817  &pixmr, &pixmg, &pixmb);
818  if (!pixmr || !pixmg || !pixmb) {
819  pixDestroy(&pixmr);
820  pixDestroy(&pixmg);
821  pixDestroy(&pixmb);
822  return ERROR_INT("not all pixm* made", __func__, 1);
823  }
824 
825  *ppixr = pixGetInvBackgroundMap(pixmr, bgval, 0, 0);
826  *ppixg = pixGetInvBackgroundMap(pixmg, bgval, 0, 0);
827  *ppixb = pixGetInvBackgroundMap(pixmb, bgval, 0, 0);
828  pixDestroy(&pixmr);
829  pixDestroy(&pixmg);
830  pixDestroy(&pixmb);
831  return 0;
832 }
833 
834 
835 /*------------------------------------------------------------------*
836  * Measurement of local background *
837  *------------------------------------------------------------------*/
857 l_ok
859  PIX *pixim,
860  l_int32 sx,
861  l_int32 sy,
862  l_int32 thresh,
863  l_int32 mincount,
864  PIX **ppixd)
865 {
866 l_int32 w, h, wd, hd, wim, him, wpls, wplim, wpld, wplf;
867 l_int32 xim, yim, delx, nx, ny, i, j, k, m;
868 l_int32 count, sum, val8;
869 l_int32 empty, fgpixels;
870 l_uint32 *datas, *dataim, *datad, *dataf, *lines, *lineim, *lined, *linef;
871 l_float32 scalex, scaley;
872 PIX *pixd, *piximi, *pixb, *pixf, *pixims;
873 
874  if (!ppixd)
875  return ERROR_INT("&pixd not defined", __func__, 1);
876  *ppixd = NULL;
877  if (!pixs || pixGetDepth(pixs) != 8)
878  return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
879  if (pixGetColormap(pixs))
880  return ERROR_INT("pixs is colormapped", __func__, 1);
881  if (pixim && pixGetDepth(pixim) != 1)
882  return ERROR_INT("pixim not 1 bpp", __func__, 1);
883  if (sx < 4 || sy < 4)
884  return ERROR_INT("sx and sy must be >= 4", __func__, 1);
885  if (mincount > sx * sy) {
886  L_WARNING("mincount too large for tile size\n", __func__);
887  mincount = (sx * sy) / 3;
888  }
889 
890  /* Evaluate the 'image' mask, pixim, and make sure
891  * it is not all fg. */
892  fgpixels = 0; /* boolean for existence of fg pixels in the image mask. */
893  if (pixim) {
894  piximi = pixInvert(NULL, pixim); /* set non-'image' pixels to 1 */
895  pixZero(piximi, &empty);
896  pixDestroy(&piximi);
897  if (empty)
898  return ERROR_INT("pixim all fg; no background", __func__, 1);
899  pixZero(pixim, &empty);
900  if (!empty) /* there are fg pixels in pixim */
901  fgpixels = 1;
902  }
903 
904  /* Generate the foreground mask, pixf, which is at
905  * full resolution. These pixels will be ignored when
906  * computing the background values. */
907  pixb = pixThresholdToBinary(pixs, thresh);
908  pixf = pixMorphSequence(pixb, "d7.1 + d1.7", 0);
909  pixDestroy(&pixb);
910  if (!pixf)
911  return ERROR_INT("pixf not made", __func__, 1);
912 
913 
914  /* ------------- Set up the output map pixd --------------- */
915  /* Generate pixd, which is reduced by the factors (sx, sy). */
916  w = pixGetWidth(pixs);
917  h = pixGetHeight(pixs);
918  wd = (w + sx - 1) / sx;
919  hd = (h + sy - 1) / sy;
920  pixd = pixCreate(wd, hd, 8);
921 
922  /* Note: we only compute map values in tiles that are complete.
923  * In general, tiles at right and bottom edges will not be
924  * complete, and we must fill them in later. */
925  nx = w / sx;
926  ny = h / sy;
927  wpls = pixGetWpl(pixs);
928  datas = pixGetData(pixs);
929  wpld = pixGetWpl(pixd);
930  datad = pixGetData(pixd);
931  wplf = pixGetWpl(pixf);
932  dataf = pixGetData(pixf);
933  for (i = 0; i < ny; i++) {
934  lines = datas + sy * i * wpls;
935  linef = dataf + sy * i * wplf;
936  lined = datad + i * wpld;
937  for (j = 0; j < nx; j++) {
938  delx = j * sx;
939  sum = 0;
940  count = 0;
941  for (k = 0; k < sy; k++) {
942  for (m = 0; m < sx; m++) {
943  if (GET_DATA_BIT(linef + k * wplf, delx + m) == 0) {
944  sum += GET_DATA_BYTE(lines + k * wpls, delx + m);
945  count++;
946  }
947  }
948  }
949  if (count >= mincount) {
950  val8 = sum / count;
951  SET_DATA_BYTE(lined, j, val8);
952  }
953  }
954  }
955  pixDestroy(&pixf);
956 
957  /* If there is an optional mask with fg pixels, erase the previous
958  * calculation for the corresponding map pixels, setting the
959  * map values to 0. Then, when all the map holes are filled,
960  * these erased pixels will be set by the surrounding map values.
961  *
962  * The calculation here is relatively efficient: for each pixel
963  * in pixd (which corresponds to a tile of mask pixels in pixim)
964  * we look only at the pixel in pixim that is at the center
965  * of the tile. If the mask pixel is ON, we reset the map
966  * pixel in pixd to 0, so that it can later be filled in. */
967  pixims = NULL;
968  if (pixim && fgpixels) {
969  wim = pixGetWidth(pixim);
970  him = pixGetHeight(pixim);
971  dataim = pixGetData(pixim);
972  wplim = pixGetWpl(pixim);
973  for (i = 0; i < ny; i++) {
974  yim = i * sy + sy / 2;
975  if (yim >= him)
976  break;
977  lineim = dataim + yim * wplim;
978  for (j = 0; j < nx; j++) {
979  xim = j * sx + sx / 2;
980  if (xim >= wim)
981  break;
982  if (GET_DATA_BIT(lineim, xim))
983  pixSetPixel(pixd, j, i, 0);
984  }
985  }
986  }
987 
988  /* Fill all the holes in the map. */
989  if (pixFillMapHoles(pixd, nx, ny, L_FILL_BLACK)) {
990  pixDestroy(&pixd);
991  L_WARNING("can't make the map\n", __func__);
992  return 1;
993  }
994 
995  /* Finally, for each connected region corresponding to the
996  * 'image' mask, reset all pixels to their average value.
997  * Each of these components represents an image (or part of one)
998  * in the input, and this smooths the background values
999  * in each of these regions. */
1000  if (pixim && fgpixels) {
1001  scalex = 1. / (l_float32)sx;
1002  scaley = 1. / (l_float32)sy;
1003  pixims = pixScaleBySampling(pixim, scalex, scaley);
1004  pixSmoothConnectedRegions(pixd, pixims, 2);
1005  pixDestroy(&pixims);
1006  }
1007 
1008  *ppixd = pixd;
1009  pixCopyResolution(*ppixd, pixs);
1010  return 0;
1011 }
1012 
1013 
1037 l_ok
1039  PIX *pixim,
1040  PIX *pixg,
1041  l_int32 sx,
1042  l_int32 sy,
1043  l_int32 thresh,
1044  l_int32 mincount,
1045  PIX **ppixmr,
1046  PIX **ppixmg,
1047  PIX **ppixmb)
1048 {
1049 l_int32 w, h, wm, hm, wim, him, wpls, wplim, wplf;
1050 l_int32 xim, yim, delx, nx, ny, i, j, k, m;
1051 l_int32 count, rsum, gsum, bsum, rval, gval, bval;
1052 l_int32 empty, fgpixels;
1053 l_uint32 pixel;
1054 l_uint32 *datas, *dataim, *dataf, *lines, *lineim, *linef;
1055 l_float32 scalex, scaley;
1056 PIX *piximi, *pixgc, *pixb, *pixf, *pixims;
1057 PIX *pixmr, *pixmg, *pixmb;
1058 
1059  if (!ppixmr || !ppixmg || !ppixmb)
1060  return ERROR_INT("&pixm* not all defined", __func__, 1);
1061  *ppixmr = *ppixmg = *ppixmb = NULL;
1062  if (!pixs)
1063  return ERROR_INT("pixs not defined", __func__, 1);
1064  if (pixGetDepth(pixs) != 32)
1065  return ERROR_INT("pixs not 32 bpp", __func__, 1);
1066  if (pixim && pixGetDepth(pixim) != 1)
1067  return ERROR_INT("pixim not 1 bpp", __func__, 1);
1068  if (sx < 4 || sy < 4)
1069  return ERROR_INT("sx and sy must be >= 4", __func__, 1);
1070  if (mincount > sx * sy) {
1071  L_WARNING("mincount too large for tile size\n", __func__);
1072  mincount = (sx * sy) / 3;
1073  }
1074 
1075  /* Evaluate the mask pixim and make sure it is not all foreground */
1076  fgpixels = 0; /* boolean for existence of fg mask pixels */
1077  if (pixim) {
1078  piximi = pixInvert(NULL, pixim); /* set non-'image' pixels to 1 */
1079  pixZero(piximi, &empty);
1080  pixDestroy(&piximi);
1081  if (empty)
1082  return ERROR_INT("pixim all fg; no background", __func__, 1);
1083  pixZero(pixim, &empty);
1084  if (!empty) /* there are fg pixels in pixim */
1085  fgpixels = 1;
1086  }
1087 
1088  /* Generate the foreground mask. These pixels will be
1089  * ignored when computing the background values. */
1090  if (pixg) /* use the input grayscale version if it is provided */
1091  pixgc = pixClone(pixg);
1092  else
1093  pixgc = pixConvertRGBToGrayFast(pixs);
1094  pixb = pixThresholdToBinary(pixgc, thresh);
1095  pixf = pixMorphSequence(pixb, "d7.1 + d1.7", 0);
1096  pixDestroy(&pixgc);
1097  pixDestroy(&pixb);
1098 
1099  /* Generate the output mask images */
1100  w = pixGetWidth(pixs);
1101  h = pixGetHeight(pixs);
1102  wm = (w + sx - 1) / sx;
1103  hm = (h + sy - 1) / sy;
1104  pixmr = pixCreate(wm, hm, 8);
1105  pixmg = pixCreate(wm, hm, 8);
1106  pixmb = pixCreate(wm, hm, 8);
1107 
1108  /* ------------- Set up the mapping images --------------- */
1109  /* Note: we only compute map values in tiles that are complete.
1110  * In general, tiles at right and bottom edges will not be
1111  * complete, and we must fill them in later. */
1112  nx = w / sx;
1113  ny = h / sy;
1114  wpls = pixGetWpl(pixs);
1115  datas = pixGetData(pixs);
1116  wplf = pixGetWpl(pixf);
1117  dataf = pixGetData(pixf);
1118  for (i = 0; i < ny; i++) {
1119  lines = datas + sy * i * wpls;
1120  linef = dataf + sy * i * wplf;
1121  for (j = 0; j < nx; j++) {
1122  delx = j * sx;
1123  rsum = gsum = bsum = 0;
1124  count = 0;
1125  for (k = 0; k < sy; k++) {
1126  for (m = 0; m < sx; m++) {
1127  if (GET_DATA_BIT(linef + k * wplf, delx + m) == 0) {
1128  pixel = *(lines + k * wpls + delx + m);
1129  rsum += (pixel >> 24);
1130  gsum += ((pixel >> 16) & 0xff);
1131  bsum += ((pixel >> 8) & 0xff);
1132  count++;
1133  }
1134  }
1135  }
1136  if (count >= mincount) {
1137  rval = rsum / count;
1138  gval = gsum / count;
1139  bval = bsum / count;
1140  pixSetPixel(pixmr, j, i, rval);
1141  pixSetPixel(pixmg, j, i, gval);
1142  pixSetPixel(pixmb, j, i, bval);
1143  }
1144  }
1145  }
1146  pixDestroy(&pixf);
1147 
1148  /* If there is an optional mask with fg pixels, erase the previous
1149  * calculation for the corresponding map pixels, setting the
1150  * map values in each of the 3 color maps to 0. Then, when
1151  * all the map holes are filled, these erased pixels will
1152  * be set by the surrounding map values. */
1153  if (pixim) {
1154  wim = pixGetWidth(pixim);
1155  him = pixGetHeight(pixim);
1156  dataim = pixGetData(pixim);
1157  wplim = pixGetWpl(pixim);
1158  for (i = 0; i < ny; i++) {
1159  yim = i * sy + sy / 2;
1160  if (yim >= him)
1161  break;
1162  lineim = dataim + yim * wplim;
1163  for (j = 0; j < nx; j++) {
1164  xim = j * sx + sx / 2;
1165  if (xim >= wim)
1166  break;
1167  if (GET_DATA_BIT(lineim, xim)) {
1168  pixSetPixel(pixmr, j, i, 0);
1169  pixSetPixel(pixmg, j, i, 0);
1170  pixSetPixel(pixmb, j, i, 0);
1171  }
1172  }
1173  }
1174  }
1175 
1176  /* ----------------- Now fill in the holes ----------------------- */
1177  if (pixFillMapHoles(pixmr, nx, ny, L_FILL_BLACK) ||
1178  pixFillMapHoles(pixmg, nx, ny, L_FILL_BLACK) ||
1179  pixFillMapHoles(pixmb, nx, ny, L_FILL_BLACK)) {
1180  pixDestroy(&pixmr);
1181  pixDestroy(&pixmg);
1182  pixDestroy(&pixmb);
1183  L_WARNING("can't make the maps\n", __func__);
1184  return 1;
1185  }
1186 
1187  /* Finally, for each connected region corresponding to the
1188  * fg mask, reset all pixels to their average value. */
1189  if (pixim && fgpixels) {
1190  scalex = 1. / (l_float32)sx;
1191  scaley = 1. / (l_float32)sy;
1192  pixims = pixScaleBySampling(pixim, scalex, scaley);
1193  pixSmoothConnectedRegions(pixmr, pixims, 2);
1194  pixSmoothConnectedRegions(pixmg, pixims, 2);
1195  pixSmoothConnectedRegions(pixmb, pixims, 2);
1196  pixDestroy(&pixims);
1197  }
1198 
1199  *ppixmr = pixmr;
1200  *ppixmg = pixmg;
1201  *ppixmb = pixmb;
1202  pixCopyResolution(*ppixmr, pixs);
1203  pixCopyResolution(*ppixmg, pixs);
1204  pixCopyResolution(*ppixmb, pixs);
1205  return 0;
1206 }
1207 
1208 
1220 l_ok
1222  PIX *pixim,
1223  l_int32 reduction,
1224  l_int32 size,
1225  PIX **ppixm)
1226 {
1227 l_int32 nx, ny, empty, fgpixels;
1228 l_float32 scale;
1229 PIX *pixm, *pix1, *pix2, *pix3, *pixims;
1230 
1231  if (!ppixm)
1232  return ERROR_INT("&pixm not defined", __func__, 1);
1233  *ppixm = NULL;
1234  if (!pixs || pixGetDepth(pixs) != 8)
1235  return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
1236  if (pixGetColormap(pixs))
1237  return ERROR_INT("pixs is colormapped", __func__, 1);
1238  if (pixim && pixGetDepth(pixim) != 1)
1239  return ERROR_INT("pixim not 1 bpp", __func__, 1);
1240 
1241  /* Evaluate the mask pixim and make sure it is not all foreground. */
1242  fgpixels = 0; /* boolean for existence of fg mask pixels */
1243  if (pixim) {
1244  pixInvert(pixim, pixim); /* set background pixels to 1 */
1245  pixZero(pixim, &empty);
1246  if (empty)
1247  return ERROR_INT("pixim all fg; no background", __func__, 1);
1248  pixInvert(pixim, pixim); /* revert to original mask */
1249  pixZero(pixim, &empty);
1250  if (!empty) /* there are fg pixels in pixim */
1251  fgpixels = 1;
1252  }
1253 
1254  /* Downscale as requested and do the closing to get the background. */
1255  scale = 1. / (l_float32)reduction;
1256  pix1 = pixScaleBySampling(pixs, scale, scale);
1257  pix2 = pixCloseGray(pix1, size, size);
1258  pix3 = pixExtendByReplication(pix2, 1, 1);
1259  pixDestroy(&pix1);
1260  pixDestroy(&pix2);
1261 
1262  /* Downscale the image mask, if any, and remove it from the
1263  * background. These pixels will be filled in (twice). */
1264  pixims = NULL;
1265  if (pixim) {
1266  pixims = pixScale(pixim, scale, scale);
1267  pixm = pixConvertTo8(pixims, FALSE);
1268  pixAnd(pixm, pixm, pix3);
1269  }
1270  else
1271  pixm = pixClone(pix3);
1272  pixDestroy(&pix3);
1273 
1274  /* Fill all the holes in the map. */
1275  nx = pixGetWidth(pixs) / reduction;
1276  ny = pixGetHeight(pixs) / reduction;
1277  if (pixFillMapHoles(pixm, nx, ny, L_FILL_BLACK)) {
1278  pixDestroy(&pixm);
1279  pixDestroy(&pixims);
1280  L_WARNING("can't make the map\n", __func__);
1281  return 1;
1282  }
1283 
1284  /* Finally, for each connected region corresponding to the
1285  * fg mask, reset all pixels to their average value. */
1286  if (pixim && fgpixels)
1287  pixSmoothConnectedRegions(pixm, pixims, 2);
1288  pixDestroy(&pixims);
1289 
1290  *ppixm = pixm;
1291  pixCopyResolution(*ppixm, pixs);
1292  return 0;
1293 }
1294 
1295 
1309 l_ok
1311  PIX *pixim,
1312  l_int32 reduction,
1313  l_int32 size,
1314  PIX **ppixmr,
1315  PIX **ppixmg,
1316  PIX **ppixmb)
1317 {
1318 l_int32 nx, ny, empty, fgpixels;
1319 l_float32 scale;
1320 PIX *pixm, *pixmr, *pixmg, *pixmb, *pix1, *pix2, *pix3, *pixims;
1321 
1322  if (!ppixmr || !ppixmg || !ppixmb)
1323  return ERROR_INT("&pixm* not all defined", __func__, 1);
1324  *ppixmr = *ppixmg = *ppixmb = NULL;
1325  if (!pixs)
1326  return ERROR_INT("pixs not defined", __func__, 1);
1327  if (pixGetDepth(pixs) != 32)
1328  return ERROR_INT("pixs not 32 bpp", __func__, 1);
1329  if (pixim && pixGetDepth(pixim) != 1)
1330  return ERROR_INT("pixim not 1 bpp", __func__, 1);
1331 
1332  /* Evaluate the mask pixim and make sure it is not all foreground. */
1333  fgpixels = 0; /* boolean for existence of fg mask pixels */
1334  if (pixim) {
1335  pixInvert(pixim, pixim); /* set background pixels to 1 */
1336  pixZero(pixim, &empty);
1337  if (empty)
1338  return ERROR_INT("pixim all fg; no background", __func__, 1);
1339  pixInvert(pixim, pixim); /* revert to original mask */
1340  pixZero(pixim, &empty);
1341  if (!empty) /* there are fg pixels in pixim */
1342  fgpixels = 1;
1343  }
1344 
1345  /* Generate an 8 bpp version of the image mask, if it exists */
1346  scale = 1. / (l_float32)reduction;
1347  pixims = NULL;
1348  pixm = NULL;
1349  if (pixim) {
1350  pixims = pixScale(pixim, scale, scale);
1351  pixm = pixConvertTo8(pixims, FALSE);
1352  }
1353 
1354  /* Downscale as requested and do the closing to get the background.
1355  * Then remove the image mask pixels from the background. They
1356  * will be filled in (twice) later. Do this for all 3 components. */
1357  pix1 = pixScaleRGBToGrayFast(pixs, reduction, COLOR_RED);
1358  pix2 = pixCloseGray(pix1, size, size);
1359  pix3 = pixExtendByReplication(pix2, 1, 1);
1360  if (pixim)
1361  pixmr = pixAnd(NULL, pixm, pix3);
1362  else
1363  pixmr = pixClone(pix3);
1364  pixDestroy(&pix1);
1365  pixDestroy(&pix2);
1366  pixDestroy(&pix3);
1367 
1368  pix1 = pixScaleRGBToGrayFast(pixs, reduction, COLOR_GREEN);
1369  pix2 = pixCloseGray(pix1, size, size);
1370  pix3 = pixExtendByReplication(pix2, 1, 1);
1371  if (pixim)
1372  pixmg = pixAnd(NULL, pixm, pix3);
1373  else
1374  pixmg = pixClone(pix3);
1375  pixDestroy(&pix1);
1376  pixDestroy(&pix2);
1377  pixDestroy(&pix3);
1378 
1379  pix1 = pixScaleRGBToGrayFast(pixs, reduction, COLOR_BLUE);
1380  pix2 = pixCloseGray(pix1, size, size);
1381  pix3 = pixExtendByReplication(pix2, 1, 1);
1382  if (pixim)
1383  pixmb = pixAnd(NULL, pixm, pix3);
1384  else
1385  pixmb = pixClone(pix3);
1386  pixDestroy(&pixm);
1387  pixDestroy(&pix1);
1388  pixDestroy(&pix2);
1389  pixDestroy(&pix3);
1390 
1391  /* Fill all the holes in the three maps. */
1392  nx = pixGetWidth(pixs) / reduction;
1393  ny = pixGetHeight(pixs) / reduction;
1394  if (pixFillMapHoles(pixmr, nx, ny, L_FILL_BLACK) ||
1395  pixFillMapHoles(pixmg, nx, ny, L_FILL_BLACK) ||
1396  pixFillMapHoles(pixmb, nx, ny, L_FILL_BLACK)) {
1397  pixDestroy(&pixmr);
1398  pixDestroy(&pixmg);
1399  pixDestroy(&pixmb);
1400  pixDestroy(&pixims);
1401  L_WARNING("can't make the maps\n", __func__);
1402  return 1;
1403  }
1404 
1405  /* Finally, for each connected region corresponding to the
1406  * fg mask in each component, reset all pixels to their
1407  * average value. */
1408  if (pixim && fgpixels) {
1409  pixSmoothConnectedRegions(pixmr, pixims, 2);
1410  pixSmoothConnectedRegions(pixmg, pixims, 2);
1411  pixSmoothConnectedRegions(pixmb, pixims, 2);
1412  pixDestroy(&pixims);
1413  }
1414 
1415  *ppixmr = pixmr;
1416  *ppixmg = pixmg;
1417  *ppixmb = pixmb;
1418  pixCopyResolution(*ppixmr, pixs);
1419  pixCopyResolution(*ppixmg, pixs);
1420  pixCopyResolution(*ppixmb, pixs);
1421  return 0;
1422 }
1423 
1424 
1461 l_ok
1463  l_int32 nx,
1464  l_int32 ny,
1465  l_int32 filltype)
1466 {
1467 l_int32 w, h, y, nmiss, goodcol, i, j, found, ival, valtest;
1468 l_uint32 val, lastval;
1469 NUMA *na; /* indicates if there is any data in the column */
1470 
1471  if (!pix || pixGetDepth(pix) != 8)
1472  return ERROR_INT("pix not defined or not 8 bpp", __func__, 1);
1473  if (pixGetColormap(pix))
1474  return ERROR_INT("pix is colormapped", __func__, 1);
1475 
1476  /* ------------- Fill holes in the mapping image columns ----------- */
1477  pixGetDimensions(pix, &w, &h, NULL);
1478  na = numaCreate(0); /* holds flag for which columns have data */
1479  nmiss = 0;
1480  valtest = (filltype == L_FILL_WHITE) ? 255 : 0;
1481  for (j = 0; j < nx; j++) { /* do it by columns */
1482  found = FALSE;
1483  for (i = 0; i < ny; i++) {
1484  pixGetPixel(pix, j, i, &val);
1485  if (val != valtest) {
1486  y = i;
1487  found = TRUE;
1488  break;
1489  }
1490  }
1491  if (found == FALSE) {
1492  numaAddNumber(na, 0); /* no data in the column */
1493  nmiss++;
1494  }
1495  else {
1496  numaAddNumber(na, 1); /* data in the column */
1497  for (i = y - 1; i >= 0; i--) /* replicate upwards to top */
1498  pixSetPixel(pix, j, i, val);
1499  pixGetPixel(pix, j, 0, &lastval);
1500  for (i = 1; i < h; i++) { /* set going down to bottom */
1501  pixGetPixel(pix, j, i, &val);
1502  if (val == valtest)
1503  pixSetPixel(pix, j, i, lastval);
1504  else
1505  lastval = val;
1506  }
1507  }
1508  }
1509 
1510  if (nmiss == nx) { /* no data in any column! */
1511  numaDestroy(&na);
1512  L_WARNING("no bg found; no data in any column\n", __func__);
1513  return 1;
1514  }
1515 
1516  /* ---------- Fill in missing columns by replication ----------- */
1517  if (nmiss > 0) { /* replicate columns */
1518  /* Find the first good column */
1519  goodcol = 0;
1520  for (j = 0; j < w; j++) {
1521  numaGetIValue(na, j, &ival);
1522  if (ival == 1) {
1523  goodcol = j;
1524  break;
1525  }
1526  }
1527  if (goodcol > 0) { /* copy cols backward */
1528  for (j = goodcol - 1; j >= 0; j--)
1529  pixRasterop(pix, j, 0, 1, h, PIX_SRC, pix, j + 1, 0);
1530  }
1531  for (j = goodcol + 1; j < w; j++) { /* copy cols forward */
1532  numaGetIValue(na, j, &ival);
1533  if (ival == 0) {
1534  /* Copy the column to the left of j */
1535  pixRasterop(pix, j, 0, 1, h, PIX_SRC, pix, j - 1, 0);
1536  }
1537  }
1538  }
1539  if (w > nx) { /* replicate the last column */
1540  pixRasterop(pix, w - 1, 0, 1, h, PIX_SRC, pix, w - 2, 0);
1541  }
1542 
1543  numaDestroy(&na);
1544  return 0;
1545 }
1546 
1547 
1561 PIX *
1563  l_int32 addw,
1564  l_int32 addh)
1565 {
1566 l_int32 w, h, i, j;
1567 l_uint32 val;
1568 PIX *pixd;
1569 
1570  if (!pixs || pixGetDepth(pixs) != 8)
1571  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
1572 
1573  if (addw == 0 && addh == 0)
1574  return pixCopy(NULL, pixs);
1575 
1576  pixGetDimensions(pixs, &w, &h, NULL);
1577  if ((pixd = pixCreate(w + addw, h + addh, 8)) == NULL)
1578  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1579  pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
1580 
1581  if (addw > 0) {
1582  for (i = 0; i < h; i++) {
1583  pixGetPixel(pixd, w - 1, i, &val);
1584  for (j = 0; j < addw; j++)
1585  pixSetPixel(pixd, w + j, i, val);
1586  }
1587  }
1588 
1589  if (addh > 0) {
1590  for (j = 0; j < w + addw; j++) {
1591  pixGetPixel(pixd, j, h - 1, &val);
1592  for (i = 0; i < addh; i++)
1593  pixSetPixel(pixd, j, h + i, val);
1594  }
1595  }
1596 
1597  pixCopyResolution(pixd, pixs);
1598  return pixd;
1599 }
1600 
1601 
1622 l_ok
1624  PIX *pixm,
1625  l_int32 factor)
1626 {
1627 l_int32 empty, i, n, x, y;
1628 l_float32 aveval;
1629 BOXA *boxa;
1630 PIX *pixmc;
1631 PIXA *pixa;
1632 
1633  if (!pixs || pixGetDepth(pixs) != 8)
1634  return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
1635  if (pixGetColormap(pixs))
1636  return ERROR_INT("pixs has colormap", __func__, 1);
1637  if (!pixm) {
1638  L_INFO("pixm not defined\n", __func__);
1639  return 0;
1640  }
1641  if (pixGetDepth(pixm) != 1)
1642  return ERROR_INT("pixm not 1 bpp", __func__, 1);
1643  pixZero(pixm, &empty);
1644  if (empty) {
1645  L_INFO("pixm has no fg pixels; nothing to do\n", __func__);
1646  return 0;
1647  }
1648 
1649  boxa = pixConnComp(pixm, &pixa, 8);
1650  n = boxaGetCount(boxa);
1651  for (i = 0; i < n; i++) {
1652  if ((pixmc = pixaGetPix(pixa, i, L_CLONE)) == NULL) {
1653  L_WARNING("missing pixmc!\n", __func__);
1654  continue;
1655  }
1656  boxaGetBoxGeometry(boxa, i, &x, &y, NULL, NULL);
1657  pixGetAverageMasked(pixs, pixmc, x, y, factor, L_MEAN_ABSVAL, &aveval);
1658  pixPaintThroughMask(pixs, pixmc, x, y, (l_int32)aveval);
1659  pixDestroy(&pixmc);
1660  }
1661 
1662  boxaDestroy(&boxa);
1663  pixaDestroy(&pixa);
1664  return 0;
1665 }
1666 
1667 
1668 /*------------------------------------------------------------------*
1669  * Measurement of local foreground *
1670  *------------------------------------------------------------------*/
1671 #if 0 /* Not working properly: do not use */
1672 
1709 l_ok
1710 pixGetForegroundGrayMap(PIX *pixs,
1711  PIX *pixim,
1712  l_int32 sx,
1713  l_int32 sy,
1714  l_int32 thresh,
1715  PIX **ppixd)
1716 {
1717 l_int32 w, h, d, wd, hd;
1718 l_int32 empty, fgpixels;
1719 PIX *pixd, *piximi, *pixim2, *pixims, *pixs2, *pixb, *pixt1, *pixt2, *pixt3;
1720 
1721  if (!ppixd)
1722  return ERROR_INT("&pixd not defined", __func__, 1);
1723  *ppixd = NULL;
1724  if (!pixs)
1725  return ERROR_INT("pixs not defined", __func__, 1);
1726  pixGetDimensions(pixs, &w, &h, &d);
1727  if (d != 8)
1728  return ERROR_INT("pixs not 8 bpp", __func__, 1);
1729  if (pixim && pixGetDepth(pixim) != 1)
1730  return ERROR_INT("pixim not 1 bpp", __func__, 1);
1731  if (sx < 2 || sy < 2)
1732  return ERROR_INT("sx and sy must be >= 2", __func__, 1);
1733 
1734  /* Generate pixd, which is reduced by the factors (sx, sy). */
1735  wd = (w + sx - 1) / sx;
1736  hd = (h + sy - 1) / sy;
1737  pixd = pixCreate(wd, hd, 8);
1738  *ppixd = pixd;
1739 
1740  /* Evaluate the 'image' mask, pixim. If it is all fg,
1741  * the output pixd has all pixels with value 0. */
1742  fgpixels = 0; /* boolean for existence of fg pixels in the image mask. */
1743  if (pixim) {
1744  piximi = pixInvert(NULL, pixim); /* set non-image pixels to 1 */
1745  pixZero(piximi, &empty);
1746  pixDestroy(&piximi);
1747  if (empty) /* all 'image'; return with all pixels set to 0 */
1748  return 0;
1749  pixZero(pixim, &empty);
1750  if (!empty) /* there are fg pixels in pixim */
1751  fgpixels = 1;
1752  }
1753 
1754  /* 2x subsampling; paint white through 'image' mask. */
1755  pixs2 = pixScaleBySampling(pixs, 0.5, 0.5);
1756  if (pixim && fgpixels) {
1757  pixim2 = pixReduceBinary2(pixim, NULL);
1758  pixPaintThroughMask(pixs2, pixim2, 0, 0, 255);
1759  pixDestroy(&pixim2);
1760  }
1761 
1762  /* Min (erosion) downscaling; total reduction (4 sx, 4 sy). */
1763  pixt1 = pixScaleGrayMinMax(pixs2, sx, sy, L_CHOOSE_MIN);
1764 
1765 /* pixDisplay(pixt1, 300, 200); */
1766 
1767  /* Threshold to identify fg; paint bg pixels to white. */
1768  pixb = pixThresholdToBinary(pixt1, thresh); /* fg pixels */
1769  pixInvert(pixb, pixb);
1770  pixPaintThroughMask(pixt1, pixb, 0, 0, 255);
1771  pixDestroy(&pixb);
1772 
1773  /* Replicative expansion by 2x to (sx, sy). */
1774  pixt2 = pixExpandReplicate(pixt1, 2);
1775 
1776 /* pixDisplay(pixt2, 500, 200); */
1777 
1778  /* Fill holes in the fg by propagation */
1779  pixFillMapHoles(pixt2, w / sx, h / sy, L_FILL_WHITE);
1780 
1781 /* pixDisplay(pixt2, 700, 200); */
1782 
1783  /* Smooth with 17x17 kernel. */
1784  pixt3 = pixBlockconv(pixt2, 8, 8);
1785  pixRasterop(pixd, 0, 0, wd, hd, PIX_SRC, pixt3, 0, 0);
1786 
1787  /* Paint the image parts black. */
1788  pixims = pixScaleBySampling(pixim, 1. / sx, 1. / sy);
1789  pixPaintThroughMask(pixd, pixims, 0, 0, 0);
1790 
1791  pixDestroy(&pixs2);
1792  pixDestroy(&pixt1);
1793  pixDestroy(&pixt2);
1794  pixDestroy(&pixt3);
1795  return 0;
1796 }
1797 #endif /* Not working properly: do not use */
1798 
1799 
1800 /*------------------------------------------------------------------*
1801  * Generate inverted background map *
1802  *------------------------------------------------------------------*/
1819 PIX *
1821  l_int32 bgval,
1822  l_int32 smoothx,
1823  l_int32 smoothy)
1824 {
1825 l_int32 w, h, wplsm, wpld, i, j;
1826 l_int32 val, val16;
1827 l_uint32 *datasm, *datad, *linesm, *lined;
1828 PIX *pixsm, *pixd;
1829 
1830  if (!pixs || pixGetDepth(pixs) != 8)
1831  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
1832  if (pixGetColormap(pixs))
1833  return (PIX *)ERROR_PTR("pixs has colormap", __func__, NULL);
1834  pixGetDimensions(pixs, &w, &h, NULL);
1835  if (w < 5 || h < 5)
1836  return (PIX *)ERROR_PTR("w and h must be >= 5", __func__, NULL);
1837 
1838  /* smooth the map image */
1839  pixsm = pixBlockconv(pixs, smoothx, smoothy);
1840  datasm = pixGetData(pixsm);
1841  wplsm = pixGetWpl(pixsm);
1842 
1843  /* invert the map image, scaling up to preserve dynamic range */
1844  pixd = pixCreate(w, h, 16);
1845  datad = pixGetData(pixd);
1846  wpld = pixGetWpl(pixd);
1847  for (i = 0; i < h; i++) {
1848  linesm = datasm + i * wplsm;
1849  lined = datad + i * wpld;
1850  for (j = 0; j < w; j++) {
1851  val = GET_DATA_BYTE(linesm, j);
1852  if (val > 0)
1853  val16 = (256 * bgval) / val;
1854  else { /* shouldn't happen */
1855  L_WARNING("smoothed bg has 0 pixel!\n", __func__);
1856  val16 = bgval / 2;
1857  }
1858  SET_DATA_TWO_BYTES(lined, j, val16);
1859  }
1860  }
1861 
1862  pixDestroy(&pixsm);
1863  pixCopyResolution(pixd, pixs);
1864  return pixd;
1865 }
1866 
1867 
1868 /*------------------------------------------------------------------*
1869  * Apply background map to image *
1870  *------------------------------------------------------------------*/
1880 PIX *
1882  PIX *pixm,
1883  l_int32 sx,
1884  l_int32 sy)
1885 {
1886 l_int32 w, h, wm, hm, wpls, wpld, i, j, k, m, xoff, yoff;
1887 l_int32 vals, vald;
1888 l_uint32 val16;
1889 l_uint32 *datas, *datad, *lines, *lined, *flines, *flined;
1890 PIX *pixd;
1891 
1892  if (!pixs || pixGetDepth(pixs) != 8)
1893  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
1894  if (pixGetColormap(pixs))
1895  return (PIX *)ERROR_PTR("pixs has colormap", __func__, NULL);
1896  if (!pixm || pixGetDepth(pixm) != 16)
1897  return (PIX *)ERROR_PTR("pixm undefined or not 16 bpp", __func__, NULL);
1898  if (sx == 0 || sy == 0)
1899  return (PIX *)ERROR_PTR("invalid sx and/or sy", __func__, NULL);
1900 
1901  datas = pixGetData(pixs);
1902  wpls = pixGetWpl(pixs);
1903  pixGetDimensions(pixs, &w, &h, NULL);
1904  pixGetDimensions(pixm, &wm, &hm, NULL);
1905  if ((pixd = pixCreateTemplate(pixs)) == NULL)
1906  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1907  datad = pixGetData(pixd);
1908  wpld = pixGetWpl(pixd);
1909  for (i = 0; i < hm; i++) {
1910  lines = datas + sy * i * wpls;
1911  lined = datad + sy * i * wpld;
1912  yoff = sy * i;
1913  for (j = 0; j < wm; j++) {
1914  pixGetPixel(pixm, j, i, &val16);
1915  xoff = sx * j;
1916  for (k = 0; k < sy && yoff + k < h; k++) {
1917  flines = lines + k * wpls;
1918  flined = lined + k * wpld;
1919  for (m = 0; m < sx && xoff + m < w; m++) {
1920  vals = GET_DATA_BYTE(flines, xoff + m);
1921  vald = (vals * val16) / 256;
1922  vald = L_MIN(vald, 255);
1923  SET_DATA_BYTE(flined, xoff + m, vald);
1924  }
1925  }
1926  }
1927  }
1928 
1929  return pixd;
1930 }
1931 
1932 
1944 PIX *
1946  PIX *pixmr,
1947  PIX *pixmg,
1948  PIX *pixmb,
1949  l_int32 sx,
1950  l_int32 sy)
1951 {
1952 l_int32 w, h, wm, hm, wpls, wpld, i, j, k, m, xoff, yoff;
1953 l_int32 rvald, gvald, bvald;
1954 l_uint32 vals;
1955 l_uint32 rval16, gval16, bval16;
1956 l_uint32 *datas, *datad, *lines, *lined, *flines, *flined;
1957 PIX *pixd;
1958 
1959  if (!pixs)
1960  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1961  if (pixGetDepth(pixs) != 32)
1962  return (PIX *)ERROR_PTR("pixs not 32 bpp", __func__, NULL);
1963  if (!pixmr || !pixmg || !pixmb)
1964  return (PIX *)ERROR_PTR("pix maps not all defined", __func__, NULL);
1965  if (pixGetDepth(pixmr) != 16 || pixGetDepth(pixmg) != 16 ||
1966  pixGetDepth(pixmb) != 16)
1967  return (PIX *)ERROR_PTR("pix maps not all 16 bpp", __func__, NULL);
1968  if (sx == 0 || sy == 0)
1969  return (PIX *)ERROR_PTR("invalid sx and/or sy", __func__, NULL);
1970 
1971  datas = pixGetData(pixs);
1972  wpls = pixGetWpl(pixs);
1973  w = pixGetWidth(pixs);
1974  h = pixGetHeight(pixs);
1975  wm = pixGetWidth(pixmr);
1976  hm = pixGetHeight(pixmr);
1977  if ((pixd = pixCreateTemplate(pixs)) == NULL)
1978  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1979  datad = pixGetData(pixd);
1980  wpld = pixGetWpl(pixd);
1981  for (i = 0; i < hm; i++) {
1982  lines = datas + sy * i * wpls;
1983  lined = datad + sy * i * wpld;
1984  yoff = sy * i;
1985  for (j = 0; j < wm; j++) {
1986  pixGetPixel(pixmr, j, i, &rval16);
1987  pixGetPixel(pixmg, j, i, &gval16);
1988  pixGetPixel(pixmb, j, i, &bval16);
1989  xoff = sx * j;
1990  for (k = 0; k < sy && yoff + k < h; k++) {
1991  flines = lines + k * wpls;
1992  flined = lined + k * wpld;
1993  for (m = 0; m < sx && xoff + m < w; m++) {
1994  vals = *(flines + xoff + m);
1995  rvald = ((vals >> 24) * rval16) / 256;
1996  rvald = L_MIN(rvald, 255);
1997  gvald = (((vals >> 16) & 0xff) * gval16) / 256;
1998  gvald = L_MIN(gvald, 255);
1999  bvald = (((vals >> 8) & 0xff) * bval16) / 256;
2000  bvald = L_MIN(bvald, 255);
2001  composeRGBPixel(rvald, gvald, bvald, flined + xoff + m);
2002  }
2003  }
2004  }
2005  }
2006 
2007  return pixd;
2008 }
2009 
2010 
2011 /*------------------------------------------------------------------*
2012  * Apply variable map *
2013  *------------------------------------------------------------------*/
2040 PIX *
2042  PIX *pixg,
2043  l_int32 target)
2044 {
2045 l_int32 i, j, w, h, d, wpls, wplg, wpld, vals, valg, vald;
2046 l_uint8 *lut;
2047 l_uint32 *datas, *datag, *datad, *lines, *lineg, *lined;
2048 l_float32 fval;
2049 PIX *pixd;
2050 
2051  if (!pixs)
2052  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2053  if (!pixg)
2054  return (PIX *)ERROR_PTR("pixg not defined", __func__, NULL);
2055  if (!pixSizesEqual(pixs, pixg))
2056  return (PIX *)ERROR_PTR("pix sizes not equal", __func__, NULL);
2057  pixGetDimensions(pixs, &w, &h, &d);
2058  if (d != 8)
2059  return (PIX *)ERROR_PTR("depth not 8 bpp", __func__, NULL);
2060 
2061  /* Generate a LUT for the mapping if the image is large enough
2062  * to warrant the overhead. The LUT is of size 2^16. For the
2063  * index to the table, get the MSB from pixs and the LSB from pixg.
2064  * Note: this LUT is bigger than the typical 32K L1 cache, so
2065  * we expect cache misses. L2 latencies are about 5ns. But
2066  * division is slooooow. For large images, this function is about
2067  * 4x faster when using the LUT. C'est la vie. */
2068  lut = NULL;
2069  if (w * h > 100000) { /* more pixels than 2^16 */
2070  lut = (l_uint8 *)LEPT_CALLOC(0x10000, sizeof(l_uint8));
2071  for (i = 0; i < 256; i++) {
2072  for (j = 0; j < 256; j++) {
2073  fval = (l_float32)(i * target) / (j + 0.5);
2074  lut[(i << 8) + j] = L_MIN(255, (l_int32)(fval + 0.5));
2075  }
2076  }
2077  }
2078 
2079  if ((pixd = pixCreate(w, h, 8)) == NULL) {
2080  LEPT_FREE(lut);
2081  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2082  }
2083  pixCopyResolution(pixd, pixs);
2084  datad = pixGetData(pixd);
2085  wpld = pixGetWpl(pixd);
2086  datas = pixGetData(pixs);
2087  wpls = pixGetWpl(pixs);
2088  datag = pixGetData(pixg);
2089  wplg = pixGetWpl(pixg);
2090  for (i = 0; i < h; i++) {
2091  lines = datas + i * wpls;
2092  lineg = datag + i * wplg;
2093  lined = datad + i * wpld;
2094  if (lut) {
2095  for (j = 0; j < w; j++) {
2096  vals = GET_DATA_BYTE(lines, j);
2097  valg = GET_DATA_BYTE(lineg, j);
2098  vald = lut[(vals << 8) + valg];
2099  SET_DATA_BYTE(lined, j, vald);
2100  }
2101  }
2102  else {
2103  for (j = 0; j < w; j++) {
2104  vals = GET_DATA_BYTE(lines, j);
2105  valg = GET_DATA_BYTE(lineg, j);
2106  fval = (l_float32)(vals * target) / (valg + 0.5);
2107  vald = L_MIN(255, (l_int32)(fval + 0.5));
2108  SET_DATA_BYTE(lined, j, vald);
2109  }
2110  }
2111  }
2112 
2113  LEPT_FREE(lut);
2114  return pixd;
2115 }
2116 
2117 
2118 /*------------------------------------------------------------------*
2119  * Non-adaptive (global) mapping *
2120  *------------------------------------------------------------------*/
2155 PIX *
2157  PIX *pixs,
2158  l_int32 rval,
2159  l_int32 gval,
2160  l_int32 bval,
2161  l_int32 mapval)
2162 {
2163 l_int32 w, h, d, i, j, ncolors, rv, gv, bv, wpl;
2164 l_int32 *rarray, *garray, *barray;
2165 l_uint32 *data, *line;
2166 NUMA *nar, *nag, *nab;
2167 PIXCMAP *cmap;
2168 
2169  if (!pixs)
2170  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2171  cmap = pixGetColormap(pixs);
2172  pixGetDimensions(pixs, &w, &h, &d);
2173  if (!cmap && d != 32)
2174  return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", __func__, NULL);
2175  if (mapval <= 0) {
2176  L_WARNING("mapval must be > 0; setting to 255\n", __func__);
2177  mapval = 255;
2178  }
2179 
2180  /* Prepare pixd to be a copy of pixs */
2181  if ((pixd = pixCopy(pixd, pixs)) == NULL)
2182  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2183 
2184  /* Generate the TRC maps for each component. Make sure the
2185  * upper range for each color is greater than zero. */
2186  nar = numaGammaTRC(1.0, 0, L_MAX(1, 255 * rval / mapval));
2187  nag = numaGammaTRC(1.0, 0, L_MAX(1, 255 * gval / mapval));
2188  nab = numaGammaTRC(1.0, 0, L_MAX(1, 255 * bval / mapval));
2189 
2190  /* Extract copies of the internal arrays */
2191  rarray = numaGetIArray(nar);
2192  garray = numaGetIArray(nag);
2193  barray = numaGetIArray(nab);
2194  if (!nar || !nag || !nab || !rarray || !garray || !barray) {
2195  L_ERROR("allocation failure in arrays\n", __func__);
2196  goto cleanup_arrays;
2197  }
2198 
2199  if (cmap) {
2200  ncolors = pixcmapGetCount(cmap);
2201  for (i = 0; i < ncolors; i++) {
2202  pixcmapGetColor(cmap, i, &rv, &gv, &bv);
2203  pixcmapResetColor(cmap, i, rarray[rv], garray[gv], barray[bv]);
2204  }
2205  }
2206  else {
2207  data = pixGetData(pixd);
2208  wpl = pixGetWpl(pixd);
2209  for (i = 0; i < h; i++) {
2210  line = data + i * wpl;
2211  for (j = 0; j < w; j++) {
2212  extractRGBValues(line[j], &rv, &gv, &bv);
2213  composeRGBPixel(rarray[rv], garray[gv], barray[bv], line + j);
2214  }
2215  }
2216  }
2217 
2218 cleanup_arrays:
2219  numaDestroy(&nar);
2220  numaDestroy(&nag);
2221  numaDestroy(&nab);
2222  LEPT_FREE(rarray);
2223  LEPT_FREE(garray);
2224  LEPT_FREE(barray);
2225  return pixd;
2226 }
2227 
2228 
2262 PIX *
2264  PIX *pixs,
2265  l_int32 rval,
2266  l_int32 gval,
2267  l_int32 bval,
2268  l_int32 factor,
2269  l_float32 rank)
2270 {
2271 l_int32 mapval;
2272 l_float32 rankrval, rankgval, rankbval;
2273 l_float32 rfract, gfract, bfract, maxfract;
2274 
2275  if (!pixs)
2276  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2277  if (pixGetDepth(pixs) != 32)
2278  return (PIX *)ERROR_PTR("pixs not 32 bpp", __func__, NULL);
2279  if (factor < 1)
2280  return (PIX *)ERROR_PTR("sampling factor < 1", __func__, NULL);
2281  if (rank < 0.0 || rank > 1.0)
2282  return (PIX *)ERROR_PTR("rank not in [0.0 ... 1.0]", __func__, NULL);
2283  if (rval <= 0 || gval <= 0 || bval <= 0)
2284  return (PIX *)ERROR_PTR("invalid estim. color values", __func__, NULL);
2285 
2286  /* The max value for each component may be larger than the
2287  * input estimated background value. In that case, mapping
2288  * for those pixels would saturate. To prevent saturation,
2289  * we compute the fraction for each component by which we
2290  * would oversaturate. Then take the max of these, and
2291  * reduce, uniformly over all components, the output intensity
2292  * by this value. Then no component will saturate.
2293  * In practice, if rank < 1.0, a fraction of pixels
2294  * may have a component saturate. By keeping rank close to 1.0,
2295  * that fraction can be made arbitrarily small. */
2296  pixGetRankValueMaskedRGB(pixs, NULL, 0, 0, factor, rank, &rankrval,
2297  &rankgval, &rankbval);
2298  rfract = rankrval / (l_float32)rval;
2299  gfract = rankgval / (l_float32)gval;
2300  bfract = rankbval / (l_float32)bval;
2301  maxfract = L_MAX(rfract, gfract);
2302  maxfract = L_MAX(maxfract, bfract);
2303 #if DEBUG_GLOBAL
2304  lept_stderr("rankrval = %7.2f, rankgval = %7.2f, rankbval = %7.2f\n",
2305  rankrval, rankgval, rankbval);
2306  lept_stderr("rfract = %7.4f, gfract = %7.4f, bfract = %7.4f\n",
2307  rfract, gfract, bfract);
2308 #endif /* DEBUG_GLOBAL */
2309 
2310  mapval = (l_int32)(255. / maxfract);
2311  pixd = pixGlobalNormRGB(pixd, pixs, rval, gval, bval, mapval);
2312  return pixd;
2313 }
2314 
2315 
2316 /*------------------------------------------------------------------*
2317  * Adaptive threshold spread normalization *
2318  *------------------------------------------------------------------*/
2362 l_ok
2364  l_int32 filtertype,
2365  l_int32 edgethresh,
2366  l_int32 smoothx,
2367  l_int32 smoothy,
2368  l_float32 gamma,
2369  l_int32 minval,
2370  l_int32 maxval,
2371  l_int32 targetthresh,
2372  PIX **ppixth,
2373  PIX **ppixb,
2374  PIX **ppixd)
2375 {
2376 PIX *pixe, *pixet, *pixsd, *pixg1, *pixg2, *pixth;
2377 
2378  if (ppixth) *ppixth = NULL;
2379  if (ppixb) *ppixb = NULL;
2380  if (ppixd) *ppixd = NULL;
2381  if (!pixs || pixGetDepth(pixs) != 8)
2382  return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
2383  if (pixGetColormap(pixs))
2384  return ERROR_INT("pixs is colormapped", __func__, 1);
2385  if (!ppixth && !ppixb && !ppixd)
2386  return ERROR_INT("no output requested", __func__, 1);
2387  if (filtertype != L_SOBEL_EDGE && filtertype != L_TWO_SIDED_EDGE)
2388  return ERROR_INT("invalid filter type", __func__, 1);
2389 
2390  /* Get the thresholded edge pixels. These are the ones
2391  * that have values in pixs near the local optimal fg/bg threshold. */
2392  if (filtertype == L_SOBEL_EDGE)
2393  pixe = pixSobelEdgeFilter(pixs, L_VERTICAL_EDGES);
2394  else /* L_TWO_SIDED_EDGE */
2396  pixet = pixThresholdToBinary(pixe, edgethresh);
2397  pixInvert(pixet, pixet);
2398 
2399  /* Build a seed image whose only nonzero values are those
2400  * values of pixs corresponding to pixels in the fg of pixet. */
2401  pixsd = pixCreateTemplate(pixs);
2402  pixCombineMasked(pixsd, pixs, pixet);
2403 
2404  /* Spread the seed and optionally smooth to reduce noise */
2405  pixg1 = pixSeedspread(pixsd, 4);
2406  pixg2 = pixBlockconv(pixg1, smoothx, smoothy);
2407 
2408  /* Optionally do a gamma enhancement */
2409  pixth = pixGammaTRC(NULL, pixg2, gamma, minval, maxval);
2410 
2411  /* Do the mapping and thresholding */
2412  if (ppixd) {
2413  *ppixd = pixApplyVariableGrayMap(pixs, pixth, targetthresh);
2414  if (ppixb)
2415  *ppixb = pixThresholdToBinary(*ppixd, targetthresh);
2416  }
2417  else if (ppixb)
2418  *ppixb = pixVarThresholdToBinary(pixs, pixth);
2419 
2420  if (ppixth)
2421  *ppixth = pixth;
2422  else
2423  pixDestroy(&pixth);
2424 
2425  pixDestroy(&pixe);
2426  pixDestroy(&pixet);
2427  pixDestroy(&pixsd);
2428  pixDestroy(&pixg1);
2429  pixDestroy(&pixg2);
2430  return 0;
2431 }
2432 
2433 
2434 /*------------------------------------------------------------------*
2435  * Adaptive background normalization (flexible adaptaption) *
2436  *------------------------------------------------------------------*/
2466 PIX *
2468  l_int32 sx,
2469  l_int32 sy,
2470  l_int32 smoothx,
2471  l_int32 smoothy,
2472  l_int32 delta)
2473 {
2474 l_float32 scalex, scaley;
2475 PIX *pixt, *pixsd, *pixmin, *pixbg, *pixbgi, *pixd;
2476 
2477  if (!pixs || pixGetDepth(pixs) != 8)
2478  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
2479  if (pixGetColormap(pixs))
2480  return (PIX *)ERROR_PTR("pixs is colormapped", __func__, NULL);
2481  if (sx < 3 || sy < 3)
2482  return (PIX *)ERROR_PTR("sx and/or sy less than 3", __func__, NULL);
2483  if (sx > 10 || sy > 10)
2484  return (PIX *)ERROR_PTR("sx and/or sy exceed 10", __func__, NULL);
2485  if (smoothx < 1 || smoothy < 1)
2486  return (PIX *)ERROR_PTR("smooth params less than 1", __func__, NULL);
2487  if (smoothx > 3 || smoothy > 3)
2488  return (PIX *)ERROR_PTR("smooth params exceed 3", __func__, NULL);
2489 
2490  /* Generate the bg estimate using smoothed average with subsampling */
2491  scalex = 1. / (l_float32)sx;
2492  scaley = 1. / (l_float32)sy;
2493  pixt = pixScaleSmooth(pixs, scalex, scaley);
2494 
2495  /* Do basin filling on the bg estimate if requested */
2496  if (delta <= 0)
2497  pixsd = pixClone(pixt);
2498  else {
2499  pixLocalExtrema(pixt, 0, 0, &pixmin, NULL);
2500  pixsd = pixSeedfillGrayBasin(pixmin, pixt, delta, 4);
2501  pixDestroy(&pixmin);
2502  }
2503  pixbg = pixExtendByReplication(pixsd, 1, 1);
2504 
2505  /* Map the bg to 200 */
2506  pixbgi = pixGetInvBackgroundMap(pixbg, 200, smoothx, smoothy);
2507  pixd = pixApplyInvBackgroundGrayMap(pixs, pixbgi, sx, sy);
2508 
2509  pixDestroy(&pixt);
2510  pixDestroy(&pixsd);
2511  pixDestroy(&pixbg);
2512  pixDestroy(&pixbgi);
2513  return pixd;
2514 }
2515 
2516 
2517 /*------------------------------------------------------------------*
2518  * Adaptive contrast normalization *
2519  *------------------------------------------------------------------*/
2559 PIX *
2561  PIX *pixs,
2562  l_int32 sx,
2563  l_int32 sy,
2564  l_int32 mindiff,
2565  l_int32 smoothx,
2566  l_int32 smoothy)
2567 {
2568 PIX *pixmin, *pixmax;
2569 
2570  if (!pixs || pixGetDepth(pixs) != 8)
2571  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, pixd);
2572  if (pixd && pixd != pixs)
2573  return (PIX *)ERROR_PTR("pixd not null or == pixs", __func__, pixd);
2574  if (pixGetColormap(pixs))
2575  return (PIX *)ERROR_PTR("pixs is colormapped", __func__, pixd);
2576  if (sx < 5 || sy < 5)
2577  return (PIX *)ERROR_PTR("sx and/or sy less than 5", __func__, pixd);
2578  if (smoothx < 0 || smoothy < 0)
2579  return (PIX *)ERROR_PTR("smooth params less than 0", __func__, pixd);
2580  if (smoothx > 8 || smoothy > 8)
2581  return (PIX *)ERROR_PTR("smooth params exceed 8", __func__, pixd);
2582 
2583  /* Get the min and max pixel values in each tile, and represent
2584  * each value as a pixel in pixmin and pixmax, respectively. */
2585  pixMinMaxTiles(pixs, sx, sy, mindiff, smoothx, smoothy, &pixmin, &pixmax);
2586 
2587  /* For each tile, do a linear expansion of the dynamic range
2588  * of pixels so that the min value is mapped to 0 and the
2589  * max value is mapped to 255. */
2590  pixd = pixLinearTRCTiled(pixd, pixs, sx, sy, pixmin, pixmax);
2591 
2592  pixDestroy(&pixmin);
2593  pixDestroy(&pixmax);
2594  return pixd;
2595 }
2596 
2597 
2617 static l_ok
2619  l_int32 sx,
2620  l_int32 sy,
2621  l_int32 mindiff,
2622  l_int32 smoothx,
2623  l_int32 smoothy,
2624  PIX **ppixmin,
2625  PIX **ppixmax)
2626 {
2627 l_int32 w, h;
2628 PIX *pixmin1, *pixmax1, *pixmin2, *pixmax2;
2629 
2630  if (ppixmin) *ppixmin = NULL;
2631  if (ppixmax) *ppixmax = NULL;
2632  if (!ppixmin || !ppixmax)
2633  return ERROR_INT("&pixmin or &pixmax undefined", __func__, 1);
2634  if (!pixs || pixGetDepth(pixs) != 8)
2635  return ERROR_INT("pixs undefined or not 8 bpp", __func__, 1);
2636  if (pixGetColormap(pixs))
2637  return ERROR_INT("pixs is colormapped", __func__, 1);
2638  if (sx < 5 || sy < 5)
2639  return ERROR_INT("sx and/or sy less than 3", __func__, 1);
2640  if (smoothx < 0 || smoothy < 0)
2641  return ERROR_INT("smooth params less than 0", __func__, 1);
2642  if (smoothx > 5 || smoothy > 5)
2643  return ERROR_INT("smooth params exceed 5", __func__, 1);
2644 
2645  /* Get the min and max values in each tile */
2646  pixmin1 = pixScaleGrayMinMax(pixs, sx, sy, L_CHOOSE_MIN);
2647  pixmax1 = pixScaleGrayMinMax(pixs, sx, sy, L_CHOOSE_MAX);
2648 
2649  pixmin2 = pixExtendByReplication(pixmin1, 1, 1);
2650  pixmax2 = pixExtendByReplication(pixmax1, 1, 1);
2651  pixDestroy(&pixmin1);
2652  pixDestroy(&pixmax1);
2653 
2654  /* Make sure no value is 0 */
2655  pixAddConstantGray(pixmin2, 1);
2656  pixAddConstantGray(pixmax2, 1);
2657 
2658  /* Generate holes where the contrast is too small */
2659  pixSetLowContrast(pixmin2, pixmax2, mindiff);
2660 
2661  /* Fill the holes (0 values) */
2662  pixGetDimensions(pixmin2, &w, &h, NULL);
2663  pixFillMapHoles(pixmin2, w, h, L_FILL_BLACK);
2664  pixFillMapHoles(pixmax2, w, h, L_FILL_BLACK);
2665 
2666  /* Smooth if requested */
2667  if (smoothx > 0 || smoothy > 0) {
2668  smoothx = L_MIN(smoothx, (w - 1) / 2);
2669  smoothy = L_MIN(smoothy, (h - 1) / 2);
2670  *ppixmin = pixBlockconv(pixmin2, smoothx, smoothy);
2671  *ppixmax = pixBlockconv(pixmax2, smoothx, smoothy);
2672  }
2673  else {
2674  *ppixmin = pixClone(pixmin2);
2675  *ppixmax = pixClone(pixmax2);
2676  }
2677  pixCopyResolution(*ppixmin, pixs);
2678  pixCopyResolution(*ppixmax, pixs);
2679  pixDestroy(&pixmin2);
2680  pixDestroy(&pixmax2);
2681 
2682  return 0;
2683 }
2684 
2685 
2706 static l_ok
2708  PIX *pixs2,
2709  l_int32 mindiff)
2710 {
2711 l_int32 i, j, w, h, d, wpl, val1, val2, found;
2712 l_uint32 *data1, *data2, *line1, *line2;
2713 
2714  if (!pixs1 || !pixs2)
2715  return ERROR_INT("pixs1 and pixs2 not both defined", __func__, 1);
2716  if (pixSizesEqual(pixs1, pixs2) == 0)
2717  return ERROR_INT("pixs1 and pixs2 not equal size", __func__, 1);
2718  pixGetDimensions(pixs1, &w, &h, &d);
2719  if (d != 8)
2720  return ERROR_INT("depth not 8 bpp", __func__, 1);
2721  if (mindiff > 254) return 0;
2722 
2723  data1 = pixGetData(pixs1);
2724  data2 = pixGetData(pixs2);
2725  wpl = pixGetWpl(pixs1);
2726  found = 0; /* init to not finding any diffs >= mindiff */
2727  for (i = 0; i < h; i++) {
2728  line1 = data1 + i * wpl;
2729  line2 = data2 + i * wpl;
2730  for (j = 0; j < w; j++) {
2731  val1 = GET_DATA_BYTE(line1, j);
2732  val2 = GET_DATA_BYTE(line2, j);
2733  if (L_ABS(val1 - val2) >= mindiff) {
2734  found = 1;
2735  break;
2736  }
2737  }
2738  if (found) break;
2739  }
2740  if (!found) {
2741  L_WARNING("no pixel pair diffs as large as mindiff\n", __func__);
2742  pixClearAll(pixs1);
2743  pixClearAll(pixs2);
2744  return 1;
2745  }
2746 
2747  for (i = 0; i < h; i++) {
2748  line1 = data1 + i * wpl;
2749  line2 = data2 + i * wpl;
2750  for (j = 0; j < w; j++) {
2751  val1 = GET_DATA_BYTE(line1, j);
2752  val2 = GET_DATA_BYTE(line2, j);
2753  if (L_ABS(val1 - val2) < mindiff) {
2754  SET_DATA_BYTE(line1, j, 0);
2755  SET_DATA_BYTE(line2, j, 0);
2756  }
2757  }
2758  }
2759 
2760  return 0;
2761 }
2762 
2763 
2787 static PIX *
2789  PIX *pixs,
2790  l_int32 sx,
2791  l_int32 sy,
2792  PIX *pixmin,
2793  PIX *pixmax)
2794 {
2795 l_int32 i, j, k, m, w, h, wt, ht, wpl, wplt, xoff, yoff;
2796 l_int32 minval, maxval, val, sval;
2797 l_int32 *ia;
2798 l_int32 **iaa;
2799 l_uint32 *data, *datamin, *datamax, *line, *tline, *linemin, *linemax;
2800 
2801  if (!pixs || pixGetDepth(pixs) != 8)
2802  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, pixd);
2803  if (pixd && pixd != pixs)
2804  return (PIX *)ERROR_PTR("pixd not null or == pixs", __func__, pixd);
2805  if (pixGetColormap(pixs))
2806  return (PIX *)ERROR_PTR("pixs is colormapped", __func__, pixd);
2807  if (!pixmin || !pixmax)
2808  return (PIX *)ERROR_PTR("pixmin & pixmax not defined", __func__, pixd);
2809  if (sx < 5 || sy < 5)
2810  return (PIX *)ERROR_PTR("sx and/or sy less than 5", __func__, pixd);
2811 
2812  iaa = (l_int32 **)LEPT_CALLOC(256, sizeof(l_int32 *));
2813  if ((pixd = pixCopy(pixd, pixs)) == NULL) {
2814  LEPT_FREE(iaa);
2815  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2816  }
2817  pixGetDimensions(pixd, &w, &h, NULL);
2818 
2819  data = pixGetData(pixd);
2820  wpl = pixGetWpl(pixd);
2821  datamin = pixGetData(pixmin);
2822  datamax = pixGetData(pixmax);
2823  wplt = pixGetWpl(pixmin);
2824  pixGetDimensions(pixmin, &wt, &ht, NULL);
2825  for (i = 0; i < ht; i++) {
2826  line = data + sy * i * wpl;
2827  linemin = datamin + i * wplt;
2828  linemax = datamax + i * wplt;
2829  yoff = sy * i;
2830  for (j = 0; j < wt; j++) {
2831  xoff = sx * j;
2832  minval = GET_DATA_BYTE(linemin, j);
2833  maxval = GET_DATA_BYTE(linemax, j);
2834  if (maxval == minval) {
2835  L_ERROR("shouldn't happen! i,j = %d,%d, minval = %d\n",
2836  __func__, i, j, minval);
2837  continue;
2838  }
2839  if ((ia = iaaGetLinearTRC(iaa, maxval - minval)) == NULL) {
2840  L_ERROR("failure to make ia for j = %d!\n", __func__, j);
2841  continue;
2842  }
2843  for (k = 0; k < sy && yoff + k < h; k++) {
2844  tline = line + k * wpl;
2845  for (m = 0; m < sx && xoff + m < w; m++) {
2846  val = GET_DATA_BYTE(tline, xoff + m);
2847  sval = val - minval;
2848  sval = L_MAX(0, sval);
2849  SET_DATA_BYTE(tline, xoff + m, ia[sval]);
2850  }
2851  }
2852  }
2853  }
2854 
2855  for (i = 0; i < 256; i++)
2856  LEPT_FREE(iaa[i]);
2857  LEPT_FREE(iaa);
2858  return pixd;
2859 }
2860 
2861 
2871 static l_int32 *
2872 iaaGetLinearTRC(l_int32 **iaa,
2873  l_int32 diff)
2874 {
2875 l_int32 i;
2876 l_int32 *ia;
2877 l_float32 factor;
2878 
2879  if (!iaa)
2880  return (l_int32 *)ERROR_PTR("iaa not defined", __func__, NULL);
2881 
2882  if (iaa[diff] != NULL) /* already have it */
2883  return iaa[diff];
2884 
2885  ia = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2886  iaa[diff] = ia;
2887  if (diff == 0) { /* shouldn't happen */
2888  for (i = 0; i < 256; i++)
2889  ia[i] = 128;
2890  }
2891  else {
2892  factor = 255. / (l_float32)diff;
2893  for (i = 0; i < diff + 1; i++)
2894  ia[i] = (l_int32)(factor * i + 0.5);
2895  for (i = diff + 1; i < 256; i++)
2896  ia[i] = 255;
2897  }
2898 
2899  return ia;
2900 }
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:1038
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:783
static const l_int32 DefaultFgThreshold
Definition: adaptmap.c:150
static const l_int32 DefaultTileHeight
Definition: adaptmap.c:149
PIX * pixBackgroundNormSimple(PIX *pixs, PIX *pixim, PIX *pixg)
pixBackgroundNormSimple()
Definition: adaptmap.c:245
static l_int32 * iaaGetLinearTRC(l_int32 **iaa, l_int32 diff)
iaaGetLinearTRC()
Definition: adaptmap.c:2872
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:639
l_ok pixSmoothConnectedRegions(PIX *pixs, PIX *pixm, l_int32 factor)
pixSmoothConnectedRegions()
Definition: adaptmap.c:1623
PIX * pixGlobalNormRGB(PIX *pixd, PIX *pixs, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 mapval)
pixGlobalNormRGB()
Definition: adaptmap.c:2156
PIX * pixCleanBackgroundToWhite(PIX *pixs, PIX *pixim, PIX *pixg, l_float32 gamma, l_int32 blackval, l_int32 whiteval)
pixCleanBackgroundToWhite()
Definition: adaptmap.c:196
PIX * pixContrastNorm(PIX *pixd, PIX *pixs, l_int32 sx, l_int32 sy, l_int32 mindiff, l_int32 smoothx, l_int32 smoothy)
pixContrastNorm()
Definition: adaptmap.c:2560
l_ok pixBackgroundNormGrayArrayMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, l_int32 bgval, PIX **ppixd)
pixBackgroundNormGrayArrayMorph()
Definition: adaptmap.c:720
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:858
PIX * pixGetInvBackgroundMap(PIX *pixs, l_int32 bgval, l_int32 smoothx, l_int32 smoothy)
pixGetInvBackgroundMap()
Definition: adaptmap.c:1820
PIX * pixApplyInvBackgroundGrayMap(PIX *pixs, PIX *pixm, l_int32 sx, l_int32 sy)
pixApplyInvBackgroundGrayMap()
Definition: adaptmap.c:1881
l_ok pixGetBackgroundRGBMapMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, PIX **ppixmr, PIX **ppixmg, PIX **ppixmb)
pixGetBackgroundRGBMapMorph()
Definition: adaptmap.c:1310
static l_int32 pixSetLowContrast(PIX *pixs1, PIX *pixs2, l_int32 mindiff)
pixSetLowContrast()
Definition: adaptmap.c:2707
static const l_int32 DefaultBgVal
Definition: adaptmap.c:152
PIX * pixGlobalNormNoSatRGB(PIX *pixd, PIX *pixs, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 factor, l_float32 rank)
pixGlobalNormNoSatRGB()
Definition: adaptmap.c:2263
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:564
static const l_int32 DefaultTileWidth
Definition: adaptmap.c:148
PIX * pixBackgroundNorm(PIX *pixs, PIX *pixim, PIX *pixg, l_int32 sx, l_int32 sy, l_int32 thresh, l_int32 mincount, l_int32 bgval, l_int32 smoothx, l_int32 smoothy)
pixBackgroundNorm()
Definition: adaptmap.c:320
static const l_int32 DefaultMinCount
Definition: adaptmap.c:151
PIX * pixApplyVariableGrayMap(PIX *pixs, PIX *pixg, l_int32 target)
pixApplyVariableGrayMap()
Definition: adaptmap.c:2041
PIX * pixBackgroundNormFlex(PIX *pixs, l_int32 sx, l_int32 sy, l_int32 smoothx, l_int32 smoothy, l_int32 delta)
pixBackgroundNormFlex()
Definition: adaptmap.c:2467
PIX * pixApplyInvBackgroundRGBMap(PIX *pixs, PIX *pixmr, PIX *pixmg, PIX *pixmb, l_int32 sx, l_int32 sy)
pixApplyInvBackgroundRGBMap()
Definition: adaptmap.c:1945
l_ok pixFillMapHoles(PIX *pix, l_int32 nx, l_int32 ny, l_int32 filltype)
pixFillMapHoles()
Definition: adaptmap.c:1462
l_ok pixGetBackgroundGrayMapMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, PIX **ppixm)
pixGetBackgroundGrayMapMorph()
Definition: adaptmap.c:1221
PIX * pixExtendByReplication(PIX *pixs, l_int32 addw, l_int32 addh)
pixExtendByReplication()
Definition: adaptmap.c:1562
static l_int32 pixMinMaxTiles(PIX *pixs, l_int32 sx, l_int32 sy, l_int32 mindiff, l_int32 smoothx, l_int32 smoothy, PIX **ppixmin, PIX **ppixmax)
pixMinMaxTiles()
Definition: adaptmap.c:2618
static const l_int32 DefaultXSmoothSize
Definition: adaptmap.c:153
static PIX * pixLinearTRCTiled(PIX *pixd, PIX *pixs, l_int32 sx, l_int32 sy, PIX *pixmin, PIX *pixmax)
pixLinearTRCTiled()
Definition: adaptmap.c:2788
static const l_int32 DefaultYSmoothSize
Definition: adaptmap.c:154
l_ok pixThresholdSpreadNorm(PIX *pixs, l_int32 filtertype, l_int32 edgethresh, l_int32 smoothx, l_int32 smoothy, l_float32 gamma, l_int32 minval, l_int32 maxval, l_int32 targetthresh, PIX **ppixth, PIX **ppixb, PIX **ppixd)
pixThresholdSpreadNorm()
Definition: adaptmap.c:2363
PIX * pixBackgroundNormMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, l_int32 bgval)
pixBackgroundNormMorph()
Definition: adaptmap.c:455
#define SET_DATA_TWO_BYTES(pdata, n, val)
Definition: arrayaccess.h:222
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
PIX * pixReduceBinary2(PIX *pixs, l_uint8 *intab)
pixReduceBinary2()
Definition: binreduce.c:74
l_ok boxaGetBoxGeometry(BOXA *boxa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetBoxGeometry()
Definition: boxbasic.c:796
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:519
l_int32 boxaGetCount(const BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:661
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:683
l_ok pixcmapResetColor(PIXCMAP *cmap, l_int32 index, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapResetColor()
Definition: colormap.c:923
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:789
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:152
PIX * pixBlockconv(PIX *pix, l_int32 wc, l_int32 hc)
pixBlockconv()
Definition: convolve.c:132
PIX * pixTwoSidedEdgeFilter(PIX *pixs, l_int32 orientflag)
pixTwoSidedEdgeFilter()
Definition: edge.c:200
PIX * pixSobelEdgeFilter(PIX *pixs, l_int32 orientflag)
pixSobelEdgeFilter()
Definition: edge.c:94
NUMA * numaGammaTRC(l_float32 gamma, l_int32 minval, l_int32 maxval)
numaGammaTRC()
Definition: enhance.c:363
PIX * pixGammaTRC(PIX *pixd, PIX *pixs, l_float32 gamma, l_int32 minval, l_int32 maxval)
pixGammaTRC()
Definition: enhance.c:176
PIX * pixCloseGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseGray()
Definition: graymorph.c:520
PIX * pixVarThresholdToBinary(PIX *pixs, PIX *pixg)
pixVarThresholdToBinary()
Definition: grayquant.c:647
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:443
PIX * pixMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequence()
Definition: morphseq.c:137
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:460
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:193
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:720
l_int32 * numaGetIArray(NUMA *na)
numaGetIArray()
Definition: numabasic.c:807
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1642
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
l_int32 pixSizesEqual(const PIX *pix1, const PIX *pix2)
pixSizesEqual()
Definition: pix1.c:1878
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:689
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:380
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:263
l_ok pixClearAll(PIX *pix)
pixClearAll()
Definition: pix2.c:773
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:192
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2728
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2793
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1777
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1481
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:618
PIX * pixAnd(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixAnd()
Definition: pix3.c:1592
l_ok pixCombineMasked(PIX *pixd, PIX *pixs, PIX *pixm)
pixCombineMasked()
Definition: pix3.c:378
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:1488
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:1048
@ COLOR_BLUE
Definition: pix.h:330
@ COLOR_RED
Definition: pix.h:328
@ COLOR_GREEN
Definition: pix.h:329
@ L_CLONE
Definition: pix.h:506
@ L_TWO_SIDED_EDGE
Definition: pix.h:964
@ L_SOBEL_EDGE
Definition: pix.h:963
#define PIX_SRC
Definition: pix.h:444
@ L_MEAN_ABSVAL
Definition: pix.h:761
@ L_VERTICAL_EDGES
Definition: pix.h:797
@ L_FILL_WHITE
Definition: pix.h:690
@ L_FILL_BLACK
Definition: pix.h:691
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:404
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:647
l_ok pixAddConstantGray(PIX *pixs, l_int32 val)
pixAddConstantGray()
Definition: pixarith.c:119
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3055
PIX * pixConvertRGBToGrayFast(PIX *pixs)
pixConvertRGBToGrayFast()
Definition: pixconv.c:891
l_ok pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:204
PIX * pixScaleRGBToGrayFast(PIX *pixs, l_int32 factor, l_int32 color)
pixScaleRGBToGrayFast()
Definition: scale1.c:1448
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:250
PIX * pixScaleSmooth(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleSmooth()
Definition: scale1.c:1665
PIX * pixScaleBySampling(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBySampling()
Definition: scale1.c:1306
PIX * pixExpandReplicate(PIX *pixs, l_int32 factor)
pixExpandReplicate()
Definition: scale2.c:852
PIX * pixScaleGrayMinMax(PIX *pixs, l_int32 xfact, l_int32 yfact, l_int32 type)
pixScaleGrayMinMax()
Definition: scale2.c:997
PIX * pixSeedspread(PIX *pixs, l_int32 connectivity)
pixSeedspread()
Definition: seedfill.c:2752
PIX * pixSeedfillGrayBasin(PIX *pixb, PIX *pixm, l_int32 delta, l_int32 connectivity)
pixSeedfillGrayBasin()
Definition: seedfill.c:2410
l_ok pixLocalExtrema(PIX *pixs, l_int32 maxmin, l_int32 minmax, PIX **ppixmin, PIX **ppixmax)
pixLocalExtrema()
Definition: seedfill.c:2975
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306