Leptonica  1.83.1
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 
108 static void ditherToBinaryLow(l_uint32 *datad, l_int32 w, l_int32 h,
109  l_int32 wpld, l_uint32 *datas, l_int32 wpls,
110  l_uint32 *bufs1, l_uint32 *bufs2,
111  l_int32 lowerclip, l_int32 upperclip);
112 static void thresholdToBinaryLow(l_uint32 *datad, l_int32 w, l_int32 h,
113  l_int32 wpld, l_uint32 *datas, l_int32 d,
114  l_int32 wpls, l_int32 thresh);
115 static void ditherTo2bppLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld,
116  l_uint32 *datas, l_int32 wpls, l_uint32 *bufs1,
117  l_uint32 *bufs2, l_int32 *tabval, l_int32 *tab38,
118  l_int32 *tab14);
119 static void ditherTo2bppLineLow(l_uint32 *lined, l_int32 w, l_uint32 *bufs1,
120  l_uint32 *bufs2, l_int32 *tabval,
121  l_int32 *tab38, l_int32 *tab14,
122  l_int32 lastlineflag);
123 static l_int32 make8To2DitherTables(l_int32 **ptabval, l_int32 **ptab38,
124  l_int32 **ptab14, l_int32 cliptoblack,
125  l_int32 cliptowhite);
126 static void thresholdTo2bppLow(l_uint32 *datad, l_int32 h, l_int32 wpld,
127  l_uint32 *datas, l_int32 wpls, l_int32 *tab);
128 static void thresholdTo4bppLow(l_uint32 *datad, l_int32 h, l_int32 wpld,
129  l_uint32 *datas, l_int32 wpls, l_int32 *tab);
130 static l_int32 *makeGrayQuantTargetTable(l_int32 nlevels, l_int32 depth);
131 static l_int32 makeGrayQuantColormapArb(PIX *pixs, l_int32 *tab,
132  l_int32 outdepth, PIXCMAP **pcmap);
133 static l_int32 numaFillCmapFromHisto(NUMA *na, PIXCMAP *cmap,
134  l_float32 minfract, l_int32 maxsize,
135  l_int32 **plut);
136 
137 #ifndef NO_CONSOLE_IO
138 #define DEBUG_UNROLLING 0
139 #endif /* ~NO_CONSOLE_IO */
140 
141 /*------------------------------------------------------------------*
142  * Binarization by Floyd-Steinberg dithering *
143  *------------------------------------------------------------------*/
174 PIX *
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 
204 PIX *
206  l_int32 lowerclip,
207  l_int32 upperclip)
208 {
209 l_int32 w, h, d, wplt, wpld;
210 l_uint32 *datat, *datad;
211 l_uint32 *bufs1, *bufs2;
212 PIX *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 
265 static void
266 ditherToBinaryLow(l_uint32 *datad,
267  l_int32 w,
268  l_int32 h,
269  l_int32 wpld,
270  l_uint32 *datas,
271  l_int32 wpls,
272  l_uint32 *bufs1,
273  l_uint32 *bufs2,
274  l_int32 lowerclip,
275  l_int32 upperclip)
276 {
277 l_int32 i;
278 l_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 
321 void
322 ditherToBinaryLineLow(l_uint32 *lined,
323  l_int32 w,
324  l_uint32 *bufs1,
325  l_uint32 *bufs2,
326  l_int32 lowerclip,
327  l_int32 upperclip,
328  l_int32 lastlineflag)
329 {
330 l_int32 j;
331 l_int32 oval, eval;
332 l_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  *------------------------------------------------------------------*/
442 PIX *
444  l_int32 thresh)
445 {
446 l_int32 d, w, h, wplt, wpld;
447 l_uint32 *datat, *datad;
448 PIX *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. */
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 
491 static void
492 thresholdToBinaryLow(l_uint32 *datad,
493  l_int32 w,
494  l_int32 h,
495  l_int32 wpld,
496  l_uint32 *datas,
497  l_int32 d,
498  l_int32 wpls,
499  l_int32 thresh)
500 {
501 l_int32 i;
502 l_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  */
516 void
517 thresholdToBinaryLineLow(l_uint32 *lined,
518  l_int32 w,
519  l_uint32 *lines,
520  l_int32 d,
521  l_int32 thresh)
522 {
523 l_int32 j, k, gval, scount, dcount;
524 l_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  *------------------------------------------------------------------*/
646 PIX *
648  PIX *pixg)
649 {
650 l_int32 i, j, vals, valg, w, h, d, wpls, wplg, wpld;
651 l_uint32 *datas, *datag, *datad, *lines, *lineg, *lined;
652 PIX *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  *------------------------------------------------------------------*/
719 PIX *
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 
757 PIX *
759  PIX *pixm,
760  l_float32 gamma,
761  l_int32 blackval,
762  l_int32 whiteval,
763  l_int32 thresh)
764 {
765 PIX *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  *--------------------------------------------------------------------*/
801 PIX *
803  l_int32 val,
804  l_int32 usecmap)
805 {
806 l_int32 i, j, w, h, d, wplg, wpld;
807 l_uint32 *datag, *datad, *lineg, *lined;
808 PIX *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))
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 
890 PIX *
892  l_int32 lower,
893  l_int32 upper,
894  l_int32 inband,
895  l_int32 usecmap)
896 {
897 l_int32 i, j, w, h, d, wplg, wpld, val;
898 l_uint32 *datag, *datad, *lineg, *lined;
899 PIX *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))
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  *------------------------------------------------------------------*/
1001 PIX *
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 
1033 PIX *
1035  l_int32 lowerclip,
1036  l_int32 upperclip,
1037  l_int32 cmapflag)
1038 {
1039 l_int32 w, h, d, wplt, wpld;
1040 l_int32 *tabval, *tab38, *tab14;
1041 l_uint32 *datat, *datad;
1042 l_uint32 *bufs1, *bufs2;
1043 PIX *pixt, *pixd;
1044 PIXCMAP *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 */
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 
1114 static void
1115 ditherTo2bppLow(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 {
1127 l_int32 i;
1128 l_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 
1172 static void
1173 ditherTo2bppLineLow(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 {
1182 l_int32 j;
1183 l_int32 oval, tab38val, tab14val;
1184 l_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 
1250 static l_int32
1251 make8To2DitherTables(l_int32 **ptabval,
1252  l_int32 **ptab38,
1253  l_int32 **ptab14,
1254  l_int32 cliptoblack,
1255  l_int32 cliptowhite)
1256 {
1257 l_int32 i;
1258 l_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  *--------------------------------------------------------------------*/
1355 PIX *
1357  l_int32 nlevels,
1358  l_int32 cmapflag)
1359 {
1360 l_int32 *qtab;
1361 l_int32 w, h, d, wplt, wpld;
1362 l_uint32 *datat, *datad;
1363 PIX *pixt, *pixd;
1364 PIXCMAP *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 */
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 
1417 static void
1418 thresholdTo2bppLow(l_uint32 *datad,
1419  l_int32 h,
1420  l_int32 wpld,
1421  l_uint32 *datas,
1422  l_int32 wpls,
1423  l_int32 *tab)
1424 {
1425 l_uint8 sval1, sval2, sval3, sval4, dval;
1426 l_int32 i, j, k;
1427 l_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  *----------------------------------------------------------------------*/
1495 PIX *
1497  l_int32 nlevels,
1498  l_int32 cmapflag)
1499 {
1500 l_int32 *qtab;
1501 l_int32 w, h, d, wplt, wpld;
1502 l_uint32 *datat, *datad;
1503 PIX *pixt, *pixd;
1504 PIXCMAP *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 */
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 
1557 static void
1558 thresholdTo4bppLow(l_uint32 *datad,
1559  l_int32 h,
1560  l_int32 wpld,
1561  l_uint32 *datas,
1562  l_int32 wpls,
1563  l_int32 *tab)
1564 {
1565 l_uint8 sval1, sval2, sval3, sval4;
1566 l_uint16 dval;
1567 l_int32 i, j, k;
1568 l_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  *----------------------------------------------------------------------*/
1610 PIX *
1612  l_int32 nlevels,
1613  l_int32 cmapflag)
1614 {
1615 l_int32 *qtab; /* quantization table */
1616 l_int32 i, j, w, h, wpld, val, newval;
1617 l_uint32 *datad, *lined;
1618 PIX *pixd;
1619 PIXCMAP *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))
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  *----------------------------------------------------------------------*/
1709 PIX *
1711  const char *edgevals,
1712  l_int32 outdepth,
1713  l_int32 use_average,
1714  l_int32 setblack,
1715  l_int32 setwhite)
1716 {
1717 l_int32 *qtab;
1718 l_int32 w, h, d, i, j, n, wplt, wpld, val, newval;
1719 l_uint32 *datat, *datad, *linet, *lined;
1720 NUMA *na;
1721 PIX *pixt, *pixd;
1722 PIXCMAP *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 */
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  *----------------------------------------------------------------------*/
1817 l_int32 *
1818 makeGrayQuantIndexTable(l_int32 nlevels)
1819 {
1820 l_int32 *tab;
1821 l_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 
1866 static l_int32 *
1868  l_int32 depth)
1869 {
1870 l_int32 *tab;
1871 l_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  *----------------------------------------------------------------------*/
1919 l_ok
1921  l_int32 outdepth,
1922  l_int32 **ptab,
1923  PIXCMAP **pcmap)
1924 {
1925 l_int32 i, j, n, jstart, ave, val;
1926 l_int32 *tab;
1927 PIXCMAP *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 
1989 static l_int32
1991  l_int32 *tab,
1992  l_int32 outdepth,
1993  PIXCMAP **pcmap)
1994 {
1995 l_int32 i, j, index, w, h, d, nbins, wpl, factor, val;
1996 l_int32 *bincount, *binave, *binstart;
1997 l_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  *--------------------------------------------------------------------*/
2092 PIX *
2094  l_uint32 refval,
2095  l_int32 delm,
2096  l_int32 delp,
2097  l_float32 fractm,
2098  l_float32 fractp)
2099 {
2100 l_int32 i, j, w, h, d, wpls, wpld;
2101 l_int32 rref, gref, bref, rval, gval, bval;
2102 l_int32 rmin, gmin, bmin, rmax, gmax, bmax;
2103 l_uint32 pixel;
2104 l_uint32 *datas, *datad, *lines, *lined;
2105 PIX *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 
2188 PIX *
2190  l_uint32 refval1,
2191  l_uint32 refval2,
2192  l_int32 distflag)
2193 {
2194 l_int32 i, j, w, h, d, wpls, wpld;
2195 l_int32 rref1, gref1, bref1, rref2, gref2, bref2, rval, gval, bval;
2196 l_uint32 pixel, dist1, dist2;
2197 l_uint32 *datas, *datad, *lines, *lined;
2198 PIX *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  *----------------------------------------------------------------------*/
2300 PIX *
2302  PIX *pixs,
2303  PIX *pixm,
2304  l_float32 minfract,
2305  l_int32 maxsize)
2306 {
2307 l_int32 w, h, wd, hd, wm, hm, wpls, wplm, wpld;
2308 l_int32 nc, nestim, i, j, vals, vald;
2309 l_int32 *lut;
2310 l_uint32 *datas, *datam, *datad, *lines, *linem, *lined;
2311 NUMA *na;
2312 PIX *pixmr; /* resized mask */
2313 PIXCMAP *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.05;
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 
2430 static l_int32
2432  PIXCMAP *cmap,
2433  l_float32 minfract,
2434  l_int32 maxsize,
2435  l_int32 **plut)
2436 {
2437 l_int32 mincount, index, sum, wtsum, span, istart, i, val, ret;
2438 l_int32 *iahisto, *lut;
2439 l_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  *----------------------------------------------------------------------*/
2519 PIX *
2521  PIXCMAP *cmap,
2522  l_int32 mindepth)
2523 {
2524 l_int32 i, j, index, w, h, d, depth, wpls, wpld;
2525 l_int32 hascolor, vals, vald;
2526 l_int32 *tab;
2527 l_uint32 *datas, *datad, *lines, *lined;
2528 PIXCMAP *cmapd;
2529 PIX *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.3, 0.5, 0.2);
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  *--------------------------------------------------------------------*/
2610 PIX *
2611 pixDitherToBinaryLUT(PIX *pixs,
2612  l_int32 lowerclip,
2613  l_int32 upperclip)
2614 {
2615 l_int32 w, h, d, wplt, wpld;
2616 l_int32 *tabval, *tab38, *tab14;
2617 l_uint32 *datat, *datad;
2618 l_uint32 *bufs1, *bufs2;
2619 PIX *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 */
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 
2682 void
2683 ditherToBinaryLUTLow(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 {
2695 l_int32 i;
2696 l_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 
2728 void
2729 ditherToBinaryLineLUTLow(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 {
2738 l_int32 j;
2739 l_int32 oval, tab38val, tab14val;
2740 l_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 
2817 l_ok
2818 make8To1DitherTables(l_int32 **ptabval,
2819  l_int32 **ptab38,
2820  l_int32 **ptab14,
2821  l_int32 lowerclip,
2822  l_int32 upperclip)
2823 {
2824 l_int32 i;
2825 l_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:245
#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:272
l_ok pixcmapHasColor(PIXCMAP *cmap, l_int32 *pcolor)
pixcmapHasColor()
Definition: colormap.c:1026
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:683
l_ok pixcmapSetBlackAndWhite(PIXCMAP *cmap, l_int32 setblack, l_int32 setwhite)
pixcmapSetBlackAndWhite()
Definition: colormap.c:655
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:126
PIXCMAP * pixcmapColorToGray(PIXCMAP *cmaps, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixcmapColorToGray()
Definition: colormap.c:1641
l_ok pixcmapGetMinDepth(PIXCMAP *cmap, l_int32 *pmindepth)
pixcmapGetMinDepth()
Definition: colormap.c:734
PIXCMAP * pixcmapCreateLinear(l_int32 d, l_int32 nlevels)
pixcmapCreateLinear()
Definition: colormap.c:215
PIXCMAP * pixcmapCopy(const PIXCMAP *cmaps)
pixcmapCopy()
Definition: colormap.c:243
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:403
l_ok pixcmapGetNearestGrayIndex(PIXCMAP *cmap, l_int32 val, l_int32 *pindex)
pixcmapGetNearestGrayIndex()
Definition: colormap.c:1348
PIX * pixGammaTRC(PIX *pixd, PIX *pixs, l_float32 gamma, l_int32 minval, l_int32 maxval)
pixGammaTRC()
Definition: enhance.c:176
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 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 * pixThresholdTo2bpp(PIX *pixs, l_int32 nlevels, l_int32 cmapflag)
pixThresholdTo2bpp()
Definition: grayquant.c:1356
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 * pixThresholdTo4bpp(PIX *pixs, l_int32 nlevels, l_int32 cmapflag)
pixThresholdTo4bpp()
Definition: grayquant.c:1496
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
static l_int32 makeGrayQuantColormapArb(PIX *pixs, l_int32 *tab, l_int32 outdepth, PIXCMAP **pcmap)
makeGrayQuantColormapArb()
Definition: grayquant.c:1990
PIX * pixGrayQuantFromCmap(PIX *pixs, PIXCMAP *cmap, l_int32 mindepth)
pixGrayQuantFromCmap()
Definition: grayquant.c:2520
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 * 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
PIX * pixGenerateMaskByValue(PIX *pixs, l_int32 val, l_int32 usecmap)
pixGenerateMaskByValue()
Definition: grayquant.c:802
l_int32 * makeGrayQuantIndexTable(l_int32 nlevels)
makeGrayQuantIndexTable()
Definition: grayquant.c:1818
PIX * pixAdaptThresholdToBinary(PIX *pixs, PIX *pixm, l_float32 gamma)
pixAdaptThresholdToBinary()
Definition: grayquant.c:720
PIX * pixGenerateMaskByBand(PIX *pixs, l_int32 lower, l_int32 upper, l_int32 inband, l_int32 usecmap)
pixGenerateMaskByBand()
Definition: grayquant.c:891
PIX * pixGenerateMaskByDiscr32(PIX *pixs, l_uint32 refval1, l_uint32 refval2, l_int32 distflag)
pixGenerateMaskByDiscr32()
Definition: grayquant.c:2189
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 * pixThresholdGrayArb(PIX *pixs, const char *edgevals, l_int32 outdepth, l_int32 use_average, l_int32 setblack, l_int32 setwhite)
pixThresholdGrayArb()
Definition: grayquant.c:1710
PIX * pixVarThresholdToBinary(PIX *pixs, PIX *pixg)
pixVarThresholdToBinary()
Definition: grayquant.c:647
PIX * pixDitherToBinarySpec(PIX *pixs, l_int32 lowerclip, l_int32 upperclip)
pixDitherToBinarySpec()
Definition: grayquant.c:205
PIX * pixDitherTo2bppSpec(PIX *pixs, l_int32 lowerclip, l_int32 upperclip, l_int32 cmapflag)
pixDitherTo2bppSpec()
Definition: grayquant.c:1034
PIX * pixDitherToBinary(PIX *pixs)
pixDitherToBinary()
Definition: grayquant.c:175
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
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 * pixGrayQuantFromHisto(PIX *pixd, PIX *pixs, PIX *pixm, l_float32 minfract, l_int32 maxsize)
pixGrayQuantFromHisto()
Definition: grayquant.c:2301
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:443
PIX * pixAdaptThresholdToBinaryGen(PIX *pixs, PIX *pixm, l_float32 gamma, l_int32 blackval, l_int32 whiteval, l_int32 thresh)
pixAdaptThresholdToBinaryGen()
Definition: grayquant.c:758
NUMA * parseStringForNumbers(const char *str, const char *seps)
parseStringForNumbers()
Definition: kernel.c:1015
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:720
l_int32 * numaGetIArray(NUMA *na)
numaGetIArray()
Definition: numabasic.c:807
NUMA * numaSort(NUMA *naout, NUMA *nain, l_int32 sortorder)
numaSort()
Definition: numafunc1.c:2567
l_ok numaGetSum(NUMA *na, l_float32 *psum)
numaGetSum()
Definition: numafunc1.c:525
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1642
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1582
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
l_int32 pixSizesEqual(const PIX *pix1, const PIX *pix2)
pixSizesEqual()
Definition: pix1.c:1878
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:689
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:380
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2793
NUMA * pixGetGrayHistogramMasked(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_int32 factor)
pixGetGrayHistogramMasked()
Definition: pix4.c:209
@ 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
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:324
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
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306