Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
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
150#ifdef HAVE_CONFIG_H
151#include <config_auto.h>
152#endif /* HAVE_CONFIG_H */
153
154#include "allheaders.h"
155
156 /* Default input parameters for pixBackgroundNormSimple()
157 * Notes:
158 * (1) mincount must never exceed the tile area (width * height)
159 * (2) bgval must be sufficiently below 255 to avoid accidental
160 * saturation; otherwise it should be large to avoid
161 * shrinking the dynamic range
162 * (3) results should otherwise not be sensitive to these values
163 */
164static const l_int32 DefaultTileWidth = 10;
165static const l_int32 DefaultTileHeight = 15;
166static const l_int32 DefaultFgThreshold = 60;
167static const l_int32 DefaultMinCount = 40;
168static const l_int32 DefaultBgVal = 200;
169static const l_int32 DefaultXSmoothSize = 2;
170static const l_int32 DefaultYSmoothSize = 1;
172static l_int32 pixMinMaxTiles(PIX *pixs, l_int32 sx, l_int32 sy,
173 l_int32 mindiff, l_int32 smoothx, l_int32 smoothy,
174 PIX **ppixmin, PIX **ppixmax);
175static l_int32 pixSetLowContrast(PIX *pixs1, PIX *pixs2, l_int32 mindiff);
176static PIX *pixLinearTRCTiled(PIX *pixd, PIX *pixs, l_int32 sx, l_int32 sy,
177 PIX *pixmin, PIX *pixmax);
178static l_int32 *iaaGetLinearTRC(l_int32 **iaa, l_int32 diff);
179
180static l_ok pixSelectiveContrastMod(PIX *pixs, l_int32 contrast);
181
182#ifndef NO_CONSOLE_IO
183#define DEBUG_GLOBAL 0
184#endif /* ~NO_CONSOLE_IO */
185
186/*------------------------------------------------------------------*
187 * Clean background to white using background normalization *
188 *------------------------------------------------------------------*/
213PIX *
215 PIX *pixim,
216 PIX *pixg,
217 l_float32 gamma,
218 l_int32 blackval,
219 l_int32 whiteval)
220{
221l_int32 d;
222PIX *pixd;
223
224 if (!pixs)
225 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
226 d = pixGetDepth(pixs);
227 if (d != 8 && d != 32)
228 return (PIX *)ERROR_PTR("depth not 8 or 32", __func__, NULL);
229 if (whiteval > 200) {
230 L_WARNING("white value %d must not exceed 200; reset to 190",
231 __func__, whiteval);
232 whiteval = 190;
233 }
234
235 pixd = pixBackgroundNormSimple(pixs, pixim, pixg);
236 if (!pixd)
237 return (PIX *)ERROR_PTR("background norm failedd", __func__, NULL);
238 pixGammaTRC(pixd, pixd, gamma, blackval, whiteval);
239 return pixd;
240}
241
242
243/*------------------------------------------------------------------*
244 * Adaptive background normalization *
245 *------------------------------------------------------------------*/
262PIX *
273
274
337PIX *
339 PIX *pixim,
340 PIX *pixg,
341 l_int32 sx,
342 l_int32 sy,
343 l_int32 thresh,
344 l_int32 mincount,
345 l_int32 bgval,
346 l_int32 smoothx,
347 l_int32 smoothy)
348{
349l_int32 d, allfg;
350PIX *pixm, *pixmi, *pixd;
351PIX *pixmr, *pixmg, *pixmb, *pixmri, *pixmgi, *pixmbi;
352
353 if (!pixs)
354 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
355 d = pixGetDepth(pixs);
356 if (d != 8 && d != 32)
357 return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", __func__, NULL);
358 if (sx < 4 || sy < 4)
359 return (PIX *)ERROR_PTR("sx and sy must be >= 4", __func__, NULL);
360 if (mincount > sx * sy) {
361 L_WARNING("mincount too large for tile size\n", __func__);
362 mincount = (sx * sy) / 3;
363 }
364
365 /* If pixim exists, verify that it is not all foreground. */
366 if (pixim) {
367 pixInvert(pixim, pixim);
368 pixZero(pixim, &allfg);
369 pixInvert(pixim, pixim);
370 if (allfg)
371 return (PIX *)ERROR_PTR("pixim all foreground", __func__, NULL);
372 }
373
374 pixd = NULL;
375 if (d == 8) {
376 pixm = NULL;
377 pixGetBackgroundGrayMap(pixs, pixim, sx, sy, thresh, mincount, &pixm);
378 if (!pixm) {
379 L_WARNING("map not made; return a copy of the source\n", __func__);
380 return pixCopy(NULL, pixs);
381 }
382
383 pixmi = pixGetInvBackgroundMap(pixm, bgval, smoothx, smoothy);
384 if (!pixmi) {
385 L_WARNING("pixmi not made; return a copy of source\n", __func__);
386 pixDestroy(&pixm);
387 return pixCopy(NULL, pixs);
388 } else {
389 pixd = pixApplyInvBackgroundGrayMap(pixs, pixmi, sx, sy);
390 }
391
392 pixDestroy(&pixm);
393 pixDestroy(&pixmi);
394 }
395 else {
396 pixmr = pixmg = pixmb = NULL;
397 pixGetBackgroundRGBMap(pixs, pixim, pixg, sx, sy, thresh,
398 mincount, &pixmr, &pixmg, &pixmb);
399 if (!pixmr || !pixmg || !pixmb) {
400 pixDestroy(&pixmr);
401 pixDestroy(&pixmg);
402 pixDestroy(&pixmb);
403 L_WARNING("map not made; return a copy of the source\n", __func__);
404 return pixCopy(NULL, pixs);
405 }
406
407 pixmri = pixGetInvBackgroundMap(pixmr, bgval, smoothx, smoothy);
408 pixmgi = pixGetInvBackgroundMap(pixmg, bgval, smoothx, smoothy);
409 pixmbi = pixGetInvBackgroundMap(pixmb, bgval, smoothx, smoothy);
410 if (!pixmri || !pixmgi || !pixmbi) {
411 L_WARNING("not all pixm*i are made; return src copy\n", __func__);
412 pixd = pixCopy(NULL, pixs);
413 } else {
414 pixd = pixApplyInvBackgroundRGBMap(pixs, pixmri, pixmgi, pixmbi,
415 sx, sy);
416 }
417
418 pixDestroy(&pixmr);
419 pixDestroy(&pixmg);
420 pixDestroy(&pixmb);
421 pixDestroy(&pixmri);
422 pixDestroy(&pixmgi);
423 pixDestroy(&pixmbi);
424 }
425
426 if (!pixd)
427 ERROR_PTR("pixd not made", __func__, NULL);
428 pixCopyResolution(pixd, pixs);
429 return pixd;
430}
431
432
472PIX *
474 PIX *pixim,
475 l_int32 reduction,
476 l_int32 size,
477 l_int32 bgval)
478{
479l_int32 d, allfg;
480PIX *pixm, *pixmi, *pixd;
481PIX *pixmr, *pixmg, *pixmb, *pixmri, *pixmgi, *pixmbi;
482
483 if (!pixs)
484 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
485 d = pixGetDepth(pixs);
486 if (d != 8 && d != 32)
487 return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", __func__, NULL);
488 if (reduction < 2 || reduction > 16)
489 return (PIX *)ERROR_PTR("reduction must be between 2 and 16",
490 __func__, NULL);
491
492 /* If pixim exists, verify that it is not all foreground. */
493 if (pixim) {
494 pixInvert(pixim, pixim);
495 pixZero(pixim, &allfg);
496 pixInvert(pixim, pixim);
497 if (allfg)
498 return (PIX *)ERROR_PTR("pixim all foreground", __func__, NULL);
499 }
500
501 pixd = NULL;
502 if (d == 8) {
503 pixGetBackgroundGrayMapMorph(pixs, pixim, reduction, size, &pixm);
504 if (!pixm)
505 return (PIX *)ERROR_PTR("pixm not made", __func__, NULL);
506 pixmi = pixGetInvBackgroundMap(pixm, bgval, 0, 0);
507 if (!pixmi)
508 ERROR_PTR("pixmi not made", __func__, NULL);
509 else
510 pixd = pixApplyInvBackgroundGrayMap(pixs, pixmi,
511 reduction, reduction);
512 pixDestroy(&pixm);
513 pixDestroy(&pixmi);
514 }
515 else { /* d == 32 */
516 pixmr = pixmg = pixmb = NULL;
517 pixGetBackgroundRGBMapMorph(pixs, pixim, reduction, size,
518 &pixmr, &pixmg, &pixmb);
519 if (!pixmr || !pixmg || !pixmb) {
520 pixDestroy(&pixmr);
521 pixDestroy(&pixmg);
522 pixDestroy(&pixmb);
523 return (PIX *)ERROR_PTR("not all pixm*", __func__, NULL);
524 }
525
526 pixmri = pixGetInvBackgroundMap(pixmr, bgval, 0, 0);
527 pixmgi = pixGetInvBackgroundMap(pixmg, bgval, 0, 0);
528 pixmbi = pixGetInvBackgroundMap(pixmb, bgval, 0, 0);
529 if (!pixmri || !pixmgi || !pixmbi)
530 ERROR_PTR("not all pixm*i are made", __func__, NULL);
531 else
532 pixd = pixApplyInvBackgroundRGBMap(pixs, pixmri, pixmgi, pixmbi,
533 reduction, reduction);
534
535 pixDestroy(&pixmr);
536 pixDestroy(&pixmg);
537 pixDestroy(&pixmb);
538 pixDestroy(&pixmri);
539 pixDestroy(&pixmgi);
540 pixDestroy(&pixmbi);
541 }
542
543 if (!pixd)
544 ERROR_PTR("pixd not made", __func__, NULL);
545 pixCopyResolution(pixd, pixs);
546 return pixd;
547}
548
549
550/*-------------------------------------------------------------------------*
551 * Arrays of inverted background values for normalization *
552 *-------------------------------------------------------------------------*
553 * Notes for these four functions: *
554 * (1) They are useful if you need to save the actual mapping array. *
555 * (2) They could be used in the top-level functions but are *
556 * not because their use makes those functions less clear. *
557 * (3) Each component in the input pixs generates a 16 bpp pix array. *
558 *-------------------------------------------------------------------------*/
581l_ok
583 PIX *pixim,
584 l_int32 sx,
585 l_int32 sy,
586 l_int32 thresh,
587 l_int32 mincount,
588 l_int32 bgval,
589 l_int32 smoothx,
590 l_int32 smoothy,
591 PIX **ppixd)
592{
593l_int32 allfg;
594PIX *pixm;
595
596 if (!ppixd)
597 return ERROR_INT("&pixd not defined", __func__, 1);
598 *ppixd = NULL;
599 if (!pixs || pixGetDepth(pixs) != 8)
600 return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
601 if (pixGetColormap(pixs))
602 return ERROR_INT("pixs is colormapped", __func__, 1);
603 if (pixim && pixGetDepth(pixim) != 1)
604 return ERROR_INT("pixim not 1 bpp", __func__, 1);
605 if (sx < 4 || sy < 4)
606 return ERROR_INT("sx and sy must be >= 4", __func__, 1);
607 if (mincount > sx * sy) {
608 L_WARNING("mincount too large for tile size\n", __func__);
609 mincount = (sx * sy) / 3;
610 }
611
612 /* If pixim exists, verify that it is not all foreground. */
613 if (pixim) {
614 pixInvert(pixim, pixim);
615 pixZero(pixim, &allfg);
616 pixInvert(pixim, pixim);
617 if (allfg)
618 return ERROR_INT("pixim all foreground", __func__, 1);
619 }
620
621 pixGetBackgroundGrayMap(pixs, pixim, sx, sy, thresh, mincount, &pixm);
622 if (!pixm)
623 return ERROR_INT("pixm not made", __func__, 1);
624 *ppixd = pixGetInvBackgroundMap(pixm, bgval, smoothx, smoothy);
625 pixCopyResolution(*ppixd, pixs);
626 pixDestroy(&pixm);
627 return 0;
628}
629
630
656l_ok
658 PIX *pixim,
659 PIX *pixg,
660 l_int32 sx,
661 l_int32 sy,
662 l_int32 thresh,
663 l_int32 mincount,
664 l_int32 bgval,
665 l_int32 smoothx,
666 l_int32 smoothy,
667 PIX **ppixr,
668 PIX **ppixg,
669 PIX **ppixb)
670{
671l_int32 allfg;
672PIX *pixmr, *pixmg, *pixmb;
673
674 if (!ppixr || !ppixg || !ppixb)
675 return ERROR_INT("&pixr, &pixg, &pixb not all defined", __func__, 1);
676 *ppixr = *ppixg = *ppixb = NULL;
677 if (!pixs)
678 return ERROR_INT("pixs not defined", __func__, 1);
679 if (pixGetDepth(pixs) != 32)
680 return ERROR_INT("pixs not 32 bpp", __func__, 1);
681 if (pixim && pixGetDepth(pixim) != 1)
682 return ERROR_INT("pixim not 1 bpp", __func__, 1);
683 if (sx < 4 || sy < 4)
684 return ERROR_INT("sx and sy must be >= 4", __func__, 1);
685 if (mincount > sx * sy) {
686 L_WARNING("mincount too large for tile size\n", __func__);
687 mincount = (sx * sy) / 3;
688 }
689
690 /* If pixim exists, verify that it is not all foreground. */
691 if (pixim) {
692 pixInvert(pixim, pixim);
693 pixZero(pixim, &allfg);
694 pixInvert(pixim, pixim);
695 if (allfg)
696 return ERROR_INT("pixim all foreground", __func__, 1);
697 }
698
699 pixGetBackgroundRGBMap(pixs, pixim, pixg, sx, sy, thresh, mincount,
700 &pixmr, &pixmg, &pixmb);
701 if (!pixmr || !pixmg || !pixmb) {
702 pixDestroy(&pixmr);
703 pixDestroy(&pixmg);
704 pixDestroy(&pixmb);
705 return ERROR_INT("not all pixm* made", __func__, 1);
706 }
707
708 *ppixr = pixGetInvBackgroundMap(pixmr, bgval, smoothx, smoothy);
709 *ppixg = pixGetInvBackgroundMap(pixmg, bgval, smoothx, smoothy);
710 *ppixb = pixGetInvBackgroundMap(pixmb, bgval, smoothx, smoothy);
711 pixDestroy(&pixmr);
712 pixDestroy(&pixmg);
713 pixDestroy(&pixmb);
714 return 0;
715}
716
717
737l_ok
739 PIX *pixim,
740 l_int32 reduction,
741 l_int32 size,
742 l_int32 bgval,
743 PIX **ppixd)
744{
745l_int32 allfg;
746PIX *pixm;
747
748 if (!ppixd)
749 return ERROR_INT("&pixd not defined", __func__, 1);
750 *ppixd = NULL;
751 if (!pixs)
752 return ERROR_INT("pixs not defined", __func__, 1);
753 if (pixGetDepth(pixs) != 8)
754 return ERROR_INT("pixs not 8 bpp", __func__, 1);
755 if (pixim && pixGetDepth(pixim) != 1)
756 return ERROR_INT("pixim not 1 bpp", __func__, 1);
757 if (reduction < 2 || reduction > 16)
758 return ERROR_INT("reduction must be between 2 and 16", __func__, 1);
759
760 /* If pixim exists, verify that it is not all foreground. */
761 if (pixim) {
762 pixInvert(pixim, pixim);
763 pixZero(pixim, &allfg);
764 pixInvert(pixim, pixim);
765 if (allfg)
766 return ERROR_INT("pixim all foreground", __func__, 1);
767 }
768
769 pixGetBackgroundGrayMapMorph(pixs, pixim, reduction, size, &pixm);
770 if (!pixm)
771 return ERROR_INT("pixm not made", __func__, 1);
772 *ppixd = pixGetInvBackgroundMap(pixm, bgval, 0, 0);
773 pixCopyResolution(*ppixd, pixs);
774 pixDestroy(&pixm);
775 return 0;
776}
777
778
800l_ok
802 PIX *pixim,
803 l_int32 reduction,
804 l_int32 size,
805 l_int32 bgval,
806 PIX **ppixr,
807 PIX **ppixg,
808 PIX **ppixb)
809{
810l_int32 allfg;
811PIX *pixmr, *pixmg, *pixmb;
812
813 if (!ppixr || !ppixg || !ppixb)
814 return ERROR_INT("&pixr, &pixg, &pixb not all defined", __func__, 1);
815 *ppixr = *ppixg = *ppixb = NULL;
816 if (!pixs)
817 return ERROR_INT("pixs not defined", __func__, 1);
818 if (pixGetDepth(pixs) != 32)
819 return ERROR_INT("pixs not 32 bpp", __func__, 1);
820 if (pixim && pixGetDepth(pixim) != 1)
821 return ERROR_INT("pixim not 1 bpp", __func__, 1);
822 if (reduction < 2 || reduction > 16)
823 return ERROR_INT("reduction must be between 2 and 16", __func__, 1);
824
825 /* If pixim exists, verify that it is not all foreground. */
826 if (pixim) {
827 pixInvert(pixim, pixim);
828 pixZero(pixim, &allfg);
829 pixInvert(pixim, pixim);
830 if (allfg)
831 return ERROR_INT("pixim all foreground", __func__, 1);
832 }
833
834 pixGetBackgroundRGBMapMorph(pixs, pixim, reduction, size,
835 &pixmr, &pixmg, &pixmb);
836 if (!pixmr || !pixmg || !pixmb) {
837 pixDestroy(&pixmr);
838 pixDestroy(&pixmg);
839 pixDestroy(&pixmb);
840 return ERROR_INT("not all pixm* made", __func__, 1);
841 }
842
843 *ppixr = pixGetInvBackgroundMap(pixmr, bgval, 0, 0);
844 *ppixg = pixGetInvBackgroundMap(pixmg, bgval, 0, 0);
845 *ppixb = pixGetInvBackgroundMap(pixmb, bgval, 0, 0);
846 pixDestroy(&pixmr);
847 pixDestroy(&pixmg);
848 pixDestroy(&pixmb);
849 return 0;
850}
851
852
853/*------------------------------------------------------------------*
854 * Measurement of local background *
855 *------------------------------------------------------------------*/
875l_ok
877 PIX *pixim,
878 l_int32 sx,
879 l_int32 sy,
880 l_int32 thresh,
881 l_int32 mincount,
882 PIX **ppixd)
883{
884l_int32 w, h, wd, hd, wim, him, wpls, wplim, wpld, wplf;
885l_int32 xim, yim, delx, nx, ny, i, j, k, m;
886l_int32 count, sum, val8;
887l_int32 empty, fgpixels;
888l_uint32 *datas, *dataim, *datad, *dataf, *lines, *lineim, *lined, *linef;
889l_float32 scalex, scaley;
890PIX *pixd, *piximi, *pixb, *pixf, *pixims;
891
892 if (!ppixd)
893 return ERROR_INT("&pixd not defined", __func__, 1);
894 *ppixd = NULL;
895 if (!pixs || pixGetDepth(pixs) != 8)
896 return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
897 if (pixGetColormap(pixs))
898 return ERROR_INT("pixs is colormapped", __func__, 1);
899 if (pixim && pixGetDepth(pixim) != 1)
900 return ERROR_INT("pixim not 1 bpp", __func__, 1);
901 if (sx < 4 || sy < 4)
902 return ERROR_INT("sx and sy must be >= 4", __func__, 1);
903 if (mincount > sx * sy) {
904 L_WARNING("mincount too large for tile size\n", __func__);
905 mincount = (sx * sy) / 3;
906 }
907
908 /* Evaluate the 'image' mask, pixim, and make sure
909 * it is not all fg. */
910 fgpixels = 0; /* boolean for existence of fg pixels in the image mask. */
911 if (pixim) {
912 piximi = pixInvert(NULL, pixim); /* set non-'image' pixels to 1 */
913 pixZero(piximi, &empty);
914 pixDestroy(&piximi);
915 if (empty)
916 return ERROR_INT("pixim all fg; no background", __func__, 1);
917 pixZero(pixim, &empty);
918 if (!empty) /* there are fg pixels in pixim */
919 fgpixels = 1;
920 }
921
922 /* Generate the foreground mask, pixf, which is at
923 * full resolution. These pixels will be ignored when
924 * computing the background values. */
925 pixb = pixThresholdToBinary(pixs, thresh);
926 pixf = pixMorphSequence(pixb, "d7.1 + d1.7", 0);
927 pixDestroy(&pixb);
928 if (!pixf)
929 return ERROR_INT("pixf not made", __func__, 1);
930
931
932 /* ------------- Set up the output map pixd --------------- */
933 /* Generate pixd, which is reduced by the factors (sx, sy). */
934 w = pixGetWidth(pixs);
935 h = pixGetHeight(pixs);
936 wd = (w + sx - 1) / sx;
937 hd = (h + sy - 1) / sy;
938 pixd = pixCreate(wd, hd, 8);
939
940 /* Note: we only compute map values in tiles that are complete.
941 * In general, tiles at right and bottom edges will not be
942 * complete, and we must fill them in later. */
943 nx = w / sx;
944 ny = h / sy;
945 wpls = pixGetWpl(pixs);
946 datas = pixGetData(pixs);
947 wpld = pixGetWpl(pixd);
948 datad = pixGetData(pixd);
949 wplf = pixGetWpl(pixf);
950 dataf = pixGetData(pixf);
951 for (i = 0; i < ny; i++) {
952 lines = datas + sy * i * wpls;
953 linef = dataf + sy * i * wplf;
954 lined = datad + i * wpld;
955 for (j = 0; j < nx; j++) {
956 delx = j * sx;
957 sum = 0;
958 count = 0;
959 for (k = 0; k < sy; k++) {
960 for (m = 0; m < sx; m++) {
961 if (GET_DATA_BIT(linef + k * wplf, delx + m) == 0) {
962 sum += GET_DATA_BYTE(lines + k * wpls, delx + m);
963 count++;
964 }
965 }
966 }
967 if (count >= mincount) {
968 val8 = sum / count;
969 SET_DATA_BYTE(lined, j, val8);
970 }
971 }
972 }
973 pixDestroy(&pixf);
974
975 /* If there is an optional mask with fg pixels, erase the previous
976 * calculation for the corresponding map pixels, setting the
977 * map values to 0. Then, when all the map holes are filled,
978 * these erased pixels will be set by the surrounding map values.
979 *
980 * The calculation here is relatively efficient: for each pixel
981 * in pixd (which corresponds to a tile of mask pixels in pixim)
982 * we look only at the pixel in pixim that is at the center
983 * of the tile. If the mask pixel is ON, we reset the map
984 * pixel in pixd to 0, so that it can later be filled in. */
985 pixims = NULL;
986 if (pixim && fgpixels) {
987 wim = pixGetWidth(pixim);
988 him = pixGetHeight(pixim);
989 dataim = pixGetData(pixim);
990 wplim = pixGetWpl(pixim);
991 for (i = 0; i < ny; i++) {
992 yim = i * sy + sy / 2;
993 if (yim >= him)
994 break;
995 lineim = dataim + yim * wplim;
996 for (j = 0; j < nx; j++) {
997 xim = j * sx + sx / 2;
998 if (xim >= wim)
999 break;
1000 if (GET_DATA_BIT(lineim, xim))
1001 pixSetPixel(pixd, j, i, 0);
1002 }
1003 }
1004 }
1005
1006 /* Fill all the holes in the map. */
1007 if (pixFillMapHoles(pixd, nx, ny, L_FILL_BLACK)) {
1008 pixDestroy(&pixd);
1009 L_WARNING("can't make the map\n", __func__);
1010 return 1;
1011 }
1012
1013 /* Finally, for each connected region corresponding to the
1014 * 'image' mask, reset all pixels to their average value.
1015 * Each of these components represents an image (or part of one)
1016 * in the input, and this smooths the background values
1017 * in each of these regions. */
1018 if (pixim && fgpixels) {
1019 scalex = 1. / (l_float32)sx;
1020 scaley = 1. / (l_float32)sy;
1021 pixims = pixScaleBySampling(pixim, scalex, scaley);
1022 pixSmoothConnectedRegions(pixd, pixims, 2);
1023 pixDestroy(&pixims);
1024 }
1025
1026 *ppixd = pixd;
1027 pixCopyResolution(*ppixd, pixs);
1028 return 0;
1029}
1030
1031
1055l_ok
1057 PIX *pixim,
1058 PIX *pixg,
1059 l_int32 sx,
1060 l_int32 sy,
1061 l_int32 thresh,
1062 l_int32 mincount,
1063 PIX **ppixmr,
1064 PIX **ppixmg,
1065 PIX **ppixmb)
1066{
1067l_int32 w, h, wm, hm, wim, him, wpls, wplim, wplf;
1068l_int32 xim, yim, delx, nx, ny, i, j, k, m;
1069l_int32 count, rsum, gsum, bsum, rval, gval, bval;
1070l_int32 empty, fgpixels;
1071l_uint32 pixel;
1072l_uint32 *datas, *dataim, *dataf, *lines, *lineim, *linef;
1073l_float32 scalex, scaley;
1074PIX *piximi, *pixgc, *pixb, *pixf, *pixims;
1075PIX *pixmr, *pixmg, *pixmb;
1076
1077 if (!ppixmr || !ppixmg || !ppixmb)
1078 return ERROR_INT("&pixm* not all defined", __func__, 1);
1079 *ppixmr = *ppixmg = *ppixmb = NULL;
1080 if (!pixs)
1081 return ERROR_INT("pixs not defined", __func__, 1);
1082 if (pixGetDepth(pixs) != 32)
1083 return ERROR_INT("pixs not 32 bpp", __func__, 1);
1084 if (pixim && pixGetDepth(pixim) != 1)
1085 return ERROR_INT("pixim not 1 bpp", __func__, 1);
1086 if (sx < 4 || sy < 4)
1087 return ERROR_INT("sx and sy must be >= 4", __func__, 1);
1088 if (mincount > sx * sy) {
1089 L_WARNING("mincount too large for tile size\n", __func__);
1090 mincount = (sx * sy) / 3;
1091 }
1092
1093 /* Evaluate the mask pixim and make sure it is not all foreground */
1094 fgpixels = 0; /* boolean for existence of fg mask pixels */
1095 if (pixim) {
1096 piximi = pixInvert(NULL, pixim); /* set non-'image' pixels to 1 */
1097 pixZero(piximi, &empty);
1098 pixDestroy(&piximi);
1099 if (empty)
1100 return ERROR_INT("pixim all fg; no background", __func__, 1);
1101 pixZero(pixim, &empty);
1102 if (!empty) /* there are fg pixels in pixim */
1103 fgpixels = 1;
1104 }
1105
1106 /* Generate the foreground mask. These pixels will be
1107 * ignored when computing the background values. */
1108 if (pixg) /* use the input grayscale version if it is provided */
1109 pixgc = pixClone(pixg);
1110 else
1111 pixgc = pixConvertRGBToGrayFast(pixs);
1112 pixb = pixThresholdToBinary(pixgc, thresh);
1113 pixf = pixMorphSequence(pixb, "d7.1 + d1.7", 0);
1114 pixDestroy(&pixgc);
1115 pixDestroy(&pixb);
1116
1117 /* Generate the output mask images */
1118 w = pixGetWidth(pixs);
1119 h = pixGetHeight(pixs);
1120 wm = (w + sx - 1) / sx;
1121 hm = (h + sy - 1) / sy;
1122 pixmr = pixCreate(wm, hm, 8);
1123 pixmg = pixCreate(wm, hm, 8);
1124 pixmb = pixCreate(wm, hm, 8);
1125
1126 /* ------------- Set up the mapping images --------------- */
1127 /* Note: we only compute map values in tiles that are complete.
1128 * In general, tiles at right and bottom edges will not be
1129 * complete, and we must fill them in later. */
1130 nx = w / sx;
1131 ny = h / sy;
1132 wpls = pixGetWpl(pixs);
1133 datas = pixGetData(pixs);
1134 wplf = pixGetWpl(pixf);
1135 dataf = pixGetData(pixf);
1136 for (i = 0; i < ny; i++) {
1137 lines = datas + sy * i * wpls;
1138 linef = dataf + sy * i * wplf;
1139 for (j = 0; j < nx; j++) {
1140 delx = j * sx;
1141 rsum = gsum = bsum = 0;
1142 count = 0;
1143 for (k = 0; k < sy; k++) {
1144 for (m = 0; m < sx; m++) {
1145 if (GET_DATA_BIT(linef + k * wplf, delx + m) == 0) {
1146 pixel = *(lines + k * wpls + delx + m);
1147 rsum += (pixel >> 24);
1148 gsum += ((pixel >> 16) & 0xff);
1149 bsum += ((pixel >> 8) & 0xff);
1150 count++;
1151 }
1152 }
1153 }
1154 if (count >= mincount) {
1155 rval = rsum / count;
1156 gval = gsum / count;
1157 bval = bsum / count;
1158 pixSetPixel(pixmr, j, i, rval);
1159 pixSetPixel(pixmg, j, i, gval);
1160 pixSetPixel(pixmb, j, i, bval);
1161 }
1162 }
1163 }
1164 pixDestroy(&pixf);
1165
1166 /* If there is an optional mask with fg pixels, erase the previous
1167 * calculation for the corresponding map pixels, setting the
1168 * map values in each of the 3 color maps to 0. Then, when
1169 * all the map holes are filled, these erased pixels will
1170 * be set by the surrounding map values. */
1171 if (pixim) {
1172 wim = pixGetWidth(pixim);
1173 him = pixGetHeight(pixim);
1174 dataim = pixGetData(pixim);
1175 wplim = pixGetWpl(pixim);
1176 for (i = 0; i < ny; i++) {
1177 yim = i * sy + sy / 2;
1178 if (yim >= him)
1179 break;
1180 lineim = dataim + yim * wplim;
1181 for (j = 0; j < nx; j++) {
1182 xim = j * sx + sx / 2;
1183 if (xim >= wim)
1184 break;
1185 if (GET_DATA_BIT(lineim, xim)) {
1186 pixSetPixel(pixmr, j, i, 0);
1187 pixSetPixel(pixmg, j, i, 0);
1188 pixSetPixel(pixmb, j, i, 0);
1189 }
1190 }
1191 }
1192 }
1193
1194 /* ----------------- Now fill in the holes ----------------------- */
1195 if (pixFillMapHoles(pixmr, nx, ny, L_FILL_BLACK) ||
1196 pixFillMapHoles(pixmg, nx, ny, L_FILL_BLACK) ||
1197 pixFillMapHoles(pixmb, nx, ny, L_FILL_BLACK)) {
1198 pixDestroy(&pixmr);
1199 pixDestroy(&pixmg);
1200 pixDestroy(&pixmb);
1201 L_WARNING("can't make the maps\n", __func__);
1202 return 1;
1203 }
1204
1205 /* Finally, for each connected region corresponding to the
1206 * fg mask, reset all pixels to their average value. */
1207 if (pixim && fgpixels) {
1208 scalex = 1. / (l_float32)sx;
1209 scaley = 1. / (l_float32)sy;
1210 pixims = pixScaleBySampling(pixim, scalex, scaley);
1211 pixSmoothConnectedRegions(pixmr, pixims, 2);
1212 pixSmoothConnectedRegions(pixmg, pixims, 2);
1213 pixSmoothConnectedRegions(pixmb, pixims, 2);
1214 pixDestroy(&pixims);
1215 }
1216
1217 *ppixmr = pixmr;
1218 *ppixmg = pixmg;
1219 *ppixmb = pixmb;
1220 pixCopyResolution(*ppixmr, pixs);
1221 pixCopyResolution(*ppixmg, pixs);
1222 pixCopyResolution(*ppixmb, pixs);
1223 return 0;
1224}
1225
1226
1238l_ok
1240 PIX *pixim,
1241 l_int32 reduction,
1242 l_int32 size,
1243 PIX **ppixm)
1244{
1245l_int32 nx, ny, empty, fgpixels;
1246l_float32 scale;
1247PIX *pixm, *pix1, *pix2, *pix3, *pixims;
1248
1249 if (!ppixm)
1250 return ERROR_INT("&pixm not defined", __func__, 1);
1251 *ppixm = NULL;
1252 if (!pixs || pixGetDepth(pixs) != 8)
1253 return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
1254 if (pixGetColormap(pixs))
1255 return ERROR_INT("pixs is colormapped", __func__, 1);
1256 if (pixim && pixGetDepth(pixim) != 1)
1257 return ERROR_INT("pixim not 1 bpp", __func__, 1);
1258
1259 /* Evaluate the mask pixim and make sure it is not all foreground. */
1260 fgpixels = 0; /* boolean for existence of fg mask pixels */
1261 if (pixim) {
1262 pixInvert(pixim, pixim); /* set background pixels to 1 */
1263 pixZero(pixim, &empty);
1264 if (empty)
1265 return ERROR_INT("pixim all fg; no background", __func__, 1);
1266 pixInvert(pixim, pixim); /* revert to original mask */
1267 pixZero(pixim, &empty);
1268 if (!empty) /* there are fg pixels in pixim */
1269 fgpixels = 1;
1270 }
1271
1272 /* Downscale as requested and do the closing to get the background. */
1273 scale = 1. / (l_float32)reduction;
1274 pix1 = pixScaleBySampling(pixs, scale, scale);
1275 pix2 = pixCloseGray(pix1, size, size);
1276 pix3 = pixExtendByReplication(pix2, 1, 1);
1277 pixDestroy(&pix1);
1278 pixDestroy(&pix2);
1279
1280 /* Downscale the image mask, if any, and remove it from the
1281 * background. These pixels will be filled in (twice). */
1282 pixims = NULL;
1283 if (pixim) {
1284 pixims = pixScale(pixim, scale, scale);
1285 pixm = pixConvertTo8(pixims, FALSE);
1286 pixAnd(pixm, pixm, pix3);
1287 }
1288 else
1289 pixm = pixClone(pix3);
1290 pixDestroy(&pix3);
1291
1292 /* Fill all the holes in the map. */
1293 nx = pixGetWidth(pixs) / reduction;
1294 ny = pixGetHeight(pixs) / reduction;
1295 if (pixFillMapHoles(pixm, nx, ny, L_FILL_BLACK)) {
1296 pixDestroy(&pixm);
1297 pixDestroy(&pixims);
1298 L_WARNING("can't make the map\n", __func__);
1299 return 1;
1300 }
1301
1302 /* Finally, for each connected region corresponding to the
1303 * fg mask, reset all pixels to their average value. */
1304 if (pixim && fgpixels)
1305 pixSmoothConnectedRegions(pixm, pixims, 2);
1306 pixDestroy(&pixims);
1307
1308 *ppixm = pixm;
1309 pixCopyResolution(*ppixm, pixs);
1310 return 0;
1311}
1312
1313
1327l_ok
1329 PIX *pixim,
1330 l_int32 reduction,
1331 l_int32 size,
1332 PIX **ppixmr,
1333 PIX **ppixmg,
1334 PIX **ppixmb)
1335{
1336l_int32 nx, ny, empty, fgpixels;
1337l_float32 scale;
1338PIX *pixm, *pixmr, *pixmg, *pixmb, *pix1, *pix2, *pix3, *pixims;
1339
1340 if (!ppixmr || !ppixmg || !ppixmb)
1341 return ERROR_INT("&pixm* not all defined", __func__, 1);
1342 *ppixmr = *ppixmg = *ppixmb = NULL;
1343 if (!pixs)
1344 return ERROR_INT("pixs not defined", __func__, 1);
1345 if (pixGetDepth(pixs) != 32)
1346 return ERROR_INT("pixs not 32 bpp", __func__, 1);
1347 if (pixim && pixGetDepth(pixim) != 1)
1348 return ERROR_INT("pixim not 1 bpp", __func__, 1);
1349
1350 /* Evaluate the mask pixim and make sure it is not all foreground. */
1351 fgpixels = 0; /* boolean for existence of fg mask pixels */
1352 if (pixim) {
1353 pixInvert(pixim, pixim); /* set background pixels to 1 */
1354 pixZero(pixim, &empty);
1355 if (empty)
1356 return ERROR_INT("pixim all fg; no background", __func__, 1);
1357 pixInvert(pixim, pixim); /* revert to original mask */
1358 pixZero(pixim, &empty);
1359 if (!empty) /* there are fg pixels in pixim */
1360 fgpixels = 1;
1361 }
1362
1363 /* Generate an 8 bpp version of the image mask, if it exists */
1364 scale = 1. / (l_float32)reduction;
1365 pixims = NULL;
1366 pixm = NULL;
1367 if (pixim) {
1368 pixims = pixScale(pixim, scale, scale);
1369 pixm = pixConvertTo8(pixims, FALSE);
1370 }
1371
1372 /* Downscale as requested and do the closing to get the background.
1373 * Then remove the image mask pixels from the background. They
1374 * will be filled in (twice) later. Do this for all 3 components. */
1375 pix1 = pixScaleRGBToGrayFast(pixs, reduction, COLOR_RED);
1376 pix2 = pixCloseGray(pix1, size, size);
1377 pix3 = pixExtendByReplication(pix2, 1, 1);
1378 if (pixim)
1379 pixmr = pixAnd(NULL, pixm, pix3);
1380 else
1381 pixmr = pixClone(pix3);
1382 pixDestroy(&pix1);
1383 pixDestroy(&pix2);
1384 pixDestroy(&pix3);
1385
1386 pix1 = pixScaleRGBToGrayFast(pixs, reduction, COLOR_GREEN);
1387 pix2 = pixCloseGray(pix1, size, size);
1388 pix3 = pixExtendByReplication(pix2, 1, 1);
1389 if (pixim)
1390 pixmg = pixAnd(NULL, pixm, pix3);
1391 else
1392 pixmg = pixClone(pix3);
1393 pixDestroy(&pix1);
1394 pixDestroy(&pix2);
1395 pixDestroy(&pix3);
1396
1397 pix1 = pixScaleRGBToGrayFast(pixs, reduction, COLOR_BLUE);
1398 pix2 = pixCloseGray(pix1, size, size);
1399 pix3 = pixExtendByReplication(pix2, 1, 1);
1400 if (pixim)
1401 pixmb = pixAnd(NULL, pixm, pix3);
1402 else
1403 pixmb = pixClone(pix3);
1404 pixDestroy(&pixm);
1405 pixDestroy(&pix1);
1406 pixDestroy(&pix2);
1407 pixDestroy(&pix3);
1408
1409 /* Fill all the holes in the three maps. */
1410 nx = pixGetWidth(pixs) / reduction;
1411 ny = pixGetHeight(pixs) / reduction;
1412 if (pixFillMapHoles(pixmr, nx, ny, L_FILL_BLACK) ||
1413 pixFillMapHoles(pixmg, nx, ny, L_FILL_BLACK) ||
1414 pixFillMapHoles(pixmb, nx, ny, L_FILL_BLACK)) {
1415 pixDestroy(&pixmr);
1416 pixDestroy(&pixmg);
1417 pixDestroy(&pixmb);
1418 pixDestroy(&pixims);
1419 L_WARNING("can't make the maps\n", __func__);
1420 return 1;
1421 }
1422
1423 /* Finally, for each connected region corresponding to the
1424 * fg mask in each component, reset all pixels to their
1425 * average value. */
1426 if (pixim && fgpixels) {
1427 pixSmoothConnectedRegions(pixmr, pixims, 2);
1428 pixSmoothConnectedRegions(pixmg, pixims, 2);
1429 pixSmoothConnectedRegions(pixmb, pixims, 2);
1430 pixDestroy(&pixims);
1431 }
1432
1433 *ppixmr = pixmr;
1434 *ppixmg = pixmg;
1435 *ppixmb = pixmb;
1436 pixCopyResolution(*ppixmr, pixs);
1437 pixCopyResolution(*ppixmg, pixs);
1438 pixCopyResolution(*ppixmb, pixs);
1439 return 0;
1440}
1441
1442
1479l_ok
1481 l_int32 nx,
1482 l_int32 ny,
1483 l_int32 filltype)
1484{
1485l_int32 w, h, y, nmiss, goodcol, i, j, found, ival, valtest;
1486l_uint32 val, lastval;
1487NUMA *na; /* indicates if there is any data in the column */
1488
1489 if (!pix || pixGetDepth(pix) != 8)
1490 return ERROR_INT("pix not defined or not 8 bpp", __func__, 1);
1491 if (pixGetColormap(pix))
1492 return ERROR_INT("pix is colormapped", __func__, 1);
1493
1494 /* ------------- Fill holes in the mapping image columns ----------- */
1495 pixGetDimensions(pix, &w, &h, NULL);
1496 na = numaCreate(0); /* holds flag for which columns have data */
1497 nmiss = 0;
1498 valtest = (filltype == L_FILL_WHITE) ? 255 : 0;
1499 for (j = 0; j < nx; j++) { /* do it by columns */
1500 found = FALSE;
1501 for (i = 0; i < ny; i++) {
1502 pixGetPixel(pix, j, i, &val);
1503 if (val != valtest) {
1504 y = i;
1505 found = TRUE;
1506 break;
1507 }
1508 }
1509 if (found == FALSE) {
1510 numaAddNumber(na, 0); /* no data in the column */
1511 nmiss++;
1512 }
1513 else {
1514 numaAddNumber(na, 1); /* data in the column */
1515 for (i = y - 1; i >= 0; i--) /* replicate upwards to top */
1516 pixSetPixel(pix, j, i, val);
1517 pixGetPixel(pix, j, 0, &lastval);
1518 for (i = 1; i < h; i++) { /* set going down to bottom */
1519 pixGetPixel(pix, j, i, &val);
1520 if (val == valtest)
1521 pixSetPixel(pix, j, i, lastval);
1522 else
1523 lastval = val;
1524 }
1525 }
1526 }
1527
1528 if (nmiss == nx) { /* no data in any column! */
1529 numaDestroy(&na);
1530 L_WARNING("no bg found; no data in any column\n", __func__);
1531 return 1;
1532 }
1533
1534 /* ---------- Fill in missing columns by replication ----------- */
1535 if (nmiss > 0) { /* replicate columns */
1536 /* Find the first good column */
1537 goodcol = 0;
1538 for (j = 0; j < w; j++) {
1539 numaGetIValue(na, j, &ival);
1540 if (ival == 1) {
1541 goodcol = j;
1542 break;
1543 }
1544 }
1545 if (goodcol > 0) { /* copy cols backward */
1546 for (j = goodcol - 1; j >= 0; j--)
1547 pixRasterop(pix, j, 0, 1, h, PIX_SRC, pix, j + 1, 0);
1548 }
1549 for (j = goodcol + 1; j < w; j++) { /* copy cols forward */
1550 numaGetIValue(na, j, &ival);
1551 if (ival == 0) {
1552 /* Copy the column to the left of j */
1553 pixRasterop(pix, j, 0, 1, h, PIX_SRC, pix, j - 1, 0);
1554 }
1555 }
1556 }
1557 if (w > nx) { /* replicate the last column */
1558 pixRasterop(pix, w - 1, 0, 1, h, PIX_SRC, pix, w - 2, 0);
1559 }
1560
1561 numaDestroy(&na);
1562 return 0;
1563}
1564
1565
1579PIX *
1581 l_int32 addw,
1582 l_int32 addh)
1583{
1584l_int32 w, h, i, j;
1585l_uint32 val;
1586PIX *pixd;
1587
1588 if (!pixs || pixGetDepth(pixs) != 8)
1589 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
1590
1591 if (addw == 0 && addh == 0)
1592 return pixCopy(NULL, pixs);
1593
1594 pixGetDimensions(pixs, &w, &h, NULL);
1595 if ((pixd = pixCreate(w + addw, h + addh, 8)) == NULL)
1596 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1597 pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
1598
1599 if (addw > 0) {
1600 for (i = 0; i < h; i++) {
1601 pixGetPixel(pixd, w - 1, i, &val);
1602 for (j = 0; j < addw; j++)
1603 pixSetPixel(pixd, w + j, i, val);
1604 }
1605 }
1606
1607 if (addh > 0) {
1608 for (j = 0; j < w + addw; j++) {
1609 pixGetPixel(pixd, j, h - 1, &val);
1610 for (i = 0; i < addh; i++)
1611 pixSetPixel(pixd, j, h + i, val);
1612 }
1613 }
1614
1615 pixCopyResolution(pixd, pixs);
1616 return pixd;
1617}
1618
1619
1640l_ok
1642 PIX *pixm,
1643 l_int32 factor)
1644{
1645l_int32 empty, i, n, x, y;
1646l_float32 aveval;
1647BOXA *boxa;
1648PIX *pixmc;
1649PIXA *pixa;
1650
1651 if (!pixs || pixGetDepth(pixs) != 8)
1652 return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
1653 if (pixGetColormap(pixs))
1654 return ERROR_INT("pixs has colormap", __func__, 1);
1655 if (!pixm) {
1656 L_INFO("pixm not defined\n", __func__);
1657 return 0;
1658 }
1659 if (pixGetDepth(pixm) != 1)
1660 return ERROR_INT("pixm not 1 bpp", __func__, 1);
1661 pixZero(pixm, &empty);
1662 if (empty) {
1663 L_INFO("pixm has no fg pixels; nothing to do\n", __func__);
1664 return 0;
1665 }
1666
1667 boxa = pixConnComp(pixm, &pixa, 8);
1668 n = boxaGetCount(boxa);
1669 for (i = 0; i < n; i++) {
1670 if ((pixmc = pixaGetPix(pixa, i, L_CLONE)) == NULL) {
1671 L_WARNING("missing pixmc!\n", __func__);
1672 continue;
1673 }
1674 boxaGetBoxGeometry(boxa, i, &x, &y, NULL, NULL);
1675 pixGetAverageMasked(pixs, pixmc, x, y, factor, L_MEAN_ABSVAL, &aveval);
1676 pixPaintThroughMask(pixs, pixmc, x, y, (l_int32)aveval);
1677 pixDestroy(&pixmc);
1678 }
1679
1680 boxaDestroy(&boxa);
1681 pixaDestroy(&pixa);
1682 return 0;
1683}
1684
1685
1686/*------------------------------------------------------------------*
1687 * Measurement of local foreground *
1688 *------------------------------------------------------------------*/
1689#if 0 /* Not working properly: do not use */
1690
1727l_ok
1728pixGetForegroundGrayMap(PIX *pixs,
1729 PIX *pixim,
1730 l_int32 sx,
1731 l_int32 sy,
1732 l_int32 thresh,
1733 PIX **ppixd)
1734{
1735l_int32 w, h, d, wd, hd;
1736l_int32 empty, fgpixels;
1737PIX *pixd, *piximi, *pixim2, *pixims, *pixs2, *pixb, *pixt1, *pixt2, *pixt3;
1738
1739 if (!ppixd)
1740 return ERROR_INT("&pixd not defined", __func__, 1);
1741 *ppixd = NULL;
1742 if (!pixs)
1743 return ERROR_INT("pixs not defined", __func__, 1);
1744 pixGetDimensions(pixs, &w, &h, &d);
1745 if (d != 8)
1746 return ERROR_INT("pixs not 8 bpp", __func__, 1);
1747 if (pixim && pixGetDepth(pixim) != 1)
1748 return ERROR_INT("pixim not 1 bpp", __func__, 1);
1749 if (sx < 2 || sy < 2)
1750 return ERROR_INT("sx and sy must be >= 2", __func__, 1);
1751
1752 /* Generate pixd, which is reduced by the factors (sx, sy). */
1753 wd = (w + sx - 1) / sx;
1754 hd = (h + sy - 1) / sy;
1755 pixd = pixCreate(wd, hd, 8);
1756 *ppixd = pixd;
1757
1758 /* Evaluate the 'image' mask, pixim. If it is all fg,
1759 * the output pixd has all pixels with value 0. */
1760 fgpixels = 0; /* boolean for existence of fg pixels in the image mask. */
1761 if (pixim) {
1762 piximi = pixInvert(NULL, pixim); /* set non-image pixels to 1 */
1763 pixZero(piximi, &empty);
1764 pixDestroy(&piximi);
1765 if (empty) /* all 'image'; return with all pixels set to 0 */
1766 return 0;
1767 pixZero(pixim, &empty);
1768 if (!empty) /* there are fg pixels in pixim */
1769 fgpixels = 1;
1770 }
1771
1772 /* 2x subsampling; paint white through 'image' mask. */
1773 pixs2 = pixScaleBySampling(pixs, 0.5, 0.5);
1774 if (pixim && fgpixels) {
1775 pixim2 = pixReduceBinary2(pixim, NULL);
1776 pixPaintThroughMask(pixs2, pixim2, 0, 0, 255);
1777 pixDestroy(&pixim2);
1778 }
1779
1780 /* Min (erosion) downscaling; total reduction (4 sx, 4 sy). */
1781 pixt1 = pixScaleGrayMinMax(pixs2, sx, sy, L_CHOOSE_MIN);
1782
1783/* pixDisplay(pixt1, 300, 200); */
1784
1785 /* Threshold to identify fg; paint bg pixels to white. */
1786 pixb = pixThresholdToBinary(pixt1, thresh); /* fg pixels */
1787 pixInvert(pixb, pixb);
1788 pixPaintThroughMask(pixt1, pixb, 0, 0, 255);
1789 pixDestroy(&pixb);
1790
1791 /* Replicative expansion by 2x to (sx, sy). */
1792 pixt2 = pixExpandReplicate(pixt1, 2);
1793
1794/* pixDisplay(pixt2, 500, 200); */
1795
1796 /* Fill holes in the fg by propagation */
1797 pixFillMapHoles(pixt2, w / sx, h / sy, L_FILL_WHITE);
1798
1799/* pixDisplay(pixt2, 700, 200); */
1800
1801 /* Smooth with 17x17 kernel. */
1802 pixt3 = pixBlockconv(pixt2, 8, 8);
1803 pixRasterop(pixd, 0, 0, wd, hd, PIX_SRC, pixt3, 0, 0);
1804
1805 /* Paint the image parts black. */
1806 pixims = pixScaleBySampling(pixim, 1. / sx, 1. / sy);
1807 pixPaintThroughMask(pixd, pixims, 0, 0, 0);
1808
1809 pixDestroy(&pixs2);
1810 pixDestroy(&pixt1);
1811 pixDestroy(&pixt2);
1812 pixDestroy(&pixt3);
1813 return 0;
1814}
1815#endif /* Not working properly: do not use */
1816
1817
1818/*------------------------------------------------------------------*
1819 * Generate inverted background map *
1820 *------------------------------------------------------------------*/
1837PIX *
1839 l_int32 bgval,
1840 l_int32 smoothx,
1841 l_int32 smoothy)
1842{
1843l_int32 w, h, wplsm, wpld, i, j;
1844l_int32 val, val16;
1845l_uint32 *datasm, *datad, *linesm, *lined;
1846PIX *pixsm, *pixd;
1847
1848 if (!pixs || pixGetDepth(pixs) != 8)
1849 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
1850 if (pixGetColormap(pixs))
1851 return (PIX *)ERROR_PTR("pixs has colormap", __func__, NULL);
1852 pixGetDimensions(pixs, &w, &h, NULL);
1853 if (w < 5 || h < 5)
1854 return (PIX *)ERROR_PTR("w and h must be >= 5", __func__, NULL);
1855
1856 /* smooth the map image */
1857 pixsm = pixBlockconv(pixs, smoothx, smoothy);
1858 datasm = pixGetData(pixsm);
1859 wplsm = pixGetWpl(pixsm);
1860
1861 /* invert the map image, scaling up to preserve dynamic range */
1862 pixd = pixCreate(w, h, 16);
1863 datad = pixGetData(pixd);
1864 wpld = pixGetWpl(pixd);
1865 for (i = 0; i < h; i++) {
1866 linesm = datasm + i * wplsm;
1867 lined = datad + i * wpld;
1868 for (j = 0; j < w; j++) {
1869 val = GET_DATA_BYTE(linesm, j);
1870 if (val > 0)
1871 val16 = (256 * bgval) / val;
1872 else { /* shouldn't happen */
1873 L_WARNING("smoothed bg has 0 pixel!\n", __func__);
1874 val16 = bgval / 2;
1875 }
1876 SET_DATA_TWO_BYTES(lined, j, val16);
1877 }
1878 }
1879
1880 pixDestroy(&pixsm);
1881 pixCopyResolution(pixd, pixs);
1882 return pixd;
1883}
1884
1885
1886/*------------------------------------------------------------------*
1887 * Apply background map to image *
1888 *------------------------------------------------------------------*/
1898PIX *
1900 PIX *pixm,
1901 l_int32 sx,
1902 l_int32 sy)
1903{
1904l_int32 w, h, wm, hm, wpls, wpld, i, j, k, m, xoff, yoff;
1905l_int32 vals, vald;
1906l_uint32 val16;
1907l_uint32 *datas, *datad, *lines, *lined, *flines, *flined;
1908PIX *pixd;
1909
1910 if (!pixs || pixGetDepth(pixs) != 8)
1911 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
1912 if (pixGetColormap(pixs))
1913 return (PIX *)ERROR_PTR("pixs has colormap", __func__, NULL);
1914 if (!pixm || pixGetDepth(pixm) != 16)
1915 return (PIX *)ERROR_PTR("pixm undefined or not 16 bpp", __func__, NULL);
1916 if (sx == 0 || sy == 0)
1917 return (PIX *)ERROR_PTR("invalid sx and/or sy", __func__, NULL);
1918
1919 datas = pixGetData(pixs);
1920 wpls = pixGetWpl(pixs);
1921 pixGetDimensions(pixs, &w, &h, NULL);
1922 pixGetDimensions(pixm, &wm, &hm, NULL);
1923 if ((pixd = pixCreateTemplate(pixs)) == NULL)
1924 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1925 datad = pixGetData(pixd);
1926 wpld = pixGetWpl(pixd);
1927 for (i = 0; i < hm; i++) {
1928 lines = datas + sy * i * wpls;
1929 lined = datad + sy * i * wpld;
1930 yoff = sy * i;
1931 for (j = 0; j < wm; j++) {
1932 pixGetPixel(pixm, j, i, &val16);
1933 xoff = sx * j;
1934 for (k = 0; k < sy && yoff + k < h; k++) {
1935 flines = lines + k * wpls;
1936 flined = lined + k * wpld;
1937 for (m = 0; m < sx && xoff + m < w; m++) {
1938 vals = GET_DATA_BYTE(flines, xoff + m);
1939 vald = (vals * val16) / 256;
1940 vald = L_MIN(vald, 255);
1941 SET_DATA_BYTE(flined, xoff + m, vald);
1942 }
1943 }
1944 }
1945 }
1946
1947 return pixd;
1948}
1949
1950
1962PIX *
1964 PIX *pixmr,
1965 PIX *pixmg,
1966 PIX *pixmb,
1967 l_int32 sx,
1968 l_int32 sy)
1969{
1970l_int32 w, h, wm, hm, wpls, wpld, i, j, k, m, xoff, yoff;
1971l_int32 rvald, gvald, bvald;
1972l_uint32 vals;
1973l_uint32 rval16, gval16, bval16;
1974l_uint32 *datas, *datad, *lines, *lined, *flines, *flined;
1975PIX *pixd;
1976
1977 if (!pixs)
1978 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1979 if (pixGetDepth(pixs) != 32)
1980 return (PIX *)ERROR_PTR("pixs not 32 bpp", __func__, NULL);
1981 if (!pixmr || !pixmg || !pixmb)
1982 return (PIX *)ERROR_PTR("pix maps not all defined", __func__, NULL);
1983 if (pixGetDepth(pixmr) != 16 || pixGetDepth(pixmg) != 16 ||
1984 pixGetDepth(pixmb) != 16)
1985 return (PIX *)ERROR_PTR("pix maps not all 16 bpp", __func__, NULL);
1986 if (sx == 0 || sy == 0)
1987 return (PIX *)ERROR_PTR("invalid sx and/or sy", __func__, NULL);
1988
1989 datas = pixGetData(pixs);
1990 wpls = pixGetWpl(pixs);
1991 w = pixGetWidth(pixs);
1992 h = pixGetHeight(pixs);
1993 wm = pixGetWidth(pixmr);
1994 hm = pixGetHeight(pixmr);
1995 if ((pixd = pixCreateTemplate(pixs)) == NULL)
1996 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1997 datad = pixGetData(pixd);
1998 wpld = pixGetWpl(pixd);
1999 for (i = 0; i < hm; i++) {
2000 lines = datas + sy * i * wpls;
2001 lined = datad + sy * i * wpld;
2002 yoff = sy * i;
2003 for (j = 0; j < wm; j++) {
2004 pixGetPixel(pixmr, j, i, &rval16);
2005 pixGetPixel(pixmg, j, i, &gval16);
2006 pixGetPixel(pixmb, j, i, &bval16);
2007 xoff = sx * j;
2008 for (k = 0; k < sy && yoff + k < h; k++) {
2009 flines = lines + k * wpls;
2010 flined = lined + k * wpld;
2011 for (m = 0; m < sx && xoff + m < w; m++) {
2012 vals = *(flines + xoff + m);
2013 rvald = ((vals >> 24) * rval16) / 256;
2014 rvald = L_MIN(rvald, 255);
2015 gvald = (((vals >> 16) & 0xff) * gval16) / 256;
2016 gvald = L_MIN(gvald, 255);
2017 bvald = (((vals >> 8) & 0xff) * bval16) / 256;
2018 bvald = L_MIN(bvald, 255);
2019 composeRGBPixel(rvald, gvald, bvald, flined + xoff + m);
2020 }
2021 }
2022 }
2023 }
2024
2025 return pixd;
2026}
2027
2028
2029/*------------------------------------------------------------------*
2030 * Apply variable map *
2031 *------------------------------------------------------------------*/
2058PIX *
2060 PIX *pixg,
2061 l_int32 target)
2062{
2063l_int32 i, j, w, h, d, wpls, wplg, wpld, vals, valg, vald;
2064l_uint8 *lut;
2065l_uint32 *datas, *datag, *datad, *lines, *lineg, *lined;
2066l_float32 fval;
2067PIX *pixd;
2068
2069 if (!pixs)
2070 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2071 if (!pixg)
2072 return (PIX *)ERROR_PTR("pixg not defined", __func__, NULL);
2073 if (!pixSizesEqual(pixs, pixg))
2074 return (PIX *)ERROR_PTR("pix sizes not equal", __func__, NULL);
2075 pixGetDimensions(pixs, &w, &h, &d);
2076 if (d != 8)
2077 return (PIX *)ERROR_PTR("depth not 8 bpp", __func__, NULL);
2078
2079 /* Generate a LUT for the mapping if the image is large enough
2080 * to warrant the overhead. The LUT is of size 2^16. For the
2081 * index to the table, get the MSB from pixs and the LSB from pixg.
2082 * Note: this LUT is bigger than the typical 32K L1 cache, so
2083 * we expect cache misses. L2 latencies are about 5ns. But
2084 * division is slooooow. For large images, this function is about
2085 * 4x faster when using the LUT. C'est la vie. */
2086 lut = NULL;
2087 if (w * h > 100000) { /* more pixels than 2^16 */
2088 lut = (l_uint8 *)LEPT_CALLOC(0x10000, sizeof(l_uint8));
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 = pixCreate(w, h, 8)) == NULL) {
2098 LEPT_FREE(lut);
2099 return (PIX *)ERROR_PTR("pixd not made", __func__, 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 *------------------------------------------------------------------*/
2173PIX *
2175 PIX *pixs,
2176 l_int32 rval,
2177 l_int32 gval,
2178 l_int32 bval,
2179 l_int32 mapval)
2180{
2181l_int32 w, h, d, i, j, ncolors, rv, gv, bv, wpl;
2182l_int32 *rarray, *garray, *barray;
2183l_uint32 *data, *line;
2184NUMA *nar, *nag, *nab;
2185PIXCMAP *cmap;
2186
2187 if (!pixs)
2188 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2189 cmap = pixGetColormap(pixs);
2190 pixGetDimensions(pixs, &w, &h, &d);
2191 if (!cmap && d != 32)
2192 return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", __func__, NULL);
2193 if (mapval <= 0) {
2194 L_WARNING("mapval must be > 0; setting to 255\n", __func__);
2195 mapval = 255;
2196 }
2197
2198 /* Prepare pixd to be a copy of pixs */
2199 if ((pixd = pixCopy(pixd, pixs)) == NULL)
2200 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2201
2202 /* Generate the TRC maps for each component. Make sure the
2203 * upper range for each color is greater than zero. */
2204 nar = numaGammaTRC(1.0, 0, L_MAX(1, 255 * rval / mapval));
2205 nag = numaGammaTRC(1.0, 0, L_MAX(1, 255 * gval / mapval));
2206 nab = numaGammaTRC(1.0, 0, L_MAX(1, 255 * bval / mapval));
2207
2208 /* Extract copies of the internal arrays */
2209 rarray = numaGetIArray(nar);
2210 garray = numaGetIArray(nag);
2211 barray = numaGetIArray(nab);
2212 if (!nar || !nag || !nab || !rarray || !garray || !barray) {
2213 L_ERROR("allocation failure in arrays\n", __func__);
2214 goto cleanup_arrays;
2215 }
2216
2217 if (cmap) {
2218 ncolors = pixcmapGetCount(cmap);
2219 for (i = 0; i < ncolors; i++) {
2220 pixcmapGetColor(cmap, i, &rv, &gv, &bv);
2221 pixcmapResetColor(cmap, i, rarray[rv], garray[gv], barray[bv]);
2222 }
2223 }
2224 else {
2225 data = pixGetData(pixd);
2226 wpl = pixGetWpl(pixd);
2227 for (i = 0; i < h; i++) {
2228 line = data + i * wpl;
2229 for (j = 0; j < w; j++) {
2230 extractRGBValues(line[j], &rv, &gv, &bv);
2231 composeRGBPixel(rarray[rv], garray[gv], barray[bv], line + j);
2232 }
2233 }
2234 }
2235
2236cleanup_arrays:
2237 numaDestroy(&nar);
2238 numaDestroy(&nag);
2239 numaDestroy(&nab);
2240 LEPT_FREE(rarray);
2241 LEPT_FREE(garray);
2242 LEPT_FREE(barray);
2243 return pixd;
2244}
2245
2246
2280PIX *
2282 PIX *pixs,
2283 l_int32 rval,
2284 l_int32 gval,
2285 l_int32 bval,
2286 l_int32 factor,
2287 l_float32 rank)
2288{
2289l_int32 mapval;
2290l_float32 rankrval, rankgval, rankbval;
2291l_float32 rfract, gfract, bfract, maxfract;
2292
2293 if (!pixs)
2294 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2295 if (pixGetDepth(pixs) != 32)
2296 return (PIX *)ERROR_PTR("pixs not 32 bpp", __func__, NULL);
2297 if (factor < 1)
2298 return (PIX *)ERROR_PTR("sampling factor < 1", __func__, NULL);
2299 if (rank < 0.0 || rank > 1.0)
2300 return (PIX *)ERROR_PTR("rank not in [0.0 ... 1.0]", __func__, NULL);
2301 if (rval <= 0 || gval <= 0 || bval <= 0)
2302 return (PIX *)ERROR_PTR("invalid estim. color values", __func__, NULL);
2303
2304 /* The max value for each component may be larger than the
2305 * input estimated background value. In that case, mapping
2306 * for those pixels would saturate. To prevent saturation,
2307 * we compute the fraction for each component by which we
2308 * would oversaturate. Then take the max of these, and
2309 * reduce, uniformly over all components, the output intensity
2310 * by this value. Then no component will saturate.
2311 * In practice, if rank < 1.0, a fraction of pixels
2312 * may have a component saturate. By keeping rank close to 1.0,
2313 * that fraction can be made arbitrarily small. */
2314 pixGetRankValueMaskedRGB(pixs, NULL, 0, 0, factor, rank, &rankrval,
2315 &rankgval, &rankbval);
2316 rfract = rankrval / (l_float32)rval;
2317 gfract = rankgval / (l_float32)gval;
2318 bfract = rankbval / (l_float32)bval;
2319 maxfract = L_MAX(rfract, gfract);
2320 maxfract = L_MAX(maxfract, bfract);
2321#if DEBUG_GLOBAL
2322 lept_stderr("rankrval = %7.2f, rankgval = %7.2f, rankbval = %7.2f\n",
2323 rankrval, rankgval, rankbval);
2324 lept_stderr("rfract = %7.4f, gfract = %7.4f, bfract = %7.4f\n",
2325 rfract, gfract, bfract);
2326#endif /* DEBUG_GLOBAL */
2327
2328 mapval = (l_int32)(255. / maxfract);
2329 pixd = pixGlobalNormRGB(pixd, pixs, rval, gval, bval, mapval);
2330 return pixd;
2331}
2332
2333
2334/*------------------------------------------------------------------*
2335 * Adaptive threshold spread normalization *
2336 *------------------------------------------------------------------*/
2380l_ok
2382 l_int32 filtertype,
2383 l_int32 edgethresh,
2384 l_int32 smoothx,
2385 l_int32 smoothy,
2386 l_float32 gamma,
2387 l_int32 minval,
2388 l_int32 maxval,
2389 l_int32 targetthresh,
2390 PIX **ppixth,
2391 PIX **ppixb,
2392 PIX **ppixd)
2393{
2394PIX *pixe, *pixet, *pixsd, *pixg1, *pixg2, *pixth;
2395
2396 if (ppixth) *ppixth = NULL;
2397 if (ppixb) *ppixb = NULL;
2398 if (ppixd) *ppixd = NULL;
2399 if (!pixs || pixGetDepth(pixs) != 8)
2400 return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
2401 if (pixGetColormap(pixs))
2402 return ERROR_INT("pixs is colormapped", __func__, 1);
2403 if (!ppixth && !ppixb && !ppixd)
2404 return ERROR_INT("no output requested", __func__, 1);
2405 if (filtertype != L_SOBEL_EDGE && filtertype != L_TWO_SIDED_EDGE)
2406 return ERROR_INT("invalid filter type", __func__, 1);
2407
2408 /* Get the thresholded edge pixels. These are the ones
2409 * that have values in pixs near the local optimal fg/bg threshold. */
2410 if (filtertype == L_SOBEL_EDGE)
2411 pixe = pixSobelEdgeFilter(pixs, L_VERTICAL_EDGES);
2412 else /* L_TWO_SIDED_EDGE */
2413 pixe = pixTwoSidedEdgeFilter(pixs, L_VERTICAL_EDGES);
2414 pixet = pixThresholdToBinary(pixe, edgethresh);
2415 pixInvert(pixet, pixet);
2416
2417 /* Build a seed image whose only nonzero values are those
2418 * values of pixs corresponding to pixels in the fg of pixet. */
2419 pixsd = pixCreateTemplate(pixs);
2420 pixCombineMasked(pixsd, pixs, pixet);
2421
2422 /* Spread the seed and optionally smooth to reduce noise */
2423 pixg1 = pixSeedspread(pixsd, 4);
2424 pixg2 = pixBlockconv(pixg1, smoothx, smoothy);
2425
2426 /* Optionally do a gamma enhancement */
2427 pixth = pixGammaTRC(NULL, pixg2, gamma, minval, maxval);
2428
2429 /* Do the mapping and thresholding */
2430 if (ppixd) {
2431 *ppixd = pixApplyVariableGrayMap(pixs, pixth, targetthresh);
2432 if (ppixb)
2433 *ppixb = pixThresholdToBinary(*ppixd, targetthresh);
2434 }
2435 else if (ppixb)
2436 *ppixb = pixVarThresholdToBinary(pixs, pixth);
2437
2438 if (ppixth)
2439 *ppixth = pixth;
2440 else
2441 pixDestroy(&pixth);
2442
2443 pixDestroy(&pixe);
2444 pixDestroy(&pixet);
2445 pixDestroy(&pixsd);
2446 pixDestroy(&pixg1);
2447 pixDestroy(&pixg2);
2448 return 0;
2449}
2450
2451
2452/*------------------------------------------------------------------*
2453 * Adaptive background normalization (flexible adaptaption) *
2454 *------------------------------------------------------------------*/
2484PIX *
2486 l_int32 sx,
2487 l_int32 sy,
2488 l_int32 smoothx,
2489 l_int32 smoothy,
2490 l_int32 delta)
2491{
2492l_float32 scalex, scaley;
2493PIX *pixt, *pixsd, *pixmin, *pixbg, *pixbgi, *pixd;
2494
2495 if (!pixs || pixGetDepth(pixs) != 8)
2496 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
2497 if (pixGetColormap(pixs))
2498 return (PIX *)ERROR_PTR("pixs is colormapped", __func__, NULL);
2499 if (sx < 3 || sy < 3)
2500 return (PIX *)ERROR_PTR("sx and/or sy less than 3", __func__, NULL);
2501 if (sx > 10 || sy > 10)
2502 return (PIX *)ERROR_PTR("sx and/or sy exceed 10", __func__, NULL);
2503 if (smoothx < 1 || smoothy < 1)
2504 return (PIX *)ERROR_PTR("smooth params less than 1", __func__, NULL);
2505 if (smoothx > 3 || smoothy > 3)
2506 return (PIX *)ERROR_PTR("smooth params exceed 3", __func__, NULL);
2507
2508 /* Generate the bg estimate using smoothed average with subsampling */
2509 scalex = 1. / (l_float32)sx;
2510 scaley = 1. / (l_float32)sy;
2511 pixt = pixScaleSmooth(pixs, scalex, scaley);
2512
2513 /* Do basin filling on the bg estimate if requested */
2514 if (delta <= 0)
2515 pixsd = pixClone(pixt);
2516 else {
2517 pixLocalExtrema(pixt, 0, 0, &pixmin, NULL);
2518 pixsd = pixSeedfillGrayBasin(pixmin, pixt, delta, 4);
2519 pixDestroy(&pixmin);
2520 }
2521 pixbg = pixExtendByReplication(pixsd, 1, 1);
2522
2523 /* Map the bg to 200 */
2524 pixbgi = pixGetInvBackgroundMap(pixbg, 200, smoothx, smoothy);
2525 pixd = pixApplyInvBackgroundGrayMap(pixs, pixbgi, sx, sy);
2526
2527 pixDestroy(&pixt);
2528 pixDestroy(&pixsd);
2529 pixDestroy(&pixbg);
2530 pixDestroy(&pixbgi);
2531 return pixd;
2532}
2533
2534
2535/*------------------------------------------------------------------*
2536 * Adaptive contrast normalization *
2537 *------------------------------------------------------------------*/
2577PIX *
2579 PIX *pixs,
2580 l_int32 sx,
2581 l_int32 sy,
2582 l_int32 mindiff,
2583 l_int32 smoothx,
2584 l_int32 smoothy)
2585{
2586PIX *pixmin, *pixmax;
2587
2588 if (!pixs || pixGetDepth(pixs) != 8)
2589 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, pixd);
2590 if (pixd && pixd != pixs)
2591 return (PIX *)ERROR_PTR("pixd not null or == pixs", __func__, pixd);
2592 if (pixGetColormap(pixs))
2593 return (PIX *)ERROR_PTR("pixs is colormapped", __func__, pixd);
2594 if (sx < 5 || sy < 5)
2595 return (PIX *)ERROR_PTR("sx and/or sy less than 5", __func__, pixd);
2596 if (smoothx < 0 || smoothy < 0)
2597 return (PIX *)ERROR_PTR("smooth params less than 0", __func__, pixd);
2598 if (smoothx > 8 || smoothy > 8)
2599 return (PIX *)ERROR_PTR("smooth params exceed 8", __func__, pixd);
2600
2601 /* Get the min and max pixel values in each tile, and represent
2602 * each value as a pixel in pixmin and pixmax, respectively. */
2603 pixMinMaxTiles(pixs, sx, sy, mindiff, smoothx, smoothy, &pixmin, &pixmax);
2604
2605 /* For each tile, do a linear expansion of the dynamic range
2606 * of pixels so that the min value is mapped to 0 and the
2607 * max value is mapped to 255. */
2608 pixd = pixLinearTRCTiled(pixd, pixs, sx, sy, pixmin, pixmax);
2609
2610 pixDestroy(&pixmin);
2611 pixDestroy(&pixmax);
2612 return pixd;
2613}
2614
2615
2635static l_ok
2637 l_int32 sx,
2638 l_int32 sy,
2639 l_int32 mindiff,
2640 l_int32 smoothx,
2641 l_int32 smoothy,
2642 PIX **ppixmin,
2643 PIX **ppixmax)
2644{
2645l_int32 w, h;
2646PIX *pixmin1, *pixmax1, *pixmin2, *pixmax2;
2647
2648 if (ppixmin) *ppixmin = NULL;
2649 if (ppixmax) *ppixmax = NULL;
2650 if (!ppixmin || !ppixmax)
2651 return ERROR_INT("&pixmin or &pixmax undefined", __func__, 1);
2652 if (!pixs || pixGetDepth(pixs) != 8)
2653 return ERROR_INT("pixs undefined or not 8 bpp", __func__, 1);
2654 if (pixGetColormap(pixs))
2655 return ERROR_INT("pixs is colormapped", __func__, 1);
2656 if (sx < 5 || sy < 5)
2657 return ERROR_INT("sx and/or sy less than 3", __func__, 1);
2658 if (smoothx < 0 || smoothy < 0)
2659 return ERROR_INT("smooth params less than 0", __func__, 1);
2660 if (smoothx > 5 || smoothy > 5)
2661 return ERROR_INT("smooth params exceed 5", __func__, 1);
2662
2663 /* Get the min and max values in each tile */
2664 pixmin1 = pixScaleGrayMinMax(pixs, sx, sy, L_CHOOSE_MIN);
2665 pixmax1 = pixScaleGrayMinMax(pixs, sx, sy, L_CHOOSE_MAX);
2666
2667 pixmin2 = pixExtendByReplication(pixmin1, 1, 1);
2668 pixmax2 = pixExtendByReplication(pixmax1, 1, 1);
2669 pixDestroy(&pixmin1);
2670 pixDestroy(&pixmax1);
2671
2672 /* Make sure no value is 0 */
2673 pixAddConstantGray(pixmin2, 1);
2674 pixAddConstantGray(pixmax2, 1);
2675
2676 /* Generate holes where the contrast is too small */
2677 pixSetLowContrast(pixmin2, pixmax2, mindiff);
2678
2679 /* Fill the holes (0 values) */
2680 pixGetDimensions(pixmin2, &w, &h, NULL);
2681 pixFillMapHoles(pixmin2, w, h, L_FILL_BLACK);
2682 pixFillMapHoles(pixmax2, w, h, L_FILL_BLACK);
2683
2684 /* Smooth if requested */
2685 if (smoothx > 0 || smoothy > 0) {
2686 smoothx = L_MIN(smoothx, (w - 1) / 2);
2687 smoothy = L_MIN(smoothy, (h - 1) / 2);
2688 *ppixmin = pixBlockconv(pixmin2, smoothx, smoothy);
2689 *ppixmax = pixBlockconv(pixmax2, smoothx, smoothy);
2690 }
2691 else {
2692 *ppixmin = pixClone(pixmin2);
2693 *ppixmax = pixClone(pixmax2);
2694 }
2695 pixCopyResolution(*ppixmin, pixs);
2696 pixCopyResolution(*ppixmax, pixs);
2697 pixDestroy(&pixmin2);
2698 pixDestroy(&pixmax2);
2699
2700 return 0;
2701}
2702
2703
2724static l_ok
2726 PIX *pixs2,
2727 l_int32 mindiff)
2728{
2729l_int32 i, j, w, h, d, wpl, val1, val2, found;
2730l_uint32 *data1, *data2, *line1, *line2;
2731
2732 if (!pixs1 || !pixs2)
2733 return ERROR_INT("pixs1 and pixs2 not both defined", __func__, 1);
2734 if (pixSizesEqual(pixs1, pixs2) == 0)
2735 return ERROR_INT("pixs1 and pixs2 not equal size", __func__, 1);
2736 pixGetDimensions(pixs1, &w, &h, &d);
2737 if (d != 8)
2738 return ERROR_INT("depth not 8 bpp", __func__, 1);
2739 if (mindiff > 254) return 0;
2740
2741 data1 = pixGetData(pixs1);
2742 data2 = pixGetData(pixs2);
2743 wpl = pixGetWpl(pixs1);
2744 found = 0; /* init to not finding any diffs >= mindiff */
2745 for (i = 0; i < h; i++) {
2746 line1 = data1 + i * wpl;
2747 line2 = data2 + i * wpl;
2748 for (j = 0; j < w; j++) {
2749 val1 = GET_DATA_BYTE(line1, j);
2750 val2 = GET_DATA_BYTE(line2, j);
2751 if (L_ABS(val1 - val2) >= mindiff) {
2752 found = 1;
2753 break;
2754 }
2755 }
2756 if (found) break;
2757 }
2758 if (!found) {
2759 L_WARNING("no pixel pair diffs as large as mindiff\n", __func__);
2760 pixClearAll(pixs1);
2761 pixClearAll(pixs2);
2762 return 1;
2763 }
2764
2765 for (i = 0; i < h; i++) {
2766 line1 = data1 + i * wpl;
2767 line2 = data2 + i * wpl;
2768 for (j = 0; j < w; j++) {
2769 val1 = GET_DATA_BYTE(line1, j);
2770 val2 = GET_DATA_BYTE(line2, j);
2771 if (L_ABS(val1 - val2) < mindiff) {
2772 SET_DATA_BYTE(line1, j, 0);
2773 SET_DATA_BYTE(line2, j, 0);
2774 }
2775 }
2776 }
2777
2778 return 0;
2779}
2780
2781
2805static PIX *
2807 PIX *pixs,
2808 l_int32 sx,
2809 l_int32 sy,
2810 PIX *pixmin,
2811 PIX *pixmax)
2812{
2813l_int32 i, j, k, m, w, h, wt, ht, wpl, wplt, xoff, yoff;
2814l_int32 minval, maxval, val, sval;
2815l_int32 *ia;
2816l_int32 **iaa;
2817l_uint32 *data, *datamin, *datamax, *line, *tline, *linemin, *linemax;
2818
2819 if (!pixs || pixGetDepth(pixs) != 8)
2820 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, pixd);
2821 if (pixd && pixd != pixs)
2822 return (PIX *)ERROR_PTR("pixd not null or == pixs", __func__, pixd);
2823 if (pixGetColormap(pixs))
2824 return (PIX *)ERROR_PTR("pixs is colormapped", __func__, pixd);
2825 if (!pixmin || !pixmax)
2826 return (PIX *)ERROR_PTR("pixmin & pixmax not defined", __func__, pixd);
2827 if (sx < 5 || sy < 5)
2828 return (PIX *)ERROR_PTR("sx and/or sy less than 5", __func__, pixd);
2829
2830 iaa = (l_int32 **)LEPT_CALLOC(256, sizeof(l_int32 *));
2831 if ((pixd = pixCopy(pixd, pixs)) == NULL) {
2832 LEPT_FREE(iaa);
2833 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2834 }
2835 pixGetDimensions(pixd, &w, &h, NULL);
2836
2837 data = pixGetData(pixd);
2838 wpl = pixGetWpl(pixd);
2839 datamin = pixGetData(pixmin);
2840 datamax = pixGetData(pixmax);
2841 wplt = pixGetWpl(pixmin);
2842 pixGetDimensions(pixmin, &wt, &ht, NULL);
2843 for (i = 0; i < ht; i++) {
2844 line = data + sy * i * wpl;
2845 linemin = datamin + i * wplt;
2846 linemax = datamax + i * wplt;
2847 yoff = sy * i;
2848 for (j = 0; j < wt; j++) {
2849 xoff = sx * j;
2850 minval = GET_DATA_BYTE(linemin, j);
2851 maxval = GET_DATA_BYTE(linemax, j);
2852 if (maxval == minval) {
2853 L_ERROR("shouldn't happen! i,j = %d,%d, minval = %d\n",
2854 __func__, i, j, minval);
2855 continue;
2856 }
2857 if ((ia = iaaGetLinearTRC(iaa, maxval - minval)) == NULL) {
2858 L_ERROR("failure to make ia for j = %d!\n", __func__, j);
2859 continue;
2860 }
2861 for (k = 0; k < sy && yoff + k < h; k++) {
2862 tline = line + k * wpl;
2863 for (m = 0; m < sx && xoff + m < w; m++) {
2864 val = GET_DATA_BYTE(tline, xoff + m);
2865 sval = val - minval;
2866 sval = L_MAX(0, sval);
2867 SET_DATA_BYTE(tline, xoff + m, ia[sval]);
2868 }
2869 }
2870 }
2871 }
2872
2873 for (i = 0; i < 256; i++)
2874 LEPT_FREE(iaa[i]);
2875 LEPT_FREE(iaa);
2876 return pixd;
2877}
2878
2879
2889static l_int32 *
2890iaaGetLinearTRC(l_int32 **iaa,
2891 l_int32 diff)
2892{
2893l_int32 i;
2894l_int32 *ia;
2895l_float32 factor;
2896
2897 if (!iaa)
2898 return (l_int32 *)ERROR_PTR("iaa not defined", __func__, NULL);
2899
2900 if (iaa[diff] != NULL) /* already have it */
2901 return iaa[diff];
2902
2903 ia = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2904 iaa[diff] = ia;
2905 if (diff == 0) { /* shouldn't happen */
2906 for (i = 0; i < 256; i++)
2907 ia[i] = 128;
2908 }
2909 else {
2910 factor = 255. / (l_float32)diff;
2911 for (i = 0; i < diff + 1; i++)
2912 ia[i] = (l_int32)(factor * i + 0.5);
2913 for (i = diff + 1; i < 256; i++)
2914 ia[i] = 255;
2915 }
2916
2917 return ia;
2918}
2919
2920
2921/*------------------------------------------------------------------*
2922 * Adaptive normalization with MinMax conversion of RGB to gray, *
2923 * contrast enhancement and optional 2x upscale binarization *
2924 *------------------------------------------------------------------*/
2948PIX *
2950 l_int32 contrast,
2951 l_int32 scalefactor)
2952{
2953PIX *pix1, *pix2, *pixd;
2954
2955 if (!pixs)
2956 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2957 if (contrast < 1 || contrast > 10)
2958 return (PIX *)ERROR_PTR("contrast not in [1 ... 10]", __func__, NULL);
2959 if (scalefactor != 1 && scalefactor != 2)
2960 return (PIX *)ERROR_PTR("scalefactor not 1 or 2", __func__, NULL);
2961
2962 if (pixGetDepth(pixs) == 1) {
2963 pixd = pixCopy(NULL, pixs);
2964 } else {
2965 pix1 = pixConvertTo8MinMax(pixs);
2966 pix2 = pixBackgroundNormSimple(pix1, NULL, NULL);
2967 pixSelectiveContrastMod(pix2, contrast);
2968 if (scalefactor == 1)
2969 pixd = pixThresholdToBinary(pix2, 180);
2970 else /* scalefactor == 2 */
2971 pixd = pixScaleGray2xLIThresh(pix2, 180);
2972 pixDestroy(&pix1);
2973 pixDestroy(&pix2);
2974 }
2975 return pixd;
2976}
2977
2978
2992PIX *
2994{
2995l_int32 d;
2996
2997 if (!pixs)
2998 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2999
3000 d = pixGetDepth(pixs);
3001 if (d == 1) {
3002 return pixConvert1To8(NULL, pixs, 255, 0);
3003 } else if (d == 2) {
3004 return pixConvert2To8(pixs, 0, 85, 170, 255, FALSE);
3005 } else if (d == 4) {
3006 return pixConvert4To8(pixs, FALSE);
3007 } else if (d == 8) {
3008 if (pixGetColormap(pixs) != NULL)
3009 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
3010 else
3011 return pixCopy(NULL, pixs);
3012 } else if (d == 16) {
3013 return pixConvert16To8(pixs, L_MS_BYTE);
3014 } else if (d == 32) {
3015 return pixConvertRGBToGrayMinMax(pixs, L_CHOOSE_MIN);
3016 }
3017
3018 L_ERROR("Invalid depth d = %d\n", __func__, d);
3019 return NULL;
3020}
3021
3022
3045static l_ok
3047 l_int32 contrast)
3048{
3049 if (!pixs || pixGetDepth(pixs) != 8)
3050 return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
3051
3052 if (contrast == 1)
3053 pixGammaTRC(pixs, pixs, 2.0, 50, 200);
3054 else if (contrast == 2)
3055 pixGammaTRC(pixs, pixs, 1.8, 60, 200);
3056 else if (contrast == 3)
3057 pixGammaTRC(pixs, pixs, 1.6, 70, 200);
3058 else if (contrast == 4)
3059 pixGammaTRC(pixs, pixs, 1.4, 80, 200);
3060 else if (contrast == 5)
3061 pixGammaTRC(pixs, pixs, 1.2, 90, 200);
3062 else if (contrast == 6)
3063 pixGammaTRC(pixs, pixs, 1.0, 100, 200);
3064 else if (contrast == 7)
3065 pixGammaTRC(pixs, pixs, 0.85, 110, 200);
3066 else if (contrast == 8)
3067 pixGammaTRC(pixs, pixs, 0.7, 120, 200);
3068 else if (contrast == 9)
3069 pixGammaTRC(pixs, pixs, 0.6, 130, 200);
3070 else /* contrast == 10 */
3071 pixGammaTRC(pixs, pixs, 0.5, 140, 200);
3072
3073 return 0;
3074}
3075
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:1056
PIX * pixApplyVariableGrayMap(PIX *pixs, PIX *pixg, l_int32 target)
pixApplyVariableGrayMap()
Definition adaptmap.c:2059
PIX * pixBackgroundNormMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, l_int32 bgval)
pixBackgroundNormMorph()
Definition adaptmap.c:473
static l_ok pixSelectiveContrastMod(PIX *pixs, l_int32 contrast)
pixSelectiveContrastMod()
Definition adaptmap.c:3046
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:801
static const l_int32 DefaultFgThreshold
Definition adaptmap.c:166
static const l_int32 DefaultTileHeight
Definition adaptmap.c:165
static l_int32 * iaaGetLinearTRC(l_int32 **iaa, l_int32 diff)
iaaGetLinearTRC()
Definition adaptmap.c:2890
PIX * pixBackgroundNormFlex(PIX *pixs, l_int32 sx, l_int32 sy, l_int32 smoothx, l_int32 smoothy, l_int32 delta)
pixBackgroundNormFlex()
Definition adaptmap.c:2485
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:657
l_ok pixSmoothConnectedRegions(PIX *pixs, PIX *pixm, l_int32 factor)
pixSmoothConnectedRegions()
Definition adaptmap.c:1641
PIX * pixApplyInvBackgroundGrayMap(PIX *pixs, PIX *pixm, l_int32 sx, l_int32 sy)
pixApplyInvBackgroundGrayMap()
Definition adaptmap.c:1899
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:2281
l_ok pixBackgroundNormGrayArrayMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, l_int32 bgval, PIX **ppixd)
pixBackgroundNormGrayArrayMorph()
Definition adaptmap.c:738
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:876
PIX * pixApplyInvBackgroundRGBMap(PIX *pixs, PIX *pixmr, PIX *pixmg, PIX *pixmb, l_int32 sx, l_int32 sy)
pixApplyInvBackgroundRGBMap()
Definition adaptmap.c:1963
l_ok pixGetBackgroundRGBMapMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, PIX **ppixmr, PIX **ppixmg, PIX **ppixmb)
pixGetBackgroundRGBMapMorph()
Definition adaptmap.c:1328
PIX * pixBackgroundNormSimple(PIX *pixs, PIX *pixim, PIX *pixg)
pixBackgroundNormSimple()
Definition adaptmap.c:263
static l_int32 pixSetLowContrast(PIX *pixs1, PIX *pixs2, l_int32 mindiff)
pixSetLowContrast()
Definition adaptmap.c:2725
PIX * pixExtendByReplication(PIX *pixs, l_int32 addw, l_int32 addh)
pixExtendByReplication()
Definition adaptmap.c:1580
PIX * pixGlobalNormRGB(PIX *pixd, PIX *pixs, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 mapval)
pixGlobalNormRGB()
Definition adaptmap.c:2174
static const l_int32 DefaultBgVal
Definition adaptmap.c:168
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:582
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:2578
static const l_int32 DefaultTileWidth
Definition adaptmap.c:164
static const l_int32 DefaultMinCount
Definition adaptmap.c:167
PIX * pixConvertTo8MinMax(PIX *pixs)
pixConvertTo8MinMax()
Definition adaptmap.c:2993
l_ok pixFillMapHoles(PIX *pix, l_int32 nx, l_int32 ny, l_int32 filltype)
pixFillMapHoles()
Definition adaptmap.c:1480
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:338
l_ok pixGetBackgroundGrayMapMorph(PIX *pixs, PIX *pixim, l_int32 reduction, l_int32 size, PIX **ppixm)
pixGetBackgroundGrayMapMorph()
Definition adaptmap.c:1239
PIX * pixGetInvBackgroundMap(PIX *pixs, l_int32 bgval, l_int32 smoothx, l_int32 smoothy)
pixGetInvBackgroundMap()
Definition adaptmap.c:1838
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:2636
static const l_int32 DefaultXSmoothSize
Definition adaptmap.c:169
PIX * pixBackgroundNormTo1MinMax(PIX *pixs, l_int32 contrast, l_int32 scalefactor)
pixBackgroundNormTo1MinMax()
Definition adaptmap.c:2949
static PIX * pixLinearTRCTiled(PIX *pixd, PIX *pixs, l_int32 sx, l_int32 sy, PIX *pixmin, PIX *pixmax)
pixLinearTRCTiled()
Definition adaptmap.c:2806
PIX * pixCleanBackgroundToWhite(PIX *pixs, PIX *pixim, PIX *pixg, l_float32 gamma, l_int32 blackval, l_int32 whiteval)
pixCleanBackgroundToWhite()
Definition adaptmap.c:214
static const l_int32 DefaultYSmoothSize
Definition adaptmap.c:170
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:2381
#define SET_DATA_TWO_BYTES(pdata, n, val)
#define GET_DATA_BYTE(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
#define GET_DATA_BIT(pdata, n)
@ COLOR_BLUE
Definition pix.h:330
@ COLOR_RED
Definition pix.h:328
@ COLOR_GREEN
Definition pix.h:329
@ REMOVE_CMAP_TO_GRAYSCALE
Definition pix.h:381
@ L_CLONE
Definition pix.h:506
@ L_TWO_SIDED_EDGE
Definition pix.h:964
@ L_SOBEL_EDGE
Definition pix.h:963
@ L_MS_BYTE
Definition pix.h:642
#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