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 
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  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 
206 PIX *
208  l_int32 lowerclip,
209  l_int32 upperclip)
210 {
211 l_int32 w, h, d, wplt, wpld;
212 l_uint32 *datat, *datad;
213 l_uint32 *bufs1, *bufs2;
214 PIX *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 
269 static void
270 ditherToBinaryLow(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 {
281 l_int32 i;
282 l_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 
325 void
326 ditherToBinaryLineLow(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 {
334 l_int32 j;
335 l_int32 oval, eval;
336 l_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  *------------------------------------------------------------------*/
446 PIX *
448  l_int32 thresh)
449 {
450 l_int32 d, w, h, wplt, wpld;
451 l_uint32 *datat, *datad;
452 PIX *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 
497 static void
498 thresholdToBinaryLow(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 {
507 l_int32 i;
508 l_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  */
522 void
523 thresholdToBinaryLineLow(l_uint32 *lined,
524  l_int32 w,
525  l_uint32 *lines,
526  l_int32 d,
527  l_int32 thresh)
528 {
529 l_int32 j, k, gval, scount, dcount;
530 l_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  *------------------------------------------------------------------*/
654 PIX *
656  PIX *pixg)
657 {
658 l_int32 i, j, vals, valg, w, h, d, wpls, wplg, wpld;
659 l_uint32 *datas, *datag, *datad, *lines, *lineg, *lined;
660 PIX *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  *------------------------------------------------------------------*/
729 PIX *
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 
769 PIX *
771  PIX *pixm,
772  l_float32 gamma,
773  l_int32 blackval,
774  l_int32 whiteval,
775  l_int32 thresh)
776 {
777 PIX *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  *--------------------------------------------------------------------*/
815 PIX *
817  l_int32 val,
818  l_int32 usecmap)
819 {
820 l_int32 i, j, w, h, d, wplg, wpld;
821 l_uint32 *datag, *datad, *lineg, *lined;
822 PIX *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 
906 PIX *
908  l_int32 lower,
909  l_int32 upper,
910  l_int32 inband,
911  l_int32 usecmap)
912 {
913 l_int32 i, j, w, h, d, wplg, wpld, val;
914 l_uint32 *datag, *datad, *lineg, *lined;
915 PIX *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  *------------------------------------------------------------------*/
1019 PIX *
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 
1053 PIX *
1055  l_int32 lowerclip,
1056  l_int32 upperclip,
1057  l_int32 cmapflag)
1058 {
1059 l_int32 w, h, d, wplt, wpld;
1060 l_int32 *tabval, *tab38, *tab14;
1061 l_uint32 *datat, *datad;
1062 l_uint32 *bufs1, *bufs2;
1063 PIX *pixt, *pixd;
1064 PIXCMAP *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 
1136 static void
1137 ditherTo2bppLow(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 {
1149 l_int32 i;
1150 l_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 
1194 static void
1195 ditherTo2bppLineLow(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 {
1204 l_int32 j;
1205 l_int32 oval, tab38val, tab14val;
1206 l_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 
1272 static l_int32
1273 make8To2DitherTables(l_int32 **ptabval,
1274  l_int32 **ptab38,
1275  l_int32 **ptab14,
1276  l_int32 cliptoblack,
1277  l_int32 cliptowhite)
1278 {
1279 l_int32 i;
1280 l_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  *--------------------------------------------------------------------*/
1377 PIX *
1379  l_int32 nlevels,
1380  l_int32 cmapflag)
1381 {
1382 l_int32 *qtab;
1383 l_int32 w, h, d, wplt, wpld;
1384 l_uint32 *datat, *datad;
1385 PIX *pixt, *pixd;
1386 PIXCMAP *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 
1441 static void
1442 thresholdTo2bppLow(l_uint32 *datad,
1443  l_int32 h,
1444  l_int32 wpld,
1445  l_uint32 *datas,
1446  l_int32 wpls,
1447  l_int32 *tab)
1448 {
1449 l_uint8 sval1, sval2, sval3, sval4, dval;
1450 l_int32 i, j, k;
1451 l_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  *----------------------------------------------------------------------*/
1519 PIX *
1521  l_int32 nlevels,
1522  l_int32 cmapflag)
1523 {
1524 l_int32 *qtab;
1525 l_int32 w, h, d, wplt, wpld;
1526 l_uint32 *datat, *datad;
1527 PIX *pixt, *pixd;
1528 PIXCMAP *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 
1583 static void
1584 thresholdTo4bppLow(l_uint32 *datad,
1585  l_int32 h,
1586  l_int32 wpld,
1587  l_uint32 *datas,
1588  l_int32 wpls,
1589  l_int32 *tab)
1590 {
1591 l_uint8 sval1, sval2, sval3, sval4;
1592 l_uint16 dval;
1593 l_int32 i, j, k;
1594 l_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  *----------------------------------------------------------------------*/
1636 PIX *
1638  l_int32 nlevels,
1639  l_int32 cmapflag)
1640 {
1641 l_int32 *qtab; /* quantization table */
1642 l_int32 i, j, w, h, wpld, val, newval;
1643 l_uint32 *datad, *lined;
1644 PIX *pixd;
1645 PIXCMAP *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  *----------------------------------------------------------------------*/
1737 PIX *
1739  const char *edgevals,
1740  l_int32 outdepth,
1741  l_int32 use_average,
1742  l_int32 setblack,
1743  l_int32 setwhite)
1744 {
1745 l_int32 *qtab;
1746 l_int32 w, h, d, i, j, n, wplt, wpld, val, newval;
1747 l_uint32 *datat, *datad, *linet, *lined;
1748 NUMA *na;
1749 PIX *pixt, *pixd;
1750 PIXCMAP *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  *----------------------------------------------------------------------*/
1847 l_int32 *
1848 makeGrayQuantIndexTable(l_int32 nlevels)
1849 {
1850 l_int32 *tab;
1851 l_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 
1896 static l_int32 *
1898  l_int32 depth)
1899 {
1900 l_int32 *tab;
1901 l_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  *----------------------------------------------------------------------*/
1949 l_ok
1951  l_int32 outdepth,
1952  l_int32 **ptab,
1953  PIXCMAP **pcmap)
1954 {
1955 l_int32 i, j, n, jstart, ave, val;
1956 l_int32 *tab;
1957 PIXCMAP *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 
2021 static l_int32
2023  l_int32 *tab,
2024  l_int32 outdepth,
2025  PIXCMAP **pcmap)
2026 {
2027 l_int32 i, j, index, w, h, d, nbins, wpl, factor, val;
2028 l_int32 *bincount, *binave, *binstart;
2029 l_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  *--------------------------------------------------------------------*/
2126 PIX *
2128  l_uint32 refval,
2129  l_int32 delm,
2130  l_int32 delp,
2131  l_float32 fractm,
2132  l_float32 fractp)
2133 {
2134 l_int32 i, j, w, h, d, wpls, wpld;
2135 l_int32 rref, gref, bref, rval, gval, bval;
2136 l_int32 rmin, gmin, bmin, rmax, gmax, bmax;
2137 l_uint32 pixel;
2138 l_uint32 *datas, *datad, *lines, *lined;
2139 PIX *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 
2224 PIX *
2226  l_uint32 refval1,
2227  l_uint32 refval2,
2228  l_int32 distflag)
2229 {
2230 l_int32 i, j, w, h, d, wpls, wpld;
2231 l_int32 rref1, gref1, bref1, rref2, gref2, bref2, rval, gval, bval;
2232 l_uint32 pixel, dist1, dist2;
2233 l_uint32 *datas, *datad, *lines, *lined;
2234 PIX *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  *----------------------------------------------------------------------*/
2338 PIX *
2340  PIX *pixs,
2341  PIX *pixm,
2342  l_float32 minfract,
2343  l_int32 maxsize)
2344 {
2345 l_int32 w, h, wd, hd, wm, hm, wpls, wplm, wpld;
2346 l_int32 nc, nestim, i, j, vals, vald;
2347 l_int32 *lut;
2348 l_uint32 *datas, *datam, *datad, *lines, *linem, *lined;
2349 NUMA *na;
2350 PIX *pixmr; /* resized mask */
2351 PIXCMAP *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 
2470 static l_int32
2472  PIXCMAP *cmap,
2473  l_float32 minfract,
2474  l_int32 maxsize,
2475  l_int32 **plut)
2476 {
2477 l_int32 mincount, index, sum, wtsum, span, istart, i, val, ret;
2478 l_int32 *iahisto, *lut;
2479 l_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  *----------------------------------------------------------------------*/
2561 PIX *
2563  PIXCMAP *cmap,
2564  l_int32 mindepth)
2565 {
2566 l_int32 i, j, index, w, h, d, depth, wpls, wpld;
2567 l_int32 hascolor, vals, vald;
2568 l_int32 *tab;
2569 l_uint32 *datas, *datad, *lines, *lined;
2570 PIXCMAP *cmapd;
2571 PIX *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  *--------------------------------------------------------------------*/
2654 PIX *
2655 pixDitherToBinaryLUT(PIX *pixs,
2656  l_int32 lowerclip,
2657  l_int32 upperclip)
2658 {
2659 l_int32 w, h, d, wplt, wpld;
2660 l_int32 *tabval, *tab38, *tab14;
2661 l_uint32 *datat, *datad;
2662 l_uint32 *bufs1, *bufs2;
2663 PIX *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 
2728 void
2729 ditherToBinaryLUTLow(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 {
2741 l_int32 i;
2742 l_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 
2774 void
2775 ditherToBinaryLineLUTLow(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 {
2784 l_int32 j;
2785 l_int32 oval, tab38val, tab14val;
2786 l_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 
2863 l_ok
2864 make8To1DitherTables(l_int32 **ptabval,
2865  l_int32 **ptab38,
2866  l_int32 **ptab14,
2867  l_int32 lowerclip,
2868  l_int32 upperclip)
2869 {
2870 l_int32 i;
2871 l_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 * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:125
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
PIXCMAP * pixcmapCreateLinear(l_int32 d, l_int32 nlevels)
pixcmapCreateLinear()
Definition: colormap.c:218
PIXCMAP * pixcmapCopy(const PIXCMAP *cmaps)
pixcmapCopy()
Definition: colormap.c:248
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 * 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 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 * pixThresholdTo2bpp(PIX *pixs, l_int32 nlevels, l_int32 cmapflag)
pixThresholdTo2bpp()
Definition: grayquant.c:1378
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 * pixThresholdTo4bpp(PIX *pixs, l_int32 nlevels, l_int32 cmapflag)
pixThresholdTo4bpp()
Definition: grayquant.c:1520
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
static l_int32 makeGrayQuantColormapArb(PIX *pixs, l_int32 *tab, l_int32 outdepth, PIXCMAP **pcmap)
makeGrayQuantColormapArb()
Definition: grayquant.c:2022
PIX * pixGrayQuantFromCmap(PIX *pixs, PIXCMAP *cmap, l_int32 mindepth)
pixGrayQuantFromCmap()
Definition: grayquant.c:2562
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 * 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
PIX * pixGenerateMaskByValue(PIX *pixs, l_int32 val, l_int32 usecmap)
pixGenerateMaskByValue()
Definition: grayquant.c:816
l_int32 * makeGrayQuantIndexTable(l_int32 nlevels)
makeGrayQuantIndexTable()
Definition: grayquant.c:1848
PIX * pixAdaptThresholdToBinary(PIX *pixs, PIX *pixm, l_float32 gamma)
pixAdaptThresholdToBinary()
Definition: grayquant.c:730
PIX * pixGenerateMaskByBand(PIX *pixs, l_int32 lower, l_int32 upper, l_int32 inband, l_int32 usecmap)
pixGenerateMaskByBand()
Definition: grayquant.c:907
PIX * pixGenerateMaskByDiscr32(PIX *pixs, l_uint32 refval1, l_uint32 refval2, l_int32 distflag)
pixGenerateMaskByDiscr32()
Definition: grayquant.c:2225
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 * pixThresholdGrayArb(PIX *pixs, const char *edgevals, l_int32 outdepth, l_int32 use_average, l_int32 setblack, l_int32 setwhite)
pixThresholdGrayArb()
Definition: grayquant.c:1738
PIX * pixVarThresholdToBinary(PIX *pixs, PIX *pixg)
pixVarThresholdToBinary()
Definition: grayquant.c:655
PIX * pixDitherToBinarySpec(PIX *pixs, l_int32 lowerclip, l_int32 upperclip)
pixDitherToBinarySpec()
Definition: grayquant.c:207
PIX * pixDitherTo2bppSpec(PIX *pixs, l_int32 lowerclip, l_int32 upperclip, l_int32 cmapflag)
pixDitherTo2bppSpec()
Definition: grayquant.c:1054
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: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
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 * pixGrayQuantFromHisto(PIX *pixd, PIX *pixs, PIX *pixm, l_float32 minfract, l_int32 maxsize)
pixGrayQuantFromHisto()
Definition: grayquant.c:2339
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:447
PIX * pixAdaptThresholdToBinaryGen(PIX *pixs, PIX *pixm, l_float32 gamma, l_int32 blackval, l_int32 whiteval, l_int32 thresh)
pixAdaptThresholdToBinaryGen()
Definition: grayquant.c:770
NUMA * parseStringForNumbers(const char *str, const char *seps)
parseStringForNumbers()
Definition: kernel.c:1055
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
l_int32 * numaGetIArray(NUMA *na)
numaGetIArray()
Definition: numabasic.c:847
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_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
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 * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
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 * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
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