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