Coverage Report

Created: 2024-07-27 06:27

/src/leptonica/src/grayquant.c
Line
Count
Source (jump to first uncovered line)
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
 * \file grayquant.c
29
 * <pre>
30
 *
31
 *      Thresholding from 8 bpp to 1 bpp
32
 *
33
 *          Floyd-Steinberg dithering to binary
34
 *              PIX         *pixDitherToBinary()
35
 *              PIX         *pixDitherToBinarySpec()
36
 *              static void  ditherToBinaryLow()
37
 *              void         ditherToBinaryLineLow()
38
 *
39
 *          Simple (pixelwise) binarization with fixed threshold
40
 *              PIX         *pixThresholdToBinary()
41
 *              static void  thresholdToBinaryLow()
42
 *              void         thresholdToBinaryLineLow()
43
 *
44
 *          Binarization with variable threshold
45
 *              PIX         *pixVarThresholdToBinary()
46
 *
47
 *          Binarization by adaptive mapping
48
 *              PIX         *pixAdaptThresholdToBinary()
49
 *              PIX         *pixAdaptThresholdToBinaryGen()
50
 *
51
 *          Generate a binary mask from pixels of particular values
52
 *              PIX         *pixGenerateMaskByValue()
53
 *              PIX         *pixGenerateMaskByBand()
54
 *
55
 *      Thresholding from 8 bpp to 2 bpp
56
 *
57
 *          Floyd-Steinberg-like dithering to 2 bpp
58
 *              PIX         *pixDitherTo2bpp()
59
 *              PIX         *pixDitherTo2bppSpec()
60
 *              static void  ditherTo2bppLow()
61
 *              static void  ditherTo2bppLineLow()
62
 *              static l_int32  make8To2DitherTables()
63
 *
64
 *          Simple (pixelwise) thresholding to 2 bpp with optional cmap
65
 *              PIX         *pixThresholdTo2bpp()
66
 *              static void  thresholdTo2bppLow()
67
 *
68
 *      Simple (pixelwise) thresholding from 8 bpp to 4 bpp
69
 *              PIX         *pixThresholdTo4bpp()
70
 *              static void  thresholdTo4bppLow()
71
 *
72
 *      Simple (pixelwise) quantization on 8 bpp grayscale
73
 *              PIX         *pixThresholdOn8bpp()
74
 *
75
 *      Arbitrary (pixelwise) thresholding from 8 bpp to 2, 4 or 8 bpp
76
 *              PIX         *pixThresholdGrayArb()
77
 *
78
 *      Quantization tables for linear thresholds of grayscale images
79
 *              l_int32     *makeGrayQuantIndexTable()
80
 *              static l_int32  *makeGrayQuantTargetTable()
81
 *
82
 *      Quantization table for arbitrary thresholding of grayscale images
83
 *              l_int32      makeGrayQuantTableArb()
84
 *              static l_int32   makeGrayQuantColormapArb()
85
 *
86
 *      Thresholding from 32 bpp rgb to 1 bpp
87
 *      (really color quantization, but it's better placed in this file)
88
 *              PIX         *pixGenerateMaskByBand32()
89
 *              PIX         *pixGenerateMaskByDiscr32()
90
 *
91
 *      Histogram-based grayscale quantization
92
 *              PIX         *pixGrayQuantFromHisto()
93
 *              static l_int32  numaFillCmapFromHisto()
94
 *
95
 *      Color quantize grayscale image using existing colormap
96
 *              PIX         *pixGrayQuantFromCmap()
97
 * </pre>
98
 */
99
100
#ifdef HAVE_CONFIG_H
101
#include <config_auto.h>
102
#endif  /* HAVE_CONFIG_H */
103
104
#include <string.h>
105
#include <math.h>
106
#include "allheaders.h"
107
108
static void ditherToBinaryLow(l_uint32 *datad, l_int32 w, l_int32 h,
109
                              l_int32 wpld, l_uint32 *datas, l_int32 wpls,
110
                              l_uint32 *bufs1, l_uint32 *bufs2,
111
                              l_int32 lowerclip, l_int32 upperclip);
112
static void thresholdToBinaryLow(l_uint32 *datad, l_int32 w, l_int32 h,
113
                                 l_int32 wpld, l_uint32 *datas, l_int32 d,
114
                                 l_int32 wpls, l_int32 thresh);
115
static void ditherTo2bppLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld,
116
                            l_uint32 *datas, l_int32 wpls, l_uint32 *bufs1,
117
                            l_uint32 *bufs2, l_int32 *tabval, l_int32 *tab38,
118
                            l_int32   *tab14);
119
static void ditherTo2bppLineLow(l_uint32 *lined, l_int32 w, l_uint32 *bufs1,
120
                                l_uint32 *bufs2, l_int32 *tabval,
121
                                l_int32 *tab38, l_int32 *tab14,
122
                                l_int32 lastlineflag);
123
static l_int32 make8To2DitherTables(l_int32 **ptabval, l_int32 **ptab38,
124
                                    l_int32 **ptab14, l_int32 cliptoblack,
125
                                    l_int32 cliptowhite);
126
static void thresholdTo2bppLow(l_uint32 *datad, l_int32 h, l_int32 wpld,
127
                               l_uint32 *datas, l_int32 wpls, l_int32 *tab);
128
static void thresholdTo4bppLow(l_uint32 *datad, l_int32 h, l_int32 wpld,
129
                               l_uint32 *datas, l_int32 wpls, l_int32 *tab);
130
static l_int32 *makeGrayQuantTargetTable(l_int32 nlevels, l_int32 depth);
131
static l_int32 makeGrayQuantColormapArb(PIX *pixs, l_int32 *tab,
132
                                        l_int32 outdepth, PIXCMAP **pcmap);
133
static l_int32 numaFillCmapFromHisto(NUMA *na, PIXCMAP *cmap,
134
                                     l_float32 minfract, l_int32 maxsize,
135
                                     l_int32 **plut);
136
137
#ifndef  NO_CONSOLE_IO
138
#define DEBUG_UNROLLING 0
139
#endif   /* ~NO_CONSOLE_IO */
140
141
/*------------------------------------------------------------------*
142
 *             Binarization by Floyd-Steinberg dithering            *
143
 *------------------------------------------------------------------*/
144
/*!
145
 * \brief   pixDitherToBinary()
146
 *
147
 * \param[in]    pixs
148
 * \return  pixd dithered binary, or NULL on error
149
 *
150
 *  The Floyd-Steinberg error diffusion dithering algorithm
151
 *  binarizes an 8 bpp grayscale image to a threshold of 128.
152
 *  If a pixel has a value above 127, it is binarized to white
153
 *  and the excess below 255 is subtracted from three
154
 *  neighboring pixels in the fractions 3/8 to i, j+1,
155
 *  3/8 to i+1, j) and 1/4 to (i+1,j+1, truncating to 0
156
 *  if necessary.  Likewise, if it the pixel has a value
157
 *  below 128, it is binarized to black and the excess above 0
158
 *  is added to the neighboring pixels, truncating to 255 if necessary.
159
 *
160
 *  This function differs from straight dithering in that it allows
161
 *  clipping of grayscale to 0 or 255 if the values are
162
 *  sufficiently close, without distribution of the excess.
163
 *  This uses default values to specify the range of lower
164
 *  and upper values near 0 and 255, rsp that are clipped
165
 *  to black and white without propagating the excess.
166
 *  Not propagating the excess has the effect of reducing the
167
 *  snake patterns in parts of the image that are nearly black or white;
168
 *  however, it also prevents the attempt to reproduce gray for those values.
169
 *
170
 *  The implementation is straightforward.  It uses a pair of
171
 *  line buffers to avoid changing pixs.  It is about the same speed
172
 *  as pixDitherToBinaryLUT(), which uses three LUTs.
173
 */
174
PIX *
175
pixDitherToBinary(PIX  *pixs)
176
0
{
177
0
    if (!pixs)
178
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
179
0
    if (pixGetDepth(pixs) != 8)
180
0
        return (PIX *)ERROR_PTR("must be 8 bpp for dithering", __func__, NULL);
181
182
0
    return pixDitherToBinarySpec(pixs, DEFAULT_CLIP_LOWER_1,
183
0
                                 DEFAULT_CLIP_UPPER_1);
184
0
}
185
186
187
/*!
188
 * \brief   pixDitherToBinarySpec()
189
 *
190
 * \param[in]    pixs
191
 * \param[in]    lowerclip   lower clip distance to black; use 0 for default
192
 * \param[in]    upperclip   upper clip distance to white; use 0 for default
193
 * \return  pixd dithered binary, or NULL on error
194
 *
195
 * <pre>
196
 * Notes:
197
 *      (1) See comments above in pixDitherToBinary() for details.
198
 *      (2) The input parameters lowerclip and upperclip specify the range
199
 *          of lower and upper values (near 0 and 255, rsp) that are
200
 *          clipped to black and white without propagating the excess.
201
 *          For that reason, lowerclip and upperclip should be small numbers.
202
 * </pre>
203
 */
204
PIX *
205
pixDitherToBinarySpec(PIX     *pixs,
206
                      l_int32  lowerclip,
207
                      l_int32  upperclip)
208
0
{
209
0
l_int32    w, h, d, wplt, wpld;
210
0
l_uint32  *datat, *datad;
211
0
l_uint32  *bufs1, *bufs2;
212
0
PIX       *pixt, *pixd;
213
214
0
    if (!pixs)
215
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
216
0
    pixGetDimensions(pixs, &w, &h, &d);
217
0
    if (d != 8)
218
0
        return (PIX *)ERROR_PTR("must be 8 bpp for dithering", __func__, NULL);
219
0
    if (lowerclip < 0 || lowerclip > 255)
220
0
        return (PIX *)ERROR_PTR("invalid value for lowerclip", __func__, NULL);
221
0
    if (upperclip < 0 || upperclip > 255)
222
0
        return (PIX *)ERROR_PTR("invalid value for upperclip", __func__, NULL);
223
224
0
    if ((pixd = pixCreate(w, h, 1)) == NULL)
225
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
226
0
    pixCopyResolution(pixd, pixs);
227
0
    pixCopyInputFormat(pixd, pixs);
228
0
    datad = pixGetData(pixd);
229
0
    wpld = pixGetWpl(pixd);
230
231
        /* Remove colormap if it exists */
232
0
    if ((pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE)) == NULL) {
233
0
        pixDestroy(&pixd);
234
0
        return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
235
0
    }
236
0
    datat = pixGetData(pixt);
237
0
    wplt = pixGetWpl(pixt);
238
239
        /* Two line buffers, 1 for current line and 2 for next line */
240
0
    bufs1 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
241
0
    bufs2 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
242
0
    if (!bufs1 || !bufs2) {
243
0
        LEPT_FREE(bufs1);
244
0
        LEPT_FREE(bufs2);
245
0
        pixDestroy(&pixd);
246
0
        pixDestroy(&pixt);
247
0
        return (PIX *)ERROR_PTR("bufs1, bufs2 not both made", __func__, NULL);
248
0
    }
249
250
0
    ditherToBinaryLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2,
251
0
                      lowerclip, upperclip);
252
253
0
    LEPT_FREE(bufs1);
254
0
    LEPT_FREE(bufs2);
255
0
    pixDestroy(&pixt);
256
0
    return pixd;
257
0
}
258
259
260
/*!
261
 * \brief   ditherToBinaryLow()
262
 *
263
 *  See comments in pixDitherToBinary() in binarize.c
264
 */
265
static void
266
ditherToBinaryLow(l_uint32  *datad,
267
                  l_int32    w,
268
                  l_int32    h,
269
                  l_int32    wpld,
270
                  l_uint32  *datas,
271
                  l_int32    wpls,
272
                  l_uint32  *bufs1,
273
                  l_uint32  *bufs2,
274
                  l_int32    lowerclip,
275
                  l_int32    upperclip)
276
0
{
277
0
l_int32    i;
278
0
l_uint32  *lined;
279
280
        /* do all lines except last line */
281
0
    memcpy(bufs2, datas, 4 * wpls);  /* prime the buffer */
282
0
    for (i = 0; i < h - 1; i++) {
283
0
        memcpy(bufs1, bufs2, 4 * wpls);
284
0
        memcpy(bufs2, datas + (i + 1) * wpls, 4 * wpls);
285
0
        lined = datad + i * wpld;
286
0
        ditherToBinaryLineLow(lined, w, bufs1, bufs2, lowerclip, upperclip, 0);
287
0
    }
288
289
        /* do last line */
290
0
    memcpy(bufs1, bufs2, 4 * wpls);
291
0
    lined = datad + (h - 1) * wpld;
292
0
    ditherToBinaryLineLow(lined, w, bufs1, bufs2, lowerclip, upperclip, 1);
293
0
}
294
295
296
/*!
297
 * \brief   ditherToBinaryLineLow()
298
 *
299
 * \param[in]    lined         ptr to beginning of dest line
300
 * \param[in]    w             width of image in pixels
301
 * \param[in]    bufs1         buffer of current source line
302
 * \param[in]    bufs2         buffer of next source line
303
 * \param[in]    lowerclip     lower clip distance to black
304
 * \param[in]    upperclip     upper clip distance to white
305
 * \param[in]    lastlineflag  0 if not last dest line, 1 if last dest line
306
 * \return  void
307
 *
308
 *  Dispatches FS error diffusion dithering for
309
 *  a single line of the image.  If lastlineflag == 0,
310
 *  both source buffers are used; otherwise, only bufs1
311
 *  is used.  We use source buffers because the error
312
 *  is propagated into them, and we don't want to change
313
 *  the input src image.
314
 *
315
 *  We break dithering out line by line to make it
316
 *  easier to combine functions like interpolative
317
 *  scaling and error diffusion dithering, as such a
318
 *  combination of operations obviates the need to
319
 *  generate a 2x grayscale image as an intermediary.
320
 */
321
void
322
ditherToBinaryLineLow(l_uint32  *lined,
323
                      l_int32    w,
324
                      l_uint32  *bufs1,
325
                      l_uint32  *bufs2,
326
                      l_int32    lowerclip,
327
                      l_int32    upperclip,
328
                      l_int32    lastlineflag)
329
0
{
330
0
l_int32   j;
331
0
l_int32   oval, eval;
332
0
l_uint8   fval1, fval2, rval, bval, dval;
333
334
0
    if (lastlineflag == 0) {
335
0
        for (j = 0; j < w - 1; j++) {
336
0
            oval = GET_DATA_BYTE(bufs1, j);
337
0
            if (oval > 127) {   /* binarize to OFF */
338
0
                if ((eval = 255 - oval) > upperclip) {
339
                        /* subtract from neighbors */
340
0
                    fval1 = (3 * eval) / 8;
341
0
                    fval2 = eval / 4;
342
0
                    rval = GET_DATA_BYTE(bufs1, j + 1);
343
0
                    rval = L_MAX(0, rval - fval1);
344
0
                    SET_DATA_BYTE(bufs1, j + 1, rval);
345
0
                    bval = GET_DATA_BYTE(bufs2, j);
346
0
                    bval = L_MAX(0, bval - fval1);
347
0
                    SET_DATA_BYTE(bufs2, j, bval);
348
0
                    dval = GET_DATA_BYTE(bufs2, j + 1);
349
0
                    dval = L_MAX(0, dval - fval2);
350
0
                    SET_DATA_BYTE(bufs2, j + 1, dval);
351
0
                }
352
0
            } else {   /* oval <= 127; binarize to ON  */
353
0
                SET_DATA_BIT(lined, j);   /* ON pixel */
354
0
                if (oval > lowerclip) {
355
                        /* add to neighbors */
356
0
                    fval1 = (3 * oval) / 8;
357
0
                    fval2 = oval / 4;
358
0
                    rval = GET_DATA_BYTE(bufs1, j + 1);
359
0
                    rval = L_MIN(255, rval + fval1);
360
0
                    SET_DATA_BYTE(bufs1, j + 1, rval);
361
0
                    bval = GET_DATA_BYTE(bufs2, j);
362
0
                    bval = L_MIN(255, bval + fval1);
363
0
                    SET_DATA_BYTE(bufs2, j, bval);
364
0
                    dval = GET_DATA_BYTE(bufs2, j + 1);
365
0
                    dval = L_MIN(255, dval + fval2);
366
0
                    SET_DATA_BYTE(bufs2, j + 1, dval);
367
0
                }
368
0
            }
369
0
        }
370
371
            /* do last column: j = w - 1 */
372
0
        oval = GET_DATA_BYTE(bufs1, j);
373
0
        if (oval > 127) {  /* binarize to OFF */
374
0
            if ((eval = 255 - oval) > upperclip) {
375
                    /* subtract from neighbors */
376
0
                fval1 = (3 * eval) / 8;
377
0
                bval = GET_DATA_BYTE(bufs2, j);
378
0
                bval = L_MAX(0, bval - fval1);
379
0
                SET_DATA_BYTE(bufs2, j, bval);
380
0
            }
381
0
        } else {  /*oval <= 127; binarize to ON */
382
0
            SET_DATA_BIT(lined, j);   /* ON pixel */
383
0
            if (oval > lowerclip) {
384
                    /* add to neighbors */
385
0
                fval1 = (3 * oval) / 8;
386
0
                bval = GET_DATA_BYTE(bufs2, j);
387
0
                bval = L_MIN(255, bval + fval1);
388
0
                SET_DATA_BYTE(bufs2, j, bval);
389
0
            }
390
0
        }
391
0
    } else {   /* lastlineflag == 1 */
392
0
        for (j = 0; j < w - 1; j++) {
393
0
            oval = GET_DATA_BYTE(bufs1, j);
394
0
            if (oval > 127) {   /* binarize to OFF */
395
0
                if ((eval = 255 - oval) > upperclip) {
396
                        /* subtract from neighbors */
397
0
                    fval1 = (3 * eval) / 8;
398
0
                    rval = GET_DATA_BYTE(bufs1, j + 1);
399
0
                    rval = L_MAX(0, rval - fval1);
400
0
                    SET_DATA_BYTE(bufs1, j + 1, rval);
401
0
                }
402
0
            } else {   /* oval <= 127; binarize to ON  */
403
0
                SET_DATA_BIT(lined, j);   /* ON pixel */
404
0
                if (oval > lowerclip) {
405
                        /* add to neighbors */
406
0
                    fval1 = (3 * oval) / 8;
407
0
                    rval = GET_DATA_BYTE(bufs1, j + 1);
408
0
                    rval = L_MIN(255, rval + fval1);
409
0
                    SET_DATA_BYTE(bufs1, j + 1, rval);
410
0
                }
411
0
            }
412
0
        }
413
414
            /* do last pixel: (i, j) = (h - 1, w - 1) */
415
0
        oval = GET_DATA_BYTE(bufs1, j);
416
0
        if (oval < 128)
417
0
            SET_DATA_BIT(lined, j);   /* ON pixel */
418
0
    }
419
0
}
420
421
422
/*------------------------------------------------------------------*
423
 *       Simple (pixelwise) binarization with fixed threshold       *
424
 *------------------------------------------------------------------*/
425
/*!
426
 * \brief   pixThresholdToBinary()
427
 *
428
 * \param[in]    pixs     4 or 8 bpp
429
 * \param[in]    thresh   threshold value
430
 * \return  pixd 1 bpp, or NULL on error
431
 *
432
 * <pre>
433
 * Notes:
434
 *      (1) If the source pixel is less than the threshold value,
435
 *          the dest will be 1; otherwise, it will be 0.
436
 *      (2) For example, for 8 bpp src pix, if %thresh == 256, the dest
437
 *          1 bpp pix is all ones (fg), and if %thresh == 0, the dest
438
 *          pix is all zeros (bg).
439
 *
440
 * </pre>
441
 */
442
PIX *
443
pixThresholdToBinary(PIX     *pixs,
444
                     l_int32  thresh)
445
0
{
446
0
l_int32    d, w, h, wplt, wpld;
447
0
l_uint32  *datat, *datad;
448
0
PIX       *pixt, *pixd;
449
450
0
    if (!pixs)
451
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
452
0
    pixGetDimensions(pixs, &w, &h, &d);
453
0
    if (d != 4 && d != 8)
454
0
        return (PIX *)ERROR_PTR("pixs must be 4 or 8 bpp", __func__, NULL);
455
0
    if (thresh < 0)
456
0
        return (PIX *)ERROR_PTR("thresh must be non-negative", __func__, NULL);
457
0
    if (d == 4 && thresh > 16)
458
0
        return (PIX *)ERROR_PTR("4 bpp thresh not in {0-16}", __func__, NULL);
459
0
    if (d == 8 && thresh > 256)
460
0
        return (PIX *)ERROR_PTR("8 bpp thresh not in {0-256}", __func__, NULL);
461
462
0
    if ((pixd = pixCreate(w, h, 1)) == NULL)
463
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
464
0
    pixCopyResolution(pixd, pixs);
465
0
    pixCopyInputFormat(pixd, pixs);
466
0
    datad = pixGetData(pixd);
467
0
    wpld = pixGetWpl(pixd);
468
469
        /* Remove colormap if it exists.  If there is a colormap,
470
         * pixt will be 8 bpp regardless of the depth of pixs. */
471
0
    pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
472
0
    datat = pixGetData(pixt);
473
0
    wplt = pixGetWpl(pixt);
474
0
    if (pixGetColormap(pixs) && d == 4) {  /* promoted to 8 bpp */
475
0
        d = 8;
476
0
        thresh *= 16;
477
0
    }
478
479
0
    thresholdToBinaryLow(datad, w, h, wpld, datat, d, wplt, thresh);
480
0
    pixDestroy(&pixt);
481
0
    return pixd;
482
0
}
483
484
485
/*!
486
 * \brief   thresholdToBinaryLow()
487
 *
488
 *  If the source pixel is less than thresh,
489
 *  the dest will be 1; otherwise, it will be 0
490
 */
491
static void
492
thresholdToBinaryLow(l_uint32  *datad,
493
                     l_int32    w,
494
                     l_int32    h,
495
                     l_int32    wpld,
496
                     l_uint32  *datas,
497
                     l_int32    d,
498
                     l_int32    wpls,
499
                     l_int32    thresh)
500
0
{
501
0
l_int32    i;
502
0
l_uint32  *lines, *lined;
503
504
0
    for (i = 0; i < h; i++) {
505
0
        lines = datas + i * wpls;
506
0
        lined = datad + i * wpld;
507
0
        thresholdToBinaryLineLow(lined, w, lines, d, thresh);
508
0
    }
509
0
}
510
511
512
/*
513
 *  thresholdToBinaryLineLow()
514
 *
515
 */
516
void
517
thresholdToBinaryLineLow(l_uint32  *lined,
518
                         l_int32    w,
519
                         l_uint32  *lines,
520
                         l_int32    d,
521
                         l_int32    thresh)
522
0
{
523
0
l_int32  j, k, gval, scount, dcount;
524
0
l_uint32 sword, dword;
525
526
0
    switch (d)
527
0
    {
528
0
    case 4:
529
            /* Unrolled as 4 source words, 1 dest word */
530
0
        for (j = 0, scount = 0, dcount = 0; j + 31 < w; j += 32) {
531
0
            dword = 0;
532
0
            for (k = 0; k < 4; k++) {
533
0
                sword = lines[scount++];
534
0
                dword <<= 8;
535
0
                gval = (sword >> 28) & 0xf;
536
                    /* Trick used here and below: if gval < thresh then
537
                     * gval - thresh < 0, so its high-order bit is 1, and
538
                     * ((gval - thresh) >> 31) & 1 == 1; likewise, if
539
                     * gval >= thresh, then ((gval - thresh) >> 31) & 1 == 0
540
                     * Doing it this way avoids a random (and thus easily
541
                     * mispredicted) branch on each pixel. */
542
0
                dword |= ((gval - thresh) >> 24) & 128;
543
0
                gval = (sword >> 24) & 0xf;
544
0
                dword |= ((gval - thresh) >> 25) & 64;
545
0
                gval = (sword >> 20) & 0xf;
546
0
                dword |= ((gval - thresh) >> 26) & 32;
547
0
                gval = (sword >> 16) & 0xf;
548
0
                dword |= ((gval - thresh) >> 27) & 16;
549
0
                gval = (sword >> 12) & 0xf;
550
0
                dword |= ((gval - thresh) >> 28) & 8;
551
0
                gval = (sword >> 8) & 0xf;
552
0
                dword |= ((gval - thresh) >> 29) & 4;
553
0
                gval = (sword >> 4) & 0xf;
554
0
                dword |= ((gval - thresh) >> 30) & 2;
555
0
                gval = sword & 0xf;
556
0
                dword |= ((gval - thresh) >> 31) & 1;
557
0
            }
558
0
            lined[dcount++] = dword;
559
0
        }
560
561
0
        if (j < w) {
562
0
          dword = 0;
563
0
          for (; j < w; j++) {
564
0
              if ((j & 7) == 0) {
565
0
                  sword = lines[scount++];
566
0
              }
567
0
              gval = (sword >> 28) & 0xf;
568
0
              sword <<= 4;
569
0
              dword |= (((gval - thresh) >> 31) & 1) << (31 - (j & 31));
570
0
          }
571
0
          lined[dcount] = dword;
572
0
        }
573
#if DEBUG_UNROLLING
574
#define CHECK_BIT(a, b, c) if (GET_DATA_BIT(a, b) != c) { \
575
    lept_stderr("Error: mismatch at %d/%d(%d), %d vs %d\n", \
576
                j, w, d, GET_DATA_BIT(a, b), c); }
577
        for (j = 0; j < w; j++) {
578
            gval = GET_DATA_QBIT(lines, j);
579
            CHECK_BIT(lined, j, gval < thresh ? 1 : 0);
580
        }
581
#endif
582
0
        break;
583
0
    case 8:
584
            /* Unrolled as 8 source words, 1 dest word */
585
0
        for (j = 0, scount = 0, dcount = 0; j + 31 < w; j += 32) {
586
0
            dword = 0;
587
0
            for (k = 0; k < 8; k++) {
588
0
                sword = lines[scount++];
589
0
                dword <<= 4;
590
0
                gval = (sword >> 24) & 0xff;
591
0
                dword |= ((gval - thresh) >> 28) & 8;
592
0
                gval = (sword >> 16) & 0xff;
593
0
                dword |= ((gval - thresh) >> 29) & 4;
594
0
                gval = (sword >> 8) & 0xff;
595
0
                dword |= ((gval - thresh) >> 30) & 2;
596
0
                gval = sword & 0xff;
597
0
                dword |= ((gval - thresh) >> 31) & 1;
598
0
            }
599
0
            lined[dcount++] = dword;
600
0
        }
601
602
0
        if (j < w) {
603
0
            dword = 0;
604
0
            for (; j < w; j++) {
605
0
                if ((j & 3) == 0) {
606
0
                    sword = lines[scount++];
607
0
                }
608
0
                gval = (sword >> 24) & 0xff;
609
0
                sword <<= 8;
610
0
                dword |= (l_uint64)(((gval - thresh) >> 31) & 1)
611
0
                             << (31 - (j & 31));
612
0
            }
613
0
            lined[dcount] = dword;
614
0
        }
615
#if DEBUG_UNROLLING
616
        for (j = 0; j < w; j++) {
617
            gval = GET_DATA_BYTE(lines, j);
618
            CHECK_BIT(lined, j, gval < thresh ? 1 : 0);
619
        }
620
#undef CHECK_BIT
621
#endif
622
0
        break;
623
0
    default:
624
0
        L_ERROR("src depth not 4 or 8 bpp\n", __func__);
625
0
        break;
626
0
    }
627
0
}
628
629
630
/*------------------------------------------------------------------*
631
 *                Binarization with variable threshold              *
632
 *------------------------------------------------------------------*/
633
/*!
634
 * \brief   pixVarThresholdToBinary()
635
 *
636
 * \param[in]    pixs    8 bpp
637
 * \param[in]    pixg    8 bpp; contains threshold values for each pixel
638
 * \return  pixd 1 bpp, or NULL on error
639
 *
640
 * <pre>
641
 * Notes:
642
 *      (1) If the pixel in pixs is less than the corresponding pixel
643
 *          in pixg, the dest will be 1; otherwise it will be 0.
644
 * </pre>
645
 */
646
PIX *
647
pixVarThresholdToBinary(PIX  *pixs,
648
                        PIX  *pixg)
649
0
{
650
0
l_int32    i, j, vals, valg, w, h, d, wpls, wplg, wpld;
651
0
l_uint32  *datas, *datag, *datad, *lines, *lineg, *lined;
652
0
PIX       *pixd;
653
654
0
    if (!pixs)
655
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
656
0
    if (!pixg)
657
0
        return (PIX *)ERROR_PTR("pixg not defined", __func__, NULL);
658
0
    if (!pixSizesEqual(pixs, pixg))
659
0
        return (PIX *)ERROR_PTR("pix sizes not equal", __func__, NULL);
660
0
    pixGetDimensions(pixs, &w, &h, &d);
661
0
    if (d != 8)
662
0
        return (PIX *)ERROR_PTR("pixs must be 8 bpp", __func__, NULL);
663
664
0
    pixd = pixCreate(w, h, 1);
665
0
    pixCopyResolution(pixd, pixs);
666
0
    pixCopyInputFormat(pixd, pixs);
667
0
    datad = pixGetData(pixd);
668
0
    wpld = pixGetWpl(pixd);
669
0
    datas = pixGetData(pixs);
670
0
    wpls = pixGetWpl(pixs);
671
0
    datag = pixGetData(pixg);
672
0
    wplg = pixGetWpl(pixg);
673
0
    for (i = 0; i < h; i++) {
674
0
        lines = datas + i * wpls;
675
0
        lineg = datag + i * wplg;
676
0
        lined = datad + i * wpld;
677
0
        for (j = 0; j < w; j++) {
678
0
            vals = GET_DATA_BYTE(lines, j);
679
0
            valg = GET_DATA_BYTE(lineg, j);
680
0
            if (vals < valg)
681
0
                SET_DATA_BIT(lined, j);
682
0
        }
683
0
    }
684
685
0
    return pixd;
686
0
}
687
688
689
/*------------------------------------------------------------------*
690
 *                  Binarization by adaptive mapping                *
691
 *------------------------------------------------------------------*/
692
/*!
693
 * \brief   pixAdaptThresholdToBinary()
694
 *
695
 * \param[in]    pixs    8 bpp
696
 * \param[in]    pixm    [optional] 1 bpp image mask; can be null
697
 * \param[in]    gamma   gamma correction; must be > 0.0; typically ~1.0
698
 * \return  pixd 1 bpp, or NULL on error
699
 *
700
 * <pre>
701
 * Notes:
702
 *      (1) This is a simple convenience function for doing adaptive
703
 *          thresholding on a grayscale image with variable background.
704
 *          It uses default parameters appropriate for typical text images.
705
 *          Other high-level adaptive thresholding functions are
706
 *          pixConvertTo1Adaptive() and pixCleanImage().
707
 *      (2) %pixm is a 1 bpp mask over "image" regions, which are not
708
 *          expected to have a white background.  The mask inhibits
709
 *          background finding under the fg pixels of the mask.  For
710
 *          images with both text and image, the image regions would
711
 *          be binarized (or quantized) by a different set of operations.
712
 *      (3) As %gamma is increased, the foreground pixels are reduced.
713
 *      (4) Under the covers:  The default background value for normalization
714
 *          is 200, so we choose 170 for 'maxval' in pixGammaTRC.  Likewise,
715
 *          the default foreground threshold for normalization is 60,
716
 *          so we choose 50 for 'minval' in pixGammaTRC.  Because
717
 *          170 was mapped to 255, choosing 200 for the threshold is
718
 *          quite safe for avoiding speckle noise from the background.
719
 * </pre>
720
 */
721
PIX *
722
pixAdaptThresholdToBinary(PIX       *pixs,
723
                          PIX       *pixm,
724
                          l_float32  gamma)
725
0
{
726
0
    if (!pixs || pixGetDepth(pixs) != 8)
727
0
        return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
728
729
0
    return pixAdaptThresholdToBinaryGen(pixs, pixm, gamma, 50, 170, 200);
730
0
}
731
732
733
/*!
734
 * \brief   pixAdaptThresholdToBinaryGen()
735
 *
736
 * \param[in]    pixs       8 bpp
737
 * \param[in]    pixm       [optional] 1 bpp image mask; can be null
738
 * \param[in]    gamma      gamma correction; must be > 0.0; typically ~1.0
739
 * \param[in]    blackval   dark value to set to black (0)
740
 * \param[in]    whiteval   light value to set to white (255)
741
 * \param[in]    thresh     final threshold for binarization
742
 * \return  pixd 1 bpp, or NULL on error
743
 *
744
 * <pre>
745
 * Notes:
746
 *      (1) This is a convenience function for doing adaptive thresholding
747
 *          on a grayscale image with variable background.  Also see notes
748
 *          in pixAdaptThresholdToBinary().
749
 *      (2) Reducing %gamma increases the foreground (text) pixels.
750
 *          Use a low value (e.g., 0.5) for images with light text.
751
 *      (3) For normal images, see default args in pixAdaptThresholdToBinary().
752
 *          For images with very light text, these values are appropriate:
753
 *             gamma     ~0.5
754
 *             blackval  ~70
755
 *             whiteval  ~190
756
 *             thresh    ~200
757
 * </pre>
758
 */
759
PIX *
760
pixAdaptThresholdToBinaryGen(PIX       *pixs,
761
                             PIX       *pixm,
762
                             l_float32  gamma,
763
                             l_int32    blackval,
764
                             l_int32    whiteval,
765
                             l_int32    thresh)
766
0
{
767
0
PIX  *pix1, *pixd;
768
769
0
    if (!pixs || pixGetDepth(pixs) != 8)
770
0
        return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
771
772
0
    if ((pix1 = pixBackgroundNormSimple(pixs, pixm, NULL)) == NULL)
773
0
        return (PIX *)ERROR_PTR("pix1 not made", __func__, NULL);
774
0
    pixGammaTRC(pix1, pix1, gamma, blackval, whiteval);
775
0
    pixd = pixThresholdToBinary(pix1, thresh);
776
0
    pixDestroy(&pix1);
777
0
    return pixd;
778
0
}
779
780
781
/*--------------------------------------------------------------------*
782
 *       Generate a binary mask from pixels of particular value(s)    *
783
 *--------------------------------------------------------------------*/
784
/*!
785
 * \brief   pixGenerateMaskByValue()
786
 *
787
 * \param[in]    pixs      2, 4 or 8 bpp, or colormapped
788
 * \param[in]    val       of pixels for which we set 1 in dest
789
 * \param[in]    usecmap   1 to retain cmap values; 0 to convert to gray
790
 * \return  pixd 1 bpp, or NULL on error
791
 *
792
 * <pre>
793
 * Notes:
794
 *      (1) %val is the pixel value that we are selecting.  It can be
795
 *          either a gray value or a colormap index.
796
 *      (2) If pixs is colormapped, %usecmap determines if the colormap
797
 *          index values are used, or if the colormap is removed to gray and
798
 *          the gray values are used.  For the latter, it generates
799
 *          an approximate grayscale value for each pixel, and then looks
800
 *          for gray pixels with the value %val.
801
 * </pre>
802
 */
803
PIX *
804
pixGenerateMaskByValue(PIX     *pixs,
805
                       l_int32  val,
806
                       l_int32  usecmap)
807
0
{
808
0
l_int32    i, j, w, h, d, wplg, wpld;
809
0
l_uint32  *datag, *datad, *lineg, *lined;
810
0
PIX       *pixg, *pixd;
811
812
0
    if (!pixs)
813
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
814
0
    d = pixGetDepth(pixs);
815
0
    if (d != 2 && d != 4 && d != 8)
816
0
        return (PIX *)ERROR_PTR("not 2, 4 or 8 bpp", __func__, NULL);
817
818
0
    if (!usecmap && pixGetColormap(pixs))
819
0
        pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
820
0
    else
821
0
        pixg = pixClone(pixs);
822
0
    pixGetDimensions(pixg, &w, &h, &d);
823
0
    if (d == 8 && (val < 0 || val > 255)) {
824
0
        pixDestroy(&pixg);
825
0
        return (PIX *)ERROR_PTR("val out of 8 bpp range", __func__, NULL);
826
0
    }
827
0
    if (d == 4 && (val < 0 || val > 15)) {
828
0
        pixDestroy(&pixg);
829
0
        return (PIX *)ERROR_PTR("val out of 4 bpp range", __func__, NULL);
830
0
    }
831
0
    if (d == 2 && (val < 0 || val > 3)) {
832
0
        pixDestroy(&pixg);
833
0
        return (PIX *)ERROR_PTR("val out of 2 bpp range", __func__, NULL);
834
0
    }
835
836
0
    pixd = pixCreate(w, h, 1);
837
0
    pixCopyResolution(pixd, pixg);
838
0
    pixCopyInputFormat(pixd, pixs);
839
0
    datag = pixGetData(pixg);
840
0
    wplg = pixGetWpl(pixg);
841
0
    datad = pixGetData(pixd);
842
0
    wpld = pixGetWpl(pixd);
843
0
    for (i = 0; i < h; i++) {
844
0
        lineg = datag + i * wplg;
845
0
        lined = datad + i * wpld;
846
0
        for (j = 0; j < w; j++) {
847
0
            if (d == 8) {
848
0
                if (GET_DATA_BYTE(lineg, j) == val)
849
0
                    SET_DATA_BIT(lined, j);
850
0
            } else if (d == 4) {
851
0
                if (GET_DATA_QBIT(lineg, j) == val)
852
0
                    SET_DATA_BIT(lined, j);
853
0
            } else {  /* d == 2 */
854
0
                if (GET_DATA_DIBIT(lineg, j) == val)
855
0
                    SET_DATA_BIT(lined, j);
856
0
            }
857
0
        }
858
0
    }
859
860
0
    pixDestroy(&pixg);
861
0
    return pixd;
862
0
}
863
864
865
/*!
866
 * \brief   pixGenerateMaskByBand()
867
 *
868
 * \param[in]    pixs           2, 4 or 8 bpp, or colormapped
869
 * \param[in]    lower, upper   two pixel values from which a range, either
870
 *                              between (inband) or outside of (!inband),
871
 *                              determines which pixels in pixs cause us to
872
 *                              set a 1 in the dest mask
873
 * \param[in]    inband         1 for finding pixels in [lower, upper];
874
 *                              0 for finding pixels in
875
 *                              [0, lower) union (upper, 255]
876
 * \param[in]    usecmap        1 to retain cmap values; 0 to convert to gray
877
 * \return  pixd 1 bpp, or NULL on error
878
 *
879
 * <pre>
880
 * Notes:
881
 *      (1) Generates a 1 bpp mask pixd, the same size as pixs, where
882
 *          the fg pixels in the mask are those either within the specified
883
 *          band (for inband == 1) or outside the specified band
884
 *          (for inband == 0).
885
 *      (2) If pixs is colormapped, %usecmap determines if the colormap
886
 *          values are used, or if the colormap is removed to gray and
887
 *          the gray values are used.  For the latter, it generates
888
 *          an approximate grayscale value for each pixel, and then looks
889
 *          for gray pixels with the value %val.
890
 * </pre>
891
 */
892
PIX *
893
pixGenerateMaskByBand(PIX     *pixs,
894
                      l_int32  lower,
895
                      l_int32  upper,
896
                      l_int32  inband,
897
                      l_int32  usecmap)
898
0
{
899
0
l_int32    i, j, w, h, d, wplg, wpld, val;
900
0
l_uint32  *datag, *datad, *lineg, *lined;
901
0
PIX       *pixg, *pixd;
902
903
0
    if (!pixs)
904
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
905
0
    d = pixGetDepth(pixs);
906
0
    if (d != 2 && d != 4 && d != 8)
907
0
        return (PIX *)ERROR_PTR("not 2, 4 or 8 bpp", __func__, NULL);
908
0
    if (lower < 0 || lower > upper)
909
0
        return (PIX *)ERROR_PTR("lower < 0 or lower > upper!", __func__, NULL);
910
911
0
    if (!usecmap && pixGetColormap(pixs))
912
0
        pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
913
0
    else
914
0
        pixg = pixClone(pixs);
915
0
    pixGetDimensions(pixg, &w, &h, &d);
916
0
    if (d == 8 && upper > 255) {
917
0
        pixDestroy(&pixg);
918
0
        return (PIX *)ERROR_PTR("d == 8 and upper > 255", __func__, NULL);
919
0
    }
920
0
    if (d == 4 && upper > 15) {
921
0
        pixDestroy(&pixg);
922
0
        return (PIX *)ERROR_PTR("d == 4 and upper > 15", __func__, NULL);
923
0
    }
924
0
    if (d == 2 && upper > 3) {
925
0
        pixDestroy(&pixg);
926
0
        return (PIX *)ERROR_PTR("d == 2 and upper > 3", __func__, NULL);
927
0
    }
928
929
0
    pixd = pixCreate(w, h, 1);
930
0
    pixCopyResolution(pixd, pixg);
931
0
    pixCopyInputFormat(pixd, pixs);
932
0
    datag = pixGetData(pixg);
933
0
    wplg = pixGetWpl(pixg);
934
0
    datad = pixGetData(pixd);
935
0
    wpld = pixGetWpl(pixd);
936
0
    for (i = 0; i < h; i++) {
937
0
        lineg = datag + i * wplg;
938
0
        lined = datad + i * wpld;
939
0
        for (j = 0; j < w; j++) {
940
0
            if (d == 8)
941
0
                val = GET_DATA_BYTE(lineg, j);
942
0
            else if (d == 4)
943
0
                val = GET_DATA_QBIT(lineg, j);
944
0
            else  /* d == 2 */
945
0
                val = GET_DATA_DIBIT(lineg, j);
946
0
            if (inband) {
947
0
                if (val >= lower && val <= upper)
948
0
                    SET_DATA_BIT(lined, j);
949
0
            } else {  /* out of band */
950
0
                if (val < lower || val > upper)
951
0
                    SET_DATA_BIT(lined, j);
952
0
            }
953
0
        }
954
0
    }
955
956
0
    pixDestroy(&pixg);
957
0
    return pixd;
958
0
}
959
960
961
/*------------------------------------------------------------------*
962
 *                Thresholding to 2 bpp by dithering                *
963
 *------------------------------------------------------------------*/
964
/*!
965
 * \brief   pixDitherTo2bpp()
966
 *
967
 * \param[in]    pixs       8 bpp
968
 * \param[in]    cmapflag   1 to generate a colormap
969
 * \return  pixd dithered   2 bpp, or NULL on error
970
 *
971
 *  An analog of the Floyd-Steinberg error diffusion dithering
972
 *  algorithm is used to "dibitize" an 8 bpp grayscale image
973
 *  to 2 bpp, using equally spaced gray values of 0, 85, 170, and 255,
974
 *  which are served by thresholds of 43, 128 and 213.
975
 *  If cmapflag == 1, the colormap values are set to 0, 85, 170 and 255.
976
 *  If a pixel has a value between 0 and 42, it is dibitized
977
 *  to 0, and the excess above 0 is added to the
978
 *  three neighboring pixels, in the fractions 3/8 to i, j+1,
979
 *  3/8 to i+1, j) and 1/4 to (i+1, j+1, truncating to 255 if
980
 *  necessary.  If a pixel has a value between 43 and 127, it is
981
 *  dibitized to 1, and the excess above 85 is added to the three
982
 *  neighboring pixels as before.  If the value is below 85, the
983
 *  excess is subtracted.  With a value between 128
984
 *  and 212, it is dibitized to 2, with the excess on either side
985
 *  of 170 distributed as before.  Finally, with a value between
986
 *  213 and 255, it is dibitized to 3, with the excess below 255
987
 *  subtracted from the neighbors.  We always truncate to 0 or 255.
988
 *  The details can be seen in the lookup table generation.
989
 *
990
 *  This function differs from straight dithering in that it allows
991
 *  clipping of grayscale to 0 or 255 if the values are
992
 *  sufficiently close, without distribution of the excess.
993
 *  This uses default values from pix.h to specify the range of lower
994
 *  and upper values near 0 and 255, rsp that are clipped to black
995
 *  and white without propagating the excess.
996
 *  Not propagating the excess has the effect of reducing the snake
997
 *  patterns in parts of the image that are nearly black or white;
998
 *  however, it also prevents any attempt to reproduce gray for those values.
999
 *
1000
 *  The implementation uses 3 lookup tables for simplicity, and
1001
 *  a pair of line buffers to avoid modifying pixs.
1002
 */
1003
PIX *
1004
pixDitherTo2bpp(PIX     *pixs,
1005
                l_int32  cmapflag)
1006
0
{
1007
0
    if (!pixs)
1008
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1009
0
    if (pixGetDepth(pixs) != 8)
1010
0
        return (PIX *)ERROR_PTR("must be 8 bpp for dithering", __func__, NULL);
1011
1012
0
    return pixDitherTo2bppSpec(pixs, DEFAULT_CLIP_LOWER_2,
1013
0
                               DEFAULT_CLIP_UPPER_2, cmapflag);
1014
0
}
1015
1016
1017
/*!
1018
 * \brief   pixDitherTo2bppSpec()
1019
 *
1020
 * \param[in]    pixs        8 bpp
1021
 * \param[in]    lowerclip   lower clip distance to black; use 0 for default
1022
 * \param[in]    upperclip   upper clip distance to white; use 0 for default
1023
 * \param[in]    cmapflag    1 to generate a colormap
1024
 * \return  pixd dithered    2 bpp, or NULL on error
1025
 *
1026
 * <pre>
1027
 * Notes:
1028
 *      (1) See comments above in pixDitherTo2bpp() for details.
1029
 *      (2) The input parameters lowerclip and upperclip specify the range
1030
 *          of lower and upper values (near 0 and 255, rsp) that are
1031
 *          clipped to black and white without propagating the excess.
1032
 *          For that reason, lowerclip and upperclip should be small numbers.
1033
 * </pre>
1034
 */
1035
PIX *
1036
pixDitherTo2bppSpec(PIX     *pixs,
1037
                    l_int32  lowerclip,
1038
                    l_int32  upperclip,
1039
                    l_int32  cmapflag)
1040
0
{
1041
0
l_int32    w, h, d, wplt, wpld;
1042
0
l_int32   *tabval, *tab38, *tab14;
1043
0
l_uint32  *datat, *datad;
1044
0
l_uint32  *bufs1, *bufs2;
1045
0
PIX       *pixt, *pixd;
1046
0
PIXCMAP   *cmap;
1047
1048
0
    if (!pixs)
1049
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1050
0
    pixGetDimensions(pixs, &w, &h, &d);
1051
0
    if (d != 8)
1052
0
        return (PIX *)ERROR_PTR("must be 8 bpp for dithering", __func__, NULL);
1053
0
    if (lowerclip < 0 || lowerclip > 255)
1054
0
        return (PIX *)ERROR_PTR("invalid value for lowerclip", __func__, NULL);
1055
0
    if (upperclip < 0 || upperclip > 255)
1056
0
        return (PIX *)ERROR_PTR("invalid value for upperclip", __func__, NULL);
1057
1058
0
    if ((pixd = pixCreate(w, h, 2)) == NULL)
1059
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1060
0
    pixCopyResolution(pixd, pixs);
1061
0
    pixCopyInputFormat(pixd, pixs);
1062
0
    datad = pixGetData(pixd);
1063
0
    wpld = pixGetWpl(pixd);
1064
1065
        /* If there is a colormap, remove it */
1066
0
    pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1067
0
    datat = pixGetData(pixt);
1068
0
    wplt = pixGetWpl(pixt);
1069
1070
        /* Two line buffers, 1 for current line and 2 for next line */
1071
0
    bufs1 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
1072
0
    bufs2 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
1073
0
    if (!bufs1 || !bufs2) {
1074
0
        LEPT_FREE(bufs1);
1075
0
        LEPT_FREE(bufs2);
1076
0
        pixDestroy(&pixd);
1077
0
        pixDestroy(&pixt);
1078
0
        return (PIX *)ERROR_PTR("bufs1, bufs2 not both made", __func__, NULL);
1079
0
    }
1080
1081
        /* 3 lookup tables: 2-bit value, (3/8)excess, and (1/4)excess */
1082
0
    make8To2DitherTables(&tabval, &tab38, &tab14, lowerclip, upperclip);
1083
1084
0
    ditherTo2bppLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2,
1085
0
                    tabval, tab38, tab14);
1086
1087
0
    if (cmapflag) {
1088
0
        cmap = pixcmapCreateLinear(2, 4);
1089
0
        pixSetColormap(pixd, cmap);
1090
0
    }
1091
1092
0
    LEPT_FREE(bufs1);
1093
0
    LEPT_FREE(bufs2);
1094
0
    LEPT_FREE(tabval);
1095
0
    LEPT_FREE(tab38);
1096
0
    LEPT_FREE(tab14);
1097
0
    pixDestroy(&pixt);
1098
0
    return pixd;
1099
0
}
1100
1101
1102
/*!
1103
 * \brief   ditherTo2bppLow()
1104
 *
1105
 *  Low-level function for doing Floyd-Steinberg error diffusion
1106
 *  dithering from 8 bpp (datas) to 2 bpp (datad).  Two source
1107
 *  line buffers, bufs1 and bufs2, are provided, along with three
1108
 *  256-entry lookup tables: tabval gives the output pixel value,
1109
 *  tab38 gives the extra (plus or minus) transferred to the pixels
1110
 *  directly to the left and below, and tab14 gives the extra
1111
 *  transferred to the diagonal below.  The choice of 3/8 and 1/4
1112
 *  is traditional but arbitrary when you use a lookup table; the
1113
 *  only constraint is that the sum is 1.  See other comments
1114
 *  below and in grayquant.c.
1115
 */
1116
static void
1117
ditherTo2bppLow(l_uint32  *datad,
1118
                l_int32    w,
1119
                l_int32    h,
1120
                l_int32    wpld,
1121
                l_uint32  *datas,
1122
                l_int32    wpls,
1123
                l_uint32  *bufs1,
1124
                l_uint32  *bufs2,
1125
                l_int32   *tabval,
1126
                l_int32   *tab38,
1127
                l_int32   *tab14)
1128
0
{
1129
0
l_int32      i;
1130
0
l_uint32    *lined;
1131
1132
        /* do all lines except last line */
1133
0
    memcpy(bufs2, datas, 4 * wpls);  /* prime the buffer */
1134
0
    for (i = 0; i < h - 1; i++) {
1135
0
        memcpy(bufs1, bufs2, 4 * wpls);
1136
0
        memcpy(bufs2, datas + (i + 1) * wpls, 4 * wpls);
1137
0
        lined = datad + i * wpld;
1138
0
        ditherTo2bppLineLow(lined, w, bufs1, bufs2, tabval, tab38, tab14, 0);
1139
0
    }
1140
1141
        /* do last line */
1142
0
    memcpy(bufs1, bufs2, 4 * wpls);
1143
0
    lined = datad + (h - 1) * wpld;
1144
0
    ditherTo2bppLineLow(lined, w, bufs1, bufs2, tabval, tab38, tab14, 1);
1145
0
}
1146
1147
1148
/*!
1149
 * \brief   ditherTo2bppLineLow()
1150
 *
1151
 * \param[in]    lined          ptr to beginning of dest line
1152
 * \param[in]    w              width of image in pixels
1153
 * \param[in]    bufs1          buffer of current source line
1154
 * \param[in]    bufs2          buffer of next source line
1155
 * \param[in]    tabval         value to assign for current pixel
1156
 * \param[in]    tab38          excess value to give to neighboring 3/8 pixels
1157
 * \param[in]    tab14          excess value to give to neighboring 1/4 pixel
1158
 * \param[in]    lastlineflag   0 if not last dest line, 1 if last dest line
1159
 * \return  void
1160
 *
1161
 *  Dispatches error diffusion dithering for
1162
 *  a single line of the image.  If lastlineflag == 0,
1163
 *  both source buffers are used; otherwise, only bufs1
1164
 *  is used.  We use source buffers because the error
1165
 *  is propagated into them, and we don't want to change
1166
 *  the input src image.
1167
 *
1168
 *  We break dithering out line by line to make it
1169
 *  easier to combine functions like interpolative
1170
 *  scaling and error diffusion dithering, as such a
1171
 *  combination of operations obviates the need to
1172
 *  generate a 2x grayscale image as an intermediary.
1173
 */
1174
static void
1175
ditherTo2bppLineLow(l_uint32  *lined,
1176
                    l_int32    w,
1177
                    l_uint32  *bufs1,
1178
                    l_uint32  *bufs2,
1179
                    l_int32   *tabval,
1180
                    l_int32   *tab38,
1181
                    l_int32   *tab14,
1182
                    l_int32    lastlineflag)
1183
0
{
1184
0
l_int32  j;
1185
0
l_int32  oval, tab38val, tab14val;
1186
0
l_uint8  rval, bval, dval;
1187
1188
0
    if (lastlineflag == 0) {
1189
0
        for (j = 0; j < w - 1; j++) {
1190
0
            oval = GET_DATA_BYTE(bufs1, j);
1191
0
            SET_DATA_DIBIT(lined, j, tabval[oval]);
1192
0
            rval = GET_DATA_BYTE(bufs1, j + 1);
1193
0
            bval = GET_DATA_BYTE(bufs2, j);
1194
0
            dval = GET_DATA_BYTE(bufs2, j + 1);
1195
0
            tab38val = tab38[oval];
1196
0
            tab14val = tab14[oval];
1197
0
            if (tab38val < 0) {
1198
0
                rval = L_MAX(0, rval + tab38val);
1199
0
                bval = L_MAX(0, bval + tab38val);
1200
0
                dval = L_MAX(0, dval + tab14val);
1201
0
            } else {
1202
0
                rval = L_MIN(255, rval + tab38val);
1203
0
                bval = L_MIN(255, bval + tab38val);
1204
0
                dval = L_MIN(255, dval + tab14val);
1205
0
            }
1206
0
            SET_DATA_BYTE(bufs1, j + 1, rval);
1207
0
            SET_DATA_BYTE(bufs2, j, bval);
1208
0
            SET_DATA_BYTE(bufs2, j + 1, dval);
1209
0
        }
1210
1211
            /* do last column: j = w - 1 */
1212
0
        oval = GET_DATA_BYTE(bufs1, j);
1213
0
        SET_DATA_DIBIT(lined, j, tabval[oval]);
1214
0
        bval = GET_DATA_BYTE(bufs2, j);
1215
0
        tab38val = tab38[oval];
1216
0
        if (tab38val < 0)
1217
0
            bval = L_MAX(0, bval + tab38val);
1218
0
        else
1219
0
            bval = L_MIN(255, bval + tab38val);
1220
0
        SET_DATA_BYTE(bufs2, j, bval);
1221
0
    } else {   /* lastlineflag == 1 */
1222
0
        for (j = 0; j < w - 1; j++) {
1223
0
            oval = GET_DATA_BYTE(bufs1, j);
1224
0
            SET_DATA_DIBIT(lined, j, tabval[oval]);
1225
0
            rval = GET_DATA_BYTE(bufs1, j + 1);
1226
0
            tab38val = tab38[oval];
1227
0
            if (tab38val < 0)
1228
0
                rval = L_MAX(0, rval + tab38val);
1229
0
            else
1230
0
                rval = L_MIN(255, rval + tab38val);
1231
0
            SET_DATA_BYTE(bufs1, j + 1, rval);
1232
0
        }
1233
1234
            /* do last pixel: (i, j) = (h - 1, w - 1) */
1235
0
        oval = GET_DATA_BYTE(bufs1, j);
1236
0
        SET_DATA_DIBIT(lined, j, tabval[oval]);
1237
0
    }
1238
0
}
1239
1240
1241
/*!
1242
 * \brief   make8To2DitherTables()
1243
 *
1244
 * \param[out]  ptabval      value assigned to output pixel; 0, 1, 2 or 3
1245
 * \param[out]  ptab38       amount propagated to pixels left and below
1246
 * \param[out]  ptab14       amount propagated to pixel to left and down
1247
 * \param[in]   cliptoblack  values near 0 where the excess is not propagated
1248
 * \param[in]   cliptowhite  values near 255 where the deficit is not propagated
1249
 *
1250
 * \return  0 if OK, 1 on error
1251
 */
1252
static l_int32
1253
make8To2DitherTables(l_int32 **ptabval,
1254
                     l_int32 **ptab38,
1255
                     l_int32 **ptab14,
1256
                     l_int32   cliptoblack,
1257
                     l_int32   cliptowhite)
1258
0
{
1259
0
l_int32   i;
1260
0
l_int32  *tabval, *tab38, *tab14;
1261
1262
        /* 3 lookup tables: 2-bit value, (3/8)excess, and (1/4)excess */
1263
0
    tabval = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1264
0
    tab38 = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1265
0
    tab14 = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1266
0
    *ptabval = tabval;
1267
0
    *ptab38 = tab38;
1268
0
    *ptab14 = tab14;
1269
1270
0
    for (i = 0; i < 256; i++) {
1271
0
        if (i <= cliptoblack) {
1272
0
            tabval[i] = 0;
1273
0
            tab38[i] = 0;
1274
0
            tab14[i] = 0;
1275
0
        } else if (i < 43) {
1276
0
            tabval[i] = 0;
1277
0
            tab38[i] = (3 * i + 4) / 8;
1278
0
            tab14[i] = (i + 2) / 4;
1279
0
        } else if (i < 85) {
1280
0
            tabval[i] = 1;
1281
0
            tab38[i] = (3 * (i - 85) - 4) / 8;
1282
0
            tab14[i] = ((i - 85) - 2) / 4;
1283
0
        } else if (i < 128) {
1284
0
            tabval[i] = 1;
1285
0
            tab38[i] = (3 * (i - 85) + 4) / 8;
1286
0
            tab14[i] = ((i - 85) + 2) / 4;
1287
0
        } else if (i < 170) {
1288
0
            tabval[i] = 2;
1289
0
            tab38[i] = (3 * (i - 170) - 4) / 8;
1290
0
            tab14[i] = ((i - 170) - 2) / 4;
1291
0
        } else if (i < 213) {
1292
0
            tabval[i] = 2;
1293
0
            tab38[i] = (3 * (i - 170) + 4) / 8;
1294
0
            tab14[i] = ((i - 170) + 2) / 4;
1295
0
        } else if (i < 255 - cliptowhite) {
1296
0
            tabval[i] = 3;
1297
0
            tab38[i] = (3 * (i - 255) - 4) / 8;
1298
0
            tab14[i] = ((i - 255) - 2) / 4;
1299
0
        } else {  /* i >= 255 - cliptowhite */
1300
0
            tabval[i] = 3;
1301
0
            tab38[i] = 0;
1302
0
            tab14[i] = 0;
1303
0
        }
1304
0
    }
1305
1306
0
    return 0;
1307
0
}
1308
1309
1310
/*--------------------------------------------------------------------*
1311
 *  Simple (pixelwise) thresholding to 2 bpp with optional colormap   *
1312
 *--------------------------------------------------------------------*/
1313
/*!
1314
 * \brief   pixThresholdTo2bpp()
1315
 *
1316
 * \param[in]    pixs       8 bpp
1317
 * \param[in]    nlevels    equally spaced; must be between 2 and 4
1318
 * \param[in]    cmapflag   1 to build colormap; 0 otherwise
1319
 * \return  pixd 2 bpp, optionally with colormap, or NULL on error
1320
 *
1321
 * <pre>
1322
 * Notes:
1323
 *      (1) Valid values for nlevels is the set {2, 3, 4}.
1324
 *      (2) Any colormap on the input pixs is removed to 8 bpp grayscale.
1325
 *      (3) This function is typically invoked with cmapflag == 1.
1326
 *          In the situation where no colormap is desired, nlevels is
1327
 *          ignored and pixs is thresholded to 4 levels.
1328
 *      (4) The target output colors are equally spaced, with the
1329
 *          darkest at 0 and the lightest at 255.  The thresholds are
1330
 *          chosen halfway between adjacent output values.  A table
1331
 *          is built that specifies the mapping from src to dest.
1332
 *      (5) If cmapflag == 1, a colormap of size 'nlevels' is made,
1333
 *          and the pixel values in pixs are replaced by their
1334
 *          appropriate color indices.  The number of holdouts,
1335
 *          4 - nlevels, will be between 0 and 2.
1336
 *      (6) If you don't want the thresholding to be equally spaced,
1337
 *          either first transform the 8 bpp src using pixGammaTRC().
1338
 *          or, if cmapflag == 1, after calling this function you can use
1339
 *          pixcmapResetColor() to change any individual colors.
1340
 *      (7) If a colormap is generated, it will specify (to display
1341
 *          programs) exactly how each level is to be represented in RGB
1342
 *          space.  When representing text, 3 levels is far better than
1343
 *          2 because of the antialiasing of the single gray level,
1344
 *          and 4 levels (black, white and 2 gray levels) is getting
1345
 *          close to the perceptual quality of a (nearly continuous)
1346
 *          grayscale image.  With 2 bpp, you can set up a colormap
1347
 *          and allocate from 2 to 4 levels to represent antialiased text.
1348
 *          Any left over colormap entries can be used for coloring regions.
1349
 *          For the same number of levels, the file size of a 2 bpp image
1350
 *          is about 10% smaller than that of a 4 bpp result for the same
1351
 *          number of levels.  For both 2 bpp and 4 bpp, using 4 levels you
1352
 *          get compression far better than that of jpeg, because the
1353
 *          quantization to 4 levels will remove the jpeg ringing in the
1354
 *          background near character edges.
1355
 * </pre>
1356
 */
1357
PIX *
1358
pixThresholdTo2bpp(PIX     *pixs,
1359
                   l_int32  nlevels,
1360
                   l_int32  cmapflag)
1361
0
{
1362
0
l_int32   *qtab;
1363
0
l_int32    w, h, d, wplt, wpld;
1364
0
l_uint32  *datat, *datad;
1365
0
PIX       *pixt, *pixd;
1366
0
PIXCMAP   *cmap;
1367
1368
0
    if (!pixs)
1369
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1370
0
    pixGetDimensions(pixs, &w, &h, &d);
1371
0
    if (d != 8)
1372
0
        return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
1373
0
    if (nlevels < 2 || nlevels > 4)
1374
0
        return (PIX *)ERROR_PTR("nlevels not in {2, 3, 4}", __func__, NULL);
1375
1376
0
    if ((pixd = pixCreate(w, h, 2)) == NULL)
1377
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1378
0
    pixCopyResolution(pixd, pixs);
1379
0
    pixCopyInputFormat(pixd, pixs);
1380
0
    datad = pixGetData(pixd);
1381
0
    wpld = pixGetWpl(pixd);
1382
1383
0
    if (cmapflag) {   /* hold out (4 - nlevels) cmap entries */
1384
0
        cmap = pixcmapCreateLinear(2, nlevels);
1385
0
        pixSetColormap(pixd, cmap);
1386
0
    }
1387
1388
        /* If there is a colormap in the src, remove it */
1389
0
    pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1390
0
    datat = pixGetData(pixt);
1391
0
    wplt = pixGetWpl(pixt);
1392
1393
        /* Make the appropriate table */
1394
0
    if (cmapflag)
1395
0
        qtab = makeGrayQuantIndexTable(nlevels);
1396
0
    else
1397
0
        qtab = makeGrayQuantTargetTable(4, 2);
1398
1399
0
    thresholdTo2bppLow(datad, h, wpld, datat, wplt, qtab);
1400
1401
0
    LEPT_FREE(qtab);
1402
0
    pixDestroy(&pixt);
1403
0
    return pixd;
1404
0
}
1405
1406
1407
/*!
1408
 * \brief   thresholdTo2bppLow()
1409
 *
1410
 *  Low-level function for thresholding from 8 bpp (datas) to
1411
 *  2 bpp (datad), using thresholds implicitly defined through %tab,
1412
 *  a 256-entry lookup table that gives a 2-bit output value
1413
 *  for each possible input.
1414
 *
1415
 *  For each line, unroll the loop so that for each 32 bit src word,
1416
 *  representing four consecutive 8-bit pixels, we compose one byte
1417
 *  of output consisiting of four 2-bit pixels.
1418
 */
1419
static void
1420
thresholdTo2bppLow(l_uint32  *datad,
1421
                   l_int32    h,
1422
                   l_int32    wpld,
1423
                   l_uint32  *datas,
1424
                   l_int32    wpls,
1425
                   l_int32   *tab)
1426
0
{
1427
0
l_uint8    sval1, sval2, sval3, sval4, dval;
1428
0
l_int32    i, j, k;
1429
0
l_uint32  *lines, *lined;
1430
1431
0
    for (i = 0; i < h; i++) {
1432
0
        lines = datas + i * wpls;
1433
0
        lined = datad + i * wpld;
1434
0
        for (j = 0; j < wpls; j++) {
1435
0
            k = 4 * j;
1436
0
            sval1 = GET_DATA_BYTE(lines, k);
1437
0
            sval2 = GET_DATA_BYTE(lines, k + 1);
1438
0
            sval3 = GET_DATA_BYTE(lines, k + 2);
1439
0
            sval4 = GET_DATA_BYTE(lines, k + 3);
1440
0
            dval = (tab[sval1] << 6) | (tab[sval2] << 4) |
1441
0
                   (tab[sval3] << 2) | tab[sval4];
1442
0
            SET_DATA_BYTE(lined, j, dval);
1443
0
        }
1444
0
    }
1445
0
}
1446
1447
1448
/*----------------------------------------------------------------------*
1449
 *               Simple (pixelwise) thresholding to 4 bpp               *
1450
 *----------------------------------------------------------------------*/
1451
/*!
1452
 * \brief   pixThresholdTo4bpp()
1453
 *
1454
 * \param[in]    pixs      8 bpp, can have colormap
1455
 * \param[in]    nlevels   equally spaced; must be between 2 and 16
1456
 * \param[in]    cmapflag  1 to build colormap; 0 otherwise
1457
 * \return  pixd 4 bpp, optionally with colormap, or NULL on error
1458
 *
1459
 * <pre>
1460
 * Notes:
1461
 *      (1) Valid values for nlevels is the set {2, ... 16}.
1462
 *      (2) Any colormap on the input pixs is removed to 8 bpp grayscale.
1463
 *      (3) This function is typically invoked with cmapflag == 1.
1464
 *          In the situation where no colormap is desired, nlevels is
1465
 *          ignored and pixs is thresholded to 16 levels.
1466
 *      (4) The target output colors are equally spaced, with the
1467
 *          darkest at 0 and the lightest at 255.  The thresholds are
1468
 *          chosen halfway between adjacent output values.  A table
1469
 *          is built that specifies the mapping from src to dest.
1470
 *      (5) If cmapflag == 1, a colormap of size 'nlevels' is made,
1471
 *          and the pixel values in pixs are replaced by their
1472
 *          appropriate color indices.  The number of holdouts,
1473
 *          16 - nlevels, will be between 0 and 14.
1474
 *      (6) If you don't want the thresholding to be equally spaced,
1475
 *          either first transform the 8 bpp src using pixGammaTRC().
1476
 *          or, if cmapflag == 1, after calling this function you can use
1477
 *          pixcmapResetColor() to change any individual colors.
1478
 *      (7) If a colormap is generated, it will specify, to display
1479
 *          programs, exactly how each level is to be represented in RGB
1480
 *          space.  When representing text, 3 levels is far better than
1481
 *          2 because of the antialiasing of the single gray level,
1482
 *          and 4 levels (black, white and 2 gray levels) is getting
1483
 *          close to the perceptual quality of a (nearly continuous)
1484
 *          grayscale image.  Therefore, with 4 bpp, you can set up a
1485
 *          colormap, allocate a relatively small fraction of the 16
1486
 *          possible values to represent antialiased text, and use the
1487
 *          other colormap entries for other things, such as coloring
1488
 *          text or background.  Two other reasons for using a small number
1489
 *          of gray values for antialiased text are (1) PNG compression
1490
 *          gets worse as the number of levels that are used is increased,
1491
 *          and (2) using a small number of levels will filter out most of
1492
 *          the jpeg ringing that is typically introduced near sharp edges
1493
 *          of text.  This filtering is partly responsible for the improved
1494
 *          compression.
1495
 * </pre>
1496
 */
1497
PIX *
1498
pixThresholdTo4bpp(PIX     *pixs,
1499
                   l_int32  nlevels,
1500
                   l_int32  cmapflag)
1501
0
{
1502
0
l_int32   *qtab;
1503
0
l_int32    w, h, d, wplt, wpld;
1504
0
l_uint32  *datat, *datad;
1505
0
PIX       *pixt, *pixd;
1506
0
PIXCMAP   *cmap;
1507
1508
0
    if (!pixs)
1509
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1510
0
    pixGetDimensions(pixs, &w, &h, &d);
1511
0
    if (d != 8)
1512
0
        return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
1513
0
    if (nlevels < 2 || nlevels > 16)
1514
0
        return (PIX *)ERROR_PTR("nlevels not in [2,...,16]", __func__, NULL);
1515
1516
0
    if ((pixd = pixCreate(w, h, 4)) == NULL)
1517
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1518
0
    pixCopyResolution(pixd, pixs);
1519
0
    pixCopyInputFormat(pixd, pixs);
1520
0
    datad = pixGetData(pixd);
1521
0
    wpld = pixGetWpl(pixd);
1522
1523
0
    if (cmapflag) {   /* hold out (16 - nlevels) cmap entries */
1524
0
        cmap = pixcmapCreateLinear(4, nlevels);
1525
0
        pixSetColormap(pixd, cmap);
1526
0
    }
1527
1528
        /* If there is a colormap in the src, remove it */
1529
0
    pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1530
0
    datat = pixGetData(pixt);
1531
0
    wplt = pixGetWpl(pixt);
1532
1533
        /* Make the appropriate table */
1534
0
    if (cmapflag)
1535
0
        qtab = makeGrayQuantIndexTable(nlevels);
1536
0
    else
1537
0
        qtab = makeGrayQuantTargetTable(16, 4);
1538
1539
0
    thresholdTo4bppLow(datad, h, wpld, datat, wplt, qtab);
1540
1541
0
    LEPT_FREE(qtab);
1542
0
    pixDestroy(&pixt);
1543
0
    return pixd;
1544
0
}
1545
1546
1547
/*!
1548
 * \brief   thresholdTo4bppLow()
1549
 *
1550
 *  Low-level function for thresholding from 8 bpp (datas) to
1551
 *  4 bpp (datad), using thresholds implicitly defined through %tab,
1552
 *  a 256-entry lookup table that gives a 4-bit output value
1553
 *  for each possible input.
1554
 *
1555
 *  For each line, unroll the loop so that for each 32 bit src word,
1556
 *  representing four consecutive 8-bit pixels, we compose two bytes
1557
 *  of output consisiting of four 4-bit pixels.
1558
 */
1559
static void
1560
thresholdTo4bppLow(l_uint32  *datad,
1561
                   l_int32    h,
1562
                   l_int32    wpld,
1563
                   l_uint32  *datas,
1564
                   l_int32    wpls,
1565
                   l_int32   *tab)
1566
0
{
1567
0
l_uint8    sval1, sval2, sval3, sval4;
1568
0
l_uint16   dval;
1569
0
l_int32    i, j, k;
1570
0
l_uint32  *lines, *lined;
1571
1572
0
    for (i = 0; i < h; i++) {
1573
0
        lines = datas + i * wpls;
1574
0
        lined = datad + i * wpld;
1575
0
        for (j = 0; j < wpls; j++) {
1576
0
            k = 4 * j;
1577
0
            sval1 = GET_DATA_BYTE(lines, k);
1578
0
            sval2 = GET_DATA_BYTE(lines, k + 1);
1579
0
            sval3 = GET_DATA_BYTE(lines, k + 2);
1580
0
            sval4 = GET_DATA_BYTE(lines, k + 3);
1581
0
            dval = (tab[sval1] << 12) | (tab[sval2] << 8) |
1582
0
                   (tab[sval3] << 4) | tab[sval4];
1583
0
            SET_DATA_TWO_BYTES(lined, j, dval);
1584
0
        }
1585
0
    }
1586
0
}
1587
1588
1589
/*----------------------------------------------------------------------*
1590
 *    Simple (pixelwise) thresholding on 8 bpp with optional colormap   *
1591
 *----------------------------------------------------------------------*/
1592
/*!
1593
 * \brief   pixThresholdOn8bpp()
1594
 *
1595
 * \param[in]    pixs       8 bpp, can have colormap
1596
 * \param[in]    nlevels    equally spaced; must be between 2 and 256
1597
 * \param[in]    cmapflag   1 to build colormap; 0 otherwise
1598
 * \return  pixd 8 bpp, optionally with colormap, or NULL on error
1599
 *
1600
 * <pre>
1601
 * Notes:
1602
 *      (1) Valid values for nlevels is the set {2,...,256}.
1603
 *      (2) Any colormap on the input pixs is removed to 8 bpp grayscale.
1604
 *      (3) If cmapflag == 1, a colormap of size 'nlevels' is made,
1605
 *          and the pixel values in pixs are replaced by their
1606
 *          appropriate color indices.  Otherwise, the pixel values
1607
 *          are the actual thresholded (i.e., quantized) grayscale values.
1608
 *      (4) If you don't want the thresholding to be equally spaced,
1609
 *          first transform the input 8 bpp src using pixGammaTRC().
1610
 * </pre>
1611
 */
1612
PIX *
1613
pixThresholdOn8bpp(PIX     *pixs,
1614
                   l_int32  nlevels,
1615
                   l_int32  cmapflag)
1616
0
{
1617
0
l_int32   *qtab;  /* quantization table */
1618
0
l_int32    i, j, w, h, wpld, val, newval;
1619
0
l_uint32  *datad, *lined;
1620
0
PIX       *pixd;
1621
0
PIXCMAP   *cmap;
1622
1623
0
    if (!pixs)
1624
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1625
0
    if (pixGetDepth(pixs) != 8)
1626
0
        return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
1627
0
    if (nlevels < 2 || nlevels > 256)
1628
0
        return (PIX *)ERROR_PTR("nlevels not in [2,...,256]", __func__, NULL);
1629
1630
        /* Get a new pixd; if there is a colormap in the src, remove it */
1631
0
    if (pixGetColormap(pixs))
1632
0
        pixd = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1633
0
    else
1634
0
        pixd = pixCopy(NULL, pixs);
1635
1636
0
    if (cmapflag) {   /* hold out (256 - nlevels) cmap entries */
1637
0
        cmap = pixcmapCreateLinear(8, nlevels);
1638
0
        pixSetColormap(pixd, cmap);
1639
0
    }
1640
1641
0
    if (cmapflag)
1642
0
        qtab = makeGrayQuantIndexTable(nlevels);
1643
0
    else
1644
0
        qtab = makeGrayQuantTargetTable(nlevels, 8);
1645
1646
0
    pixGetDimensions(pixd, &w, &h, NULL);
1647
0
    pixCopyResolution(pixd, pixs);
1648
0
    pixCopyInputFormat(pixd, pixs);
1649
0
    datad = pixGetData(pixd);
1650
0
    wpld = pixGetWpl(pixd);
1651
0
    for (i = 0; i < h; i++) {
1652
0
        lined = datad + i * wpld;
1653
0
        for (j = 0; j < w; j++) {
1654
0
            val = GET_DATA_BYTE(lined, j);
1655
0
            newval = qtab[val];
1656
0
            SET_DATA_BYTE(lined, j, newval);
1657
0
        }
1658
0
    }
1659
1660
0
    LEPT_FREE(qtab);
1661
0
    return pixd;
1662
0
}
1663
1664
1665
/*----------------------------------------------------------------------*
1666
 *    Arbitrary (pixelwise) thresholding from 8 bpp to 2, 4 or 8 bpp    *
1667
 *----------------------------------------------------------------------*/
1668
/*!
1669
 * \brief   pixThresholdGrayArb()
1670
 *
1671
 * \param[in]    pixs          8 bpp grayscale; can have colormap
1672
 * \param[in]    edgevals      string giving edge value of each bin
1673
 * \param[in]    outdepth      0, 2, 4 or 8 bpp; 0 is default for min depth
1674
 * \param[in]    use_average   1 if use the average pixel value in colormap
1675
 * \param[in]    setblack      1 if darkest color is set to black
1676
 * \param[in]    setwhite      1 if lightest color is set to white
1677
 * \return  pixd 2, 4 or 8 bpp quantized image with colormap,
1678
 *                    or NULL on error
1679
 *
1680
 * <pre>
1681
 * Notes:
1682
 *      (1) This function allows exact specification of the quantization bins.
1683
 *          The string %edgevals is a space-separated set of values
1684
 *          specifying the dividing points between output quantization bins.
1685
 *          These threshold values are assigned to the bin with higher
1686
 *          values, so that each of them is the smallest value in their bin.
1687
 *      (2) The output image (pixd) depth is specified by %outdepth.  The
1688
 *          number of bins is the number of edgevals + 1.  The
1689
 *          relation between outdepth and the number of bins is:
1690
 *               outdepth = 2       nbins <= 4
1691
 *               outdepth = 4       nbins <= 16
1692
 *               outdepth = 8       nbins <= 256
1693
 *          With %outdepth == 0, the minimum required depth for the
1694
 *          given number of bins is used.
1695
 *          The output pixd has a colormap.
1696
 *      (3) The last 3 args determine the specific values that go into
1697
 *          the colormap.
1698
 *      (4) For %use_average:
1699
 *            ~ if TRUE, the average value of pixels falling in the bin is
1700
 *              chosen as the representative gray value.  Otherwise,
1701
 *            ~ if FALSE, the central value of each bin is chosen as
1702
 *              the representative value.
1703
 *          The colormap holds the representative value.
1704
 *      (5) For %setblack, if TRUE the darkest color is set to (0,0,0).
1705
 *      (6) For %setwhite, if TRUE the lightest color is set to (255,255,255).
1706
 *      (7) An alternative to using this function to quantize to
1707
 *          unequally-spaced bins is to first transform the 8 bpp pixs
1708
 *          using pixGammaTRC(), and follow this with pixThresholdTo4bpp().
1709
 * </pre>
1710
 */
1711
PIX *
1712
pixThresholdGrayArb(PIX         *pixs,
1713
                    const char  *edgevals,
1714
                    l_int32      outdepth,
1715
                    l_int32      use_average,
1716
                    l_int32      setblack,
1717
                    l_int32      setwhite)
1718
0
{
1719
0
l_int32   *qtab;
1720
0
l_int32    w, h, d, i, j, n, wplt, wpld, val, newval;
1721
0
l_uint32  *datat, *datad, *linet, *lined;
1722
0
NUMA      *na;
1723
0
PIX       *pixt, *pixd;
1724
0
PIXCMAP   *cmap;
1725
1726
0
    if (!pixs)
1727
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1728
0
    pixGetDimensions(pixs, &w, &h, &d);
1729
0
    if (d != 8)
1730
0
        return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
1731
0
    if (!edgevals)
1732
0
        return (PIX *)ERROR_PTR("edgevals not defined", __func__, NULL);
1733
0
    if (outdepth != 0 && outdepth != 2 && outdepth != 4 && outdepth != 8)
1734
0
        return (PIX *)ERROR_PTR("invalid outdepth", __func__, NULL);
1735
1736
        /* Parse and sort (if required) the bin edge values */
1737
0
    na = parseStringForNumbers(edgevals, " \t\n,");
1738
0
    n = numaGetCount(na);
1739
0
    if (n > 255) {
1740
0
        numaDestroy(&na);
1741
0
        return (PIX *)ERROR_PTR("more than 256 levels", __func__, NULL);
1742
0
    }
1743
0
    if (outdepth == 0) {
1744
0
        if (n <= 3)
1745
0
            outdepth = 2;
1746
0
        else if (n <= 15)
1747
0
            outdepth = 4;
1748
0
        else
1749
0
            outdepth = 8;
1750
0
    } else if (n + 1 > (1 << outdepth)) {
1751
0
        L_WARNING("outdepth too small; setting to 8 bpp\n", __func__);
1752
0
        outdepth = 8;
1753
0
    }
1754
0
    numaSort(na, na, L_SORT_INCREASING);
1755
1756
        /* Make the quantization LUT and the colormap */
1757
0
    makeGrayQuantTableArb(na, outdepth, &qtab, &cmap);
1758
0
    if (use_average) {  /* use the average value in each bin */
1759
0
        pixcmapDestroy(&cmap);
1760
0
        makeGrayQuantColormapArb(pixs, qtab, outdepth, &cmap);
1761
0
    }
1762
0
    pixcmapSetBlackAndWhite(cmap, setblack, setwhite);
1763
0
    numaDestroy(&na);
1764
1765
0
    if ((pixd = pixCreate(w, h, outdepth)) == NULL) {
1766
0
        LEPT_FREE(qtab);
1767
0
        pixcmapDestroy(&cmap);
1768
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1769
0
    }
1770
0
    pixCopyResolution(pixd, pixs);
1771
0
    pixCopyInputFormat(pixd, pixs);
1772
0
    pixSetColormap(pixd, cmap);
1773
0
    datad = pixGetData(pixd);
1774
0
    wpld = pixGetWpl(pixd);
1775
1776
        /* If there is a colormap in the src, remove it */
1777
0
    pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1778
0
    datat = pixGetData(pixt);
1779
0
    wplt = pixGetWpl(pixt);
1780
1781
0
    if (outdepth == 2) {
1782
0
        thresholdTo2bppLow(datad, h, wpld, datat, wplt, qtab);
1783
0
    } else if (outdepth == 4) {
1784
0
        thresholdTo4bppLow(datad, h, wpld, datat, wplt, qtab);
1785
0
    } else {
1786
0
        for (i = 0; i < h; i++) {
1787
0
            lined = datad + i * wpld;
1788
0
            linet = datat + i * wplt;
1789
0
            for (j = 0; j < w; j++) {
1790
0
                val = GET_DATA_BYTE(linet, j);
1791
0
                newval = qtab[val];
1792
0
                SET_DATA_BYTE(lined, j, newval);
1793
0
            }
1794
0
        }
1795
0
    }
1796
1797
0
    LEPT_FREE(qtab);
1798
0
    pixDestroy(&pixt);
1799
0
    return pixd;
1800
0
}
1801
1802
1803
/*----------------------------------------------------------------------*
1804
 *     Quantization tables for linear thresholds of grayscale images    *
1805
 *----------------------------------------------------------------------*/
1806
/*!
1807
 * \brief   makeGrayQuantIndexTable()
1808
 *
1809
 * \param[in]    nlevels    number of output levels
1810
 * \return  table maps input gray level to colormap index,
1811
 *                     or NULL on error
1812
 * <pre>
1813
 * Notes:
1814
 *      (1) 'nlevels' is some number between 2 and 256 (typically 8 or less).
1815
 *      (2) The table is typically used for quantizing 2, 4 and 8 bpp
1816
 *          grayscale src pix, and generating a colormapped dest pix.
1817
 * </pre>
1818
 */
1819
l_int32 *
1820
makeGrayQuantIndexTable(l_int32  nlevels)
1821
0
{
1822
0
l_int32  *tab;
1823
0
l_int32   i, j, thresh;
1824
1825
0
    tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1826
0
    for (i = 0; i < 256; i++) {
1827
0
        for (j = 0; j < nlevels; j++) {
1828
0
            thresh = 255 * (2 * j + 1) / (2 * nlevels - 2);
1829
0
            if (i <= thresh) {
1830
0
                tab[i] = j;
1831
/*                lept_stderr("tab[%d] = %d\n", i, j); */
1832
0
                break;
1833
0
            }
1834
0
        }
1835
0
    }
1836
0
    return tab;
1837
0
}
1838
1839
1840
/*!
1841
 * \brief   makeGrayQuantTargetTable()
1842
 *
1843
 * \param[in]    nlevels    number of output levels
1844
 * \param[in]    depth      of dest pix, in bpp; 2, 4 or 8 bpp
1845
 * \return  table maps input gray level to thresholded gray level,
1846
 *                     or NULL on error
1847
 *
1848
 * <pre>
1849
 * Notes:
1850
 *      (1) nlevels is some number between 2 and 2^(depth)
1851
 *      (2) The table is used in two similar ways:
1852
 *           ~ for 8 bpp, it quantizes to a given number of target levels
1853
 *           ~ for 2 and 4 bpp, it thresholds to appropriate target values
1854
 *             that will use the full dynamic range of the dest pix.
1855
 *      (3) For depth = 8, the number of thresholds chosen is
1856
 *          ('nlevels' - 1), and the 'nlevels' values stored in the
1857
 *          table are at the two at the extreme ends, (0, 255), plus
1858
 *          plus ('nlevels' - 2) values chosen at equal intervals between.
1859
 *          For example, for depth = 8 and 'nlevels' = 3, the two
1860
 *          threshold values are 3f and bf, and the three target pixel
1861
 *          values are 0, 7f and ff.
1862
 *      (4) For depth < 8, we ignore nlevels, and always use the maximum
1863
 *          number of levels, which is 2^(depth).
1864
 *          If you want nlevels < the maximum number, you should always
1865
 *          use a colormap.
1866
 * </pre>
1867
 */
1868
static l_int32 *
1869
makeGrayQuantTargetTable(l_int32  nlevels,
1870
                         l_int32  depth)
1871
0
{
1872
0
l_int32  *tab;
1873
0
l_int32   i, j, thresh, maxval, quantval;
1874
1875
0
    tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1876
0
    maxval = (1 << depth) - 1;
1877
0
    if (depth < 8)
1878
0
        nlevels = 1 << depth;
1879
0
    for (i = 0; i < 256; i++) {
1880
0
        for (j = 0; j < nlevels; j++) {
1881
0
            thresh = 255 * (2 * j + 1) / (2 * nlevels - 2);
1882
0
            if (i <= thresh) {
1883
0
                quantval = maxval * j / (nlevels - 1);
1884
0
                tab[i] = quantval;
1885
/*                lept_stderr("tab[%d] = %d\n", i, tab[i]); */
1886
0
                break;
1887
0
            }
1888
0
        }
1889
0
    }
1890
0
    return tab;
1891
0
}
1892
1893
1894
/*----------------------------------------------------------------------*
1895
 *   Quantization table for arbitrary thresholding of grayscale images  *
1896
 *----------------------------------------------------------------------*/
1897
/*!
1898
 * \brief   makeGrayQuantTableArb()
1899
 *
1900
 * \param[in]    na         numa of bin boundaries
1901
 * \param[in]    outdepth   of colormap: 1, 2, 4 or 8
1902
 * \param[out]   ptab       table mapping input gray level to cmap index
1903
 * \param[out]   pcmap      colormap
1904
 * \return  0 if OK, 1 on error
1905
 *
1906
 * <pre>
1907
 * Notes:
1908
 *      (1) The number of bins is the count of %na + 1.
1909
 *      (2) The bin boundaries in na must be sorted in increasing order.
1910
 *      (3) The table is an inverse colormap: it maps input gray level
1911
 *          to colormap index (the bin number).
1912
 *      (4) The colormap generated here has quantized values at the
1913
 *          center of each bin.  If you want to use the average gray
1914
 *          value of pixels within the bin, discard the colormap and
1915
 *          compute it using makeGrayQuantColormapArb().
1916
 *      (5) Returns an error if there are not enough levels in the
1917
 *          output colormap for the number of bins.  The number
1918
 *          of bins must not exceed 2^outdepth.
1919
 * </pre>
1920
 */
1921
l_ok
1922
makeGrayQuantTableArb(NUMA      *na,
1923
                      l_int32    outdepth,
1924
                      l_int32  **ptab,
1925
                      PIXCMAP  **pcmap)
1926
0
{
1927
0
l_int32   i, j, n, jstart, ave, val;
1928
0
l_int32  *tab;
1929
0
PIXCMAP  *cmap;
1930
1931
0
    if (!ptab)
1932
0
        return ERROR_INT("&tab not defined", __func__, 1);
1933
0
    *ptab = NULL;
1934
0
    if (!pcmap)
1935
0
        return ERROR_INT("&cmap not defined", __func__, 1);
1936
0
    *pcmap = NULL;
1937
0
    if (!na)
1938
0
        return ERROR_INT("na not defined", __func__, 1);
1939
0
    n = numaGetCount(na);
1940
0
    if (n + 1 > (1 << outdepth))
1941
0
        return ERROR_INT("more bins than cmap levels", __func__, 1);
1942
1943
0
    if ((cmap = pixcmapCreate(outdepth)) == NULL)
1944
0
        return ERROR_INT("cmap not made", __func__, 1);
1945
0
    tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1946
0
    *ptab = tab;
1947
0
    *pcmap = cmap;
1948
1949
        /* First n bins */
1950
0
    jstart = 0;
1951
0
    for (i = 0; i < n; i++) {
1952
0
        numaGetIValue(na, i, &val);
1953
0
        ave = (jstart + val) / 2;
1954
0
        pixcmapAddColor(cmap, ave, ave, ave);
1955
0
        for (j = jstart; j < val; j++)
1956
0
            tab[j] = i;
1957
0
        jstart = val;
1958
0
    }
1959
1960
        /* Last bin */
1961
0
    ave = (jstart + 255) / 2;
1962
0
    pixcmapAddColor(cmap, ave, ave, ave);
1963
0
    for (j = jstart; j < 256; j++)
1964
0
        tab[j] = n;
1965
1966
0
    return 0;
1967
0
}
1968
1969
1970
/*!
1971
 * \brief   makeGrayQuantColormapArb()
1972
 *
1973
 * \param[in]    pixs       8 bpp
1974
 * \param[in]    tab        table mapping input gray level to cmap index
1975
 * \param[in]    outdepth   of colormap: 1, 2, 4 or 8
1976
 * \param[out]   pcmap      colormap
1977
 * \return  0 if OK, 1 on error
1978
 *
1979
 * <pre>
1980
 * Notes:
1981
 *      (1) The table is a 256-entry inverse colormap: it maps input gray
1982
 *          level to colormap index (the bin number).  It is computed
1983
 *          using makeGrayQuantTableArb().
1984
 *      (2) The colormap generated here has quantized values at the
1985
 *          average gray value of the pixels that are in each bin.
1986
 *      (3) Returns an error if there are not enough levels in the
1987
 *          output colormap for the number of bins.  The number
1988
 *          of bins must not exceed 2^outdepth.
1989
 * </pre>
1990
 */
1991
static l_int32
1992
makeGrayQuantColormapArb(PIX       *pixs,
1993
                         l_int32   *tab,
1994
                         l_int32    outdepth,
1995
                         PIXCMAP  **pcmap)
1996
0
{
1997
0
l_int32    i, j, index, w, h, d, nbins, wpl, factor, val;
1998
0
l_int32   *bincount, *binave, *binstart;
1999
0
l_uint32  *line, *data;
2000
2001
0
    if (!pcmap)
2002
0
        return ERROR_INT("&cmap not defined", __func__, 1);
2003
0
    *pcmap = NULL;
2004
0
    if (!pixs)
2005
0
        return ERROR_INT("pixs not defined", __func__, 1);
2006
0
    pixGetDimensions(pixs, &w, &h, &d);
2007
0
    if (d != 8)
2008
0
        return ERROR_INT("pixs not 8 bpp", __func__, 1);
2009
0
    if (!tab)
2010
0
        return ERROR_INT("tab not defined", __func__, 1);
2011
0
    nbins = tab[255] + 1;
2012
0
    if (nbins > (1 << outdepth))
2013
0
        return ERROR_INT("more bins than cmap levels", __func__, 1);
2014
2015
        /* Find the count and weighted count for each bin */
2016
0
    if ((bincount = (l_int32 *)LEPT_CALLOC(nbins, sizeof(l_int32))) == NULL)
2017
0
        return ERROR_INT("calloc fail for bincount", __func__, 1);
2018
0
    if ((binave = (l_int32 *)LEPT_CALLOC(nbins, sizeof(l_int32))) == NULL) {
2019
0
        LEPT_FREE(bincount);
2020
0
        return ERROR_INT("calloc fail for binave", __func__, 1);
2021
0
    }
2022
0
    factor = (l_int32)(sqrt((l_float64)(w * h) / 30000.) + 0.5);
2023
0
    factor = L_MAX(1, factor);
2024
0
    data = pixGetData(pixs);
2025
0
    wpl = pixGetWpl(pixs);
2026
0
    for (i = 0; i < h; i += factor) {
2027
0
        line = data + i * wpl;
2028
0
        for (j = 0; j < w; j += factor) {
2029
0
            val = GET_DATA_BYTE(line, j);
2030
0
            bincount[tab[val]]++;
2031
0
            binave[tab[val]] += val;
2032
0
        }
2033
0
    }
2034
2035
        /* Find the smallest gray values in each bin */
2036
0
    binstart = (l_int32 *)LEPT_CALLOC(nbins, sizeof(l_int32));
2037
0
    for (i = 1, index = 1; i < 256; i++) {
2038
0
        if (tab[i] < index) continue;
2039
0
        if (tab[i] == index)
2040
0
            binstart[index++] = i;
2041
0
    }
2042
2043
        /* Get the averages.  If there are no samples in a bin, use
2044
         * the center value of the bin. */
2045
0
    *pcmap = pixcmapCreate(outdepth);
2046
0
    for (i = 0; i < nbins; i++) {
2047
0
        if (bincount[i]) {
2048
0
            val = binave[i] / bincount[i];
2049
0
        } else {  /* no samples in the bin */
2050
0
            if (i < nbins - 1)
2051
0
                val = (binstart[i] + binstart[i + 1]) / 2;
2052
0
            else  /* last bin */
2053
0
                val = (binstart[i] + 255) / 2;
2054
0
        }
2055
0
        pixcmapAddColor(*pcmap, val, val, val);
2056
0
    }
2057
2058
0
    LEPT_FREE(bincount);
2059
0
    LEPT_FREE(binave);
2060
0
    LEPT_FREE(binstart);
2061
0
    return 0;
2062
0
}
2063
2064
2065
/*--------------------------------------------------------------------*
2066
 *                 Thresholding from 32 bpp rgb to 1 bpp              *
2067
 *--------------------------------------------------------------------*/
2068
/*!
2069
 * \brief   pixGenerateMaskByBand32()
2070
 *
2071
 * \param[in]    pixs     32 bpp
2072
 * \param[in]    refval   reference rgb value
2073
 * \param[in]    delm     max amount below the ref value for any component
2074
 * \param[in]    delp     max amount above the ref value for any component
2075
 * \param[in]    fractm   fractional amount below ref value for all components
2076
 * \param[in]    fractp   fractional amount above ref value for all components
2077
 * \return  pixd 1 bpp, or NULL on error
2078
 *
2079
 * <pre>
2080
 * Notes:
2081
 *      (1) Generates a 1 bpp mask pixd, the same size as pixs, where
2082
 *          the fg pixels in the mask within a band of rgb values
2083
 *          surrounding %refval.  The band can be chosen in two ways
2084
 *          for each component:
2085
 *          (a) Use (%delm, %delp) to specify how many levels down and up
2086
 *          (b) Use (%fractm, %fractp) to specify the fractional
2087
 *              distance toward 0 and 255, respectively.
2088
 *          Note that %delm and %delp must be in [0 ... 255], whereas
2089
 *          %fractm and %fractp must be in [0.0 - 1.0].
2090
 *      (2) Either (%delm, %delp) or (%fractm, %fractp) can be used.
2091
 *          Set each value in the other pair to 0.
2092
 * </pre>
2093
 */
2094
PIX *
2095
pixGenerateMaskByBand32(PIX       *pixs,
2096
                        l_uint32   refval,
2097
                        l_int32    delm,
2098
                        l_int32    delp,
2099
                        l_float32  fractm,
2100
                        l_float32  fractp)
2101
0
{
2102
0
l_int32    i, j, w, h, d, wpls, wpld;
2103
0
l_int32    rref, gref, bref, rval, gval, bval;
2104
0
l_int32    rmin, gmin, bmin, rmax, gmax, bmax;
2105
0
l_uint32   pixel;
2106
0
l_uint32  *datas, *datad, *lines, *lined;
2107
0
PIX       *pixd;
2108
2109
0
    if (!pixs)
2110
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2111
0
    pixGetDimensions(pixs, &w, &h, &d);
2112
0
    if (d != 32)
2113
0
        return (PIX *)ERROR_PTR("not 32 bpp", __func__, NULL);
2114
0
    if (delm < 0 || delp < 0)
2115
0
        return (PIX *)ERROR_PTR("delm and delp must be >= 0", __func__, NULL);
2116
0
    if (fractm < 0.0 || fractm > 1.0 || fractp < 0.0 || fractp > 1.0)
2117
0
        return (PIX *)ERROR_PTR("fractm and/or fractp invalid", __func__, NULL);
2118
2119
0
    extractRGBValues(refval, &rref, &gref, &bref);
2120
0
    if (fractm == 0.0 && fractp == 0.0) {
2121
0
        rmin = rref - delm;
2122
0
        gmin = gref - delm;
2123
0
        bmin = bref - delm;
2124
0
        rmax = rref + delm;
2125
0
        gmax = gref + delm;
2126
0
        bmax = bref + delm;
2127
0
    } else if (delm == 0 && delp == 0) {
2128
0
        rmin = (l_int32)((1.0 - fractm) * rref);
2129
0
        gmin = (l_int32)((1.0 - fractm) * gref);
2130
0
        bmin = (l_int32)((1.0 - fractm) * bref);
2131
0
        rmax = rref + (l_int32)(fractp * (255 - rref));
2132
0
        gmax = gref + (l_int32)(fractp * (255 - gref));
2133
0
        bmax = bref + (l_int32)(fractp * (255 - bref));
2134
0
    } else {
2135
0
        L_ERROR("bad input: either (delm, delp) or (fractm, fractp) "
2136
0
                "must be 0\n", __func__);
2137
0
        return NULL;
2138
0
    }
2139
2140
0
    pixd = pixCreate(w, h, 1);
2141
0
    pixCopyResolution(pixd, pixs);
2142
0
    pixCopyInputFormat(pixd, pixs);
2143
0
    datas = pixGetData(pixs);
2144
0
    wpls = pixGetWpl(pixs);
2145
0
    datad = pixGetData(pixd);
2146
0
    wpld = pixGetWpl(pixd);
2147
0
    for (i = 0; i < h; i++) {
2148
0
        lines = datas + i * wpls;
2149
0
        lined = datad + i * wpld;
2150
0
        for (j = 0; j < w; j++) {
2151
0
            pixel = lines[j];
2152
0
            rval = (pixel >> L_RED_SHIFT) & 0xff;
2153
0
            if (rval < rmin || rval > rmax)
2154
0
                continue;
2155
0
            gval = (pixel >> L_GREEN_SHIFT) & 0xff;
2156
0
            if (gval < gmin || gval > gmax)
2157
0
                continue;
2158
0
            bval = (pixel >> L_BLUE_SHIFT) & 0xff;
2159
0
            if (bval < bmin || bval > bmax)
2160
0
                continue;
2161
0
            SET_DATA_BIT(lined, j);
2162
0
        }
2163
0
    }
2164
2165
0
    return pixd;
2166
0
}
2167
2168
2169
/*!
2170
 * \brief   pixGenerateMaskByDiscr32()
2171
 *
2172
 * \param[in]    pixs       32 bpp
2173
 * \param[in]    refval1    reference rgb value
2174
 * \param[in]    refval2    reference rgb value
2175
 * \param[in]    distflag   L_MANHATTAN_DISTANCE, L_EUCLIDEAN_DISTANCE
2176
 * \return  pixd 1 bpp, or NULL on error
2177
 *
2178
 * <pre>
2179
 * Notes:
2180
 *      (1) Generates a 1 bpp mask pixd, the same size as pixs, where
2181
 *          the fg pixels in the mask are those where the pixel in pixs
2182
 *          is "closer" to refval1 than to refval2.
2183
 *      (2) "Closer" can be defined in several ways, such as:
2184
 *            ~ manhattan distance (L1)
2185
 *            ~ euclidean distance (L2)
2186
 *            ~ majority vote of the individual components
2187
 *          Here, we have a choice of L1 or L2.
2188
 * </pre>
2189
 */
2190
PIX *
2191
pixGenerateMaskByDiscr32(PIX      *pixs,
2192
                         l_uint32  refval1,
2193
                         l_uint32  refval2,
2194
                         l_int32   distflag)
2195
0
{
2196
0
l_int32    i, j, w, h, d, wpls, wpld;
2197
0
l_int32    rref1, gref1, bref1, rref2, gref2, bref2, rval, gval, bval;
2198
0
l_uint32   pixel, dist1, dist2;
2199
0
l_uint32  *datas, *datad, *lines, *lined;
2200
0
PIX       *pixd;
2201
2202
0
    if (!pixs)
2203
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2204
0
    pixGetDimensions(pixs, &w, &h, &d);
2205
0
    if (d != 32)
2206
0
        return (PIX *)ERROR_PTR("not 32 bpp", __func__, NULL);
2207
0
    if (distflag != L_MANHATTAN_DISTANCE && distflag != L_EUCLIDEAN_DISTANCE)
2208
0
        return (PIX *)ERROR_PTR("invalid distflag", __func__, NULL);
2209
2210
0
    extractRGBValues(refval1, &rref1, &gref1, &bref1);
2211
0
    extractRGBValues(refval2, &rref2, &gref2, &bref2);
2212
0
    pixd = pixCreate(w, h, 1);
2213
0
    pixCopyResolution(pixd, pixs);
2214
0
    pixCopyInputFormat(pixd, pixs);
2215
0
    datas = pixGetData(pixs);
2216
0
    wpls = pixGetWpl(pixs);
2217
0
    datad = pixGetData(pixd);
2218
0
    wpld = pixGetWpl(pixd);
2219
0
    for (i = 0; i < h; i++) {
2220
0
        lines = datas + i * wpls;
2221
0
        lined = datad + i * wpld;
2222
0
        for (j = 0; j < w; j++) {
2223
0
            pixel = lines[j];
2224
0
            extractRGBValues(pixel, &rval, &gval, &bval);
2225
0
            if (distflag == L_MANHATTAN_DISTANCE) {
2226
0
                dist1 = L_ABS(rref1 - rval);
2227
0
                dist2 = L_ABS(rref2 - rval);
2228
0
                dist1 += L_ABS(gref1 - gval);
2229
0
                dist2 += L_ABS(gref2 - gval);
2230
0
                dist1 += L_ABS(bref1 - bval);
2231
0
                dist2 += L_ABS(bref2 - bval);
2232
0
            } else {
2233
0
                dist1 = (rref1 - rval) * (rref1 - rval);
2234
0
                dist2 = (rref2 - rval) * (rref2 - rval);
2235
0
                dist1 += (gref1 - gval) * (gref1 - gval);
2236
0
                dist2 += (gref2 - gval) * (gref2 - gval);
2237
0
                dist1 += (bref1 - bval) * (bref1 - bval);
2238
0
                dist2 += (bref2 - bval) * (bref2 - bval);
2239
0
            }
2240
0
            if (dist1 < dist2)
2241
0
                SET_DATA_BIT(lined, j);
2242
0
        }
2243
0
    }
2244
2245
0
    return pixd;
2246
0
}
2247
2248
2249
/*----------------------------------------------------------------------*
2250
 *                Histogram-based grayscale quantization                *
2251
 *----------------------------------------------------------------------*/
2252
/*!
2253
 * \brief   pixGrayQuantFromHisto()
2254
 *
2255
 * \param[in]    pixd       [optional] quantized pix with cmap; can be null
2256
 * \param[in]    pixs       8 bpp gray input pix; not cmapped
2257
 * \param[in]    pixm       [optional] mask over pixels in pixs to quantize
2258
 * \param[in]    minfract   minimum fraction of pixels in a set of adjacent
2259
 *                          histo bins that causes the set to be automatically
2260
 *                          set aside as a color in the colormap; must be
2261
 *                          at least 0.01
2262
 * \param[in]    maxsize    maximum number of adjacent bins allowed to represent
2263
 *                          a color, regardless of the population of pixels
2264
 *                          in the bins; must be at least 2
2265
 * \return  pixd 8 bpp, cmapped, or NULL on error
2266
 *
2267
 * <pre>
2268
 * Notes:
2269
 *      (1) This is useful for quantizing images with relatively few
2270
 *          colors, but which may have both color and gray pixels.
2271
 *          If there are color pixels, it is assumed that an input
2272
 *          rgb image has been color quantized first so that:
2273
 *            ~ pixd has a colormap describing the color pixels
2274
 *            ~ pixm is a mask over the non-color pixels in pixd
2275
 *            ~ the colormap in pixd, and the color pixels in pixd,
2276
 *              have been repacked to go from 0 to n-1 (n colors)
2277
 *          If there are no color pixels, pixd and pixm are both null,
2278
 *          and all pixels in pixs are quantized to gray.
2279
 *      (2) A 256-entry histogram is built of the gray values in pixs.
2280
 *          If pixm exists, the pixels contributing to the histogram are
2281
 *          restricted to the fg of pixm.  A colormap and LUT are generated
2282
 *          from this histogram.  We break up the array into a set
2283
 *          of intervals, each one constituting a color in the colormap:
2284
 *          An interval is identified by summing histogram bins until
2285
 *          either the sum equals or exceeds the %minfract of the total
2286
 *          number of pixels, or the span itself equals or exceeds %maxsize.
2287
 *          The color of each bin is always an average of the pixels
2288
 *          that constitute it.
2289
 *      (3) Note that we do not specify the number of gray colors in
2290
 *          the colormap.  Instead, we specify two parameters that
2291
 *          describe the accuracy of the color assignments; this and
2292
 *          the actual image determine the number of resulting colors.
2293
 *      (4) If a mask exists and it is not the same size as pixs, make
2294
 *          a new mask the same size as pixs, with the original mask
2295
 *          aligned at the UL corners.  Set all additional pixels
2296
 *          in the (larger) new mask set to 1, causing those pixels
2297
 *          in pixd to be set as gray.
2298
 *      (5) We estimate the total number of colors (color plus gray);
2299
 *          if it exceeds 255, return null.
2300
 * </pre>
2301
 */
2302
PIX *
2303
pixGrayQuantFromHisto(PIX       *pixd,
2304
                      PIX       *pixs,
2305
                      PIX       *pixm,
2306
                      l_float32  minfract,
2307
                      l_int32    maxsize)
2308
0
{
2309
0
l_int32    w, h, wd, hd, wm, hm, wpls, wplm, wpld;
2310
0
l_int32    nc, nestim, i, j, vals, vald;
2311
0
l_int32   *lut;
2312
0
l_uint32  *datas, *datam, *datad, *lines, *linem, *lined;
2313
0
NUMA      *na;
2314
0
PIX       *pixmr = NULL;  /* resized mask */
2315
0
PIXCMAP   *cmap;
2316
2317
0
    if (!pixs || pixGetDepth(pixs) != 8)
2318
0
        return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
2319
0
    if (minfract < 0.01) {
2320
0
        L_WARNING("minfract < 0.01; setting to 0.05\n", __func__);
2321
0
        minfract = 0.05f;
2322
0
    }
2323
0
    if (maxsize < 2) {
2324
0
        L_WARNING("maxsize < 2; setting to 10\n", __func__);
2325
0
        maxsize = 10;
2326
0
    }
2327
0
    if ((pixd && !pixm) || (!pixd && pixm))
2328
0
        return (PIX *)ERROR_PTR("(pixd,pixm) not defined together",
2329
0
                                __func__, NULL);
2330
0
    pixGetDimensions(pixs, &w, &h, NULL);
2331
0
    if (pixd) {
2332
0
        if (pixGetDepth(pixm) != 1)
2333
0
            return (PIX *)ERROR_PTR("pixm not 1 bpp", __func__, NULL);
2334
0
        if ((cmap = pixGetColormap(pixd)) == NULL)
2335
0
            return (PIX *)ERROR_PTR("pixd not cmapped", __func__, NULL);
2336
0
        pixGetDimensions(pixd, &wd, &hd, NULL);
2337
0
        if (w != wd || h != hd)
2338
0
            return (PIX *)ERROR_PTR("pixs, pixd sizes differ", __func__, NULL);
2339
0
        nc = pixcmapGetCount(cmap);
2340
0
        nestim = nc + (l_int32)(1.5 * 255 / maxsize);
2341
0
        lept_stderr( "nestim = %d\n", nestim);
2342
0
        if (nestim > 255) {
2343
0
            L_ERROR("Estimate %d colors!\n", __func__, nestim);
2344
0
            return (PIX *)ERROR_PTR("probably too many colors", __func__, NULL);
2345
0
        }
2346
0
        pixGetDimensions(pixm, &wm, &hm, NULL);
2347
0
        if (w != wm || h != hm) {  /* resize the mask */
2348
0
            L_WARNING("mask and dest sizes not equal\n", __func__);
2349
0
            pixmr = pixCreate(w, h, 1);
2350
0
            pixRasterop(pixmr, 0, 0, wm, hm, PIX_SRC, pixm, 0, 0);
2351
0
            pixRasterop(pixmr, wm, 0, w - wm, h, PIX_SET, NULL, 0, 0);
2352
0
            pixRasterop(pixmr, 0, hm, wm, h - hm, PIX_SET, NULL, 0, 0);
2353
0
        } else {
2354
0
            pixmr = pixClone(pixm);
2355
0
        }
2356
0
    } else {
2357
0
        pixd = pixCreateTemplate(pixs);
2358
0
        cmap = pixcmapCreate(8);
2359
0
        pixSetColormap(pixd, cmap);
2360
0
    }
2361
0
    pixCopyResolution(pixd, pixs);
2362
0
    pixCopyInputFormat(pixd, pixs);
2363
2364
        /* Use original mask, if it exists, to select gray pixels */
2365
0
    na = pixGetGrayHistogramMasked(pixs, pixm, 0, 0, 1);
2366
2367
        /* Fill out the cmap with gray colors, and generate the lut
2368
         * for pixel assignment.  Issue a warning on failure.  */
2369
0
    if (numaFillCmapFromHisto(na, cmap, minfract, maxsize, &lut))
2370
0
        L_ERROR("ran out of colors in cmap!\n", __func__);
2371
0
    numaDestroy(&na);
2372
2373
        /* Assign the gray pixels to their cmap indices */
2374
0
    datas = pixGetData(pixs);
2375
0
    datad = pixGetData(pixd);
2376
0
    wpls = pixGetWpl(pixs);
2377
0
    wpld = pixGetWpl(pixd);
2378
0
    if (!pixm) {
2379
0
        for (i = 0; i < h; i++) {
2380
0
            lines = datas + i * wpls;
2381
0
            lined = datad + i * wpld;
2382
0
            for (j = 0; j < w; j++) {
2383
0
                vals = GET_DATA_BYTE(lines, j);
2384
0
                vald = lut[vals];
2385
0
                SET_DATA_BYTE(lined, j, vald);
2386
0
            }
2387
0
        }
2388
0
        LEPT_FREE(lut);
2389
0
        return pixd;
2390
0
    }
2391
2392
0
    datam = pixGetData(pixmr);
2393
0
    wplm = pixGetWpl(pixmr);
2394
0
    for (i = 0; i < h; i++) {
2395
0
        lines = datas + i * wpls;
2396
0
        linem = datam + i * wplm;
2397
0
        lined = datad + i * wpld;
2398
0
        for (j = 0; j < w; j++) {
2399
0
            if (!GET_DATA_BIT(linem, j))
2400
0
                continue;
2401
0
            vals = GET_DATA_BYTE(lines, j);
2402
0
            vald = lut[vals];
2403
0
            SET_DATA_BYTE(lined, j, vald);
2404
0
        }
2405
0
    }
2406
0
    pixDestroy(&pixmr);
2407
0
    LEPT_FREE(lut);
2408
0
    return pixd;
2409
0
}
2410
2411
2412
/*!
2413
 * \brief   numaFillCmapFromHisto()
2414
 *
2415
 * \param[in]    na         histogram of gray values
2416
 * \param[in]    cmap       8 bpp cmap, possibly initialized with color value
2417
 * \param[in]    minfract   minimum fraction of pixels in a set of adjacent
2418
 *                          histo bins that causes the set to be automatically
2419
 *                          set aside as a color in the colormap; must be
2420
 *                          at least 0.01
2421
 * \param[in]    maxsize    maximum number of adjacent bins allowed to represent
2422
 *                          a color, regardless of the population of pixels
2423
 *                          in the bins; must be at least 2
2424
 * \param[out]  plut        lookup table from gray value to colormap index
2425
 * \return  0 if OK, 1 on error
2426
 *
2427
 * <pre>
2428
 * Notes:
2429
 *      (1) This static function must be called from pixGrayQuantFromHisto()
2430
 * </pre>
2431
 */
2432
static l_int32
2433
numaFillCmapFromHisto(NUMA      *na,
2434
                      PIXCMAP   *cmap,
2435
                      l_float32  minfract,
2436
                      l_int32    maxsize,
2437
                      l_int32  **plut)
2438
0
{
2439
0
l_int32    mincount, index, sum, wtsum, span, istart, i, val, ret;
2440
0
l_int32   *iahisto, *lut;
2441
0
l_float32  total;
2442
2443
0
    if (!plut)
2444
0
        return ERROR_INT("&lut not defined", __func__, 1);
2445
0
    *plut = NULL;
2446
0
    if (!na)
2447
0
        return ERROR_INT("na not defined", __func__, 1);
2448
0
    if (!cmap)
2449
0
        return ERROR_INT("cmap not defined", __func__, 1);
2450
2451
0
    numaGetSum(na, &total);
2452
0
    mincount = (l_int32)(minfract * total);
2453
0
    iahisto = numaGetIArray(na);
2454
0
    lut = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2455
0
    *plut = lut;
2456
0
    index = pixcmapGetCount(cmap);  /* start with number of colors
2457
                                     * already reserved */
2458
2459
        /* March through, associating colors with sets of adjacent
2460
         * gray levels.  During the process, the LUT that gives
2461
         * the colormap index for each gray level is computed.
2462
         * To complete a color, either the total count must equal
2463
         * or exceed %mincount, or the current span of colors must
2464
         * equal or exceed %maxsize.  An empty span is not converted
2465
         * into a color; it is simply ignored.  When a span is completed for a
2466
         * color, the weighted color in the span is added to the colormap. */
2467
0
    sum = 0;
2468
0
    wtsum = 0;
2469
0
    istart = 0;
2470
0
    ret = 0;
2471
0
    for (i = 0; i < 256; i++) {
2472
0
        lut[i] = index;
2473
0
        sum += iahisto[i];
2474
0
        wtsum += i * iahisto[i];
2475
0
        span = i - istart + 1;
2476
0
        if (sum < mincount && span < maxsize)
2477
0
            continue;
2478
2479
0
        if (sum == 0) {  /* empty span; don't save */
2480
0
            istart = i + 1;
2481
0
            continue;
2482
0
        }
2483
2484
            /* Found new color; sum > 0 */
2485
0
        val = (l_int32)((l_float32)wtsum / (l_float32)sum + 0.5);
2486
0
        ret = pixcmapAddColor(cmap, val, val, val);
2487
0
        istart = i + 1;
2488
0
        sum = 0;
2489
0
        wtsum = 0;
2490
0
        index++;
2491
0
    }
2492
0
    if (istart < 256 && sum > 0) {  /* last one */
2493
0
        span = 256 - istart;
2494
0
        val = (l_int32)((l_float32)wtsum / (l_float32)sum + 0.5);
2495
0
        ret = pixcmapAddColor(cmap, val, val, val);
2496
0
    }
2497
2498
0
    LEPT_FREE(iahisto);
2499
0
    return ret;
2500
0
}
2501
2502
2503
/*----------------------------------------------------------------------*
2504
 *        Color quantize grayscale image using existing colormap        *
2505
 *----------------------------------------------------------------------*/
2506
/*!
2507
 * \brief   pixGrayQuantFromCmap()
2508
 *
2509
 * \param[in]    pixs       8 bpp grayscale without cmap
2510
 * \param[in]    cmap       to quantize to; of dest pix
2511
 * \param[in]    mindepth   minimum depth of pixd: can be 2, 4 or 8 bpp
2512
 * \return  pixd 2, 4 or 8 bpp, colormapped, or NULL on error
2513
 *
2514
 * <pre>
2515
 * Notes:
2516
 *      (1) In use, pixs is an 8 bpp grayscale image without a colormap.
2517
 *          If there is an existing colormap, a warning is issued and
2518
 *          a copy of the input pixs is returned.
2519
 * </pre>
2520
 */
2521
PIX *
2522
pixGrayQuantFromCmap(PIX      *pixs,
2523
                     PIXCMAP  *cmap,
2524
                     l_int32   mindepth)
2525
0
{
2526
0
l_int32    i, j, index, w, h, d, depth, wpls, wpld;
2527
0
l_int32    hascolor, vals, vald;
2528
0
l_int32   *tab;
2529
0
l_uint32  *datas, *datad, *lines, *lined;
2530
0
PIXCMAP   *cmapd;
2531
0
PIX       *pixd;
2532
2533
0
    if (!pixs)
2534
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2535
0
    if (pixGetColormap(pixs) != NULL) {
2536
0
        L_WARNING("pixs already has a colormap; returning a copy\n", __func__);
2537
0
        return pixCopy(NULL, pixs);
2538
0
    }
2539
0
    pixGetDimensions(pixs, &w, &h, &d);
2540
0
    if (d != 8)
2541
0
        return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
2542
0
    if (!cmap)
2543
0
        return (PIX *)ERROR_PTR("cmap not defined", __func__, NULL);
2544
0
    if (mindepth != 2 && mindepth != 4 && mindepth != 8)
2545
0
        return (PIX *)ERROR_PTR("invalid mindepth", __func__, NULL);
2546
2547
        /* Make sure the colormap is gray */
2548
0
    pixcmapHasColor(cmap, &hascolor);
2549
0
    if (hascolor) {
2550
0
        L_WARNING("Converting colormap colors to gray\n", __func__);
2551
0
        cmapd = pixcmapColorToGray(cmap, 0.3f, 0.5f, 0.2f);
2552
0
    } else {
2553
0
        cmapd = pixcmapCopy(cmap);
2554
0
    }
2555
2556
        /* Make LUT into colormap */
2557
0
    tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2558
0
    for (i = 0; i < 256; i++) {
2559
0
        pixcmapGetNearestGrayIndex(cmapd, i, &index);
2560
0
        tab[i] = index;
2561
0
    }
2562
2563
0
    pixcmapGetMinDepth(cmap, &depth);
2564
0
    depth = L_MAX(depth, mindepth);
2565
0
    pixd = pixCreate(w, h, depth);
2566
0
    pixSetColormap(pixd, cmapd);
2567
0
    pixCopyResolution(pixd, pixs);
2568
0
    pixCopyInputFormat(pixd, pixs);
2569
0
    datas = pixGetData(pixs);
2570
0
    datad = pixGetData(pixd);
2571
0
    wpls = pixGetWpl(pixs);
2572
0
    wpld = pixGetWpl(pixd);
2573
0
    for (i = 0; i < h; i++) {
2574
0
        lines = datas + i * wpls;
2575
0
        lined = datad + i * wpld;
2576
0
        for (j = 0; j < w; j++) {
2577
0
            vals = GET_DATA_BYTE(lines, j);
2578
0
            vald = tab[vals];
2579
0
            if (depth == 2)
2580
0
                SET_DATA_DIBIT(lined, j, vald);
2581
0
            else if (depth == 4)
2582
0
                SET_DATA_QBIT(lined, j, vald);
2583
0
            else  /* depth == 8 */
2584
0
                SET_DATA_BYTE(lined, j, vald);
2585
0
        }
2586
0
    }
2587
2588
0
    LEPT_FREE(tab);
2589
0
    return pixd;
2590
0
}
2591
2592
2593
#if 0   /* Documentation */
2594
/*--------------------------------------------------------------------*
2595
 *       Implementation of binarization by dithering using LUTs       *
2596
 *                        It is archived here.                        *
2597
 *--------------------------------------------------------------------*/
2598
/*!
2599
 * \brief   pixDitherToBinaryLUT()
2600
 *
2601
 * \param[in]    pixs
2602
 * \param[in]    lowerclip  lower clip distance to black; use -1 for default
2603
 * \param[in]    upperclip  upper clip distance to white; use -1 for default
2604
 * \return  pixd dithered binary, or NULL on error
2605
 *
2606
 *  We don't need two implementations of Floyd-Steinberg dithering,
2607
 *  and this one with LUTs is a little more complicated than
2608
 *  pixDitherToBinary().  It uses three lookup tables to generate the
2609
 *  output pixel value and the excess or deficit carried over to the
2610
 *  neighboring pixels.  It's here for pedagogical reasons only.
2611
 */
2612
PIX *
2613
pixDitherToBinaryLUT(PIX     *pixs,
2614
                     l_int32  lowerclip,
2615
                     l_int32  upperclip)
2616
{
2617
l_int32    w, h, d, wplt, wpld;
2618
l_int32   *tabval, *tab38, *tab14;
2619
l_uint32  *datat, *datad;
2620
l_uint32  *bufs1, *bufs2;
2621
PIX       *pixt, *pixd;
2622
2623
    if (!pixs)
2624
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2625
    pixGetDimensions(pixs, &w, &h, &d);
2626
    if (d != 8)
2627
        return (PIX *)ERROR_PTR("must be 8 bpp for dithering", __func__, NULL);
2628
    if (lowerclip < 0)
2629
        lowerclip = DEFAULT_CLIP_LOWER_1;
2630
    if (upperclip < 0)
2631
        upperclip = DEFAULT_CLIP_UPPER_1;
2632
2633
    if ((pixd = pixCreate(w, h, 1)) == NULL)
2634
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2635
    pixCopyResolution(pixd, pixs);
2636
    pixCopyInputFormat(pixd, pixs);
2637
    datad = pixGetData(pixd);
2638
    wpld = pixGetWpl(pixd);
2639
2640
        /* Remove colormap if it exists */
2641
    pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2642
    datat = pixGetData(pixt);
2643
    wplt = pixGetWpl(pixt);
2644
2645
        /* Two line buffers, 1 for current line and 2 for next line */
2646
    bufs1 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
2647
    bufs2 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
2648
    if (!bufs1 || !bufs2) {
2649
        LEPT_FREE(bufs1);
2650
        LEPT_FREE(bufs2);
2651
        pixDestroy(&pixd);
2652
        pixDestroy(&pixt);
2653
        return (PIX *)ERROR_PTR("bufs1, bufs2 not both made", __func__, NULL);
2654
    }
2655
2656
        /* 3 lookup tables: 1-bit value, (3/8)excess, and (1/4)excess */
2657
    make8To1DitherTables(&tabval, &tab38, &tab14, lowerclip, upperclip);
2658
2659
    ditherToBinaryLUTLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2,
2660
                         tabval, tab38, tab14);
2661
2662
    LEPT_FREE(bufs1);
2663
    LEPT_FREE(bufs2);
2664
    LEPT_FREE(tabval);
2665
    LEPT_FREE(tab38);
2666
    LEPT_FREE(tab14);
2667
    pixDestroy(&pixt);
2668
    return pixd;
2669
}
2670
2671
/*!
2672
 * \brief   ditherToBinaryLUTLow()
2673
 *
2674
 *  Low-level function for doing Floyd-Steinberg error diffusion
2675
 *  dithering from 8 bpp (datas) to 1 bpp (datad).  Two source
2676
 *  line buffers, bufs1 and bufs2, are provided, along with three
2677
 *  256-entry lookup tables: tabval gives the output pixel value,
2678
 *  tab38 gives the extra (plus or minus) transferred to the pixels
2679
 *  directly to the left and below, and tab14 gives the extra
2680
 *  transferred to the diagonal below.  The choice of 3/8 and 1/4
2681
 *  is traditional but arbitrary when you use a lookup table; the
2682
 *  only constraint is that the sum is 1.  See other comments below.
2683
 */
2684
void
2685
ditherToBinaryLUTLow(l_uint32  *datad,
2686
                     l_int32    w,
2687
                     l_int32    h,
2688
                     l_int32    wpld,
2689
                     l_uint32  *datas,
2690
                     l_int32    wpls,
2691
                     l_uint32  *bufs1,
2692
                     l_uint32  *bufs2,
2693
                     l_int32   *tabval,
2694
                     l_int32   *tab38,
2695
                     l_int32   *tab14)
2696
{
2697
l_int32      i;
2698
l_uint32    *lined;
2699
2700
        /* do all lines except last line */
2701
    memcpy(bufs2, datas, 4 * wpls);  /* prime the buffer */
2702
    for (i = 0; i < h - 1; i++) {
2703
        memcpy(bufs1, bufs2, 4 * wpls);
2704
        memcpy(bufs2, datas + (i + 1) * wpls, 4 * wpls);
2705
        lined = datad + i * wpld;
2706
        ditherToBinaryLineLUTLow(lined, w, bufs1, bufs2,
2707
                                 tabval, tab38, tab14, 0);
2708
    }
2709
2710
        /* do last line */
2711
    memcpy(bufs1, bufs2, 4 * wpls);
2712
    lined = datad + (h - 1) * wpld;
2713
    ditherToBinaryLineLUTLow(lined, w, bufs1, bufs2, tabval, tab38, tab14,  1);
2714
    return;
2715
}
2716
2717
/*!
2718
 * \brief   ditherToBinaryLineLUTLow()
2719
 *
2720
 * \param[in]    lined          ptr to beginning of dest line
2721
 * \param[in]    w              width of image in pixels
2722
 * \param[in]    bufs1          buffer of current source line
2723
 * \param[in]    bufs2          buffer of next source line
2724
 * \param[in]    tabval         value to assign for current pixel
2725
 * \param[in]    tab38          excess value to give to neighboring 3/8 pixels
2726
 * \param[in]    tab14          excess value to give to neighboring 1/4 pixel
2727
 * \param[in]    lastlineflag   0 if not last dest line, 1 if last dest line
2728
 * \return  void
2729
 */
2730
void
2731
ditherToBinaryLineLUTLow(l_uint32  *lined,
2732
                         l_int32    w,
2733
                         l_uint32  *bufs1,
2734
                         l_uint32  *bufs2,
2735
                         l_int32   *tabval,
2736
                         l_int32   *tab38,
2737
                         l_int32   *tab14,
2738
                         l_int32    lastlineflag)
2739
{
2740
l_int32  j;
2741
l_int32  oval, tab38val, tab14val;
2742
l_uint8  rval, bval, dval;
2743
2744
    if (lastlineflag == 0) {
2745
        for (j = 0; j < w - 1; j++) {
2746
            oval = GET_DATA_BYTE(bufs1, j);
2747
            if (tabval[oval])
2748
                SET_DATA_BIT(lined, j);
2749
            rval = GET_DATA_BYTE(bufs1, j + 1);
2750
            bval = GET_DATA_BYTE(bufs2, j);
2751
            dval = GET_DATA_BYTE(bufs2, j + 1);
2752
            tab38val = tab38[oval];
2753
            if (tab38val == 0)
2754
                continue;
2755
            tab14val = tab14[oval];
2756
            if (tab38val < 0) {
2757
                rval = L_MAX(0, rval + tab38val);
2758
                bval = L_MAX(0, bval + tab38val);
2759
                dval = L_MAX(0, dval + tab14val);
2760
            } else {
2761
                rval = L_MIN(255, rval + tab38val);
2762
                bval = L_MIN(255, bval + tab38val);
2763
                dval = L_MIN(255, dval + tab14val);
2764
            }
2765
            SET_DATA_BYTE(bufs1, j + 1, rval);
2766
            SET_DATA_BYTE(bufs2, j, bval);
2767
            SET_DATA_BYTE(bufs2, j + 1, dval);
2768
        }
2769
2770
            /* do last column: j = w - 1 */
2771
        oval = GET_DATA_BYTE(bufs1, j);
2772
        if (tabval[oval])
2773
            SET_DATA_BIT(lined, j);
2774
        bval = GET_DATA_BYTE(bufs2, j);
2775
        tab38val = tab38[oval];
2776
        if (tab38val < 0) {
2777
            bval = L_MAX(0, bval + tab38val);
2778
            SET_DATA_BYTE(bufs2, j, bval);
2779
        } else if (tab38val > 0 ) {
2780
            bval = L_MIN(255, bval + tab38val);
2781
            SET_DATA_BYTE(bufs2, j, bval);
2782
        }
2783
    } else {   /* lastlineflag == 1 */
2784
        for (j = 0; j < w - 1; j++) {
2785
            oval = GET_DATA_BYTE(bufs1, j);
2786
            if (tabval[oval])
2787
                SET_DATA_BIT(lined, j);
2788
            rval = GET_DATA_BYTE(bufs1, j + 1);
2789
            tab38val = tab38[oval];
2790
            if (tab38val == 0)
2791
                continue;
2792
            if (tab38val < 0)
2793
                rval = L_MAX(0, rval + tab38val);
2794
            else
2795
                rval = L_MIN(255, rval + tab38val);
2796
            SET_DATA_BYTE(bufs1, j + 1, rval);
2797
        }
2798
2799
            /* do last pixel: (i, j) = (h - 1, w - 1) */
2800
        oval = GET_DATA_BYTE(bufs1, j);
2801
        if (tabval[oval])
2802
            SET_DATA_BIT(lined, j);
2803
    }
2804
2805
    return;
2806
}
2807
2808
/*!
2809
 * \brief   make8To1DitherTables()
2810
 *
2811
 * \param[out]  ptabval     value assigned to output pixel; 0 or 1
2812
 * \param[out]  ptab38      amount propagated to pixels left and below
2813
 * \param[out]  ptab14      amount propagated to pixel to left and down
2814
 * \param[in]   lowerclip   values near 0 where the excess is not propagated
2815
 * \param[in]   upperclip   values near 255 where the deficit is not propagated
2816
 *
2817
 * \return  0 if OK, 1 on error
2818
 */
2819
l_ok
2820
make8To1DitherTables(l_int32 **ptabval,
2821
                     l_int32 **ptab38,
2822
                     l_int32 **ptab14,
2823
                     l_int32   lowerclip,
2824
                     l_int32   upperclip)
2825
{
2826
l_int32   i;
2827
l_int32  *tabval, *tab38, *tab14;
2828
2829
    if (ptabval) *ptabval = NULL;
2830
    if (ptab38) *ptab38 = NULL;
2831
    if (ptab14) *ptab14 = NULL;
2832
    if (!ptabval || !ptab38 || !ptab14)
2833
        return ERROR_INT("table ptrs not all defined", __func__, 1);
2834
2835
        /* 3 lookup tables: 1-bit value, (3/8)excess, and (1/4)excess */
2836
    tabval = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2837
    tab38 = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2838
    tab14 = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2839
    if (!tabval || !tab38 || !tab14)
2840
        return ERROR_INT("calloc failure to make small table", __func__, 1);
2841
    *ptabval = tabval;
2842
    *ptab38 = tab38;
2843
    *ptab14 = tab14;
2844
2845
    for (i = 0; i < 256; i++) {
2846
        if (i <= lowerclip) {
2847
            tabval[i] = 1;
2848
            tab38[i] = 0;
2849
            tab14[i] = 0;
2850
        } else if (i < 128) {
2851
            tabval[i] = 1;
2852
            tab38[i] = (3 * i + 4) / 8;
2853
            tab14[i] = (i + 2) / 4;
2854
        } else if (i < 255 - upperclip) {
2855
            tabval[i] = 0;
2856
            tab38[i] = (3 * (i - 255) + 4) / 8;
2857
            tab14[i] = ((i - 255) + 2) / 4;
2858
        } else {  /* i >= 255 - upperclip */
2859
            tabval[i] = 0;
2860
            tab38[i] = 0;
2861
            tab14[i] = 0;
2862
        }
2863
    }
2864
2865
    return 0;
2866
}
2867
#endif   /* Documentation */