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