Leptonica 1.82.0
Image processing and image analysis suite
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 PROCNAME("pixDitherToBinary");
178
179 if (!pixs)
180 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
181 if (pixGetDepth(pixs) != 8)
182 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL);
183
186}
187
188
206PIX *
208 l_int32 lowerclip,
209 l_int32 upperclip)
210{
211l_int32 w, h, d, wplt, wpld;
212l_uint32 *datat, *datad;
213l_uint32 *bufs1, *bufs2;
214PIX *pixt, *pixd;
215
216 PROCNAME("pixDitherToBinarySpec");
217
218 if (!pixs)
219 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
220 pixGetDimensions(pixs, &w, &h, &d);
221 if (d != 8)
222 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL);
223 if (lowerclip < 0 || lowerclip > 255)
224 return (PIX *)ERROR_PTR("invalid value for lowerclip", procName, NULL);
225 if (upperclip < 0 || upperclip > 255)
226 return (PIX *)ERROR_PTR("invalid value for upperclip", procName, NULL);
227
228 if ((pixd = pixCreate(w, h, 1)) == NULL)
229 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
230 pixCopyResolution(pixd, pixs);
231 pixCopyInputFormat(pixd, pixs);
232 datad = pixGetData(pixd);
233 wpld = pixGetWpl(pixd);
234
235 /* Remove colormap if it exists */
236 if ((pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE)) == NULL) {
237 pixDestroy(&pixd);
238 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
239 }
240 datat = pixGetData(pixt);
241 wplt = pixGetWpl(pixt);
242
243 /* Two line buffers, 1 for current line and 2 for next line */
244 bufs1 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
245 bufs2 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
246 if (!bufs1 || !bufs2) {
247 LEPT_FREE(bufs1);
248 LEPT_FREE(bufs2);
249 pixDestroy(&pixd);
250 pixDestroy(&pixt);
251 return (PIX *)ERROR_PTR("bufs1, bufs2 not both made", procName, NULL);
252 }
253
254 ditherToBinaryLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2,
255 lowerclip, upperclip);
256
257 LEPT_FREE(bufs1);
258 LEPT_FREE(bufs2);
259 pixDestroy(&pixt);
260 return pixd;
261}
262
263
269static void
270ditherToBinaryLow(l_uint32 *datad,
271 l_int32 w,
272 l_int32 h,
273 l_int32 wpld,
274 l_uint32 *datas,
275 l_int32 wpls,
276 l_uint32 *bufs1,
277 l_uint32 *bufs2,
278 l_int32 lowerclip,
279 l_int32 upperclip)
280{
281l_int32 i;
282l_uint32 *lined;
283
284 /* do all lines except last line */
285 memcpy(bufs2, datas, 4 * wpls); /* prime the buffer */
286 for (i = 0; i < h - 1; i++) {
287 memcpy(bufs1, bufs2, 4 * wpls);
288 memcpy(bufs2, datas + (i + 1) * wpls, 4 * wpls);
289 lined = datad + i * wpld;
290 ditherToBinaryLineLow(lined, w, bufs1, bufs2, lowerclip, upperclip, 0);
291 }
292
293 /* do last line */
294 memcpy(bufs1, bufs2, 4 * wpls);
295 lined = datad + (h - 1) * wpld;
296 ditherToBinaryLineLow(lined, w, bufs1, bufs2, lowerclip, upperclip, 1);
297}
298
299
325void
326ditherToBinaryLineLow(l_uint32 *lined,
327 l_int32 w,
328 l_uint32 *bufs1,
329 l_uint32 *bufs2,
330 l_int32 lowerclip,
331 l_int32 upperclip,
332 l_int32 lastlineflag)
333{
334l_int32 j;
335l_int32 oval, eval;
336l_uint8 fval1, fval2, rval, bval, dval;
337
338 if (lastlineflag == 0) {
339 for (j = 0; j < w - 1; j++) {
340 oval = GET_DATA_BYTE(bufs1, j);
341 if (oval > 127) { /* binarize to OFF */
342 if ((eval = 255 - oval) > upperclip) {
343 /* subtract from neighbors */
344 fval1 = (3 * eval) / 8;
345 fval2 = eval / 4;
346 rval = GET_DATA_BYTE(bufs1, j + 1);
347 rval = L_MAX(0, rval - fval1);
348 SET_DATA_BYTE(bufs1, j + 1, rval);
349 bval = GET_DATA_BYTE(bufs2, j);
350 bval = L_MAX(0, bval - fval1);
351 SET_DATA_BYTE(bufs2, j, bval);
352 dval = GET_DATA_BYTE(bufs2, j + 1);
353 dval = L_MAX(0, dval - fval2);
354 SET_DATA_BYTE(bufs2, j + 1, dval);
355 }
356 } else { /* oval <= 127; binarize to ON */
357 SET_DATA_BIT(lined, j); /* ON pixel */
358 if (oval > lowerclip) {
359 /* add to neighbors */
360 fval1 = (3 * oval) / 8;
361 fval2 = oval / 4;
362 rval = GET_DATA_BYTE(bufs1, j + 1);
363 rval = L_MIN(255, rval + fval1);
364 SET_DATA_BYTE(bufs1, j + 1, rval);
365 bval = GET_DATA_BYTE(bufs2, j);
366 bval = L_MIN(255, bval + fval1);
367 SET_DATA_BYTE(bufs2, j, bval);
368 dval = GET_DATA_BYTE(bufs2, j + 1);
369 dval = L_MIN(255, dval + fval2);
370 SET_DATA_BYTE(bufs2, j + 1, dval);
371 }
372 }
373 }
374
375 /* do last column: j = w - 1 */
376 oval = GET_DATA_BYTE(bufs1, j);
377 if (oval > 127) { /* binarize to OFF */
378 if ((eval = 255 - oval) > upperclip) {
379 /* subtract from neighbors */
380 fval1 = (3 * eval) / 8;
381 bval = GET_DATA_BYTE(bufs2, j);
382 bval = L_MAX(0, bval - fval1);
383 SET_DATA_BYTE(bufs2, j, bval);
384 }
385 } else { /*oval <= 127; binarize to ON */
386 SET_DATA_BIT(lined, j); /* ON pixel */
387 if (oval > lowerclip) {
388 /* add to neighbors */
389 fval1 = (3 * oval) / 8;
390 bval = GET_DATA_BYTE(bufs2, j);
391 bval = L_MIN(255, bval + fval1);
392 SET_DATA_BYTE(bufs2, j, bval);
393 }
394 }
395 } else { /* lastlineflag == 1 */
396 for (j = 0; j < w - 1; j++) {
397 oval = GET_DATA_BYTE(bufs1, j);
398 if (oval > 127) { /* binarize to OFF */
399 if ((eval = 255 - oval) > upperclip) {
400 /* subtract from neighbors */
401 fval1 = (3 * eval) / 8;
402 rval = GET_DATA_BYTE(bufs1, j + 1);
403 rval = L_MAX(0, rval - fval1);
404 SET_DATA_BYTE(bufs1, j + 1, rval);
405 }
406 } else { /* oval <= 127; binarize to ON */
407 SET_DATA_BIT(lined, j); /* ON pixel */
408 if (oval > lowerclip) {
409 /* add to neighbors */
410 fval1 = (3 * oval) / 8;
411 rval = GET_DATA_BYTE(bufs1, j + 1);
412 rval = L_MIN(255, rval + fval1);
413 SET_DATA_BYTE(bufs1, j + 1, rval);
414 }
415 }
416 }
417
418 /* do last pixel: (i, j) = (h - 1, w - 1) */
419 oval = GET_DATA_BYTE(bufs1, j);
420 if (oval < 128)
421 SET_DATA_BIT(lined, j); /* ON pixel */
422 }
423}
424
425
426/*------------------------------------------------------------------*
427 * Simple (pixelwise) binarization with fixed threshold *
428 *------------------------------------------------------------------*/
446PIX *
448 l_int32 thresh)
449{
450l_int32 d, w, h, wplt, wpld;
451l_uint32 *datat, *datad;
452PIX *pixt, *pixd;
453
454 PROCNAME("pixThresholdToBinary");
455
456 if (!pixs)
457 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
458 pixGetDimensions(pixs, &w, &h, &d);
459 if (d != 4 && d != 8)
460 return (PIX *)ERROR_PTR("pixs must be 4 or 8 bpp", procName, NULL);
461 if (thresh < 0)
462 return (PIX *)ERROR_PTR("thresh must be non-negative", procName, NULL);
463 if (d == 4 && thresh > 16)
464 return (PIX *)ERROR_PTR("4 bpp thresh not in {0-16}", procName, NULL);
465 if (d == 8 && thresh > 256)
466 return (PIX *)ERROR_PTR("8 bpp thresh not in {0-256}", procName, NULL);
467
468 if ((pixd = pixCreate(w, h, 1)) == NULL)
469 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
470 pixCopyResolution(pixd, pixs);
471 pixCopyInputFormat(pixd, pixs);
472 datad = pixGetData(pixd);
473 wpld = pixGetWpl(pixd);
474
475 /* Remove colormap if it exists. If there is a colormap,
476 * pixt will be 8 bpp regardless of the depth of pixs. */
478 datat = pixGetData(pixt);
479 wplt = pixGetWpl(pixt);
480 if (pixGetColormap(pixs) && d == 4) { /* promoted to 8 bpp */
481 d = 8;
482 thresh *= 16;
483 }
484
485 thresholdToBinaryLow(datad, w, h, wpld, datat, d, wplt, thresh);
486 pixDestroy(&pixt);
487 return pixd;
488}
489
490
497static void
498thresholdToBinaryLow(l_uint32 *datad,
499 l_int32 w,
500 l_int32 h,
501 l_int32 wpld,
502 l_uint32 *datas,
503 l_int32 d,
504 l_int32 wpls,
505 l_int32 thresh)
506{
507l_int32 i;
508l_uint32 *lines, *lined;
509
510 for (i = 0; i < h; i++) {
511 lines = datas + i * wpls;
512 lined = datad + i * wpld;
513 thresholdToBinaryLineLow(lined, w, lines, d, thresh);
514 }
515}
516
517
518/*
519 * thresholdToBinaryLineLow()
520 *
521 */
522void
523thresholdToBinaryLineLow(l_uint32 *lined,
524 l_int32 w,
525 l_uint32 *lines,
526 l_int32 d,
527 l_int32 thresh)
528{
529l_int32 j, k, gval, scount, dcount;
530l_uint32 sword, dword;
531
532 PROCNAME("thresholdToBinaryLineLow");
533
534 switch (d)
535 {
536 case 4:
537 /* Unrolled as 4 source words, 1 dest word */
538 for (j = 0, scount = 0, dcount = 0; j + 31 < w; j += 32) {
539 dword = 0;
540 for (k = 0; k < 4; k++) {
541 sword = lines[scount++];
542 dword <<= 8;
543 gval = (sword >> 28) & 0xf;
544 /* Trick used here and below: if gval < thresh then
545 * gval - thresh < 0, so its high-order bit is 1, and
546 * ((gval - thresh) >> 31) & 1 == 1; likewise, if
547 * gval >= thresh, then ((gval - thresh) >> 31) & 1 == 0
548 * Doing it this way avoids a random (and thus easily
549 * mispredicted) branch on each pixel. */
550 dword |= ((gval - thresh) >> 24) & 128;
551 gval = (sword >> 24) & 0xf;
552 dword |= ((gval - thresh) >> 25) & 64;
553 gval = (sword >> 20) & 0xf;
554 dword |= ((gval - thresh) >> 26) & 32;
555 gval = (sword >> 16) & 0xf;
556 dword |= ((gval - thresh) >> 27) & 16;
557 gval = (sword >> 12) & 0xf;
558 dword |= ((gval - thresh) >> 28) & 8;
559 gval = (sword >> 8) & 0xf;
560 dword |= ((gval - thresh) >> 29) & 4;
561 gval = (sword >> 4) & 0xf;
562 dword |= ((gval - thresh) >> 30) & 2;
563 gval = sword & 0xf;
564 dword |= ((gval - thresh) >> 31) & 1;
565 }
566 lined[dcount++] = dword;
567 }
568
569 if (j < w) {
570 dword = 0;
571 for (; j < w; j++) {
572 if ((j & 7) == 0) {
573 sword = lines[scount++];
574 }
575 gval = (sword >> 28) & 0xf;
576 sword <<= 4;
577 dword |= (((gval - thresh) >> 31) & 1) << (31 - (j & 31));
578 }
579 lined[dcount] = dword;
580 }
581#if DEBUG_UNROLLING
582#define CHECK_BIT(a, b, c) if (GET_DATA_BIT(a, b) != c) { \
583 lept_stderr("Error: mismatch at %d/%d(%d), %d vs %d\n", \
584 j, w, d, GET_DATA_BIT(a, b), c); }
585 for (j = 0; j < w; j++) {
586 gval = GET_DATA_QBIT(lines, j);
587 CHECK_BIT(lined, j, gval < thresh ? 1 : 0);
588 }
589#endif
590 break;
591 case 8:
592 /* Unrolled as 8 source words, 1 dest word */
593 for (j = 0, scount = 0, dcount = 0; j + 31 < w; j += 32) {
594 dword = 0;
595 for (k = 0; k < 8; k++) {
596 sword = lines[scount++];
597 dword <<= 4;
598 gval = (sword >> 24) & 0xff;
599 dword |= ((gval - thresh) >> 28) & 8;
600 gval = (sword >> 16) & 0xff;
601 dword |= ((gval - thresh) >> 29) & 4;
602 gval = (sword >> 8) & 0xff;
603 dword |= ((gval - thresh) >> 30) & 2;
604 gval = sword & 0xff;
605 dword |= ((gval - thresh) >> 31) & 1;
606 }
607 lined[dcount++] = dword;
608 }
609
610 if (j < w) {
611 dword = 0;
612 for (; j < w; j++) {
613 if ((j & 3) == 0) {
614 sword = lines[scount++];
615 }
616 gval = (sword >> 24) & 0xff;
617 sword <<= 8;
618 dword |= (l_uint64)(((gval - thresh) >> 31) & 1)
619 << (31 - (j & 31));
620 }
621 lined[dcount] = dword;
622 }
623#if DEBUG_UNROLLING
624 for (j = 0; j < w; j++) {
625 gval = GET_DATA_BYTE(lines, j);
626 CHECK_BIT(lined, j, gval < thresh ? 1 : 0);
627 }
628#undef CHECK_BIT
629#endif
630 break;
631 default:
632 L_ERROR("src depth not 4 or 8 bpp\n", procName);
633 break;
634 }
635}
636
637
638/*------------------------------------------------------------------*
639 * Binarization with variable threshold *
640 *------------------------------------------------------------------*/
654PIX *
656 PIX *pixg)
657{
658l_int32 i, j, vals, valg, w, h, d, wpls, wplg, wpld;
659l_uint32 *datas, *datag, *datad, *lines, *lineg, *lined;
660PIX *pixd;
661
662 PROCNAME("pixVarThresholdToBinary");
663
664 if (!pixs)
665 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
666 if (!pixg)
667 return (PIX *)ERROR_PTR("pixg not defined", procName, NULL);
668 if (!pixSizesEqual(pixs, pixg))
669 return (PIX *)ERROR_PTR("pix sizes not equal", procName, NULL);
670 pixGetDimensions(pixs, &w, &h, &d);
671 if (d != 8)
672 return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
673
674 pixd = pixCreate(w, h, 1);
675 pixCopyResolution(pixd, pixs);
676 pixCopyInputFormat(pixd, pixs);
677 datad = pixGetData(pixd);
678 wpld = pixGetWpl(pixd);
679 datas = pixGetData(pixs);
680 wpls = pixGetWpl(pixs);
681 datag = pixGetData(pixg);
682 wplg = pixGetWpl(pixg);
683 for (i = 0; i < h; i++) {
684 lines = datas + i * wpls;
685 lineg = datag + i * wplg;
686 lined = datad + i * wpld;
687 for (j = 0; j < w; j++) {
688 vals = GET_DATA_BYTE(lines, j);
689 valg = GET_DATA_BYTE(lineg, j);
690 if (vals < valg)
691 SET_DATA_BIT(lined, j);
692 }
693 }
694
695 return pixd;
696}
697
698
699/*------------------------------------------------------------------*
700 * Binarization by adaptive mapping *
701 *------------------------------------------------------------------*/
729PIX *
731 PIX *pixm,
732 l_float32 gamma)
733{
734 PROCNAME("pixAdaptThresholdToBinary");
735
736 if (!pixs || pixGetDepth(pixs) != 8)
737 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
738
739 return pixAdaptThresholdToBinaryGen(pixs, pixm, gamma, 50, 170, 200);
740}
741
742
769PIX *
771 PIX *pixm,
772 l_float32 gamma,
773 l_int32 blackval,
774 l_int32 whiteval,
775 l_int32 thresh)
776{
777PIX *pix1, *pixd;
778
779 PROCNAME("pixAdaptThresholdToBinaryGen");
780
781 if (!pixs || pixGetDepth(pixs) != 8)
782 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
783
784 if ((pix1 = pixBackgroundNormSimple(pixs, pixm, NULL)) == NULL)
785 return (PIX *)ERROR_PTR("pix1 not made", procName, NULL);
786 pixGammaTRC(pix1, pix1, gamma, blackval, whiteval);
787 pixd = pixThresholdToBinary(pix1, thresh);
788 pixDestroy(&pix1);
789 return pixd;
790}
791
792
793/*--------------------------------------------------------------------*
794 * Generate a binary mask from pixels of particular value(s) *
795 *--------------------------------------------------------------------*/
815PIX *
817 l_int32 val,
818 l_int32 usecmap)
819{
820l_int32 i, j, w, h, d, wplg, wpld;
821l_uint32 *datag, *datad, *lineg, *lined;
822PIX *pixg, *pixd;
823
824 PROCNAME("pixGenerateMaskByValue");
825
826 if (!pixs)
827 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
828 d = pixGetDepth(pixs);
829 if (d != 2 && d != 4 && d != 8)
830 return (PIX *)ERROR_PTR("not 2, 4 or 8 bpp", procName, NULL);
831
832 if (!usecmap && pixGetColormap(pixs))
834 else
835 pixg = pixClone(pixs);
836 pixGetDimensions(pixg, &w, &h, &d);
837 if (d == 8 && (val < 0 || val > 255)) {
838 pixDestroy(&pixg);
839 return (PIX *)ERROR_PTR("val out of 8 bpp range", procName, NULL);
840 }
841 if (d == 4 && (val < 0 || val > 15)) {
842 pixDestroy(&pixg);
843 return (PIX *)ERROR_PTR("val out of 4 bpp range", procName, NULL);
844 }
845 if (d == 2 && (val < 0 || val > 3)) {
846 pixDestroy(&pixg);
847 return (PIX *)ERROR_PTR("val out of 2 bpp range", procName, NULL);
848 }
849
850 pixd = pixCreate(w, h, 1);
851 pixCopyResolution(pixd, pixg);
852 pixCopyInputFormat(pixd, pixs);
853 datag = pixGetData(pixg);
854 wplg = pixGetWpl(pixg);
855 datad = pixGetData(pixd);
856 wpld = pixGetWpl(pixd);
857 for (i = 0; i < h; i++) {
858 lineg = datag + i * wplg;
859 lined = datad + i * wpld;
860 for (j = 0; j < w; j++) {
861 if (d == 8) {
862 if (GET_DATA_BYTE(lineg, j) == val)
863 SET_DATA_BIT(lined, j);
864 } else if (d == 4) {
865 if (GET_DATA_QBIT(lineg, j) == val)
866 SET_DATA_BIT(lined, j);
867 } else { /* d == 2 */
868 if (GET_DATA_DIBIT(lineg, j) == val)
869 SET_DATA_BIT(lined, j);
870 }
871 }
872 }
873
874 pixDestroy(&pixg);
875 return pixd;
876}
877
878
906PIX *
908 l_int32 lower,
909 l_int32 upper,
910 l_int32 inband,
911 l_int32 usecmap)
912{
913l_int32 i, j, w, h, d, wplg, wpld, val;
914l_uint32 *datag, *datad, *lineg, *lined;
915PIX *pixg, *pixd;
916
917 PROCNAME("pixGenerateMaskByBand");
918
919 if (!pixs)
920 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
921 d = pixGetDepth(pixs);
922 if (d != 2 && d != 4 && d != 8)
923 return (PIX *)ERROR_PTR("not 2, 4 or 8 bpp", procName, NULL);
924 if (lower < 0 || lower > upper)
925 return (PIX *)ERROR_PTR("lower < 0 or lower > upper!", procName, NULL);
926
927 if (!usecmap && pixGetColormap(pixs))
929 else
930 pixg = pixClone(pixs);
931 pixGetDimensions(pixg, &w, &h, &d);
932 if (d == 8 && upper > 255) {
933 pixDestroy(&pixg);
934 return (PIX *)ERROR_PTR("d == 8 and upper > 255", procName, NULL);
935 }
936 if (d == 4 && upper > 15) {
937 pixDestroy(&pixg);
938 return (PIX *)ERROR_PTR("d == 4 and upper > 15", procName, NULL);
939 }
940 if (d == 2 && upper > 3) {
941 pixDestroy(&pixg);
942 return (PIX *)ERROR_PTR("d == 2 and upper > 3", procName, NULL);
943 }
944
945 pixd = pixCreate(w, h, 1);
946 pixCopyResolution(pixd, pixg);
947 pixCopyInputFormat(pixd, pixs);
948 datag = pixGetData(pixg);
949 wplg = pixGetWpl(pixg);
950 datad = pixGetData(pixd);
951 wpld = pixGetWpl(pixd);
952 for (i = 0; i < h; i++) {
953 lineg = datag + i * wplg;
954 lined = datad + i * wpld;
955 for (j = 0; j < w; j++) {
956 if (d == 8)
957 val = GET_DATA_BYTE(lineg, j);
958 else if (d == 4)
959 val = GET_DATA_QBIT(lineg, j);
960 else /* d == 2 */
961 val = GET_DATA_DIBIT(lineg, j);
962 if (inband) {
963 if (val >= lower && val <= upper)
964 SET_DATA_BIT(lined, j);
965 } else { /* out of band */
966 if (val < lower || val > upper)
967 SET_DATA_BIT(lined, j);
968 }
969 }
970 }
971
972 pixDestroy(&pixg);
973 return pixd;
974}
975
976
977/*------------------------------------------------------------------*
978 * Thresholding to 2 bpp by dithering *
979 *------------------------------------------------------------------*/
1019PIX *
1021 l_int32 cmapflag)
1022{
1023 PROCNAME("pixDitherTo2bpp");
1024
1025 if (!pixs)
1026 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1027 if (pixGetDepth(pixs) != 8)
1028 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL);
1029
1031 DEFAULT_CLIP_UPPER_2, cmapflag);
1032}
1033
1034
1053PIX *
1055 l_int32 lowerclip,
1056 l_int32 upperclip,
1057 l_int32 cmapflag)
1058{
1059l_int32 w, h, d, wplt, wpld;
1060l_int32 *tabval, *tab38, *tab14;
1061l_uint32 *datat, *datad;
1062l_uint32 *bufs1, *bufs2;
1063PIX *pixt, *pixd;
1064PIXCMAP *cmap;
1065
1066 PROCNAME("pixDitherTo2bppSpec");
1067
1068 if (!pixs)
1069 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1070 pixGetDimensions(pixs, &w, &h, &d);
1071 if (d != 8)
1072 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL);
1073 if (lowerclip < 0 || lowerclip > 255)
1074 return (PIX *)ERROR_PTR("invalid value for lowerclip", procName, NULL);
1075 if (upperclip < 0 || upperclip > 255)
1076 return (PIX *)ERROR_PTR("invalid value for upperclip", procName, NULL);
1077
1078 if ((pixd = pixCreate(w, h, 2)) == NULL)
1079 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1080 pixCopyResolution(pixd, pixs);
1081 pixCopyInputFormat(pixd, pixs);
1082 datad = pixGetData(pixd);
1083 wpld = pixGetWpl(pixd);
1084
1085 /* If there is a colormap, remove it */
1087 datat = pixGetData(pixt);
1088 wplt = pixGetWpl(pixt);
1089
1090 /* Two line buffers, 1 for current line and 2 for next line */
1091 bufs1 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
1092 bufs2 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
1093 if (!bufs1 || !bufs2) {
1094 LEPT_FREE(bufs1);
1095 LEPT_FREE(bufs2);
1096 pixDestroy(&pixd);
1097 pixDestroy(&pixt);
1098 return (PIX *)ERROR_PTR("bufs1, bufs2 not both made", procName, NULL);
1099 }
1100
1101 /* 3 lookup tables: 2-bit value, (3/8)excess, and (1/4)excess */
1102 make8To2DitherTables(&tabval, &tab38, &tab14, lowerclip, upperclip);
1103
1104 ditherTo2bppLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2,
1105 tabval, tab38, tab14);
1106
1107 if (cmapflag) {
1108 cmap = pixcmapCreateLinear(2, 4);
1109 pixSetColormap(pixd, cmap);
1110 }
1111
1112 LEPT_FREE(bufs1);
1113 LEPT_FREE(bufs2);
1114 LEPT_FREE(tabval);
1115 LEPT_FREE(tab38);
1116 LEPT_FREE(tab14);
1117 pixDestroy(&pixt);
1118 return pixd;
1119}
1120
1121
1136static void
1137ditherTo2bppLow(l_uint32 *datad,
1138 l_int32 w,
1139 l_int32 h,
1140 l_int32 wpld,
1141 l_uint32 *datas,
1142 l_int32 wpls,
1143 l_uint32 *bufs1,
1144 l_uint32 *bufs2,
1145 l_int32 *tabval,
1146 l_int32 *tab38,
1147 l_int32 *tab14)
1148{
1149l_int32 i;
1150l_uint32 *lined;
1151
1152 /* do all lines except last line */
1153 memcpy(bufs2, datas, 4 * wpls); /* prime the buffer */
1154 for (i = 0; i < h - 1; i++) {
1155 memcpy(bufs1, bufs2, 4 * wpls);
1156 memcpy(bufs2, datas + (i + 1) * wpls, 4 * wpls);
1157 lined = datad + i * wpld;
1158 ditherTo2bppLineLow(lined, w, bufs1, bufs2, tabval, tab38, tab14, 0);
1159 }
1160
1161 /* do last line */
1162 memcpy(bufs1, bufs2, 4 * wpls);
1163 lined = datad + (h - 1) * wpld;
1164 ditherTo2bppLineLow(lined, w, bufs1, bufs2, tabval, tab38, tab14, 1);
1165}
1166
1167
1194static void
1195ditherTo2bppLineLow(l_uint32 *lined,
1196 l_int32 w,
1197 l_uint32 *bufs1,
1198 l_uint32 *bufs2,
1199 l_int32 *tabval,
1200 l_int32 *tab38,
1201 l_int32 *tab14,
1202 l_int32 lastlineflag)
1203{
1204l_int32 j;
1205l_int32 oval, tab38val, tab14val;
1206l_uint8 rval, bval, dval;
1207
1208 if (lastlineflag == 0) {
1209 for (j = 0; j < w - 1; j++) {
1210 oval = GET_DATA_BYTE(bufs1, j);
1211 SET_DATA_DIBIT(lined, j, tabval[oval]);
1212 rval = GET_DATA_BYTE(bufs1, j + 1);
1213 bval = GET_DATA_BYTE(bufs2, j);
1214 dval = GET_DATA_BYTE(bufs2, j + 1);
1215 tab38val = tab38[oval];
1216 tab14val = tab14[oval];
1217 if (tab38val < 0) {
1218 rval = L_MAX(0, rval + tab38val);
1219 bval = L_MAX(0, bval + tab38val);
1220 dval = L_MAX(0, dval + tab14val);
1221 } else {
1222 rval = L_MIN(255, rval + tab38val);
1223 bval = L_MIN(255, bval + tab38val);
1224 dval = L_MIN(255, dval + tab14val);
1225 }
1226 SET_DATA_BYTE(bufs1, j + 1, rval);
1227 SET_DATA_BYTE(bufs2, j, bval);
1228 SET_DATA_BYTE(bufs2, j + 1, dval);
1229 }
1230
1231 /* do last column: j = w - 1 */
1232 oval = GET_DATA_BYTE(bufs1, j);
1233 SET_DATA_DIBIT(lined, j, tabval[oval]);
1234 bval = GET_DATA_BYTE(bufs2, j);
1235 tab38val = tab38[oval];
1236 if (tab38val < 0)
1237 bval = L_MAX(0, bval + tab38val);
1238 else
1239 bval = L_MIN(255, bval + tab38val);
1240 SET_DATA_BYTE(bufs2, j, bval);
1241 } else { /* lastlineflag == 1 */
1242 for (j = 0; j < w - 1; j++) {
1243 oval = GET_DATA_BYTE(bufs1, j);
1244 SET_DATA_DIBIT(lined, j, tabval[oval]);
1245 rval = GET_DATA_BYTE(bufs1, j + 1);
1246 tab38val = tab38[oval];
1247 if (tab38val < 0)
1248 rval = L_MAX(0, rval + tab38val);
1249 else
1250 rval = L_MIN(255, rval + tab38val);
1251 SET_DATA_BYTE(bufs1, j + 1, rval);
1252 }
1253
1254 /* do last pixel: (i, j) = (h - 1, w - 1) */
1255 oval = GET_DATA_BYTE(bufs1, j);
1256 SET_DATA_DIBIT(lined, j, tabval[oval]);
1257 }
1258}
1259
1260
1272static l_int32
1273make8To2DitherTables(l_int32 **ptabval,
1274 l_int32 **ptab38,
1275 l_int32 **ptab14,
1276 l_int32 cliptoblack,
1277 l_int32 cliptowhite)
1278{
1279l_int32 i;
1280l_int32 *tabval, *tab38, *tab14;
1281
1282 /* 3 lookup tables: 2-bit value, (3/8)excess, and (1/4)excess */
1283 tabval = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1284 tab38 = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1285 tab14 = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1286 *ptabval = tabval;
1287 *ptab38 = tab38;
1288 *ptab14 = tab14;
1289
1290 for (i = 0; i < 256; i++) {
1291 if (i <= cliptoblack) {
1292 tabval[i] = 0;
1293 tab38[i] = 0;
1294 tab14[i] = 0;
1295 } else if (i < 43) {
1296 tabval[i] = 0;
1297 tab38[i] = (3 * i + 4) / 8;
1298 tab14[i] = (i + 2) / 4;
1299 } else if (i < 85) {
1300 tabval[i] = 1;
1301 tab38[i] = (3 * (i - 85) - 4) / 8;
1302 tab14[i] = ((i - 85) - 2) / 4;
1303 } else if (i < 128) {
1304 tabval[i] = 1;
1305 tab38[i] = (3 * (i - 85) + 4) / 8;
1306 tab14[i] = ((i - 85) + 2) / 4;
1307 } else if (i < 170) {
1308 tabval[i] = 2;
1309 tab38[i] = (3 * (i - 170) - 4) / 8;
1310 tab14[i] = ((i - 170) - 2) / 4;
1311 } else if (i < 213) {
1312 tabval[i] = 2;
1313 tab38[i] = (3 * (i - 170) + 4) / 8;
1314 tab14[i] = ((i - 170) + 2) / 4;
1315 } else if (i < 255 - cliptowhite) {
1316 tabval[i] = 3;
1317 tab38[i] = (3 * (i - 255) - 4) / 8;
1318 tab14[i] = ((i - 255) - 2) / 4;
1319 } else { /* i >= 255 - cliptowhite */
1320 tabval[i] = 3;
1321 tab38[i] = 0;
1322 tab14[i] = 0;
1323 }
1324 }
1325
1326 return 0;
1327}
1328
1329
1330/*--------------------------------------------------------------------*
1331 * Simple (pixelwise) thresholding to 2 bpp with optional colormap *
1332 *--------------------------------------------------------------------*/
1377PIX *
1379 l_int32 nlevels,
1380 l_int32 cmapflag)
1381{
1382l_int32 *qtab;
1383l_int32 w, h, d, wplt, wpld;
1384l_uint32 *datat, *datad;
1385PIX *pixt, *pixd;
1386PIXCMAP *cmap;
1387
1388 PROCNAME("pixThresholdTo2bpp");
1389
1390 if (!pixs)
1391 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1392 pixGetDimensions(pixs, &w, &h, &d);
1393 if (d != 8)
1394 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
1395 if (nlevels < 2 || nlevels > 4)
1396 return (PIX *)ERROR_PTR("nlevels not in {2, 3, 4}", procName, NULL);
1397
1398 if ((pixd = pixCreate(w, h, 2)) == NULL)
1399 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1400 pixCopyResolution(pixd, pixs);
1401 pixCopyInputFormat(pixd, pixs);
1402 datad = pixGetData(pixd);
1403 wpld = pixGetWpl(pixd);
1404
1405 if (cmapflag) { /* hold out (4 - nlevels) cmap entries */
1406 cmap = pixcmapCreateLinear(2, nlevels);
1407 pixSetColormap(pixd, cmap);
1408 }
1409
1410 /* If there is a colormap in the src, remove it */
1412 datat = pixGetData(pixt);
1413 wplt = pixGetWpl(pixt);
1414
1415 /* Make the appropriate table */
1416 if (cmapflag)
1417 qtab = makeGrayQuantIndexTable(nlevels);
1418 else
1419 qtab = makeGrayQuantTargetTable(4, 2);
1420
1421 thresholdTo2bppLow(datad, h, wpld, datat, wplt, qtab);
1422
1423 LEPT_FREE(qtab);
1424 pixDestroy(&pixt);
1425 return pixd;
1426}
1427
1428
1441static void
1442thresholdTo2bppLow(l_uint32 *datad,
1443 l_int32 h,
1444 l_int32 wpld,
1445 l_uint32 *datas,
1446 l_int32 wpls,
1447 l_int32 *tab)
1448{
1449l_uint8 sval1, sval2, sval3, sval4, dval;
1450l_int32 i, j, k;
1451l_uint32 *lines, *lined;
1452
1453 for (i = 0; i < h; i++) {
1454 lines = datas + i * wpls;
1455 lined = datad + i * wpld;
1456 for (j = 0; j < wpls; j++) {
1457 k = 4 * j;
1458 sval1 = GET_DATA_BYTE(lines, k);
1459 sval2 = GET_DATA_BYTE(lines, k + 1);
1460 sval3 = GET_DATA_BYTE(lines, k + 2);
1461 sval4 = GET_DATA_BYTE(lines, k + 3);
1462 dval = (tab[sval1] << 6) | (tab[sval2] << 4) |
1463 (tab[sval3] << 2) | tab[sval4];
1464 SET_DATA_BYTE(lined, j, dval);
1465 }
1466 }
1467}
1468
1469
1470/*----------------------------------------------------------------------*
1471 * Simple (pixelwise) thresholding to 4 bpp *
1472 *----------------------------------------------------------------------*/
1519PIX *
1521 l_int32 nlevels,
1522 l_int32 cmapflag)
1523{
1524l_int32 *qtab;
1525l_int32 w, h, d, wplt, wpld;
1526l_uint32 *datat, *datad;
1527PIX *pixt, *pixd;
1528PIXCMAP *cmap;
1529
1530 PROCNAME("pixThresholdTo4bpp");
1531
1532 if (!pixs)
1533 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1534 pixGetDimensions(pixs, &w, &h, &d);
1535 if (d != 8)
1536 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
1537 if (nlevels < 2 || nlevels > 16)
1538 return (PIX *)ERROR_PTR("nlevels not in [2,...,16]", procName, NULL);
1539
1540 if ((pixd = pixCreate(w, h, 4)) == NULL)
1541 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1542 pixCopyResolution(pixd, pixs);
1543 pixCopyInputFormat(pixd, pixs);
1544 datad = pixGetData(pixd);
1545 wpld = pixGetWpl(pixd);
1546
1547 if (cmapflag) { /* hold out (16 - nlevels) cmap entries */
1548 cmap = pixcmapCreateLinear(4, nlevels);
1549 pixSetColormap(pixd, cmap);
1550 }
1551
1552 /* If there is a colormap in the src, remove it */
1554 datat = pixGetData(pixt);
1555 wplt = pixGetWpl(pixt);
1556
1557 /* Make the appropriate table */
1558 if (cmapflag)
1559 qtab = makeGrayQuantIndexTable(nlevels);
1560 else
1561 qtab = makeGrayQuantTargetTable(16, 4);
1562
1563 thresholdTo4bppLow(datad, h, wpld, datat, wplt, qtab);
1564
1565 LEPT_FREE(qtab);
1566 pixDestroy(&pixt);
1567 return pixd;
1568}
1569
1570
1583static void
1584thresholdTo4bppLow(l_uint32 *datad,
1585 l_int32 h,
1586 l_int32 wpld,
1587 l_uint32 *datas,
1588 l_int32 wpls,
1589 l_int32 *tab)
1590{
1591l_uint8 sval1, sval2, sval3, sval4;
1592l_uint16 dval;
1593l_int32 i, j, k;
1594l_uint32 *lines, *lined;
1595
1596 for (i = 0; i < h; i++) {
1597 lines = datas + i * wpls;
1598 lined = datad + i * wpld;
1599 for (j = 0; j < wpls; j++) {
1600 k = 4 * j;
1601 sval1 = GET_DATA_BYTE(lines, k);
1602 sval2 = GET_DATA_BYTE(lines, k + 1);
1603 sval3 = GET_DATA_BYTE(lines, k + 2);
1604 sval4 = GET_DATA_BYTE(lines, k + 3);
1605 dval = (tab[sval1] << 12) | (tab[sval2] << 8) |
1606 (tab[sval3] << 4) | tab[sval4];
1607 SET_DATA_TWO_BYTES(lined, j, dval);
1608 }
1609 }
1610}
1611
1612
1613/*----------------------------------------------------------------------*
1614 * Simple (pixelwise) thresholding on 8 bpp with optional colormap *
1615 *----------------------------------------------------------------------*/
1636PIX *
1638 l_int32 nlevels,
1639 l_int32 cmapflag)
1640{
1641l_int32 *qtab; /* quantization table */
1642l_int32 i, j, w, h, wpld, val, newval;
1643l_uint32 *datad, *lined;
1644PIX *pixd;
1645PIXCMAP *cmap;
1646
1647 PROCNAME("pixThresholdOn8bpp");
1648
1649 if (!pixs)
1650 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1651 if (pixGetDepth(pixs) != 8)
1652 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
1653 if (nlevels < 2 || nlevels > 256)
1654 return (PIX *)ERROR_PTR("nlevels not in [2,...,256]", procName, NULL);
1655
1656 /* Get a new pixd; if there is a colormap in the src, remove it */
1657 if (pixGetColormap(pixs))
1659 else
1660 pixd = pixCopy(NULL, pixs);
1661
1662 if (cmapflag) { /* hold out (256 - nlevels) cmap entries */
1663 cmap = pixcmapCreateLinear(8, nlevels);
1664 pixSetColormap(pixd, cmap);
1665 }
1666
1667 if (cmapflag)
1668 qtab = makeGrayQuantIndexTable(nlevels);
1669 else
1670 qtab = makeGrayQuantTargetTable(nlevels, 8);
1671
1672 pixGetDimensions(pixd, &w, &h, NULL);
1673 pixCopyResolution(pixd, pixs);
1674 pixCopyInputFormat(pixd, pixs);
1675 datad = pixGetData(pixd);
1676 wpld = pixGetWpl(pixd);
1677 for (i = 0; i < h; i++) {
1678 lined = datad + i * wpld;
1679 for (j = 0; j < w; j++) {
1680 val = GET_DATA_BYTE(lined, j);
1681 newval = qtab[val];
1682 SET_DATA_BYTE(lined, j, newval);
1683 }
1684 }
1685
1686 LEPT_FREE(qtab);
1687 return pixd;
1688}
1689
1690
1691/*----------------------------------------------------------------------*
1692 * Arbitrary (pixelwise) thresholding from 8 bpp to 2, 4 or 8 bpp *
1693 *----------------------------------------------------------------------*/
1737PIX *
1739 const char *edgevals,
1740 l_int32 outdepth,
1741 l_int32 use_average,
1742 l_int32 setblack,
1743 l_int32 setwhite)
1744{
1745l_int32 *qtab;
1746l_int32 w, h, d, i, j, n, wplt, wpld, val, newval;
1747l_uint32 *datat, *datad, *linet, *lined;
1748NUMA *na;
1749PIX *pixt, *pixd;
1750PIXCMAP *cmap;
1751
1752 PROCNAME("pixThresholdGrayArb");
1753
1754 if (!pixs)
1755 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1756 pixGetDimensions(pixs, &w, &h, &d);
1757 if (d != 8)
1758 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
1759 if (!edgevals)
1760 return (PIX *)ERROR_PTR("edgevals not defined", procName, NULL);
1761 if (outdepth != 0 && outdepth != 2 && outdepth != 4 && outdepth != 8)
1762 return (PIX *)ERROR_PTR("invalid outdepth", procName, NULL);
1763
1764 /* Parse and sort (if required) the bin edge values */
1765 na = parseStringForNumbers(edgevals, " \t\n,");
1766 n = numaGetCount(na);
1767 if (n > 255) {
1768 numaDestroy(&na);
1769 return (PIX *)ERROR_PTR("more than 256 levels", procName, NULL);
1770 }
1771 if (outdepth == 0) {
1772 if (n <= 3)
1773 outdepth = 2;
1774 else if (n <= 15)
1775 outdepth = 4;
1776 else
1777 outdepth = 8;
1778 } else if (n + 1 > (1 << outdepth)) {
1779 L_WARNING("outdepth too small; setting to 8 bpp\n", procName);
1780 outdepth = 8;
1781 }
1782 numaSort(na, na, L_SORT_INCREASING);
1783
1784 /* Make the quantization LUT and the colormap */
1785 makeGrayQuantTableArb(na, outdepth, &qtab, &cmap);
1786 if (use_average) { /* use the average value in each bin */
1787 pixcmapDestroy(&cmap);
1788 makeGrayQuantColormapArb(pixs, qtab, outdepth, &cmap);
1789 }
1790 pixcmapSetBlackAndWhite(cmap, setblack, setwhite);
1791 numaDestroy(&na);
1792
1793 if ((pixd = pixCreate(w, h, outdepth)) == NULL) {
1794 LEPT_FREE(qtab);
1795 pixcmapDestroy(&cmap);
1796 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1797 }
1798 pixCopyResolution(pixd, pixs);
1799 pixCopyInputFormat(pixd, pixs);
1800 pixSetColormap(pixd, cmap);
1801 datad = pixGetData(pixd);
1802 wpld = pixGetWpl(pixd);
1803
1804 /* If there is a colormap in the src, remove it */
1806 datat = pixGetData(pixt);
1807 wplt = pixGetWpl(pixt);
1808
1809 if (outdepth == 2) {
1810 thresholdTo2bppLow(datad, h, wpld, datat, wplt, qtab);
1811 } else if (outdepth == 4) {
1812 thresholdTo4bppLow(datad, h, wpld, datat, wplt, qtab);
1813 } else {
1814 for (i = 0; i < h; i++) {
1815 lined = datad + i * wpld;
1816 linet = datat + i * wplt;
1817 for (j = 0; j < w; j++) {
1818 val = GET_DATA_BYTE(linet, j);
1819 newval = qtab[val];
1820 SET_DATA_BYTE(lined, j, newval);
1821 }
1822 }
1823 }
1824
1825 LEPT_FREE(qtab);
1826 pixDestroy(&pixt);
1827 return pixd;
1828}
1829
1830
1831/*----------------------------------------------------------------------*
1832 * Quantization tables for linear thresholds of grayscale images *
1833 *----------------------------------------------------------------------*/
1847l_int32 *
1849{
1850l_int32 *tab;
1851l_int32 i, j, thresh;
1852
1853 tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1854 for (i = 0; i < 256; i++) {
1855 for (j = 0; j < nlevels; j++) {
1856 thresh = 255 * (2 * j + 1) / (2 * nlevels - 2);
1857 if (i <= thresh) {
1858 tab[i] = j;
1859/* lept_stderr("tab[%d] = %d\n", i, j); */
1860 break;
1861 }
1862 }
1863 }
1864 return tab;
1865}
1866
1867
1896static l_int32 *
1898 l_int32 depth)
1899{
1900l_int32 *tab;
1901l_int32 i, j, thresh, maxval, quantval;
1902
1903 tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1904 maxval = (1 << depth) - 1;
1905 if (depth < 8)
1906 nlevels = 1 << depth;
1907 for (i = 0; i < 256; i++) {
1908 for (j = 0; j < nlevels; j++) {
1909 thresh = 255 * (2 * j + 1) / (2 * nlevels - 2);
1910 if (i <= thresh) {
1911 quantval = maxval * j / (nlevels - 1);
1912 tab[i] = quantval;
1913/* lept_stderr("tab[%d] = %d\n", i, tab[i]); */
1914 break;
1915 }
1916 }
1917 }
1918 return tab;
1919}
1920
1921
1922/*----------------------------------------------------------------------*
1923 * Quantization table for arbitrary thresholding of grayscale images *
1924 *----------------------------------------------------------------------*/
1949l_ok
1951 l_int32 outdepth,
1952 l_int32 **ptab,
1953 PIXCMAP **pcmap)
1954{
1955l_int32 i, j, n, jstart, ave, val;
1956l_int32 *tab;
1957PIXCMAP *cmap;
1958
1959 PROCNAME("makeGrayQuantTableArb");
1960
1961 if (!ptab)
1962 return ERROR_INT("&tab not defined", procName, 1);
1963 *ptab = NULL;
1964 if (!pcmap)
1965 return ERROR_INT("&cmap not defined", procName, 1);
1966 *pcmap = NULL;
1967 if (!na)
1968 return ERROR_INT("na not defined", procName, 1);
1969 n = numaGetCount(na);
1970 if (n + 1 > (1 << outdepth))
1971 return ERROR_INT("more bins than cmap levels", procName, 1);
1972
1973 if ((cmap = pixcmapCreate(outdepth)) == NULL)
1974 return ERROR_INT("cmap not made", procName, 1);
1975 tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1976 *ptab = tab;
1977 *pcmap = cmap;
1978
1979 /* First n bins */
1980 jstart = 0;
1981 for (i = 0; i < n; i++) {
1982 numaGetIValue(na, i, &val);
1983 ave = (jstart + val) / 2;
1984 pixcmapAddColor(cmap, ave, ave, ave);
1985 for (j = jstart; j < val; j++)
1986 tab[j] = i;
1987 jstart = val;
1988 }
1989
1990 /* Last bin */
1991 ave = (jstart + 255) / 2;
1992 pixcmapAddColor(cmap, ave, ave, ave);
1993 for (j = jstart; j < 256; j++)
1994 tab[j] = n;
1995
1996 return 0;
1997}
1998
1999
2021static l_int32
2023 l_int32 *tab,
2024 l_int32 outdepth,
2025 PIXCMAP **pcmap)
2026{
2027l_int32 i, j, index, w, h, d, nbins, wpl, factor, val;
2028l_int32 *bincount, *binave, *binstart;
2029l_uint32 *line, *data;
2030
2031 PROCNAME("makeGrayQuantColormapArb");
2032
2033 if (!pcmap)
2034 return ERROR_INT("&cmap not defined", procName, 1);
2035 *pcmap = NULL;
2036 if (!pixs)
2037 return ERROR_INT("pixs not defined", procName, 1);
2038 pixGetDimensions(pixs, &w, &h, &d);
2039 if (d != 8)
2040 return ERROR_INT("pixs not 8 bpp", procName, 1);
2041 if (!tab)
2042 return ERROR_INT("tab not defined", procName, 1);
2043 nbins = tab[255] + 1;
2044 if (nbins > (1 << outdepth))
2045 return ERROR_INT("more bins than cmap levels", procName, 1);
2046
2047 /* Find the count and weighted count for each bin */
2048 if ((bincount = (l_int32 *)LEPT_CALLOC(nbins, sizeof(l_int32))) == NULL)
2049 return ERROR_INT("calloc fail for bincount", procName, 1);
2050 if ((binave = (l_int32 *)LEPT_CALLOC(nbins, sizeof(l_int32))) == NULL) {
2051 LEPT_FREE(bincount);
2052 return ERROR_INT("calloc fail for binave", procName, 1);
2053 }
2054 factor = (l_int32)(sqrt((l_float64)(w * h) / 30000.) + 0.5);
2055 factor = L_MAX(1, factor);
2056 data = pixGetData(pixs);
2057 wpl = pixGetWpl(pixs);
2058 for (i = 0; i < h; i += factor) {
2059 line = data + i * wpl;
2060 for (j = 0; j < w; j += factor) {
2061 val = GET_DATA_BYTE(line, j);
2062 bincount[tab[val]]++;
2063 binave[tab[val]] += val;
2064 }
2065 }
2066
2067 /* Find the smallest gray values in each bin */
2068 binstart = (l_int32 *)LEPT_CALLOC(nbins, sizeof(l_int32));
2069 for (i = 1, index = 1; i < 256; i++) {
2070 if (tab[i] < index) continue;
2071 if (tab[i] == index)
2072 binstart[index++] = i;
2073 }
2074
2075 /* Get the averages. If there are no samples in a bin, use
2076 * the center value of the bin. */
2077 *pcmap = pixcmapCreate(outdepth);
2078 for (i = 0; i < nbins; i++) {
2079 if (bincount[i]) {
2080 val = binave[i] / bincount[i];
2081 } else { /* no samples in the bin */
2082 if (i < nbins - 1)
2083 val = (binstart[i] + binstart[i + 1]) / 2;
2084 else /* last bin */
2085 val = (binstart[i] + 255) / 2;
2086 }
2087 pixcmapAddColor(*pcmap, val, val, val);
2088 }
2089
2090 LEPT_FREE(bincount);
2091 LEPT_FREE(binave);
2092 LEPT_FREE(binstart);
2093 return 0;
2094}
2095
2096
2097/*--------------------------------------------------------------------*
2098 * Thresholding from 32 bpp rgb to 1 bpp *
2099 *--------------------------------------------------------------------*/
2126PIX *
2128 l_uint32 refval,
2129 l_int32 delm,
2130 l_int32 delp,
2131 l_float32 fractm,
2132 l_float32 fractp)
2133{
2134l_int32 i, j, w, h, d, wpls, wpld;
2135l_int32 rref, gref, bref, rval, gval, bval;
2136l_int32 rmin, gmin, bmin, rmax, gmax, bmax;
2137l_uint32 pixel;
2138l_uint32 *datas, *datad, *lines, *lined;
2139PIX *pixd;
2140
2141 PROCNAME("pixGenerateMaskByBand32");
2142
2143 if (!pixs)
2144 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2145 pixGetDimensions(pixs, &w, &h, &d);
2146 if (d != 32)
2147 return (PIX *)ERROR_PTR("not 32 bpp", procName, NULL);
2148 if (delm < 0 || delp < 0)
2149 return (PIX *)ERROR_PTR("delm and delp must be >= 0", procName, NULL);
2150 if (fractm < 0.0 || fractm > 1.0 || fractp < 0.0 || fractp > 1.0)
2151 return (PIX *)ERROR_PTR("fractm and/or fractp invalid", procName, NULL);
2152
2153 extractRGBValues(refval, &rref, &gref, &bref);
2154 if (fractm == 0.0 && fractp == 0.0) {
2155 rmin = rref - delm;
2156 gmin = gref - delm;
2157 bmin = bref - delm;
2158 rmax = rref + delm;
2159 gmax = gref + delm;
2160 bmax = bref + delm;
2161 } else if (delm == 0 && delp == 0) {
2162 rmin = (l_int32)((1.0 - fractm) * rref);
2163 gmin = (l_int32)((1.0 - fractm) * gref);
2164 bmin = (l_int32)((1.0 - fractm) * bref);
2165 rmax = rref + (l_int32)(fractp * (255 - rref));
2166 gmax = gref + (l_int32)(fractp * (255 - gref));
2167 bmax = bref + (l_int32)(fractp * (255 - bref));
2168 } else {
2169 L_ERROR("bad input: either (delm, delp) or (fractm, fractp) "
2170 "must be 0\n", procName);
2171 return NULL;
2172 }
2173
2174 pixd = pixCreate(w, h, 1);
2175 pixCopyResolution(pixd, pixs);
2176 pixCopyInputFormat(pixd, pixs);
2177 datas = pixGetData(pixs);
2178 wpls = pixGetWpl(pixs);
2179 datad = pixGetData(pixd);
2180 wpld = pixGetWpl(pixd);
2181 for (i = 0; i < h; i++) {
2182 lines = datas + i * wpls;
2183 lined = datad + i * wpld;
2184 for (j = 0; j < w; j++) {
2185 pixel = lines[j];
2186 rval = (pixel >> L_RED_SHIFT) & 0xff;
2187 if (rval < rmin || rval > rmax)
2188 continue;
2189 gval = (pixel >> L_GREEN_SHIFT) & 0xff;
2190 if (gval < gmin || gval > gmax)
2191 continue;
2192 bval = (pixel >> L_BLUE_SHIFT) & 0xff;
2193 if (bval < bmin || bval > bmax)
2194 continue;
2195 SET_DATA_BIT(lined, j);
2196 }
2197 }
2198
2199 return pixd;
2200}
2201
2202
2224PIX *
2226 l_uint32 refval1,
2227 l_uint32 refval2,
2228 l_int32 distflag)
2229{
2230l_int32 i, j, w, h, d, wpls, wpld;
2231l_int32 rref1, gref1, bref1, rref2, gref2, bref2, rval, gval, bval;
2232l_uint32 pixel, dist1, dist2;
2233l_uint32 *datas, *datad, *lines, *lined;
2234PIX *pixd;
2235
2236 PROCNAME("pixGenerateMaskByDiscr32");
2237
2238 if (!pixs)
2239 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2240 pixGetDimensions(pixs, &w, &h, &d);
2241 if (d != 32)
2242 return (PIX *)ERROR_PTR("not 32 bpp", procName, NULL);
2243 if (distflag != L_MANHATTAN_DISTANCE && distflag != L_EUCLIDEAN_DISTANCE)
2244 return (PIX *)ERROR_PTR("invalid distflag", procName, NULL);
2245
2246 extractRGBValues(refval1, &rref1, &gref1, &bref1);
2247 extractRGBValues(refval2, &rref2, &gref2, &bref2);
2248 pixd = pixCreate(w, h, 1);
2249 pixCopyResolution(pixd, pixs);
2250 pixCopyInputFormat(pixd, pixs);
2251 datas = pixGetData(pixs);
2252 wpls = pixGetWpl(pixs);
2253 datad = pixGetData(pixd);
2254 wpld = pixGetWpl(pixd);
2255 for (i = 0; i < h; i++) {
2256 lines = datas + i * wpls;
2257 lined = datad + i * wpld;
2258 for (j = 0; j < w; j++) {
2259 pixel = lines[j];
2260 extractRGBValues(pixel, &rval, &gval, &bval);
2261 if (distflag == L_MANHATTAN_DISTANCE) {
2262 dist1 = L_ABS(rref1 - rval);
2263 dist2 = L_ABS(rref2 - rval);
2264 dist1 += L_ABS(gref1 - gval);
2265 dist2 += L_ABS(gref2 - gval);
2266 dist1 += L_ABS(bref1 - bval);
2267 dist2 += L_ABS(bref2 - bval);
2268 } else {
2269 dist1 = (rref1 - rval) * (rref1 - rval);
2270 dist2 = (rref2 - rval) * (rref2 - rval);
2271 dist1 += (gref1 - gval) * (gref1 - gval);
2272 dist2 += (gref2 - gval) * (gref2 - gval);
2273 dist1 += (bref1 - bval) * (bref1 - bval);
2274 dist2 += (bref2 - bval) * (bref2 - bval);
2275 }
2276 if (dist1 < dist2)
2277 SET_DATA_BIT(lined, j);
2278 }
2279 }
2280
2281 return pixd;
2282}
2283
2284
2285/*----------------------------------------------------------------------*
2286 * Histogram-based grayscale quantization *
2287 *----------------------------------------------------------------------*/
2338PIX *
2340 PIX *pixs,
2341 PIX *pixm,
2342 l_float32 minfract,
2343 l_int32 maxsize)
2344{
2345l_int32 w, h, wd, hd, wm, hm, wpls, wplm, wpld;
2346l_int32 nc, nestim, i, j, vals, vald;
2347l_int32 *lut;
2348l_uint32 *datas, *datam, *datad, *lines, *linem, *lined;
2349NUMA *na;
2350PIX *pixmr; /* resized mask */
2351PIXCMAP *cmap;
2352
2353 PROCNAME("pixGrayQuantFromHisto");
2354
2355 if (!pixs || pixGetDepth(pixs) != 8)
2356 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
2357 if (minfract < 0.01) {
2358 L_WARNING("minfract < 0.01; setting to 0.05\n", procName);
2359 minfract = 0.05;
2360 }
2361 if (maxsize < 2) {
2362 L_WARNING("maxsize < 2; setting to 10\n", procName);
2363 maxsize = 10;
2364 }
2365 if ((pixd && !pixm) || (!pixd && pixm))
2366 return (PIX *)ERROR_PTR("(pixd,pixm) not defined together",
2367 procName, NULL);
2368 pixGetDimensions(pixs, &w, &h, NULL);
2369 if (pixd) {
2370 if (pixGetDepth(pixm) != 1)
2371 return (PIX *)ERROR_PTR("pixm not 1 bpp", procName, NULL);
2372 if ((cmap = pixGetColormap(pixd)) == NULL)
2373 return (PIX *)ERROR_PTR("pixd not cmapped", procName, NULL);
2374 pixGetDimensions(pixd, &wd, &hd, NULL);
2375 if (w != wd || h != hd)
2376 return (PIX *)ERROR_PTR("pixs, pixd sizes differ", procName, NULL);
2377 nc = pixcmapGetCount(cmap);
2378 nestim = nc + (l_int32)(1.5 * 255 / maxsize);
2379 lept_stderr( "nestim = %d\n", nestim);
2380 if (nestim > 255) {
2381 L_ERROR("Estimate %d colors!\n", procName, nestim);
2382 return (PIX *)ERROR_PTR("probably too many colors", procName, NULL);
2383 }
2384 pixGetDimensions(pixm, &wm, &hm, NULL);
2385 if (w != wm || h != hm) { /* resize the mask */
2386 L_WARNING("mask and dest sizes not equal\n", procName);
2387 pixmr = pixCreate(w, h, 1);
2388 pixRasterop(pixmr, 0, 0, wm, hm, PIX_SRC, pixm, 0, 0);
2389 pixRasterop(pixmr, wm, 0, w - wm, h, PIX_SET, NULL, 0, 0);
2390 pixRasterop(pixmr, 0, hm, wm, h - hm, PIX_SET, NULL, 0, 0);
2391 } else {
2392 pixmr = pixClone(pixm);
2393 }
2394 } else {
2395 pixd = pixCreateTemplate(pixs);
2396 cmap = pixcmapCreate(8);
2397 pixSetColormap(pixd, cmap);
2398 }
2399 pixCopyResolution(pixd, pixs);
2400 pixCopyInputFormat(pixd, pixs);
2401
2402 /* Use original mask, if it exists, to select gray pixels */
2403 na = pixGetGrayHistogramMasked(pixs, pixm, 0, 0, 1);
2404
2405 /* Fill out the cmap with gray colors, and generate the lut
2406 * for pixel assignment. Issue a warning on failure. */
2407 if (numaFillCmapFromHisto(na, cmap, minfract, maxsize, &lut))
2408 L_ERROR("ran out of colors in cmap!\n", procName);
2409 numaDestroy(&na);
2410
2411 /* Assign the gray pixels to their cmap indices */
2412 datas = pixGetData(pixs);
2413 datad = pixGetData(pixd);
2414 wpls = pixGetWpl(pixs);
2415 wpld = pixGetWpl(pixd);
2416 if (!pixm) {
2417 for (i = 0; i < h; i++) {
2418 lines = datas + i * wpls;
2419 lined = datad + i * wpld;
2420 for (j = 0; j < w; j++) {
2421 vals = GET_DATA_BYTE(lines, j);
2422 vald = lut[vals];
2423 SET_DATA_BYTE(lined, j, vald);
2424 }
2425 }
2426 LEPT_FREE(lut);
2427 return pixd;
2428 }
2429
2430 datam = pixGetData(pixmr);
2431 wplm = pixGetWpl(pixmr);
2432 for (i = 0; i < h; i++) {
2433 lines = datas + i * wpls;
2434 linem = datam + i * wplm;
2435 lined = datad + i * wpld;
2436 for (j = 0; j < w; j++) {
2437 if (!GET_DATA_BIT(linem, j))
2438 continue;
2439 vals = GET_DATA_BYTE(lines, j);
2440 vald = lut[vals];
2441 SET_DATA_BYTE(lined, j, vald);
2442 }
2443 }
2444 pixDestroy(&pixmr);
2445 LEPT_FREE(lut);
2446 return pixd;
2447}
2448
2449
2470static l_int32
2472 PIXCMAP *cmap,
2473 l_float32 minfract,
2474 l_int32 maxsize,
2475 l_int32 **plut)
2476{
2477l_int32 mincount, index, sum, wtsum, span, istart, i, val, ret;
2478l_int32 *iahisto, *lut;
2479l_float32 total;
2480
2481 PROCNAME("numaFillCmapFromHisto");
2482
2483 if (!plut)
2484 return ERROR_INT("&lut not defined", procName, 1);
2485 *plut = NULL;
2486 if (!na)
2487 return ERROR_INT("na not defined", procName, 1);
2488 if (!cmap)
2489 return ERROR_INT("cmap not defined", procName, 1);
2490
2491 numaGetSum(na, &total);
2492 mincount = (l_int32)(minfract * total);
2493 iahisto = numaGetIArray(na);
2494 lut = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2495 *plut = lut;
2496 index = pixcmapGetCount(cmap); /* start with number of colors
2497 * already reserved */
2498
2499 /* March through, associating colors with sets of adjacent
2500 * gray levels. During the process, the LUT that gives
2501 * the colormap index for each gray level is computed.
2502 * To complete a color, either the total count must equal
2503 * or exceed %mincount, or the current span of colors must
2504 * equal or exceed %maxsize. An empty span is not converted
2505 * into a color; it is simply ignored. When a span is completed for a
2506 * color, the weighted color in the span is added to the colormap. */
2507 sum = 0;
2508 wtsum = 0;
2509 istart = 0;
2510 ret = 0;
2511 for (i = 0; i < 256; i++) {
2512 lut[i] = index;
2513 sum += iahisto[i];
2514 wtsum += i * iahisto[i];
2515 span = i - istart + 1;
2516 if (sum < mincount && span < maxsize)
2517 continue;
2518
2519 if (sum == 0) { /* empty span; don't save */
2520 istart = i + 1;
2521 continue;
2522 }
2523
2524 /* Found new color; sum > 0 */
2525 val = (l_int32)((l_float32)wtsum / (l_float32)sum + 0.5);
2526 ret = pixcmapAddColor(cmap, val, val, val);
2527 istart = i + 1;
2528 sum = 0;
2529 wtsum = 0;
2530 index++;
2531 }
2532 if (istart < 256 && sum > 0) { /* last one */
2533 span = 256 - istart;
2534 val = (l_int32)((l_float32)wtsum / (l_float32)sum + 0.5);
2535 ret = pixcmapAddColor(cmap, val, val, val);
2536 }
2537
2538 LEPT_FREE(iahisto);
2539 return ret;
2540}
2541
2542
2543/*----------------------------------------------------------------------*
2544 * Color quantize grayscale image using existing colormap *
2545 *----------------------------------------------------------------------*/
2561PIX *
2563 PIXCMAP *cmap,
2564 l_int32 mindepth)
2565{
2566l_int32 i, j, index, w, h, d, depth, wpls, wpld;
2567l_int32 hascolor, vals, vald;
2568l_int32 *tab;
2569l_uint32 *datas, *datad, *lines, *lined;
2570PIXCMAP *cmapd;
2571PIX *pixd;
2572
2573 PROCNAME("pixGrayQuantFromCmap");
2574
2575 if (!pixs)
2576 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2577 if (pixGetColormap(pixs) != NULL) {
2578 L_WARNING("pixs already has a colormap; returning a copy\n", procName);
2579 return pixCopy(NULL, pixs);
2580 }
2581 pixGetDimensions(pixs, &w, &h, &d);
2582 if (d != 8)
2583 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
2584 if (!cmap)
2585 return (PIX *)ERROR_PTR("cmap not defined", procName, NULL);
2586 if (mindepth != 2 && mindepth != 4 && mindepth != 8)
2587 return (PIX *)ERROR_PTR("invalid mindepth", procName, NULL);
2588
2589 /* Make sure the colormap is gray */
2590 pixcmapHasColor(cmap, &hascolor);
2591 if (hascolor) {
2592 L_WARNING("Converting colormap colors to gray\n", procName);
2593 cmapd = pixcmapColorToGray(cmap, 0.3, 0.5, 0.2);
2594 } else {
2595 cmapd = pixcmapCopy(cmap);
2596 }
2597
2598 /* Make LUT into colormap */
2599 tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2600 for (i = 0; i < 256; i++) {
2601 pixcmapGetNearestGrayIndex(cmapd, i, &index);
2602 tab[i] = index;
2603 }
2604
2605 pixcmapGetMinDepth(cmap, &depth);
2606 depth = L_MAX(depth, mindepth);
2607 pixd = pixCreate(w, h, depth);
2608 pixSetColormap(pixd, cmapd);
2609 pixCopyResolution(pixd, pixs);
2610 pixCopyInputFormat(pixd, pixs);
2611 datas = pixGetData(pixs);
2612 datad = pixGetData(pixd);
2613 wpls = pixGetWpl(pixs);
2614 wpld = pixGetWpl(pixd);
2615 for (i = 0; i < h; i++) {
2616 lines = datas + i * wpls;
2617 lined = datad + i * wpld;
2618 for (j = 0; j < w; j++) {
2619 vals = GET_DATA_BYTE(lines, j);
2620 vald = tab[vals];
2621 if (depth == 2)
2622 SET_DATA_DIBIT(lined, j, vald);
2623 else if (depth == 4)
2624 SET_DATA_QBIT(lined, j, vald);
2625 else /* depth == 8 */
2626 SET_DATA_BYTE(lined, j, vald);
2627 }
2628 }
2629
2630 LEPT_FREE(tab);
2631 return pixd;
2632}
2633
2634
2635#if 0 /* Documentation */
2636/*--------------------------------------------------------------------*
2637 * Implementation of binarization by dithering using LUTs *
2638 * It is archived here. *
2639 *--------------------------------------------------------------------*/
2654PIX *
2655pixDitherToBinaryLUT(PIX *pixs,
2656 l_int32 lowerclip,
2657 l_int32 upperclip)
2658{
2659l_int32 w, h, d, wplt, wpld;
2660l_int32 *tabval, *tab38, *tab14;
2661l_uint32 *datat, *datad;
2662l_uint32 *bufs1, *bufs2;
2663PIX *pixt, *pixd;
2664
2665 PROCNAME("pixDitherToBinaryLUT");
2666
2667 if (!pixs)
2668 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2669 pixGetDimensions(pixs, &w, &h, &d);
2670 if (d != 8)
2671 return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL);
2672 if (lowerclip < 0)
2673 lowerclip = DEFAULT_CLIP_LOWER_1;
2674 if (upperclip < 0)
2675 upperclip = DEFAULT_CLIP_UPPER_1;
2676
2677 if ((pixd = pixCreate(w, h, 1)) == NULL)
2678 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2679 pixCopyResolution(pixd, pixs);
2680 pixCopyInputFormat(pixd, pixs);
2681 datad = pixGetData(pixd);
2682 wpld = pixGetWpl(pixd);
2683
2684 /* Remove colormap if it exists */
2686 datat = pixGetData(pixt);
2687 wplt = pixGetWpl(pixt);
2688
2689 /* Two line buffers, 1 for current line and 2 for next line */
2690 bufs1 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
2691 bufs2 = (l_uint32 *)LEPT_CALLOC(wplt, sizeof(l_uint32));
2692 if (!bufs1 || !bufs2) {
2693 LEPT_FREE(bufs1);
2694 LEPT_FREE(bufs2);
2695 pixDestroy(&pixd);
2696 pixDestroy(&pixt);
2697 return (PIX *)ERROR_PTR("bufs1, bufs2 not both made", procName, NULL);
2698 }
2699
2700 /* 3 lookup tables: 1-bit value, (3/8)excess, and (1/4)excess */
2701 make8To1DitherTables(&tabval, &tab38, &tab14, lowerclip, upperclip);
2702
2703 ditherToBinaryLUTLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2,
2704 tabval, tab38, tab14);
2705
2706 LEPT_FREE(bufs1);
2707 LEPT_FREE(bufs2);
2708 LEPT_FREE(tabval);
2709 LEPT_FREE(tab38);
2710 LEPT_FREE(tab14);
2711 pixDestroy(&pixt);
2712 return pixd;
2713}
2714
2728void
2729ditherToBinaryLUTLow(l_uint32 *datad,
2730 l_int32 w,
2731 l_int32 h,
2732 l_int32 wpld,
2733 l_uint32 *datas,
2734 l_int32 wpls,
2735 l_uint32 *bufs1,
2736 l_uint32 *bufs2,
2737 l_int32 *tabval,
2738 l_int32 *tab38,
2739 l_int32 *tab14)
2740{
2741l_int32 i;
2742l_uint32 *lined;
2743
2744 /* do all lines except last line */
2745 memcpy(bufs2, datas, 4 * wpls); /* prime the buffer */
2746 for (i = 0; i < h - 1; i++) {
2747 memcpy(bufs1, bufs2, 4 * wpls);
2748 memcpy(bufs2, datas + (i + 1) * wpls, 4 * wpls);
2749 lined = datad + i * wpld;
2750 ditherToBinaryLineLUTLow(lined, w, bufs1, bufs2,
2751 tabval, tab38, tab14, 0);
2752 }
2753
2754 /* do last line */
2755 memcpy(bufs1, bufs2, 4 * wpls);
2756 lined = datad + (h - 1) * wpld;
2757 ditherToBinaryLineLUTLow(lined, w, bufs1, bufs2, tabval, tab38, tab14, 1);
2758 return;
2759}
2760
2774void
2775ditherToBinaryLineLUTLow(l_uint32 *lined,
2776 l_int32 w,
2777 l_uint32 *bufs1,
2778 l_uint32 *bufs2,
2779 l_int32 *tabval,
2780 l_int32 *tab38,
2781 l_int32 *tab14,
2782 l_int32 lastlineflag)
2783{
2784l_int32 j;
2785l_int32 oval, tab38val, tab14val;
2786l_uint8 rval, bval, dval;
2787
2788 if (lastlineflag == 0) {
2789 for (j = 0; j < w - 1; j++) {
2790 oval = GET_DATA_BYTE(bufs1, j);
2791 if (tabval[oval])
2792 SET_DATA_BIT(lined, j);
2793 rval = GET_DATA_BYTE(bufs1, j + 1);
2794 bval = GET_DATA_BYTE(bufs2, j);
2795 dval = GET_DATA_BYTE(bufs2, j + 1);
2796 tab38val = tab38[oval];
2797 if (tab38val == 0)
2798 continue;
2799 tab14val = tab14[oval];
2800 if (tab38val < 0) {
2801 rval = L_MAX(0, rval + tab38val);
2802 bval = L_MAX(0, bval + tab38val);
2803 dval = L_MAX(0, dval + tab14val);
2804 } else {
2805 rval = L_MIN(255, rval + tab38val);
2806 bval = L_MIN(255, bval + tab38val);
2807 dval = L_MIN(255, dval + tab14val);
2808 }
2809 SET_DATA_BYTE(bufs1, j + 1, rval);
2810 SET_DATA_BYTE(bufs2, j, bval);
2811 SET_DATA_BYTE(bufs2, j + 1, dval);
2812 }
2813
2814 /* do last column: j = w - 1 */
2815 oval = GET_DATA_BYTE(bufs1, j);
2816 if (tabval[oval])
2817 SET_DATA_BIT(lined, j);
2818 bval = GET_DATA_BYTE(bufs2, j);
2819 tab38val = tab38[oval];
2820 if (tab38val < 0) {
2821 bval = L_MAX(0, bval + tab38val);
2822 SET_DATA_BYTE(bufs2, j, bval);
2823 } else if (tab38val > 0 ) {
2824 bval = L_MIN(255, bval + tab38val);
2825 SET_DATA_BYTE(bufs2, j, bval);
2826 }
2827 } else { /* lastlineflag == 1 */
2828 for (j = 0; j < w - 1; j++) {
2829 oval = GET_DATA_BYTE(bufs1, j);
2830 if (tabval[oval])
2831 SET_DATA_BIT(lined, j);
2832 rval = GET_DATA_BYTE(bufs1, j + 1);
2833 tab38val = tab38[oval];
2834 if (tab38val == 0)
2835 continue;
2836 if (tab38val < 0)
2837 rval = L_MAX(0, rval + tab38val);
2838 else
2839 rval = L_MIN(255, rval + tab38val);
2840 SET_DATA_BYTE(bufs1, j + 1, rval);
2841 }
2842
2843 /* do last pixel: (i, j) = (h - 1, w - 1) */
2844 oval = GET_DATA_BYTE(bufs1, j);
2845 if (tabval[oval])
2846 SET_DATA_BIT(lined, j);
2847 }
2848
2849 return;
2850}
2851
2863l_ok
2864make8To1DitherTables(l_int32 **ptabval,
2865 l_int32 **ptab38,
2866 l_int32 **ptab14,
2867 l_int32 lowerclip,
2868 l_int32 upperclip)
2869{
2870l_int32 i;
2871l_int32 *tabval, *tab38, *tab14;
2872
2873 PROCNAME("make8To1DitherTables");
2874
2875 if (ptabval) *ptabval = NULL;
2876 if (ptab38) *ptab38 = NULL;
2877 if (ptab14) *ptab14 = NULL;
2878 if (!ptabval || !ptab38 || !ptab14)
2879 return ERROR_INT("table ptrs not all defined", procName, 1);
2880
2881 /* 3 lookup tables: 1-bit value, (3/8)excess, and (1/4)excess */
2882 tabval = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2883 tab38 = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2884 tab14 = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2885 if (!tabval || !tab38 || !tab14)
2886 return ERROR_INT("calloc failure to make small table", procName, 1);
2887 *ptabval = tabval;
2888 *ptab38 = tab38;
2889 *ptab14 = tab14;
2890
2891 for (i = 0; i < 256; i++) {
2892 if (i <= lowerclip) {
2893 tabval[i] = 1;
2894 tab38[i] = 0;
2895 tab14[i] = 0;
2896 } else if (i < 128) {
2897 tabval[i] = 1;
2898 tab38[i] = (3 * i + 4) / 8;
2899 tab14[i] = (i + 2) / 4;
2900 } else if (i < 255 - upperclip) {
2901 tabval[i] = 0;
2902 tab38[i] = (3 * (i - 255) + 4) / 8;
2903 tab14[i] = ((i - 255) + 2) / 4;
2904 } else { /* i >= 255 - upperclip */
2905 tabval[i] = 0;
2906 tab38[i] = 0;
2907 tab14[i] = 0;
2908 }
2909 }
2910
2911 return 0;
2912}
2913#endif /* Documentation */
PIX * pixBackgroundNormSimple(PIX *pixs, PIX *pixim, PIX *pixg)
pixBackgroundNormSimple()
Definition: adaptmap.c:247
#define GET_DATA_QBIT(pdata, n)
Definition: arrayaccess.h:164
#define SET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:127
#define SET_DATA_DIBIT(pdata, n, val)
Definition: arrayaccess.h:149
#define SET_DATA_TWO_BYTES(pdata, n, val)
Definition: arrayaccess.h:222
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define GET_DATA_DIBIT(pdata, n)
Definition: arrayaccess.h:145
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
#define SET_DATA_QBIT(pdata, n, val)
Definition: arrayaccess.h:168
void pixcmapDestroy(PIXCMAP **pcmap)
pixcmapDestroy()
Definition: colormap.c:279
l_ok pixcmapHasColor(PIXCMAP *cmap, l_int32 *pcolor)
pixcmapHasColor()
Definition: colormap.c:1075
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:708
l_ok pixcmapSetBlackAndWhite(PIXCMAP *cmap, l_int32 setblack, l_int32 setwhite)
pixcmapSetBlackAndWhite()
Definition: colormap.c:678
PIXCMAP * pixcmapCopy(const PIXCMAP *cmaps)
pixcmapCopy()
Definition: colormap.c:248
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:125
PIXCMAP * pixcmapCreateLinear(l_int32 d, l_int32 nlevels)
pixcmapCreateLinear()
Definition: colormap.c:218
PIXCMAP * pixcmapColorToGray(PIXCMAP *cmaps, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixcmapColorToGray()
Definition: colormap.c:1710
l_ok pixcmapGetMinDepth(PIXCMAP *cmap, l_int32 *pmindepth)
pixcmapGetMinDepth()
Definition: colormap.c:765
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:414
l_ok pixcmapGetNearestGrayIndex(PIXCMAP *cmap, l_int32 val, l_int32 *pindex)
pixcmapGetNearestGrayIndex()
Definition: colormap.c:1411
PIX * pixGammaTRC(PIX *pixd, PIX *pixs, l_float32 gamma, l_int32 minval, l_int32 maxval)
pixGammaTRC()
Definition: enhance.c:176
PIX * pixThresholdGrayArb(PIX *pixs, const char *edgevals, l_int32 outdepth, l_int32 use_average, l_int32 setblack, l_int32 setwhite)
pixThresholdGrayArb()
Definition: grayquant.c:1738
l_int32 * makeGrayQuantIndexTable(l_int32 nlevels)
makeGrayQuantIndexTable()
Definition: grayquant.c:1848
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:498
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:326
PIX * pixDitherTo2bppSpec(PIX *pixs, l_int32 lowerclip, l_int32 upperclip, l_int32 cmapflag)
pixDitherTo2bppSpec()
Definition: grayquant.c:1054
PIX * pixDitherToBinarySpec(PIX *pixs, l_int32 lowerclip, l_int32 upperclip)
pixDitherToBinarySpec()
Definition: grayquant.c:207
PIX * pixThresholdTo4bpp(PIX *pixs, l_int32 nlevels, l_int32 cmapflag)
pixThresholdTo4bpp()
Definition: grayquant.c:1520
PIX * pixAdaptThresholdToBinaryGen(PIX *pixs, PIX *pixm, l_float32 gamma, l_int32 blackval, l_int32 whiteval, l_int32 thresh)
pixAdaptThresholdToBinaryGen()
Definition: grayquant.c:770
static l_int32 make8To2DitherTables(l_int32 **ptabval, l_int32 **ptab38, l_int32 **ptab14, l_int32 cliptoblack, l_int32 cliptowhite)
make8To2DitherTables()
Definition: grayquant.c:1273
PIX * pixGenerateMaskByBand32(PIX *pixs, l_uint32 refval, l_int32 delm, l_int32 delp, l_float32 fractm, l_float32 fractp)
pixGenerateMaskByBand32()
Definition: grayquant.c:2127
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:1584
PIX * pixAdaptThresholdToBinary(PIX *pixs, PIX *pixm, l_float32 gamma)
pixAdaptThresholdToBinary()
Definition: grayquant.c:730
static l_int32 makeGrayQuantColormapArb(PIX *pixs, l_int32 *tab, l_int32 outdepth, PIXCMAP **pcmap)
makeGrayQuantColormapArb()
Definition: grayquant.c:2022
PIX * pixGrayQuantFromHisto(PIX *pixd, PIX *pixs, PIX *pixm, l_float32 minfract, l_int32 maxsize)
pixGrayQuantFromHisto()
Definition: grayquant.c:2339
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:1137
PIX * pixVarThresholdToBinary(PIX *pixs, PIX *pixg)
pixVarThresholdToBinary()
Definition: grayquant.c:655
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:447
PIX * pixGenerateMaskByDiscr32(PIX *pixs, l_uint32 refval1, l_uint32 refval2, l_int32 distflag)
pixGenerateMaskByDiscr32()
Definition: grayquant.c:2225
PIX * pixThresholdOn8bpp(PIX *pixs, l_int32 nlevels, l_int32 cmapflag)
pixThresholdOn8bpp()
Definition: grayquant.c:1637
PIX * pixDitherTo2bpp(PIX *pixs, l_int32 cmapflag)
pixDitherTo2bpp()
Definition: grayquant.c:1020
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:270
static l_int32 * makeGrayQuantTargetTable(l_int32 nlevels, l_int32 depth)
makeGrayQuantTargetTable()
Definition: grayquant.c:1897
PIX * pixGenerateMaskByBand(PIX *pixs, l_int32 lower, l_int32 upper, l_int32 inband, l_int32 usecmap)
pixGenerateMaskByBand()
Definition: grayquant.c:907
PIX * pixDitherToBinary(PIX *pixs)
pixDitherToBinary()
Definition: grayquant.c:175
PIX * pixGrayQuantFromCmap(PIX *pixs, PIXCMAP *cmap, l_int32 mindepth)
pixGrayQuantFromCmap()
Definition: grayquant.c:2562
static l_int32 numaFillCmapFromHisto(NUMA *na, PIXCMAP *cmap, l_float32 minfract, l_int32 maxsize, l_int32 **plut)
numaFillCmapFromHisto()
Definition: grayquant.c:2471
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:1442
l_ok makeGrayQuantTableArb(NUMA *na, l_int32 outdepth, l_int32 **ptab, PIXCMAP **pcmap)
makeGrayQuantTableArb()
Definition: grayquant.c:1950
PIX * pixGenerateMaskByValue(PIX *pixs, l_int32 val, l_int32 usecmap)
pixGenerateMaskByValue()
Definition: grayquant.c:816
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:1195
PIX * pixThresholdTo2bpp(PIX *pixs, l_int32 nlevels, l_int32 cmapflag)
pixThresholdTo2bpp()
Definition: grayquant.c:1378
NUMA * parseStringForNumbers(const char *str, const char *seps)
parseStringForNumbers()
Definition: kernel.c:1055
l_int32 * numaGetIArray(NUMA *na)
numaGetIArray()
Definition: numabasic.c:847
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:658
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:754
NUMA * numaSort(NUMA *naout, NUMA *nain, l_int32 sortorder)
numaSort()
Definition: numafunc1.c:2650
l_ok numaGetSum(NUMA *na, l_float32 *psum)
numaGetSum()
Definition: numafunc1.c:538
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1699
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
l_int32 pixSizesEqual(const PIX *pix1, const PIX *pix2)
pixSizesEqual()
Definition: pix1.c:1985
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:383
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2820
NUMA * pixGetGrayHistogramMasked(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_int32 factor)
pixGetGrayHistogramMasked()
Definition: pix4.c:211
@ DEFAULT_CLIP_UPPER_2
Definition: pix.h:938
@ DEFAULT_CLIP_LOWER_1
Definition: pix.h:935
@ DEFAULT_CLIP_LOWER_2
Definition: pix.h:937
@ DEFAULT_CLIP_UPPER_1
Definition: pix.h:936
@ REMOVE_CMAP_TO_GRAYSCALE
Definition: pix.h:257
#define PIX_SRC
Definition: pix.h:330
@ L_SORT_INCREASING
Definition: pix.h:729
#define PIX_SET
Definition: pix.h:334
@ L_EUCLIDEAN_DISTANCE
Definition: pix.h:947
@ L_MANHATTAN_DISTANCE
Definition: pix.h:946
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:328
l_ok pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:204
Definition: array.h:71
Definition: pix.h:139
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306