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 
27 /*
28  *  adaptmap_dark.c
29  *
30  *    Demonstrates the effect of the fg threshold on adaptive mapping
31  *    and cleaning for images with dark and variable background.
32  *
33  *    The example pages are text and image.  For both, because the
34  *    background is both dark and variable, using a lower threshold
35  *    gives much better results.
36  *
37  *    For text, cleaning the background to white after adaptively
38  *    remapping to make the background uniform is preferable.
39  *    The final cleaning step uses pixGammaTRC() where the white value
40  *    (here, 180) is set below the remapped gray value (here, 200).
41  *
42  *    For the image, however, it is best to stop after remapping
43  *    the background.  Going further and moving pixels near the
44  *    background color to white removes the details in the lighter
45  *    regions of the image.  In practice, parts of a scanned page
46  *    that are image (as opposed to text) don't necessarily have
47  *    background pixels that should be white.  These regions can be
48  *    protected by masks from operations, such as pixGammaTRC(),
49  *    where the white value is less than 255.
50  *
51  *    This also tests some code useful for rendering:
52  *     * NUp display from pixa to pixa
53  *     * Interleaving of both pixa and pixacomp
54  */
55 
56 #include "string.h"
57 #include "allheaders.h"
58 
59 void GenCleans(const char *fname, l_int32  *pindex, l_int32 thresh, L_BMF *bmf);
60 
main(int argc,char ** argv)61 l_int32 main(int    argc,
62              char **argv)
63 {
64 l_int32  index;
65 L_BMF   *bmf;
66 PIXA    *pixa1, *pixa2, *pixa3, *pixa4;
67 PIXAC   *pixac1, *pixac2, *pixac3;
68 
69     PROCNAME("adaptmap_dark");
70 
71     setLeptDebugOK(1);
72     bmf = bmfCreate(NULL, 10);
73     index = 0;
74     lept_mkdir("lept/adapt");
75 
76         /* Using a variety of different thresholds */
77     GenCleans("cavalerie.29.jpg", &index, 80, bmf);
78     GenCleans("cavalerie.29.jpg", &index, 60, bmf);
79     GenCleans("cavalerie.29.jpg", &index, 40, bmf);
80     GenCleans("cavalerie.11.jpg", &index, 80, bmf);
81     GenCleans("cavalerie.11.jpg", &index, 60, bmf);
82     GenCleans("cavalerie.11.jpg", &index, 40, bmf);
83 
84         /* Read the images and convert to a 4-up pixa */
85     pixa1 = convertToNUpPixa("/tmp/lept/adapt", "adapt_", 2, 2, 500,
86                              6, 2, 0);
87 
88         /* Convert to pdf */
89     L_INFO("Writing to /tmp/lept/adapt/cleaning.pdf\n", procName);
90     pixaConvertToPdf(pixa1, 100, 1.0, L_JPEG_ENCODE,
91                      75, "Adaptive cleaning",
92                      "/tmp/lept/adapt/cleaning.pdf");
93     pixaDestroy(&pixa1);
94 
95         /* Test the pixac interleaving.  Make two copies,
96          * and interleave them:
97          *   (1) convert NUp 2 x 1
98          *   (2) convert twice to pixac
99          *   (3) interleave the two copies
100          *   (4) convert back to pixa
101          *   (5) convert NUp 1 x 2   (result now is 2 x 2)
102          *   (6) output as pdf   */
103     pixa1 = convertToNUpPixa("/tmp/lept/adapt", "adapt_", 2, 1, 500,
104                              6, 2, 0);
105     startTimer();
106     pixac1 = pixacompCreateFromPixa(pixa1, IFF_DEFAULT, L_CLONE);
107     pixac2 = pixacompCreateFromPixa(pixa1, IFF_DEFAULT, L_CLONE);
108     pixac3 = pixacompInterleave(pixac1, pixac2);
109     pixa2 = pixaCreateFromPixacomp(pixac3, L_CLONE);
110     pixa3 = pixaConvertToNUpPixa(pixa2, NULL, 1, 2, 1000, 6, 2, 0);
111     fprintf(stderr, "Time with pixac interleaving = %7.3f sec\n", stopTimer());
112     L_INFO("Writing to /tmp/lept/adapt/cleaning2.pdf\n", procName);
113     pixaConvertToPdf(pixa3, 100, 1.0, L_JPEG_ENCODE,
114                      75, "Adaptive cleaning", "/tmp/lept/adapt/cleaning2.pdf");
115     pixaDestroy(&pixa1);
116     pixaDestroy(&pixa2);
117     pixaDestroy(&pixa3);
118     pixacompDestroy(&pixac1);
119     pixacompDestroy(&pixac2);
120     pixacompDestroy(&pixac3);
121 
122         /* Test the pixa interleaving.  Make two copies,
123          * and interleave them:
124          *   (1) convert NUp 2 x 1
125          *   (2) copy and interleave
126          *   (3) convert NUp 1 x 2   (result now is 2 x 2)
127          *   (4) output as pdf   */
128     pixa1 = convertToNUpPixa("/tmp/lept/adapt", "adapt_", 2, 1, 500,
129                              6, 2, 0);
130     startTimer();
131     pixa2 = pixaCopy(pixa1, L_COPY_CLONE);
132     pixa3 = pixaInterleave(pixa1, pixa2, L_CLONE);
133     pixa4 = pixaConvertToNUpPixa(pixa3, NULL, 1, 2, 1000, 6, 2, 0);
134     fprintf(stderr, "Time with pixa interleaving = %7.3f sec\n", stopTimer());
135     L_INFO("Writing to /tmp/lept/adapt/cleaning3.pdf\n", procName);
136     pixaConvertToPdf(pixa4, 100, 1.0, L_JPEG_ENCODE,
137                      75, "Adaptive cleaning", "/tmp/lept/adapt/cleaning3.pdf");
138     pixaDestroy(&pixa1);
139     pixaDestroy(&pixa2);
140     pixaDestroy(&pixa3);
141     pixaDestroy(&pixa4);
142     bmfDestroy(&bmf);
143     return 0;
144 }
145 
146 void
GenCleans(const char * fname,l_int32 * pindex,l_int32 thresh,L_BMF * bmf)147 GenCleans(const char  *fname,
148           l_int32     *pindex,
149           l_int32      thresh,
150           L_BMF       *bmf)
151 {
152 l_int32  index, blackval, whiteval;
153 char     buf[256];
154 PIX     *pix1, *pix2, *pix3, *pix4, *pix5;
155 
156     blackval = 70;
157     whiteval = 180;
158     index = *pindex;
159     pix1 = pixRead(fname);
160     snprintf(buf, sizeof(buf), "/tmp/lept/adapt/adapt_%03d.jpg", index++);
161     pixWrite(buf, pix1, IFF_JFIF_JPEG);
162 
163     pix2 = pixBackgroundNorm(pix1, NULL, NULL, 10, 15, thresh, 25, 200, 2, 1);
164     snprintf(buf, sizeof(buf), "Norm color: fg thresh = %d", thresh);
165     fprintf(stderr, "%s\n", buf);
166     pix3 = pixAddTextlines(pix2, bmf, buf, 0x00ff0000, L_ADD_BELOW);
167     snprintf(buf, sizeof(buf), "/tmp/lept/adapt/adapt_%03d.jpg", index++);
168     pixWrite(buf, pix3, IFF_JFIF_JPEG);
169     pixDestroy(&pix3);
170     pix3 = pixGammaTRC(NULL, pix2, 1.0, blackval, whiteval);
171     snprintf(buf, sizeof(buf), "Clean color: fg thresh = %d", thresh);
172     pix4 = pixAddSingleTextblock(pix3, bmf, buf, 0x00ff0000, L_ADD_BELOW, NULL);
173     snprintf(buf, sizeof(buf), "/tmp/lept/adapt/adapt_%03d.jpg", index++);
174     pixWrite(buf, pix4, IFF_JFIF_JPEG);
175     pixDestroy(&pix2);
176     pixDestroy(&pix3);
177     pixDestroy(&pix4);
178 
179     pix2 = pixConvertRGBToGray(pix1, 0.33, 0.34, 0.33);
180     pix3 = pixBackgroundNorm(pix2, NULL, NULL, 10, 15, thresh, 25, 200, 2, 1);
181     pix4 = pixGammaTRC(NULL, pix3, 1.0, blackval, whiteval);
182     snprintf(buf, sizeof(buf), "Clean gray: fg thresh = %d", thresh);
183     pix5 = pixAddSingleTextblock(pix4, bmf, buf, 0x00ff0000, L_ADD_BELOW, NULL);
184     snprintf(buf, sizeof(buf), "/tmp/lept/adapt/adapt_%03d.jpg", index++);
185     pixWrite(buf, pix5, IFF_JFIF_JPEG);
186     pixDestroy(&pix2);
187     pixDestroy(&pix3);
188     pixDestroy(&pix4);
189     pixDestroy(&pix5);
190 
191     pixDestroy(&pix1);
192     *pindex = index;
193     return;
194 }
195