Leptonica 1.84.1
Image processing and image analysis suite
Loading...
Searching...
No Matches
grayquant.c
Go to the documentation of this file.
1/*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
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
108static 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);
112static 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);
115static 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);
119static 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);
123static l_int32 make8To2DitherTables(l_int32 **ptabval, l_int32 **ptab38,
124 l_int32 **ptab14, l_int32 cliptoblack,
125 l_int32 cliptowhite);
126static void thresholdTo2bppLow(l_uint32 *datad, l_int32 h, l_int32 wpld,
127 l_uint32 *datas, l_int32 wpls, l_int32 *tab);
128static void thresholdTo4bppLow(l_uint32 *datad, l_int32 h, l_int32 wpld,
129 l_uint32 *datas, l_int32 wpls, l_int32 *tab);
130static l_int32 *makeGrayQuantTargetTable(l_int32 nlevels, l_int32 depth);
131static l_int32 makeGrayQuantColormapArb(PIX *pixs, l_int32 *tab,
132 l_int32 outdepth, PIXCMAP **pcmap);
133static 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 *------------------------------------------------------------------*/
174PIX *
176{
177 if (!pixs)
178 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
179 if (pixGetDepth(pixs) != 8)
180 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", __func__, NULL);
181
184}
185
186
204PIX *
206 l_int32 lowerclip,
207 l_int32 upperclip)
208{
209l_int32 w, h, d, wplt, wpld;
210l_uint32 *datat, *datad;
211l_uint32 *bufs1, *bufs2;
212PIX *pixt, *pixd;
213
214 if (!pixs)
215 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
216 pixGetDimensions(pixs, &w, &h, &d);
217 if (d != 8)
218 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", __func__, NULL);
219 if (lowerclip < 0 || lowerclip > 255)
220 return (PIX *)ERROR_PTR("invalid value for lowerclip", __func__, NULL);
221 if (upperclip < 0 || upperclip > 255)
222 return (PIX *)ERROR_PTR("invalid value for upperclip", __func__, NULL);
223
224 if ((pixd = pixCreate(w, h, 1)) == NULL)
225 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
226 pixCopyResolution(pixd, pixs);
227 pixCopyInputFormat(pixd, pixs);
228 datad = pixGetData(pixd);
229 wpld = pixGetWpl(pixd);
230
231 /* Remove colormap if it exists */
232 if ((pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE)) == NULL) {
233 pixDestroy(&pixd);
234 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
235 }
236 datat = pixGetData(pixt);
237 wplt = pixGetWpl(pixt);
238
239 /* Two line buffers, 1 for current line and 2 for next line */
240 bufs1 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
241 bufs2 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
242 if (!bufs1 || !bufs2) {
243 LEPT_FREE(bufs1);
244 LEPT_FREE(bufs2);
245 pixDestroy(&pixd);
246 pixDestroy(&pixt);
247 return (PIX *)ERROR_PTR("bufs1, bufs2 not both made", __func__, NULL);
248 }
249
250 ditherToBinaryLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2,
251 lowerclip, upperclip);
252
253 LEPT_FREE(bufs1);
254 LEPT_FREE(bufs2);
255 pixDestroy(&pixt);
256 return pixd;
257}
258
259
265static void
266ditherToBinaryLow(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{
277l_int32 i;
278l_uint32 *lined;
279
280 /* do all lines except last line */
281 memcpy(bufs2, datas, 4 * wpls); /* prime the buffer */
282 for (i = 0; i < h - 1; i++) {
283 memcpy(bufs1, bufs2, 4 * wpls);
284 memcpy(bufs2, datas + (i + 1) * wpls, 4 * wpls);
285 lined = datad + i * wpld;
286 ditherToBinaryLineLow(lined, w, bufs1, bufs2, lowerclip, upperclip, 0);
287 }
288
289 /* do last line */
290 memcpy(bufs1, bufs2, 4 * wpls);
291 lined = datad + (h - 1) * wpld;
292 ditherToBinaryLineLow(lined, w, bufs1, bufs2, lowerclip, upperclip, 1);
293}
294
295
321void
322ditherToBinaryLineLow(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{
330l_int32 j;
331l_int32 oval, eval;
332l_uint8 fval1, fval2, rval, bval, dval;
333
334 if (lastlineflag == 0) {
335 for (j = 0; j < w - 1; j++) {
336 oval = GET_DATA_BYTE(bufs1, j);
337 if (oval > 127) { /* binarize to OFF */
338 if ((eval = 255 - oval) > upperclip) {
339 /* subtract from neighbors */
340 fval1 = (3 * eval) / 8;
341 fval2 = eval / 4;
342 rval = GET_DATA_BYTE(bufs1, j + 1);
343 rval = L_MAX(0, rval - fval1);
344 SET_DATA_BYTE(bufs1, j + 1, rval);
345 bval = GET_DATA_BYTE(bufs2, j);
346 bval = L_MAX(0, bval - fval1);
347 SET_DATA_BYTE(bufs2, j, bval);
348 dval = GET_DATA_BYTE(bufs2, j + 1);
349 dval = L_MAX(0, dval - fval2);
350 SET_DATA_BYTE(bufs2, j + 1, dval);
351 }
352 } else { /* oval <= 127; binarize to ON */
353 SET_DATA_BIT(lined, j); /* ON pixel */
354 if (oval > lowerclip) {
355 /* add to neighbors */
356 fval1 = (3 * oval) / 8;
357 fval2 = oval / 4;
358 rval = GET_DATA_BYTE(bufs1, j + 1);
359 rval = L_MIN(255, rval + fval1);
360 SET_DATA_BYTE(bufs1, j + 1, rval);
361 bval = GET_DATA_BYTE(bufs2, j);
362 bval = L_MIN(255, bval + fval1);
363 SET_DATA_BYTE(bufs2, j, bval);
364 dval = GET_DATA_BYTE(bufs2, j + 1);
365 dval = L_MIN(255, dval + fval2);
366 SET_DATA_BYTE(bufs2, j + 1, dval);
367 }
368 }
369 }
370
371 /* do last column: j = w - 1 */
372 oval = GET_DATA_BYTE(bufs1, j);
373 if (oval > 127) { /* binarize to OFF */
374 if ((eval = 255 - oval) > upperclip) {
375 /* subtract from neighbors */
376 fval1 = (3 * eval) / 8;
377 bval = GET_DATA_BYTE(bufs2, j);
378 bval = L_MAX(0, bval - fval1);
379 SET_DATA_BYTE(bufs2, j, bval);
380 }
381 } else { /*oval <= 127; binarize to ON */
382 SET_DATA_BIT(lined, j); /* ON pixel */
383 if (oval > lowerclip) {
384 /* add to neighbors */
385 fval1 = (3 * oval) / 8;
386 bval = GET_DATA_BYTE(bufs2, j);
387 bval = L_MIN(255, bval + fval1);
388 SET_DATA_BYTE(bufs2, j, bval);
389 }
390 }
391 } else { /* lastlineflag == 1 */
392 for (j = 0; j < w - 1; j++) {
393 oval = GET_DATA_BYTE(bufs1, j);
394 if (oval > 127) { /* binarize to OFF */
395 if ((eval = 255 - oval) > upperclip) {
396 /* subtract from neighbors */
397 fval1 = (3 * eval) / 8;
398 rval = GET_DATA_BYTE(bufs1, j + 1);
399 rval = L_MAX(0, rval - fval1);
400 SET_DATA_BYTE(bufs1, j + 1, rval);
401 }
402 } else { /* oval <= 127; binarize to ON */
403 SET_DATA_BIT(lined, j); /* ON pixel */
404 if (oval > lowerclip) {
405 /* add to neighbors */
406 fval1 = (3 * oval) / 8;
407 rval = GET_DATA_BYTE(bufs1, j + 1);
408 rval = L_MIN(255, rval + fval1);
409 SET_DATA_BYTE(bufs1, j + 1, rval);
410 }
411 }
412 }
413
414 /* do last pixel: (i, j) = (h - 1, w - 1) */
415 oval = GET_DATA_BYTE(bufs1, j);
416 if (oval < 128)
417 SET_DATA_BIT(lined, j); /* ON pixel */
418 }
419}
420
421
422/*------------------------------------------------------------------*
423 * Simple (pixelwise) binarization with fixed threshold *
424 *------------------------------------------------------------------*/
442PIX *
444 l_int32 thresh)
445{
446l_int32 d, w, h, wplt, wpld;
447l_uint32 *datat, *datad;
448PIX *pixt, *pixd;
449
450 if (!pixs)
451 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
452 pixGetDimensions(pixs, &w, &h, &d);
453 if (d != 4 && d != 8)
454 return (PIX *)ERROR_PTR("pixs must be 4 or 8 bpp", __func__, NULL);
455 if (thresh < 0)
456 return (PIX *)ERROR_PTR("thresh must be non-negative", __func__, NULL);
457 if (d == 4 && thresh > 16)
458 return (PIX *)ERROR_PTR("4 bpp thresh not in {0-16}", __func__, NULL);
459 if (d == 8 && thresh > 256)
460 return (PIX *)ERROR_PTR("8 bpp thresh not in {0-256}", __func__, NULL);
461
462 if ((pixd = pixCreate(w, h, 1)) == NULL)
463 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
464 pixCopyResolution(pixd, pixs);
465 pixCopyInputFormat(pixd, pixs);
466 datad = pixGetData(pixd);
467 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 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
472 datat = pixGetData(pixt);
473 wplt = pixGetWpl(pixt);
474 if (pixGetColormap(pixs) && d == 4) { /* promoted to 8 bpp */
475 d = 8;
476 thresh *= 16;
477 }
478
479 thresholdToBinaryLow(datad, w, h, wpld, datat, d, wplt, thresh);
480 pixDestroy(&pixt);
481 return pixd;
482}
483
484
491static void
492thresholdToBinaryLow(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{
501l_int32 i;
502l_uint32 *lines, *lined;
503
504 for (i = 0; i < h; i++) {
505 lines = datas + i * wpls;
506 lined = datad + i * wpld;
507 thresholdToBinaryLineLow(lined, w, lines, d, thresh);
508 }
509}
510
511
512/*
513 * thresholdToBinaryLineLow()
514 *
515 */
516void
517thresholdToBinaryLineLow(l_uint32 *lined,
518 l_int32 w,
519 l_uint32 *lines,
520 l_int32 d,
521 l_int32 thresh)
522{
523l_int32 j, k, gval, scount, dcount;
524l_uint32 sword, dword;
525
526 switch (d)
527 {
528 case 4:
529 /* Unrolled as 4 source words, 1 dest word */
530 for (j = 0, scount = 0, dcount = 0; j + 31 < w; j += 32) {
531 dword = 0;
532 for (k = 0; k < 4; k++) {
533 sword = lines[scount++];
534 dword <<= 8;
535 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 dword |= ((gval - thresh) >> 24) & 128;
543 gval = (sword >> 24) & 0xf;
544 dword |= ((gval - thresh) >> 25) & 64;
545 gval = (sword >> 20) & 0xf;
546 dword |= ((gval - thresh) >> 26) & 32;
547 gval = (sword >> 16) & 0xf;
548 dword |= ((gval - thresh) >> 27) & 16;
549 gval = (sword >> 12) & 0xf;
550 dword |= ((gval - thresh) >> 28) & 8;
551 gval = (sword >> 8) & 0xf;
552 dword |= ((gval - thresh) >> 29) & 4;
553 gval = (sword >> 4) & 0xf;
554 dword |= ((gval - thresh) >> 30) & 2;
555 gval = sword & 0xf;
556 dword |= ((gval - thresh) >> 31) & 1;
557 }
558 lined[dcount++] = dword;
559 }
560
561 if (j < w) {
562 dword = 0;
563 for (; j < w; j++) {
564 if ((j & 7) == 0) {
565 sword = lines[scount++];
566 }
567 gval = (sword >> 28) & 0xf;
568 sword <<= 4;
569 dword |= (((gval - thresh) >> 31) & 1) << (31 - (j & 31));
570 }
571 lined[dcount] = dword;
572 }
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 break;
583 case 8:
584 /* Unrolled as 8 source words, 1 dest word */
585 for (j = 0, scount = 0, dcount = 0; j + 31 < w; j += 32) {
586 dword = 0;
587 for (k = 0; k < 8; k++) {
588 sword = lines[scount++];
589 dword <<= 4;
590 gval = (sword >> 24) & 0xff;
591 dword |= ((gval - thresh) >> 28) & 8;
592 gval = (sword >> 16) & 0xff;
593 dword |= ((gval - thresh) >> 29) & 4;
594 gval = (sword >> 8) & 0xff;
595 dword |= ((gval - thresh) >> 30) & 2;
596 gval = sword & 0xff;
597 dword |= ((gval - thresh) >> 31) & 1;
598 }
599 lined[dcount++] = dword;
600 }
601
602 if (j < w) {
603 dword = 0;
604 for (; j < w; j++) {
605 if ((j & 3) == 0) {
606 sword = lines[scount++];
607 }
608 gval = (sword >> 24) & 0xff;
609 sword <<= 8;
610 dword |= (l_uint64)(((gval - thresh) >> 31) & 1)
611 << (31 - (j & 31));
612 }
613 lined[dcount] = dword;
614 }
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 break;
623 default:
624 L_ERROR("src depth not 4 or 8 bpp\n", __func__);
625 break;
626 }
627}
628
629
630/*------------------------------------------------------------------*
631 * Binarization with variable threshold *
632 *------------------------------------------------------------------*/
646PIX *
648 PIX *pixg)
649{
650l_int32 i, j, vals, valg, w, h, d, wpls, wplg, wpld;
651l_uint32 *datas, *datag, *datad, *lines, *lineg, *lined;
652PIX *pixd;
653
654 if (!pixs)
655 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
656 if (!pixg)
657 return (PIX *)ERROR_PTR("pixg not defined", __func__, NULL);
658 if (!pixSizesEqual(pixs, pixg))
659 return (PIX *)ERROR_PTR("pix sizes not equal", __func__, NULL);
660 pixGetDimensions(pixs, &w, &h, &d);
661 if (d != 8)
662 return (PIX *)ERROR_PTR("pixs must be 8 bpp", __func__, NULL);
663
664 pixd = pixCreate(w, h, 1);
665 pixCopyResolution(pixd, pixs);
666 pixCopyInputFormat(pixd, pixs);
667 datad = pixGetData(pixd);
668 wpld = pixGetWpl(pixd);
669 datas = pixGetData(pixs);
670 wpls = pixGetWpl(pixs);
671 datag = pixGetData(pixg);
672 wplg = pixGetWpl(pixg);
673 for (i = 0; i < h; i++) {
674 lines = datas + i * wpls;
675 lineg = datag + i * wplg;
676 lined = datad + i * wpld;
677 for (j = 0; j < w; j++) {
678 vals = GET_DATA_BYTE(lines, j);
679 valg = GET_DATA_BYTE(lineg, j);
680 if (vals < valg)
681 SET_DATA_BIT(lined, j);
682 }
683 }
684
685 return pixd;
686}
687
688
689/*------------------------------------------------------------------*
690 * Binarization by adaptive mapping *
691 *------------------------------------------------------------------*/
719PIX *
721 PIX *pixm,
722 l_float32 gamma)
723{
724 if (!pixs || pixGetDepth(pixs) != 8)
725 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
726
727 return pixAdaptThresholdToBinaryGen(pixs, pixm, gamma, 50, 170, 200);
728}
729
730
757PIX *
759 PIX *pixm,
760 l_float32 gamma,
761 l_int32 blackval,
762 l_int32 whiteval,
763 l_int32 thresh)
764{
765PIX *pix1, *pixd;
766
767 if (!pixs || pixGetDepth(pixs) != 8)
768 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
769
770 if ((pix1 = pixBackgroundNormSimple(pixs, pixm, NULL)) == NULL)
771 return (PIX *)ERROR_PTR("pix1 not made", __func__, NULL);
772 pixGammaTRC(pix1, pix1, gamma, blackval, whiteval);
773 pixd = pixThresholdToBinary(pix1, thresh);
774 pixDestroy(&pix1);
775 return pixd;
776}
777
778
779/*--------------------------------------------------------------------*
780 * Generate a binary mask from pixels of particular value(s) *
781 *--------------------------------------------------------------------*/
801PIX *
803 l_int32 val,
804 l_int32 usecmap)
805{
806l_int32 i, j, w, h, d, wplg, wpld;
807l_uint32 *datag, *datad, *lineg, *lined;
808PIX *pixg, *pixd;
809
810 if (!pixs)
811 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
812 d = pixGetDepth(pixs);
813 if (d != 2 && d != 4 && d != 8)
814 return (PIX *)ERROR_PTR("not 2, 4 or 8 bpp", __func__, NULL);
815
816 if (!usecmap && pixGetColormap(pixs))
817 pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
818 else
819 pixg = pixClone(pixs);
820 pixGetDimensions(pixg, &w, &h, &d);
821 if (d == 8 && (val < 0 || val > 255)) {
822 pixDestroy(&pixg);
823 return (PIX *)ERROR_PTR("val out of 8 bpp range", __func__, NULL);
824 }
825 if (d == 4 && (val < 0 || val > 15)) {
826 pixDestroy(&pixg);
827 return (PIX *)ERROR_PTR("val out of 4 bpp range", __func__, NULL);
828 }
829 if (d == 2 && (val < 0 || val > 3)) {
830 pixDestroy(&pixg);
831 return (PIX *)ERROR_PTR("val out of 2 bpp range", __func__, NULL);
832 }
833
834 pixd = pixCreate(w, h, 1);
835 pixCopyResolution(pixd, pixg);
836 pixCopyInputFormat(pixd, pixs);
837 datag = pixGetData(pixg);
838 wplg = pixGetWpl(pixg);
839 datad = pixGetData(pixd);
840 wpld = pixGetWpl(pixd);
841 for (i = 0; i < h; i++) {
842 lineg = datag + i * wplg;
843 lined = datad + i * wpld;
844 for (j = 0; j < w; j++) {
845 if (d == 8) {
846 if (GET_DATA_BYTE(lineg, j) == val)
847 SET_DATA_BIT(lined, j);
848 } else if (d == 4) {
849 if (GET_DATA_QBIT(lineg, j) == val)
850 SET_DATA_BIT(lined, j);
851 } else { /* d == 2 */
852 if (GET_DATA_DIBIT(lineg, j) == val)
853 SET_DATA_BIT(lined, j);
854 }
855 }
856 }
857
858 pixDestroy(&pixg);
859 return pixd;
860}
861
862
890PIX *
892 l_int32 lower,
893 l_int32 upper,
894 l_int32 inband,
895 l_int32 usecmap)
896{
897l_int32 i, j, w, h, d, wplg, wpld, val;
898l_uint32 *datag, *datad, *lineg, *lined;
899PIX *pixg, *pixd;
900
901 if (!pixs)
902 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
903 d = pixGetDepth(pixs);
904 if (d != 2 && d != 4 && d != 8)
905 return (PIX *)ERROR_PTR("not 2, 4 or 8 bpp", __func__, NULL);
906 if (lower < 0 || lower > upper)
907 return (PIX *)ERROR_PTR("lower < 0 or lower > upper!", __func__, NULL);
908
909 if (!usecmap && pixGetColormap(pixs))
910 pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
911 else
912 pixg = pixClone(pixs);
913 pixGetDimensions(pixg, &w, &h, &d);
914 if (d == 8 && upper > 255) {
915 pixDestroy(&pixg);
916 return (PIX *)ERROR_PTR("d == 8 and upper > 255", __func__, NULL);
917 }
918 if (d == 4 && upper > 15) {
919 pixDestroy(&pixg);
920 return (PIX *)ERROR_PTR("d == 4 and upper > 15", __func__, NULL);
921 }
922 if (d == 2 && upper > 3) {
923 pixDestroy(&pixg);
924 return (PIX *)ERROR_PTR("d == 2 and upper > 3", __func__, NULL);
925 }
926
927 pixd = pixCreate(w, h, 1);
928 pixCopyResolution(pixd, pixg);
929 pixCopyInputFormat(pixd, pixs);
930 datag = pixGetData(pixg);
931 wplg = pixGetWpl(pixg);
932 datad = pixGetData(pixd);
933 wpld = pixGetWpl(pixd);
934 for (i = 0; i < h; i++) {
935 lineg = datag + i * wplg;
936 lined = datad + i * wpld;
937 for (j = 0; j < w; j++) {
938 if (d == 8)
939 val = GET_DATA_BYTE(lineg, j);
940 else if (d == 4)
941 val = GET_DATA_QBIT(lineg, j);
942 else /* d == 2 */
943 val = GET_DATA_DIBIT(lineg, j);
944 if (inband) {
945 if (val >= lower && val <= upper)
946 SET_DATA_BIT(lined, j);
947 } else { /* out of band */
948 if (val < lower || val > upper)
949 SET_DATA_BIT(lined, j);
950 }
951 }
952 }
953
954 pixDestroy(&pixg);
955 return pixd;
956}
957
958
959/*------------------------------------------------------------------*
960 * Thresholding to 2 bpp by dithering *
961 *------------------------------------------------------------------*/
1001PIX *
1003 l_int32 cmapflag)
1004{
1005 if (!pixs)
1006 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1007 if (pixGetDepth(pixs) != 8)
1008 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", __func__, NULL);
1009
1011 DEFAULT_CLIP_UPPER_2, cmapflag);
1012}
1013
1014
1033PIX *
1035 l_int32 lowerclip,
1036 l_int32 upperclip,
1037 l_int32 cmapflag)
1038{
1039l_int32 w, h, d, wplt, wpld;
1040l_int32 *tabval, *tab38, *tab14;
1041l_uint32 *datat, *datad;
1042l_uint32 *bufs1, *bufs2;
1043PIX *pixt, *pixd;
1044PIXCMAP *cmap;
1045
1046 if (!pixs)
1047 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1048 pixGetDimensions(pixs, &w, &h, &d);
1049 if (d != 8)
1050 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", __func__, NULL);
1051 if (lowerclip < 0 || lowerclip > 255)
1052 return (PIX *)ERROR_PTR("invalid value for lowerclip", __func__, NULL);
1053 if (upperclip < 0 || upperclip > 255)
1054 return (PIX *)ERROR_PTR("invalid value for upperclip", __func__, NULL);
1055
1056 if ((pixd = pixCreate(w, h, 2)) == NULL)
1057 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1058 pixCopyResolution(pixd, pixs);
1059 pixCopyInputFormat(pixd, pixs);
1060 datad = pixGetData(pixd);
1061 wpld = pixGetWpl(pixd);
1062
1063 /* If there is a colormap, remove it */
1064 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1065 datat = pixGetData(pixt);
1066 wplt = pixGetWpl(pixt);
1067
1068 /* Two line buffers, 1 for current line and 2 for next line */
1069 bufs1 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
1070 bufs2 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
1071 if (!bufs1 || !bufs2) {
1072 LEPT_FREE(bufs1);
1073 LEPT_FREE(bufs2);
1074 pixDestroy(&pixd);
1075 pixDestroy(&pixt);
1076 return (PIX *)ERROR_PTR("bufs1, bufs2 not both made", __func__, NULL);
1077 }
1078
1079 /* 3 lookup tables: 2-bit value, (3/8)excess, and (1/4)excess */
1080 make8To2DitherTables(&tabval, &tab38, &tab14, lowerclip, upperclip);
1081
1082 ditherTo2bppLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2,
1083 tabval, tab38, tab14);
1084
1085 if (cmapflag) {
1086 cmap = pixcmapCreateLinear(2, 4);
1087 pixSetColormap(pixd, cmap);
1088 }
1089
1090 LEPT_FREE(bufs1);
1091 LEPT_FREE(bufs2);
1092 LEPT_FREE(tabval);
1093 LEPT_FREE(tab38);
1094 LEPT_FREE(tab14);
1095 pixDestroy(&pixt);
1096 return pixd;
1097}
1098
1099
1114static void
1115ditherTo2bppLow(l_uint32 *datad,
1116 l_int32 w,
1117 l_int32 h,
1118 l_int32 wpld,
1119 l_uint32 *datas,
1120 l_int32 wpls,
1121 l_uint32 *bufs1,
1122 l_uint32 *bufs2,
1123 l_int32 *tabval,
1124 l_int32 *tab38,
1125 l_int32 *tab14)
1126{
1127l_int32 i;
1128l_uint32 *lined;
1129
1130 /* do all lines except last line */
1131 memcpy(bufs2, datas, 4 * wpls); /* prime the buffer */
1132 for (i = 0; i < h - 1; i++) {
1133 memcpy(bufs1, bufs2, 4 * wpls);
1134 memcpy(bufs2, datas + (i + 1) * wpls, 4 * wpls);
1135 lined = datad + i * wpld;
1136 ditherTo2bppLineLow(lined, w, bufs1, bufs2, tabval, tab38, tab14, 0);
1137 }
1138
1139 /* do last line */
1140 memcpy(bufs1, bufs2, 4 * wpls);
1141 lined = datad + (h - 1) * wpld;
1142 ditherTo2bppLineLow(lined, w, bufs1, bufs2, tabval, tab38, tab14, 1);
1143}
1144
1145
1172static void
1173ditherTo2bppLineLow(l_uint32 *lined,
1174 l_int32 w,
1175 l_uint32 *bufs1,
1176 l_uint32 *bufs2,
1177 l_int32 *tabval,
1178 l_int32 *tab38,
1179 l_int32 *tab14,
1180 l_int32 lastlineflag)
1181{
1182l_int32 j;
1183l_int32 oval, tab38val, tab14val;
1184l_uint8 rval, bval, dval;
1185
1186 if (lastlineflag == 0) {
1187 for (j = 0; j < w - 1; j++) {
1188 oval = GET_DATA_BYTE(bufs1, j);
1189 SET_DATA_DIBIT(lined, j, tabval[oval]);
1190 rval = GET_DATA_BYTE(bufs1, j + 1);
1191 bval = GET_DATA_BYTE(bufs2, j);
1192 dval = GET_DATA_BYTE(bufs2, j + 1);
1193 tab38val = tab38[oval];
1194 tab14val = tab14[oval];
1195 if (tab38val < 0) {
1196 rval = L_MAX(0, rval + tab38val);
1197 bval = L_MAX(0, bval + tab38val);
1198 dval = L_MAX(0, dval + tab14val);
1199 } else {
1200 rval = L_MIN(255, rval + tab38val);
1201 bval = L_MIN(255, bval + tab38val);
1202 dval = L_MIN(255, dval + tab14val);
1203 }
1204 SET_DATA_BYTE(bufs1, j + 1, rval);
1205 SET_DATA_BYTE(bufs2, j, bval);
1206 SET_DATA_BYTE(bufs2, j + 1, dval);
1207 }
1208
1209 /* do last column: j = w - 1 */
1210 oval = GET_DATA_BYTE(bufs1, j);
1211 SET_DATA_DIBIT(lined, j, tabval[oval]);
1212 bval = GET_DATA_BYTE(bufs2, j);
1213 tab38val = tab38[oval];
1214 if (tab38val < 0)
1215 bval = L_MAX(0, bval + tab38val);
1216 else
1217 bval = L_MIN(255, bval + tab38val);
1218 SET_DATA_BYTE(bufs2, j, bval);
1219 } else { /* lastlineflag == 1 */
1220 for (j = 0; j < w - 1; j++) {
1221 oval = GET_DATA_BYTE(bufs1, j);
1222 SET_DATA_DIBIT(lined, j, tabval[oval]);
1223 rval = GET_DATA_BYTE(bufs1, j + 1);
1224 tab38val = tab38[oval];
1225 if (tab38val < 0)
1226 rval = L_MAX(0, rval + tab38val);
1227 else
1228 rval = L_MIN(255, rval + tab38val);
1229 SET_DATA_BYTE(bufs1, j + 1, rval);
1230 }
1231
1232 /* do last pixel: (i, j) = (h - 1, w - 1) */
1233 oval = GET_DATA_BYTE(bufs1, j);
1234 SET_DATA_DIBIT(lined, j, tabval[oval]);
1235 }
1236}
1237
1238
1250static l_int32
1251make8To2DitherTables(l_int32 **ptabval,
1252 l_int32 **ptab38,
1253 l_int32 **ptab14,
1254 l_int32 cliptoblack,
1255 l_int32 cliptowhite)
1256{
1257l_int32 i;
1258l_int32 *tabval, *tab38, *tab14;
1259
1260 /* 3 lookup tables: 2-bit value, (3/8)excess, and (1/4)excess */
1261 tabval = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1262 tab38 = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1263 tab14 = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1264 *ptabval = tabval;
1265 *ptab38 = tab38;
1266 *ptab14 = tab14;
1267
1268 for (i = 0; i < 256; i++) {
1269 if (i <= cliptoblack) {
1270 tabval[i] = 0;
1271 tab38[i] = 0;
1272 tab14[i] = 0;
1273 } else if (i < 43) {
1274 tabval[i] = 0;
1275 tab38[i] = (3 * i + 4) / 8;
1276 tab14[i] = (i + 2) / 4;
1277 } else if (i < 85) {
1278 tabval[i] = 1;
1279 tab38[i] = (3 * (i - 85) - 4) / 8;
1280 tab14[i] = ((i - 85) - 2) / 4;
1281 } else if (i < 128) {
1282 tabval[i] = 1;
1283 tab38[i] = (3 * (i - 85) + 4) / 8;
1284 tab14[i] = ((i - 85) + 2) / 4;
1285 } else if (i < 170) {
1286 tabval[i] = 2;
1287 tab38[i] = (3 * (i - 170) - 4) / 8;
1288 tab14[i] = ((i - 170) - 2) / 4;
1289 } else if (i < 213) {
1290 tabval[i] = 2;
1291 tab38[i] = (3 * (i - 170) + 4) / 8;
1292 tab14[i] = ((i - 170) + 2) / 4;
1293 } else if (i < 255 - cliptowhite) {
1294 tabval[i] = 3;
1295 tab38[i] = (3 * (i - 255) - 4) / 8;
1296 tab14[i] = ((i - 255) - 2) / 4;
1297 } else { /* i >= 255 - cliptowhite */
1298 tabval[i] = 3;
1299 tab38[i] = 0;
1300 tab14[i] = 0;
1301 }
1302 }
1303
1304 return 0;
1305}
1306
1307
1308/*--------------------------------------------------------------------*
1309 * Simple (pixelwise) thresholding to 2 bpp with optional colormap *
1310 *--------------------------------------------------------------------*/
1355PIX *
1357 l_int32 nlevels,
1358 l_int32 cmapflag)
1359{
1360l_int32 *qtab;
1361l_int32 w, h, d, wplt, wpld;
1362l_uint32 *datat, *datad;
1363PIX *pixt, *pixd;
1364PIXCMAP *cmap;
1365
1366 if (!pixs)
1367 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1368 pixGetDimensions(pixs, &w, &h, &d);
1369 if (d != 8)
1370 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
1371 if (nlevels < 2 || nlevels > 4)
1372 return (PIX *)ERROR_PTR("nlevels not in {2, 3, 4}", __func__, NULL);
1373
1374 if ((pixd = pixCreate(w, h, 2)) == NULL)
1375 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1376 pixCopyResolution(pixd, pixs);
1377 pixCopyInputFormat(pixd, pixs);
1378 datad = pixGetData(pixd);
1379 wpld = pixGetWpl(pixd);
1380
1381 if (cmapflag) { /* hold out (4 - nlevels) cmap entries */
1382 cmap = pixcmapCreateLinear(2, nlevels);
1383 pixSetColormap(pixd, cmap);
1384 }
1385
1386 /* If there is a colormap in the src, remove it */
1387 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1388 datat = pixGetData(pixt);
1389 wplt = pixGetWpl(pixt);
1390
1391 /* Make the appropriate table */
1392 if (cmapflag)
1393 qtab = makeGrayQuantIndexTable(nlevels);
1394 else
1395 qtab = makeGrayQuantTargetTable(4, 2);
1396
1397 thresholdTo2bppLow(datad, h, wpld, datat, wplt, qtab);
1398
1399 LEPT_FREE(qtab);
1400 pixDestroy(&pixt);
1401 return pixd;
1402}
1403
1404
1417static void
1418thresholdTo2bppLow(l_uint32 *datad,
1419 l_int32 h,
1420 l_int32 wpld,
1421 l_uint32 *datas,
1422 l_int32 wpls,
1423 l_int32 *tab)
1424{
1425l_uint8 sval1, sval2, sval3, sval4, dval;
1426l_int32 i, j, k;
1427l_uint32 *lines, *lined;
1428
1429 for (i = 0; i < h; i++) {
1430 lines = datas + i * wpls;
1431 lined = datad + i * wpld;
1432 for (j = 0; j < wpls; j++) {
1433 k = 4 * j;
1434 sval1 = GET_DATA_BYTE(lines, k);
1435 sval2 = GET_DATA_BYTE(lines, k + 1);
1436 sval3 = GET_DATA_BYTE(lines, k + 2);
1437 sval4 = GET_DATA_BYTE(lines, k + 3);
1438 dval = (tab[sval1] << 6) | (tab[sval2] << 4) |
1439 (tab[sval3] << 2) | tab[sval4];
1440 SET_DATA_BYTE(lined, j, dval);
1441 }
1442 }
1443}
1444
1445
1446/*----------------------------------------------------------------------*
1447 * Simple (pixelwise) thresholding to 4 bpp *
1448 *----------------------------------------------------------------------*/
1495PIX *
1497 l_int32 nlevels,
1498 l_int32 cmapflag)
1499{
1500l_int32 *qtab;
1501l_int32 w, h, d, wplt, wpld;
1502l_uint32 *datat, *datad;
1503PIX *pixt, *pixd;
1504PIXCMAP *cmap;
1505
1506 if (!pixs)
1507 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1508 pixGetDimensions(pixs, &w, &h, &d);
1509 if (d != 8)
1510 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
1511 if (nlevels < 2 || nlevels > 16)
1512 return (PIX *)ERROR_PTR("nlevels not in [2,...,16]", __func__, NULL);
1513
1514 if ((pixd = pixCreate(w, h, 4)) == NULL)
1515 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1516 pixCopyResolution(pixd, pixs);
1517 pixCopyInputFormat(pixd, pixs);
1518 datad = pixGetData(pixd);
1519 wpld = pixGetWpl(pixd);
1520
1521 if (cmapflag) { /* hold out (16 - nlevels) cmap entries */
1522 cmap = pixcmapCreateLinear(4, nlevels);
1523 pixSetColormap(pixd, cmap);
1524 }
1525
1526 /* If there is a colormap in the src, remove it */
1527 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1528 datat = pixGetData(pixt);
1529 wplt = pixGetWpl(pixt);
1530
1531 /* Make the appropriate table */
1532 if (cmapflag)
1533 qtab = makeGrayQuantIndexTable(nlevels);
1534 else
1535 qtab = makeGrayQuantTargetTable(16, 4);
1536
1537 thresholdTo4bppLow(datad, h, wpld, datat, wplt, qtab);
1538
1539 LEPT_FREE(qtab);
1540 pixDestroy(&pixt);
1541 return pixd;
1542}
1543
1544
1557static void
1558thresholdTo4bppLow(l_uint32 *datad,
1559 l_int32 h,
1560 l_int32 wpld,
1561 l_uint32 *datas,
1562 l_int32 wpls,
1563 l_int32 *tab)
1564{
1565l_uint8 sval1, sval2, sval3, sval4;
1566l_uint16 dval;
1567l_int32 i, j, k;
1568l_uint32 *lines, *lined;
1569
1570 for (i = 0; i < h; i++) {
1571 lines = datas + i * wpls;
1572 lined = datad + i * wpld;
1573 for (j = 0; j < wpls; j++) {
1574 k = 4 * j;
1575 sval1 = GET_DATA_BYTE(lines, k);
1576 sval2 = GET_DATA_BYTE(lines, k + 1);
1577 sval3 = GET_DATA_BYTE(lines, k + 2);
1578 sval4 = GET_DATA_BYTE(lines, k + 3);
1579 dval = (tab[sval1] << 12) | (tab[sval2] << 8) |
1580 (tab[sval3] << 4) | tab[sval4];
1581 SET_DATA_TWO_BYTES(lined, j, dval);
1582 }
1583 }
1584}
1585
1586
1587/*----------------------------------------------------------------------*
1588 * Simple (pixelwise) thresholding on 8 bpp with optional colormap *
1589 *----------------------------------------------------------------------*/
1610PIX *
1612 l_int32 nlevels,
1613 l_int32 cmapflag)
1614{
1615l_int32 *qtab; /* quantization table */
1616l_int32 i, j, w, h, wpld, val, newval;
1617l_uint32 *datad, *lined;
1618PIX *pixd;
1619PIXCMAP *cmap;
1620
1621 if (!pixs)
1622 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1623 if (pixGetDepth(pixs) != 8)
1624 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
1625 if (nlevels < 2 || nlevels > 256)
1626 return (PIX *)ERROR_PTR("nlevels not in [2,...,256]", __func__, NULL);
1627
1628 /* Get a new pixd; if there is a colormap in the src, remove it */
1629 if (pixGetColormap(pixs))
1630 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1631 else
1632 pixd = pixCopy(NULL, pixs);
1633
1634 if (cmapflag) { /* hold out (256 - nlevels) cmap entries */
1635 cmap = pixcmapCreateLinear(8, nlevels);
1636 pixSetColormap(pixd, cmap);
1637 }
1638
1639 if (cmapflag)
1640 qtab = makeGrayQuantIndexTable(nlevels);
1641 else
1642 qtab = makeGrayQuantTargetTable(nlevels, 8);
1643
1644 pixGetDimensions(pixd, &w, &h, NULL);
1645 pixCopyResolution(pixd, pixs);
1646 pixCopyInputFormat(pixd, pixs);
1647 datad = pixGetData(pixd);
1648 wpld = pixGetWpl(pixd);
1649 for (i = 0; i < h; i++) {
1650 lined = datad + i * wpld;
1651 for (j = 0; j < w; j++) {
1652 val = GET_DATA_BYTE(lined, j);
1653 newval = qtab[val];
1654 SET_DATA_BYTE(lined, j, newval);
1655 }
1656 }
1657
1658 LEPT_FREE(qtab);
1659 return pixd;
1660}
1661
1662
1663/*----------------------------------------------------------------------*
1664 * Arbitrary (pixelwise) thresholding from 8 bpp to 2, 4 or 8 bpp *
1665 *----------------------------------------------------------------------*/
1709PIX *
1711 const char *edgevals,
1712 l_int32 outdepth,
1713 l_int32 use_average,
1714 l_int32 setblack,
1715 l_int32 setwhite)
1716{
1717l_int32 *qtab;
1718l_int32 w, h, d, i, j, n, wplt, wpld, val, newval;
1719l_uint32 *datat, *datad, *linet, *lined;
1720NUMA *na;
1721PIX *pixt, *pixd;
1722PIXCMAP *cmap;
1723
1724 if (!pixs)
1725 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1726 pixGetDimensions(pixs, &w, &h, &d);
1727 if (d != 8)
1728 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
1729 if (!edgevals)
1730 return (PIX *)ERROR_PTR("edgevals not defined", __func__, NULL);
1731 if (outdepth != 0 && outdepth != 2 && outdepth != 4 && outdepth != 8)
1732 return (PIX *)ERROR_PTR("invalid outdepth", __func__, NULL);
1733
1734 /* Parse and sort (if required) the bin edge values */
1735 na = parseStringForNumbers(edgevals, " \t\n,");
1736 n = numaGetCount(na);
1737 if (n > 255) {
1738 numaDestroy(&na);
1739 return (PIX *)ERROR_PTR("more than 256 levels", __func__, NULL);
1740 }
1741 if (outdepth == 0) {
1742 if (n <= 3)
1743 outdepth = 2;
1744 else if (n <= 15)
1745 outdepth = 4;
1746 else
1747 outdepth = 8;
1748 } else if (n + 1 > (1 << outdepth)) {
1749 L_WARNING("outdepth too small; setting to 8 bpp\n", __func__);
1750 outdepth = 8;
1751 }
1752 numaSort(na, na, L_SORT_INCREASING);
1753
1754 /* Make the quantization LUT and the colormap */
1755 makeGrayQuantTableArb(na, outdepth, &qtab, &cmap);
1756 if (use_average) { /* use the average value in each bin */
1757 pixcmapDestroy(&cmap);
1758 makeGrayQuantColormapArb(pixs, qtab, outdepth, &cmap);
1759 }
1760 pixcmapSetBlackAndWhite(cmap, setblack, setwhite);
1761 numaDestroy(&na);
1762
1763 if ((pixd = pixCreate(w, h, outdepth)) == NULL) {
1764 LEPT_FREE(qtab);
1765 pixcmapDestroy(&cmap);
1766 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1767 }
1768 pixCopyResolution(pixd, pixs);
1769 pixCopyInputFormat(pixd, pixs);
1770 pixSetColormap(pixd, cmap);
1771 datad = pixGetData(pixd);
1772 wpld = pixGetWpl(pixd);
1773
1774 /* If there is a colormap in the src, remove it */
1775 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1776 datat = pixGetData(pixt);
1777 wplt = pixGetWpl(pixt);
1778
1779 if (outdepth == 2) {
1780 thresholdTo2bppLow(datad, h, wpld, datat, wplt, qtab);
1781 } else if (outdepth == 4) {
1782 thresholdTo4bppLow(datad, h, wpld, datat, wplt, qtab);
1783 } else {
1784 for (i = 0; i < h; i++) {
1785 lined = datad + i * wpld;
1786 linet = datat + i * wplt;
1787 for (j = 0; j < w; j++) {
1788 val = GET_DATA_BYTE(linet, j);
1789 newval = qtab[val];
1790 SET_DATA_BYTE(lined, j, newval);
1791 }
1792 }
1793 }
1794
1795 LEPT_FREE(qtab);
1796 pixDestroy(&pixt);
1797 return pixd;
1798}
1799
1800
1801/*----------------------------------------------------------------------*
1802 * Quantization tables for linear thresholds of grayscale images *
1803 *----------------------------------------------------------------------*/
1817l_int32 *
1819{
1820l_int32 *tab;
1821l_int32 i, j, thresh;
1822
1823 tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1824 for (i = 0; i < 256; i++) {
1825 for (j = 0; j < nlevels; j++) {
1826 thresh = 255 * (2 * j + 1) / (2 * nlevels - 2);
1827 if (i <= thresh) {
1828 tab[i] = j;
1829/* lept_stderr("tab[%d] = %d\n", i, j); */
1830 break;
1831 }
1832 }
1833 }
1834 return tab;
1835}
1836
1837
1866static l_int32 *
1868 l_int32 depth)
1869{
1870l_int32 *tab;
1871l_int32 i, j, thresh, maxval, quantval;
1872
1873 tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1874 maxval = (1 << depth) - 1;
1875 if (depth < 8)
1876 nlevels = 1 << depth;
1877 for (i = 0; i < 256; i++) {
1878 for (j = 0; j < nlevels; j++) {
1879 thresh = 255 * (2 * j + 1) / (2 * nlevels - 2);
1880 if (i <= thresh) {
1881 quantval = maxval * j / (nlevels - 1);
1882 tab[i] = quantval;
1883/* lept_stderr("tab[%d] = %d\n", i, tab[i]); */
1884 break;
1885 }
1886 }
1887 }
1888 return tab;
1889}
1890
1891
1892/*----------------------------------------------------------------------*
1893 * Quantization table for arbitrary thresholding of grayscale images *
1894 *----------------------------------------------------------------------*/
1919l_ok
1921 l_int32 outdepth,
1922 l_int32 **ptab,
1923 PIXCMAP **pcmap)
1924{
1925l_int32 i, j, n, jstart, ave, val;
1926l_int32 *tab;
1927PIXCMAP *cmap;
1928
1929 if (!ptab)
1930 return ERROR_INT("&tab not defined", __func__, 1);
1931 *ptab = NULL;
1932 if (!pcmap)
1933 return ERROR_INT("&cmap not defined", __func__, 1);
1934 *pcmap = NULL;
1935 if (!na)
1936 return ERROR_INT("na not defined", __func__, 1);
1937 n = numaGetCount(na);
1938 if (n + 1 > (1 << outdepth))
1939 return ERROR_INT("more bins than cmap levels", __func__, 1);
1940
1941 if ((cmap = pixcmapCreate(outdepth)) == NULL)
1942 return ERROR_INT("cmap not made", __func__, 1);
1943 tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1944 *ptab = tab;
1945 *pcmap = cmap;
1946
1947 /* First n bins */
1948 jstart = 0;
1949 for (i = 0; i < n; i++) {
1950 numaGetIValue(na, i, &val);
1951 ave = (jstart + val) / 2;
1952 pixcmapAddColor(cmap, ave, ave, ave);
1953 for (j = jstart; j < val; j++)
1954 tab[j] = i;
1955 jstart = val;
1956 }
1957
1958 /* Last bin */
1959 ave = (jstart + 255) / 2;
1960 pixcmapAddColor(cmap, ave, ave, ave);
1961 for (j = jstart; j < 256; j++)
1962 tab[j] = n;
1963
1964 return 0;
1965}
1966
1967
1989static l_int32
1991 l_int32 *tab,
1992 l_int32 outdepth,
1993 PIXCMAP **pcmap)
1994{
1995l_int32 i, j, index, w, h, d, nbins, wpl, factor, val;
1996l_int32 *bincount, *binave, *binstart;
1997l_uint32 *line, *data;
1998
1999 if (!pcmap)
2000 return ERROR_INT("&cmap not defined", __func__, 1);
2001 *pcmap = NULL;
2002 if (!pixs)
2003 return ERROR_INT("pixs not defined", __func__, 1);
2004 pixGetDimensions(pixs, &w, &h, &d);
2005 if (d != 8)
2006 return ERROR_INT("pixs not 8 bpp", __func__, 1);
2007 if (!tab)
2008 return ERROR_INT("tab not defined", __func__, 1);
2009 nbins = tab[255] + 1;
2010 if (nbins > (1 << outdepth))
2011 return ERROR_INT("more bins than cmap levels", __func__, 1);
2012
2013 /* Find the count and weighted count for each bin */
2014 if ((bincount = (l_int32 *)LEPT_CALLOC(nbins, sizeof(l_int32))) == NULL)
2015 return ERROR_INT("calloc fail for bincount", __func__, 1);
2016 if ((binave = (l_int32 *)LEPT_CALLOC(nbins, sizeof(l_int32))) == NULL) {
2017 LEPT_FREE(bincount);
2018 return ERROR_INT("calloc fail for binave", __func__, 1);
2019 }
2020 factor = (l_int32)(sqrt((l_float64)(w * h) / 30000.) + 0.5);
2021 factor = L_MAX(1, factor);
2022 data = pixGetData(pixs);
2023 wpl = pixGetWpl(pixs);
2024 for (i = 0; i < h; i += factor) {
2025 line = data + i * wpl;
2026 for (j = 0; j < w; j += factor) {
2027 val = GET_DATA_BYTE(line, j);
2028 bincount[tab[val]]++;
2029 binave[tab[val]] += val;
2030 }
2031 }
2032
2033 /* Find the smallest gray values in each bin */
2034 binstart = (l_int32 *)LEPT_CALLOC(nbins, sizeof(l_int32));
2035 for (i = 1, index = 1; i < 256; i++) {
2036 if (tab[i] < index) continue;
2037 if (tab[i] == index)
2038 binstart[index++] = i;
2039 }
2040
2041 /* Get the averages. If there are no samples in a bin, use
2042 * the center value of the bin. */
2043 *pcmap = pixcmapCreate(outdepth);
2044 for (i = 0; i < nbins; i++) {
2045 if (bincount[i]) {
2046 val = binave[i] / bincount[i];
2047 } else { /* no samples in the bin */
2048 if (i < nbins - 1)
2049 val = (binstart[i] + binstart[i + 1]) / 2;
2050 else /* last bin */
2051 val = (binstart[i] + 255) / 2;
2052 }
2053 pixcmapAddColor(*pcmap, val, val, val);
2054 }
2055
2056 LEPT_FREE(bincount);
2057 LEPT_FREE(binave);
2058 LEPT_FREE(binstart);
2059 return 0;
2060}
2061
2062
2063/*--------------------------------------------------------------------*
2064 * Thresholding from 32 bpp rgb to 1 bpp *
2065 *--------------------------------------------------------------------*/
2092PIX *
2094 l_uint32 refval,
2095 l_int32 delm,
2096 l_int32 delp,
2097 l_float32 fractm,
2098 l_float32 fractp)
2099{
2100l_int32 i, j, w, h, d, wpls, wpld;
2101l_int32 rref, gref, bref, rval, gval, bval;
2102l_int32 rmin, gmin, bmin, rmax, gmax, bmax;
2103l_uint32 pixel;
2104l_uint32 *datas, *datad, *lines, *lined;
2105PIX *pixd;
2106
2107 if (!pixs)
2108 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2109 pixGetDimensions(pixs, &w, &h, &d);
2110 if (d != 32)
2111 return (PIX *)ERROR_PTR("not 32 bpp", __func__, NULL);
2112 if (delm < 0 || delp < 0)
2113 return (PIX *)ERROR_PTR("delm and delp must be >= 0", __func__, NULL);
2114 if (fractm < 0.0 || fractm > 1.0 || fractp < 0.0 || fractp > 1.0)
2115 return (PIX *)ERROR_PTR("fractm and/or fractp invalid", __func__, NULL);
2116
2117 extractRGBValues(refval, &rref, &gref, &bref);
2118 if (fractm == 0.0 && fractp == 0.0) {
2119 rmin = rref - delm;
2120 gmin = gref - delm;
2121 bmin = bref - delm;
2122 rmax = rref + delm;
2123 gmax = gref + delm;
2124 bmax = bref + delm;
2125 } else if (delm == 0 && delp == 0) {
2126 rmin = (l_int32)((1.0 - fractm) * rref);
2127 gmin = (l_int32)((1.0 - fractm) * gref);
2128 bmin = (l_int32)((1.0 - fractm) * bref);
2129 rmax = rref + (l_int32)(fractp * (255 - rref));
2130 gmax = gref + (l_int32)(fractp * (255 - gref));
2131 bmax = bref + (l_int32)(fractp * (255 - bref));
2132 } else {
2133 L_ERROR("bad input: either (delm, delp) or (fractm, fractp) "
2134 "must be 0\n", __func__);
2135 return NULL;
2136 }
2137
2138 pixd = pixCreate(w, h, 1);
2139 pixCopyResolution(pixd, pixs);
2140 pixCopyInputFormat(pixd, pixs);
2141 datas = pixGetData(pixs);
2142 wpls = pixGetWpl(pixs);
2143 datad = pixGetData(pixd);
2144 wpld = pixGetWpl(pixd);
2145 for (i = 0; i < h; i++) {
2146 lines = datas + i * wpls;
2147 lined = datad + i * wpld;
2148 for (j = 0; j < w; j++) {
2149 pixel = lines[j];
2150 rval = (pixel >> L_RED_SHIFT) & 0xff;
2151 if (rval < rmin || rval > rmax)
2152 continue;
2153 gval = (pixel >> L_GREEN_SHIFT) & 0xff;
2154 if (gval < gmin || gval > gmax)
2155 continue;
2156 bval = (pixel >> L_BLUE_SHIFT) & 0xff;
2157 if (bval < bmin || bval > bmax)
2158 continue;
2159 SET_DATA_BIT(lined, j);
2160 }
2161 }
2162
2163 return pixd;
2164}
2165
2166
2188PIX *
2190 l_uint32 refval1,
2191 l_uint32 refval2,
2192 l_int32 distflag)
2193{
2194l_int32 i, j, w, h, d, wpls, wpld;
2195l_int32 rref1, gref1, bref1, rref2, gref2, bref2, rval, gval, bval;
2196l_uint32 pixel, dist1, dist2;
2197l_uint32 *datas, *datad, *lines, *lined;
2198PIX *pixd;
2199
2200 if (!pixs)
2201 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2202 pixGetDimensions(pixs, &w, &h, &d);
2203 if (d != 32)
2204 return (PIX *)ERROR_PTR("not 32 bpp", __func__, NULL);
2205 if (distflag != L_MANHATTAN_DISTANCE && distflag != L_EUCLIDEAN_DISTANCE)
2206 return (PIX *)ERROR_PTR("invalid distflag", __func__, NULL);
2207
2208 extractRGBValues(refval1, &rref1, &gref1, &bref1);
2209 extractRGBValues(refval2, &rref2, &gref2, &bref2);
2210 pixd = pixCreate(w, h, 1);
2211 pixCopyResolution(pixd, pixs);
2212 pixCopyInputFormat(pixd, pixs);
2213 datas = pixGetData(pixs);
2214 wpls = pixGetWpl(pixs);
2215 datad = pixGetData(pixd);
2216 wpld = pixGetWpl(pixd);
2217 for (i = 0; i < h; i++) {
2218 lines = datas + i * wpls;
2219 lined = datad + i * wpld;
2220 for (j = 0; j < w; j++) {
2221 pixel = lines[j];
2222 extractRGBValues(pixel, &rval, &gval, &bval);
2223 if (distflag == L_MANHATTAN_DISTANCE) {
2224 dist1 = L_ABS(rref1 - rval);
2225 dist2 = L_ABS(rref2 - rval);
2226 dist1 += L_ABS(gref1 - gval);
2227 dist2 += L_ABS(gref2 - gval);
2228 dist1 += L_ABS(bref1 - bval);
2229 dist2 += L_ABS(bref2 - bval);
2230 } else {
2231 dist1 = (rref1 - rval) * (rref1 - rval);
2232 dist2 = (rref2 - rval) * (rref2 - rval);
2233 dist1 += (gref1 - gval) * (gref1 - gval);
2234 dist2 += (gref2 - gval) * (gref2 - gval);
2235 dist1 += (bref1 - bval) * (bref1 - bval);
2236 dist2 += (bref2 - bval) * (bref2 - bval);
2237 }
2238 if (dist1 < dist2)
2239 SET_DATA_BIT(lined, j);
2240 }
2241 }
2242
2243 return pixd;
2244}
2245
2246
2247/*----------------------------------------------------------------------*
2248 * Histogram-based grayscale quantization *
2249 *----------------------------------------------------------------------*/
2300PIX *
2302 PIX *pixs,
2303 PIX *pixm,
2304 l_float32 minfract,
2305 l_int32 maxsize)
2306{
2307l_int32 w, h, wd, hd, wm, hm, wpls, wplm, wpld;
2308l_int32 nc, nestim, i, j, vals, vald;
2309l_int32 *lut;
2310l_uint32 *datas, *datam, *datad, *lines, *linem, *lined;
2311NUMA *na;
2312PIX *pixmr = NULL; /* resized mask */
2313PIXCMAP *cmap;
2314
2315 if (!pixs || pixGetDepth(pixs) != 8)
2316 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", __func__, NULL);
2317 if (minfract < 0.01) {
2318 L_WARNING("minfract < 0.01; setting to 0.05\n", __func__);
2319 minfract = 0.05f;
2320 }
2321 if (maxsize < 2) {
2322 L_WARNING("maxsize < 2; setting to 10\n", __func__);
2323 maxsize = 10;
2324 }
2325 if ((pixd && !pixm) || (!pixd && pixm))
2326 return (PIX *)ERROR_PTR("(pixd,pixm) not defined together",
2327 __func__, NULL);
2328 pixGetDimensions(pixs, &w, &h, NULL);
2329 if (pixd) {
2330 if (pixGetDepth(pixm) != 1)
2331 return (PIX *)ERROR_PTR("pixm not 1 bpp", __func__, NULL);
2332 if ((cmap = pixGetColormap(pixd)) == NULL)
2333 return (PIX *)ERROR_PTR("pixd not cmapped", __func__, NULL);
2334 pixGetDimensions(pixd, &wd, &hd, NULL);
2335 if (w != wd || h != hd)
2336 return (PIX *)ERROR_PTR("pixs, pixd sizes differ", __func__, NULL);
2337 nc = pixcmapGetCount(cmap);
2338 nestim = nc + (l_int32)(1.5 * 255 / maxsize);
2339 lept_stderr( "nestim = %d\n", nestim);
2340 if (nestim > 255) {
2341 L_ERROR("Estimate %d colors!\n", __func__, nestim);
2342 return (PIX *)ERROR_PTR("probably too many colors", __func__, NULL);
2343 }
2344 pixGetDimensions(pixm, &wm, &hm, NULL);
2345 if (w != wm || h != hm) { /* resize the mask */
2346 L_WARNING("mask and dest sizes not equal\n", __func__);
2347 pixmr = pixCreate(w, h, 1);
2348 pixRasterop(pixmr, 0, 0, wm, hm, PIX_SRC, pixm, 0, 0);
2349 pixRasterop(pixmr, wm, 0, w - wm, h, PIX_SET, NULL, 0, 0);
2350 pixRasterop(pixmr, 0, hm, wm, h - hm, PIX_SET, NULL, 0, 0);
2351 } else {
2352 pixmr = pixClone(pixm);
2353 }
2354 } else {
2355 pixd = pixCreateTemplate(pixs);
2356 cmap = pixcmapCreate(8);
2357 pixSetColormap(pixd, cmap);
2358 }
2359 pixCopyResolution(pixd, pixs);
2360 pixCopyInputFormat(pixd, pixs);
2361
2362 /* Use original mask, if it exists, to select gray pixels */
2363 na = pixGetGrayHistogramMasked(pixs, pixm, 0, 0, 1);
2364
2365 /* Fill out the cmap with gray colors, and generate the lut
2366 * for pixel assignment. Issue a warning on failure. */
2367 if (numaFillCmapFromHisto(na, cmap, minfract, maxsize, &lut))
2368 L_ERROR("ran out of colors in cmap!\n", __func__);
2369 numaDestroy(&na);
2370
2371 /* Assign the gray pixels to their cmap indices */
2372 datas = pixGetData(pixs);
2373 datad = pixGetData(pixd);
2374 wpls = pixGetWpl(pixs);
2375 wpld = pixGetWpl(pixd);
2376 if (!pixm) {
2377 for (i = 0; i < h; i++) {
2378 lines = datas + i * wpls;
2379 lined = datad + i * wpld;
2380 for (j = 0; j < w; j++) {
2381 vals = GET_DATA_BYTE(lines, j);
2382 vald = lut[vals];
2383 SET_DATA_BYTE(lined, j, vald);
2384 }
2385 }
2386 LEPT_FREE(lut);
2387 return pixd;
2388 }
2389
2390 datam = pixGetData(pixmr);
2391 wplm = pixGetWpl(pixmr);
2392 for (i = 0; i < h; i++) {
2393 lines = datas + i * wpls;
2394 linem = datam + i * wplm;
2395 lined = datad + i * wpld;
2396 for (j = 0; j < w; j++) {
2397 if (!GET_DATA_BIT(linem, j))
2398 continue;
2399 vals = GET_DATA_BYTE(lines, j);
2400 vald = lut[vals];
2401 SET_DATA_BYTE(lined, j, vald);
2402 }
2403 }
2404 pixDestroy(&pixmr);
2405 LEPT_FREE(lut);
2406 return pixd;
2407}
2408
2409
2430static l_int32
2432 PIXCMAP *cmap,
2433 l_float32 minfract,
2434 l_int32 maxsize,
2435 l_int32 **plut)
2436{
2437l_int32 mincount, index, sum, wtsum, span, istart, i, val, ret;
2438l_int32 *iahisto, *lut;
2439l_float32 total;
2440
2441 if (!plut)
2442 return ERROR_INT("&lut not defined", __func__, 1);
2443 *plut = NULL;
2444 if (!na)
2445 return ERROR_INT("na not defined", __func__, 1);
2446 if (!cmap)
2447 return ERROR_INT("cmap not defined", __func__, 1);
2448
2449 numaGetSum(na, &total);
2450 mincount = (l_int32)(minfract * total);
2451 iahisto = numaGetIArray(na);
2452 lut = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2453 *plut = lut;
2454 index = pixcmapGetCount(cmap); /* start with number of colors
2455 * already reserved */
2456
2457 /* March through, associating colors with sets of adjacent
2458 * gray levels. During the process, the LUT that gives
2459 * the colormap index for each gray level is computed.
2460 * To complete a color, either the total count must equal
2461 * or exceed %mincount, or the current span of colors must
2462 * equal or exceed %maxsize. An empty span is not converted
2463 * into a color; it is simply ignored. When a span is completed for a
2464 * color, the weighted color in the span is added to the colormap. */
2465 sum = 0;
2466 wtsum = 0;
2467 istart = 0;
2468 ret = 0;
2469 for (i = 0; i < 256; i++) {
2470 lut[i] = index;
2471 sum += iahisto[i];
2472 wtsum += i * iahisto[i];
2473 span = i - istart + 1;
2474 if (sum < mincount && span < maxsize)
2475 continue;
2476
2477 if (sum == 0) { /* empty span; don't save */
2478 istart = i + 1;
2479 continue;
2480 }
2481
2482 /* Found new color; sum > 0 */
2483 val = (l_int32)((l_float32)wtsum / (l_float32)sum + 0.5);
2484 ret = pixcmapAddColor(cmap, val, val, val);
2485 istart = i + 1;
2486 sum = 0;
2487 wtsum = 0;
2488 index++;
2489 }
2490 if (istart < 256 && sum > 0) { /* last one */
2491 span = 256 - istart;
2492 val = (l_int32)((l_float32)wtsum / (l_float32)sum + 0.5);
2493 ret = pixcmapAddColor(cmap, val, val, val);
2494 }
2495
2496 LEPT_FREE(iahisto);
2497 return ret;
2498}
2499
2500
2501/*----------------------------------------------------------------------*
2502 * Color quantize grayscale image using existing colormap *
2503 *----------------------------------------------------------------------*/
2519PIX *
2521 PIXCMAP *cmap,
2522 l_int32 mindepth)
2523{
2524l_int32 i, j, index, w, h, d, depth, wpls, wpld;
2525l_int32 hascolor, vals, vald;
2526l_int32 *tab;
2527l_uint32 *datas, *datad, *lines, *lined;
2528PIXCMAP *cmapd;
2529PIX *pixd;
2530
2531 if (!pixs)
2532 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2533 if (pixGetColormap(pixs) != NULL) {
2534 L_WARNING("pixs already has a colormap; returning a copy\n", __func__);
2535 return pixCopy(NULL, pixs);
2536 }
2537 pixGetDimensions(pixs, &w, &h, &d);
2538 if (d != 8)
2539 return (PIX *)ERROR_PTR("pixs not 8 bpp", __func__, NULL);
2540 if (!cmap)
2541 return (PIX *)ERROR_PTR("cmap not defined", __func__, NULL);
2542 if (mindepth != 2 && mindepth != 4 && mindepth != 8)
2543 return (PIX *)ERROR_PTR("invalid mindepth", __func__, NULL);
2544
2545 /* Make sure the colormap is gray */
2546 pixcmapHasColor(cmap, &hascolor);
2547 if (hascolor) {
2548 L_WARNING("Converting colormap colors to gray\n", __func__);
2549 cmapd = pixcmapColorToGray(cmap, 0.3f, 0.5f, 0.2f);
2550 } else {
2551 cmapd = pixcmapCopy(cmap);
2552 }
2553
2554 /* Make LUT into colormap */
2555 tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2556 for (i = 0; i < 256; i++) {
2557 pixcmapGetNearestGrayIndex(cmapd, i, &index);
2558 tab[i] = index;
2559 }
2560
2561 pixcmapGetMinDepth(cmap, &depth);
2562 depth = L_MAX(depth, mindepth);
2563 pixd = pixCreate(w, h, depth);
2564 pixSetColormap(pixd, cmapd);
2565 pixCopyResolution(pixd, pixs);
2566 pixCopyInputFormat(pixd, pixs);
2567 datas = pixGetData(pixs);
2568 datad = pixGetData(pixd);
2569 wpls = pixGetWpl(pixs);
2570 wpld = pixGetWpl(pixd);
2571 for (i = 0; i < h; i++) {
2572 lines = datas + i * wpls;
2573 lined = datad + i * wpld;
2574 for (j = 0; j < w; j++) {
2575 vals = GET_DATA_BYTE(lines, j);
2576 vald = tab[vals];
2577 if (depth == 2)
2578 SET_DATA_DIBIT(lined, j, vald);
2579 else if (depth == 4)
2580 SET_DATA_QBIT(lined, j, vald);
2581 else /* depth == 8 */
2582 SET_DATA_BYTE(lined, j, vald);
2583 }
2584 }
2585
2586 LEPT_FREE(tab);
2587 return pixd;
2588}
2589
2590
2591#if 0 /* Documentation */
2592/*--------------------------------------------------------------------*
2593 * Implementation of binarization by dithering using LUTs *
2594 * It is archived here. *
2595 *--------------------------------------------------------------------*/
2610PIX *
2611pixDitherToBinaryLUT(PIX *pixs,
2612 l_int32 lowerclip,
2613 l_int32 upperclip)
2614{
2615l_int32 w, h, d, wplt, wpld;
2616l_int32 *tabval, *tab38, *tab14;
2617l_uint32 *datat, *datad;
2618l_uint32 *bufs1, *bufs2;
2619PIX *pixt, *pixd;
2620
2621 if (!pixs)
2622 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2623 pixGetDimensions(pixs, &w, &h, &d);
2624 if (d != 8)
2625 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", __func__, NULL);
2626 if (lowerclip < 0)
2627 lowerclip = DEFAULT_CLIP_LOWER_1;
2628 if (upperclip < 0)
2629 upperclip = DEFAULT_CLIP_UPPER_1;
2630
2631 if ((pixd = pixCreate(w, h, 1)) == NULL)
2632 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2633 pixCopyResolution(pixd, pixs);
2634 pixCopyInputFormat(pixd, pixs);
2635 datad = pixGetData(pixd);
2636 wpld = pixGetWpl(pixd);
2637
2638 /* Remove colormap if it exists */
2639 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2640 datat = pixGetData(pixt);
2641 wplt = pixGetWpl(pixt);
2642
2643 /* Two line buffers, 1 for current line and 2 for next line */
2644 bufs1 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
2645 bufs2 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
2646 if (!bufs1 || !bufs2) {
2647 LEPT_FREE(bufs1);
2648 LEPT_FREE(bufs2);
2649 pixDestroy(&pixd);
2650 pixDestroy(&pixt);
2651 return (PIX *)ERROR_PTR("bufs1, bufs2 not both made", __func__, NULL);
2652 }
2653
2654 /* 3 lookup tables: 1-bit value, (3/8)excess, and (1/4)excess */
2655 make8To1DitherTables(&tabval, &tab38, &tab14, lowerclip, upperclip);
2656
2657 ditherToBinaryLUTLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2,
2658 tabval, tab38, tab14);
2659
2660 LEPT_FREE(bufs1);
2661 LEPT_FREE(bufs2);
2662 LEPT_FREE(tabval);
2663 LEPT_FREE(tab38);
2664 LEPT_FREE(tab14);
2665 pixDestroy(&pixt);
2666 return pixd;
2667}
2668
2682void
2683ditherToBinaryLUTLow(l_uint32 *datad,
2684 l_int32 w,
2685 l_int32 h,
2686 l_int32 wpld,
2687 l_uint32 *datas,
2688 l_int32 wpls,
2689 l_uint32 *bufs1,
2690 l_uint32 *bufs2,
2691 l_int32 *tabval,
2692 l_int32 *tab38,
2693 l_int32 *tab14)
2694{
2695l_int32 i;
2696l_uint32 *lined;
2697
2698 /* do all lines except last line */
2699 memcpy(bufs2, datas, 4 * wpls); /* prime the buffer */
2700 for (i = 0; i < h - 1; i++) {
2701 memcpy(bufs1, bufs2, 4 * wpls);
2702 memcpy(bufs2, datas + (i + 1) * wpls, 4 * wpls);
2703 lined = datad + i * wpld;
2704 ditherToBinaryLineLUTLow(lined, w, bufs1, bufs2,
2705 tabval, tab38, tab14, 0);
2706 }
2707
2708 /* do last line */
2709 memcpy(bufs1, bufs2, 4 * wpls);
2710 lined = datad + (h - 1) * wpld;
2711 ditherToBinaryLineLUTLow(lined, w, bufs1, bufs2, tabval, tab38, tab14, 1);
2712 return;
2713}
2714
2728void
2729ditherToBinaryLineLUTLow(l_uint32 *lined,
2730 l_int32 w,
2731 l_uint32 *bufs1,
2732 l_uint32 *bufs2,
2733 l_int32 *tabval,
2734 l_int32 *tab38,
2735 l_int32 *tab14,
2736 l_int32 lastlineflag)
2737{
2738l_int32 j;
2739l_int32 oval, tab38val, tab14val;
2740l_uint8 rval, bval, dval;
2741
2742 if (lastlineflag == 0) {
2743 for (j = 0; j < w - 1; j++) {
2744 oval = GET_DATA_BYTE(bufs1, j);
2745 if (tabval[oval])
2746 SET_DATA_BIT(lined, j);
2747 rval = GET_DATA_BYTE(bufs1, j + 1);
2748 bval = GET_DATA_BYTE(bufs2, j);
2749 dval = GET_DATA_BYTE(bufs2, j + 1);
2750 tab38val = tab38[oval];
2751 if (tab38val == 0)
2752 continue;
2753 tab14val = tab14[oval];
2754 if (tab38val < 0) {
2755 rval = L_MAX(0, rval + tab38val);
2756 bval = L_MAX(0, bval + tab38val);
2757 dval = L_MAX(0, dval + tab14val);
2758 } else {
2759 rval = L_MIN(255, rval + tab38val);
2760 bval = L_MIN(255, bval + tab38val);
2761 dval = L_MIN(255, dval + tab14val);
2762 }
2763 SET_DATA_BYTE(bufs1, j + 1, rval);
2764 SET_DATA_BYTE(bufs2, j, bval);
2765 SET_DATA_BYTE(bufs2, j + 1, dval);
2766 }
2767
2768 /* do last column: j = w - 1 */
2769 oval = GET_DATA_BYTE(bufs1, j);
2770 if (tabval[oval])
2771 SET_DATA_BIT(lined, j);
2772 bval = GET_DATA_BYTE(bufs2, j);
2773 tab38val = tab38[oval];
2774 if (tab38val < 0) {
2775 bval = L_MAX(0, bval + tab38val);
2776 SET_DATA_BYTE(bufs2, j, bval);
2777 } else if (tab38val > 0 ) {
2778 bval = L_MIN(255, bval + tab38val);
2779 SET_DATA_BYTE(bufs2, j, bval);
2780 }
2781 } else { /* lastlineflag == 1 */
2782 for (j = 0; j < w - 1; j++) {
2783 oval = GET_DATA_BYTE(bufs1, j);
2784 if (tabval[oval])
2785 SET_DATA_BIT(lined, j);
2786 rval = GET_DATA_BYTE(bufs1, j + 1);
2787 tab38val = tab38[oval];
2788 if (tab38val == 0)
2789 continue;
2790 if (tab38val < 0)
2791 rval = L_MAX(0, rval + tab38val);
2792 else
2793 rval = L_MIN(255, rval + tab38val);
2794 SET_DATA_BYTE(bufs1, j + 1, rval);
2795 }
2796
2797 /* do last pixel: (i, j) = (h - 1, w - 1) */
2798 oval = GET_DATA_BYTE(bufs1, j);
2799 if (tabval[oval])
2800 SET_DATA_BIT(lined, j);
2801 }
2802
2803 return;
2804}
2805
2817l_ok
2818make8To1DitherTables(l_int32 **ptabval,
2819 l_int32 **ptab38,
2820 l_int32 **ptab14,
2821 l_int32 lowerclip,
2822 l_int32 upperclip)
2823{
2824l_int32 i;
2825l_int32 *tabval, *tab38, *tab14;
2826
2827 if (ptabval) *ptabval = NULL;
2828 if (ptab38) *ptab38 = NULL;
2829 if (ptab14) *ptab14 = NULL;
2830 if (!ptabval || !ptab38 || !ptab14)
2831 return ERROR_INT("table ptrs not all defined", __func__, 1);
2832
2833 /* 3 lookup tables: 1-bit value, (3/8)excess, and (1/4)excess */
2834 tabval = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2835 tab38 = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2836 tab14 = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2837 if (!tabval || !tab38 || !tab14)
2838 return ERROR_INT("calloc failure to make small table", __func__, 1);
2839 *ptabval = tabval;
2840 *ptab38 = tab38;
2841 *ptab14 = tab14;
2842
2843 for (i = 0; i < 256; i++) {
2844 if (i <= lowerclip) {
2845 tabval[i] = 1;
2846 tab38[i] = 0;
2847 tab14[i] = 0;
2848 } else if (i < 128) {
2849 tabval[i] = 1;
2850 tab38[i] = (3 * i + 4) / 8;
2851 tab14[i] = (i + 2) / 4;
2852 } else if (i < 255 - upperclip) {
2853 tabval[i] = 0;
2854 tab38[i] = (3 * (i - 255) + 4) / 8;
2855 tab14[i] = ((i - 255) + 2) / 4;
2856 } else { /* i >= 255 - upperclip */
2857 tabval[i] = 0;
2858 tab38[i] = 0;
2859 tab14[i] = 0;
2860 }
2861 }
2862
2863 return 0;
2864}
2865#endif /* Documentation */
PIX * pixBackgroundNormSimple(PIX *pixs, PIX *pixim, PIX *pixg)
pixBackgroundNormSimple()
Definition adaptmap.c:253
#define GET_DATA_QBIT(pdata, n)
#define SET_DATA_BIT(pdata, n)
#define SET_DATA_DIBIT(pdata, n, val)
#define SET_DATA_TWO_BYTES(pdata, n, val)
#define GET_DATA_BYTE(pdata, n)
#define GET_DATA_DIBIT(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
#define GET_DATA_BIT(pdata, n)
#define SET_DATA_QBIT(pdata, n, val)
PIX * pixThresholdGrayArb(PIX *pixs, const char *edgevals, l_int32 outdepth, l_int32 use_average, l_int32 setblack, l_int32 setwhite)
pixThresholdGrayArb()
Definition grayquant.c:1710
l_int32 * makeGrayQuantIndexTable(l_int32 nlevels)
makeGrayQuantIndexTable()
Definition grayquant.c:1818
static void thresholdToBinaryLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 d, l_int32 wpls, l_int32 thresh)
thresholdToBinaryLow()
Definition grayquant.c:492
void ditherToBinaryLineLow(l_uint32 *lined, l_int32 w, l_uint32 *bufs1, l_uint32 *bufs2, l_int32 lowerclip, l_int32 upperclip, l_int32 lastlineflag)
ditherToBinaryLineLow()
Definition grayquant.c:322
PIX * pixDitherTo2bppSpec(PIX *pixs, l_int32 lowerclip, l_int32 upperclip, l_int32 cmapflag)
pixDitherTo2bppSpec()
Definition grayquant.c:1034
PIX * pixDitherToBinarySpec(PIX *pixs, l_int32 lowerclip, l_int32 upperclip)
pixDitherToBinarySpec()
Definition grayquant.c:205
PIX * pixThresholdTo4bpp(PIX *pixs, l_int32 nlevels, l_int32 cmapflag)
pixThresholdTo4bpp()
Definition grayquant.c:1496
PIX * pixAdaptThresholdToBinaryGen(PIX *pixs, PIX *pixm, l_float32 gamma, l_int32 blackval, l_int32 whiteval, l_int32 thresh)
pixAdaptThresholdToBinaryGen()
Definition grayquant.c:758
static l_int32 make8To2DitherTables(l_int32 **ptabval, l_int32 **ptab38, l_int32 **ptab14, l_int32 cliptoblack, l_int32 cliptowhite)
make8To2DitherTables()
Definition grayquant.c:1251
PIX * pixGenerateMaskByBand32(PIX *pixs, l_uint32 refval, l_int32 delm, l_int32 delp, l_float32 fractm, l_float32 fractp)
pixGenerateMaskByBand32()
Definition grayquant.c:2093
static void thresholdTo4bppLow(l_uint32 *datad, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 wpls, l_int32 *tab)
thresholdTo4bppLow()
Definition grayquant.c:1558
PIX * pixAdaptThresholdToBinary(PIX *pixs, PIX *pixm, l_float32 gamma)
pixAdaptThresholdToBinary()
Definition grayquant.c:720
static l_int32 makeGrayQuantColormapArb(PIX *pixs, l_int32 *tab, l_int32 outdepth, PIXCMAP **pcmap)
makeGrayQuantColormapArb()
Definition grayquant.c:1990
PIX * pixGrayQuantFromHisto(PIX *pixd, PIX *pixs, PIX *pixm, l_float32 minfract, l_int32 maxsize)
pixGrayQuantFromHisto()
Definition grayquant.c:2301
static void ditherTo2bppLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 wpls, l_uint32 *bufs1, l_uint32 *bufs2, l_int32 *tabval, l_int32 *tab38, l_int32 *tab14)
ditherTo2bppLow()
Definition grayquant.c:1115
PIX * pixVarThresholdToBinary(PIX *pixs, PIX *pixg)
pixVarThresholdToBinary()
Definition grayquant.c:647
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition grayquant.c:443
PIX * pixGenerateMaskByDiscr32(PIX *pixs, l_uint32 refval1, l_uint32 refval2, l_int32 distflag)
pixGenerateMaskByDiscr32()
Definition grayquant.c:2189
PIX * pixThresholdOn8bpp(PIX *pixs, l_int32 nlevels, l_int32 cmapflag)
pixThresholdOn8bpp()
Definition grayquant.c:1611
PIX * pixDitherTo2bpp(PIX *pixs, l_int32 cmapflag)
pixDitherTo2bpp()
Definition grayquant.c:1002
static void ditherToBinaryLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 wpls, l_uint32 *bufs1, l_uint32 *bufs2, l_int32 lowerclip, l_int32 upperclip)
ditherToBinaryLow()
Definition grayquant.c:266
static l_int32 * makeGrayQuantTargetTable(l_int32 nlevels, l_int32 depth)
makeGrayQuantTargetTable()
Definition grayquant.c:1867
PIX * pixGenerateMaskByBand(PIX *pixs, l_int32 lower, l_int32 upper, l_int32 inband, l_int32 usecmap)
pixGenerateMaskByBand()
Definition grayquant.c:891
PIX * pixDitherToBinary(PIX *pixs)
pixDitherToBinary()
Definition grayquant.c:175
PIX * pixGrayQuantFromCmap(PIX *pixs, PIXCMAP *cmap, l_int32 mindepth)
pixGrayQuantFromCmap()
Definition grayquant.c:2520
static l_int32 numaFillCmapFromHisto(NUMA *na, PIXCMAP *cmap, l_float32 minfract, l_int32 maxsize, l_int32 **plut)
numaFillCmapFromHisto()
Definition grayquant.c:2431
static void thresholdTo2bppLow(l_uint32 *datad, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 wpls, l_int32 *tab)
thresholdTo2bppLow()
Definition grayquant.c:1418
l_ok makeGrayQuantTableArb(NUMA *na, l_int32 outdepth, l_int32 **ptab, PIXCMAP **pcmap)
makeGrayQuantTableArb()
Definition grayquant.c:1920
PIX * pixGenerateMaskByValue(PIX *pixs, l_int32 val, l_int32 usecmap)
pixGenerateMaskByValue()
Definition grayquant.c:802
static void ditherTo2bppLineLow(l_uint32 *lined, l_int32 w, l_uint32 *bufs1, l_uint32 *bufs2, l_int32 *tabval, l_int32 *tab38, l_int32 *tab14, l_int32 lastlineflag)
ditherTo2bppLineLow()
Definition grayquant.c:1173
PIX * pixThresholdTo2bpp(PIX *pixs, l_int32 nlevels, l_int32 cmapflag)
pixThresholdTo2bpp()
Definition grayquant.c:1356
@ DEFAULT_CLIP_UPPER_2
Definition pix.h:731
@ DEFAULT_CLIP_LOWER_1
Definition pix.h:728
@ DEFAULT_CLIP_LOWER_2
Definition pix.h:730
@ DEFAULT_CLIP_UPPER_1
Definition pix.h:729
@ REMOVE_CMAP_TO_GRAYSCALE
Definition pix.h:381
#define PIX_SRC
Definition pix.h:444
@ L_SORT_INCREASING
Definition pix.h:522
#define PIX_SET
Definition pix.h:448
@ L_EUCLIDEAN_DISTANCE
Definition pix.h:740
@ L_MANHATTAN_DISTANCE
Definition pix.h:739