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