Leptonica  1.77.0
Image processing and image analysis suite
colorquant2.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 
171 #include <string.h>
172 #include <math.h>
173 #include "allheaders.h"
174 
175  /* Median cut 3-d volume element. Sort on first element, which
176  * can be the number of pixels, the volume or a combination
177  * of these. */
178 struct L_Box3d
179 {
180  l_float32 sortparam; /* parameter on which to sort the vbox */
181  l_int32 npix; /* number of pixels in the vbox */
182  l_int32 vol; /* quantized volume of vbox */
183  l_int32 r1; /* min r index in the vbox */
184  l_int32 r2; /* max r index in the vbox */
185  l_int32 g1; /* min g index in the vbox */
186  l_int32 g2; /* max g index in the vbox */
187  l_int32 b1; /* min b index in the vbox */
188  l_int32 b2; /* max b index in the vbox */
189 };
190 typedef struct L_Box3d L_BOX3D;
191 
192  /* Static median cut helper functions */
193 static PIXCMAP *pixcmapGenerateFromHisto(PIX *pixs, l_int32 depth,
194  l_int32 *histo, l_int32 histosize,
195  l_int32 sigbits);
196 static PIX *pixQuantizeWithColormap(PIX *pixs, l_int32 ditherflag,
197  l_int32 outdepth,
198  PIXCMAP *cmap, l_int32 *indexmap,
199  l_int32 mapsize, l_int32 sigbits);
200 static void getColorIndexMedianCut(l_uint32 pixel, l_int32 rshift,
201  l_uint32 mask, l_int32 sigbits,
202  l_int32 *pindex);
203 static L_BOX3D *pixGetColorRegion(PIX *pixs, l_int32 sigbits,
204  l_int32 subsample);
205 static l_int32 medianCutApply(l_int32 *histo, l_int32 sigbits,
206  L_BOX3D *vbox, L_BOX3D **pvbox1,
207  L_BOX3D **pvbox2);
208 static PIXCMAP *pixcmapGenerateFromMedianCuts(L_HEAP *lh, l_int32 *histo,
209  l_int32 sigbits);
210 static l_int32 vboxGetAverageColor(L_BOX3D *vbox, l_int32 *histo,
211  l_int32 sigbits, l_int32 index,
212  l_int32 *prval, l_int32 *pgval,
213  l_int32 *pbval);
214 static l_int32 vboxGetCount(L_BOX3D *vbox, l_int32 *histo, l_int32 sigbits);
215 static l_int32 vboxGetVolume(L_BOX3D *vbox);
216 static L_BOX3D *box3dCreate(l_int32 r1, l_int32 r2, l_int32 g1,
217  l_int32 g2, l_int32 b1, l_int32 b2);
218 static L_BOX3D *box3dCopy(L_BOX3D *vbox);
219 
220 
221  /* 5 significant bits for each component is generally satisfactory */
222 static const l_int32 DEFAULT_SIG_BITS = 5;
223 static const l_int32 MAX_ITERS_ALLOWED = 5000; /* prevents infinite looping */
224 
225  /* Specify fraction of vboxes made that are sorted on population alone.
226  * The remaining vboxes are sorted on (population * vbox-volume). */
227 static const l_float32 FRACT_BY_POPULATION = 0.85;
228 
229  /* To get the max value of 'dif' in the dithering color transfer,
230  * divide DIF_CAP by 8. */
231 static const l_int32 DIF_CAP = 100;
232 
233 
234 #ifndef NO_CONSOLE_IO
235 #define DEBUG_MC_COLORS 0
236 #define DEBUG_SPLIT_AXES 0
237 #endif /* ~NO_CONSOLE_IO */
238 
239 
240 /*------------------------------------------------------------------------*
241  * High level *
242  *------------------------------------------------------------------------*/
256 PIX *
258  l_int32 ditherflag)
259 {
260  return pixMedianCutQuantGeneral(pixs, ditherflag,
261  0, 256, DEFAULT_SIG_BITS, 1, 1);
262 }
263 
264 
307 PIX *
309  l_int32 ditherflag,
310  l_int32 outdepth,
311  l_int32 maxcolors,
312  l_int32 sigbits,
313  l_int32 maxsub,
314  l_int32 checkbw)
315 {
316 l_int32 i, subsample, histosize, smalln, ncolors, niters, popcolors;
317 l_int32 w, h, minside, factor, index, rval, gval, bval;
318 l_int32 *histo;
319 l_float32 pixfract, colorfract;
320 L_BOX3D *vbox, *vbox1, *vbox2;
321 L_HEAP *lh, *lhs;
322 PIX *pixd;
323 PIXCMAP *cmap;
324 
325  PROCNAME("pixMedianCutQuantGeneral");
326 
327  if (!pixs || pixGetDepth(pixs) != 32)
328  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
329  if (maxcolors < 2 || maxcolors > 256)
330  return (PIX *)ERROR_PTR("maxcolors not in [2...256]", procName, NULL);
331  if (outdepth != 0 && outdepth != 1 && outdepth != 2 && outdepth != 4 &&
332  outdepth != 8)
333  return (PIX *)ERROR_PTR("outdepth not in {0,1,2,4,8}", procName, NULL);
334  if (outdepth > 0 && (maxcolors > (1 << outdepth)))
335  return (PIX *)ERROR_PTR("maxcolors > 2^(outdepth)", procName, NULL);
336  if (sigbits == 0)
337  sigbits = DEFAULT_SIG_BITS;
338  else if (sigbits < 5 || sigbits > 6)
339  return (PIX *)ERROR_PTR("sigbits not 5 or 6", procName, NULL);
340  if (maxsub <= 0)
341  maxsub = 10; /* default will prevail for 10^7 pixels or less */
342 
343  /* Determine if the image has sufficient color content.
344  * If pixfract << 1, most pixels are close to black or white.
345  * If colorfract << 1, the pixels that are not near
346  * black or white have very little color.
347  * If with little color, quantize with a grayscale colormap. */
348  pixGetDimensions(pixs, &w, &h, NULL);
349  if (checkbw) {
350  minside = L_MIN(w, h);
351  factor = L_MAX(1, minside / 400);
352  pixColorFraction(pixs, 20, 244, 20, factor, &pixfract, &colorfract);
353  if (pixfract * colorfract < 0.00025) {
354  L_INFO("\n Pixel fraction neither white nor black = %6.3f"
355  "\n Color fraction of those pixels = %6.3f"
356  "\n Quantizing in gray\n",
357  procName, pixfract, colorfract);
358  return pixConvertTo8(pixs, 1);
359  }
360  }
361 
362  /* Compute the color space histogram. Default sampling
363  * is about 10^5 pixels. */
364  if (maxsub == 1) {
365  subsample = 1;
366  } else {
367  subsample = (l_int32)(sqrt((l_float64)(w * h) / 100000.));
368  subsample = L_MAX(1, L_MIN(maxsub, subsample));
369  }
370  histo = pixMedianCutHisto(pixs, sigbits, subsample);
371  histosize = 1 << (3 * sigbits);
372 
373  /* See if the number of quantized colors is less than maxcolors */
374  ncolors = 0;
375  smalln = TRUE;
376  for (i = 0; i < histosize; i++) {
377  if (histo[i])
378  ncolors++;
379  if (ncolors > maxcolors) {
380  smalln = FALSE;
381  break;
382  }
383  }
384  if (smalln) { /* finish up now */
385  if (outdepth == 0) {
386  if (ncolors <= 2)
387  outdepth = 1;
388  else if (ncolors <= 4)
389  outdepth = 2;
390  else if (ncolors <= 16)
391  outdepth = 4;
392  else
393  outdepth = 8;
394  }
395  cmap = pixcmapGenerateFromHisto(pixs, outdepth,
396  histo, histosize, sigbits);
397  pixd = pixQuantizeWithColormap(pixs, ditherflag, outdepth, cmap,
398  histo, histosize, sigbits);
399  LEPT_FREE(histo);
400  return pixd;
401  }
402 
403  /* Initial vbox: minimum region in colorspace occupied by pixels */
404  if (ditherflag || subsample > 1) /* use full color space */
405  vbox = box3dCreate(0, (1 << sigbits) - 1,
406  0, (1 << sigbits) - 1,
407  0, (1 << sigbits) - 1);
408  else
409  vbox = pixGetColorRegion(pixs, sigbits, subsample);
410  vbox->npix = vboxGetCount(vbox, histo, sigbits);
411  vbox->vol = vboxGetVolume(vbox);
412 
413  /* For a fraction 'popcolors' of the desired 'maxcolors',
414  * generate median cuts based on population, putting
415  * everything on a priority queue sorted by population. */
417  lheapAdd(lh, vbox);
418  ncolors = 1;
419  niters = 0;
420  popcolors = (l_int32)(FRACT_BY_POPULATION * maxcolors);
421  while (1) {
422  vbox = (L_BOX3D *)lheapRemove(lh);
423  if (vboxGetCount(vbox, histo, sigbits) == 0) { /* just put it back */
424  lheapAdd(lh, vbox);
425  continue;
426  }
427  medianCutApply(histo, sigbits, vbox, &vbox1, &vbox2);
428  if (!vbox1) {
429  L_WARNING("vbox1 not defined; shouldn't happen!\n", procName);
430  break;
431  }
432  if (vbox1->vol > 1)
433  vbox1->sortparam = vbox1->npix;
434  LEPT_FREE(vbox);
435  lheapAdd(lh, vbox1);
436  if (vbox2) { /* vbox2 can be NULL */
437  if (vbox2->vol > 1)
438  vbox2->sortparam = vbox2->npix;
439  lheapAdd(lh, vbox2);
440  ncolors++;
441  }
442  if (ncolors >= popcolors)
443  break;
444  if (niters++ > MAX_ITERS_ALLOWED) {
445  L_WARNING("infinite loop; perhaps too few pixels!\n", procName);
446  break;
447  }
448  }
449 
450  /* Re-sort by the product of pixel occupancy times the size
451  * in color space. */
452  lhs = lheapCreate(0, L_SORT_DECREASING);
453  while ((vbox = (L_BOX3D *)lheapRemove(lh))) {
454  vbox->sortparam = vbox->npix * vbox->vol;
455  lheapAdd(lhs, vbox);
456  }
457  lheapDestroy(&lh, TRUE);
458 
459  /* For the remaining (maxcolors - popcolors), generate the
460  * median cuts using the (npix * vol) sorting. */
461  while (1) {
462  vbox = (L_BOX3D *)lheapRemove(lhs);
463  if (vboxGetCount(vbox, histo, sigbits) == 0) { /* just put it back */
464  lheapAdd(lhs, vbox);
465  continue;
466  }
467  medianCutApply(histo, sigbits, vbox, &vbox1, &vbox2);
468  if (!vbox1) {
469  L_WARNING("vbox1 not defined; shouldn't happen!\n", procName);
470  break;
471  }
472  if (vbox1->vol > 1)
473  vbox1->sortparam = vbox1->npix * vbox1->vol;
474  LEPT_FREE(vbox);
475  lheapAdd(lhs, vbox1);
476  if (vbox2) { /* vbox2 can be NULL */
477  if (vbox2->vol > 1)
478  vbox2->sortparam = vbox2->npix * vbox2->vol;
479  lheapAdd(lhs, vbox2);
480  ncolors++;
481  }
482  if (ncolors >= maxcolors)
483  break;
484  if (niters++ > MAX_ITERS_ALLOWED) {
485  L_WARNING("infinite loop; perhaps too few pixels!\n", procName);
486  break;
487  }
488  }
489 
490  /* Re-sort by pixel occupancy. This is not necessary,
491  * but it makes a more useful listing. */
493  while ((vbox = (L_BOX3D *)lheapRemove(lhs))) {
494  vbox->sortparam = vbox->npix;
495 /* vbox->sortparam = vbox->npix * vbox->vol; */
496  lheapAdd(lh, vbox);
497  }
498  lheapDestroy(&lhs, TRUE);
499 
500  /* Generate colormap from median cuts and quantize pixd */
501  cmap = pixcmapGenerateFromMedianCuts(lh, histo, sigbits);
502  if (outdepth == 0) {
503  ncolors = pixcmapGetCount(cmap);
504  if (ncolors <= 2)
505  outdepth = 1;
506  else if (ncolors <= 4)
507  outdepth = 2;
508  else if (ncolors <= 16)
509  outdepth = 4;
510  else
511  outdepth = 8;
512  }
513  pixd = pixQuantizeWithColormap(pixs, ditherflag, outdepth, cmap,
514  histo, histosize, sigbits);
515 
516  /* Force darkest color to black if each component <= 4 */
517  pixcmapGetRankIntensity(cmap, 0.0, &index);
518  pixcmapGetColor(cmap, index, &rval, &gval, &bval);
519  if (rval < 5 && gval < 5 && bval < 5)
520  pixcmapResetColor(cmap, index, 0, 0, 0);
521 
522  /* Force lightest color to white if each component >= 252 */
523  pixcmapGetRankIntensity(cmap, 1.0, &index);
524  pixcmapGetColor(cmap, index, &rval, &gval, &bval);
525  if (rval > 251 && gval > 251 && bval > 251)
526  pixcmapResetColor(cmap, index, 255, 255, 255);
527 
528  lheapDestroy(&lh, TRUE);
529  LEPT_FREE(histo);
530  return pixd;
531 }
532 
533 
578 PIX *
580  l_int32 ncolor,
581  l_int32 ngray,
582  l_int32 darkthresh,
583  l_int32 lightthresh,
584  l_int32 diffthresh)
585 {
586 l_int32 i, j, w, h, wplc, wplg, wpld, nc, unused, iscolor, factor, minside;
587 l_int32 rval, gval, bval, minval, maxval, val, grayval;
588 l_float32 pixfract, colorfract;
589 l_int32 *lut;
590 l_uint32 *datac, *datag, *datad, *linec, *lineg, *lined;
591 PIX *pixc, *pixg, *pixd;
592 PIXCMAP *cmap;
593 
594  PROCNAME("pixMedianCutQuantMixed");
595 
596  if (!pixs || pixGetDepth(pixs) != 32)
597  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
598  if (ngray < 2)
599  return (PIX *)ERROR_PTR("ngray < 2", procName, NULL);
600  if (ncolor + ngray > 255)
601  return (PIX *)ERROR_PTR("ncolor + ngray > 255", procName, NULL);
602  if (darkthresh <= 0) darkthresh = 20;
603  if (lightthresh <= 0) lightthresh = 244;
604  if (diffthresh <= 0) diffthresh = 20;
605 
606  /* First check if this should be quantized in gray.
607  * Use a more sensitive parameter for detecting color than with
608  * pixMedianCutQuantGeneral(), because this function can handle
609  * gray pixels well. */
610  pixGetDimensions(pixs, &w, &h, NULL);
611  minside = L_MIN(w, h);
612  factor = L_MAX(1, minside / 400);
613  pixColorFraction(pixs, darkthresh, lightthresh, diffthresh, factor,
614  &pixfract, &colorfract);
615  if (pixfract * colorfract < 0.0001) {
616  L_INFO("\n Pixel fraction neither white nor black = %6.3f"
617  "\n Color fraction of those pixels = %6.3f"
618  "\n Quantizing in gray\n",
619  procName, pixfract, colorfract);
620  pixg = pixConvertTo8(pixs, 0);
621  pixd = pixThresholdOn8bpp(pixg, ngray, 1);
622  pixDestroy(&pixg);
623  return pixd;
624  }
625 
626  /* OK, there is color in the image.
627  * Preprocess to handle the gray pixels. Set the color pixels in pixc
628  * to black, and store their (eventual) colormap indices in pixg.*/
629  pixc = pixCopy(NULL, pixs);
630  pixg = pixCreate(w, h, 8); /* color pixels will remain 0 here */
631  datac = pixGetData(pixc);
632  datag = pixGetData(pixg);
633  wplc = pixGetWpl(pixc);
634  wplg = pixGetWpl(pixg);
635  lut = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
636  for (i = 0; i < 256; i++)
637  lut[i] = ncolor + 1 + (i * (ngray - 1) + 128) / 255;
638  for (i = 0; i < h; i++) {
639  linec = datac + i * wplc;
640  lineg = datag + i * wplg;
641  for (j = 0; j < w; j++) {
642  iscolor = FALSE;
643  extractRGBValues(linec[j], &rval, &gval, &bval);
644  minval = L_MIN(rval, gval);
645  minval = L_MIN(minval, bval);
646  maxval = L_MAX(rval, gval);
647  maxval = L_MAX(maxval, bval);
648  if (maxval >= darkthresh &&
649  minval <= lightthresh &&
650  maxval - minval >= diffthresh) {
651  iscolor = TRUE;
652  }
653  if (!iscolor) {
654  linec[j] = 0x0; /* set to black */
655  grayval = (maxval + minval) / 2;
656  SET_DATA_BYTE(lineg, j, lut[grayval]);
657  }
658  }
659  }
660 
661  /* Median cut on color pixels plus black */
662  pixd = pixMedianCutQuantGeneral(pixc, FALSE, 8, ncolor + 1,
663  DEFAULT_SIG_BITS, 1, 0);
664 
665  /* Augment the colormap with gray values. The new cmap
666  * indices should agree with the values previously stored in pixg. */
667  cmap = pixGetColormap(pixd);
668  nc = pixcmapGetCount(cmap);
669  unused = ncolor + 1 - nc;
670  if (unused < 0)
671  L_ERROR("Too many colors: extra = %d\n", procName, -unused);
672  if (unused > 0) { /* fill in with black; these won't be used */
673  L_INFO("%d unused colors\n", procName, unused);
674  for (i = 0; i < unused; i++)
675  pixcmapAddColor(cmap, 0, 0, 0);
676  }
677  for (i = 0; i < ngray; i++) {
678  grayval = (255 * i) / (ngray - 1);
679  pixcmapAddColor(cmap, grayval, grayval, grayval);
680  }
681 
682  /* Substitute cmap indices for the gray pixels into pixd */
683  datad = pixGetData(pixd);
684  wpld = pixGetWpl(pixd);
685  for (i = 0; i < h; i++) {
686  lined = datad + i * wpld;
687  lineg = datag + i * wplg;
688  for (j = 0; j < w; j++) {
689  val = GET_DATA_BYTE(lineg, j); /* if 0, it's a color pixel */
690  if (val)
691  SET_DATA_BYTE(lined, j, val);
692  }
693  }
694 
695  pixDestroy(&pixc);
696  pixDestroy(&pixg);
697  LEPT_FREE(lut);
698  return pixd;
699 }
700 
701 
753 PIX *
755  l_int32 ncolor,
756  l_int32 ngray,
757  l_int32 maxncolors,
758  l_int32 darkthresh,
759  l_int32 lightthresh,
760  l_int32 diffthresh)
761 {
762 l_int32 ncolors, iscolor;
763 PIX *pixg, *pixd;
764 
765  PROCNAME("pixFewColorsMedianCutQuantMixed");
766 
767  if (!pixs || pixGetDepth(pixs) != 32)
768  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
769  if (maxncolors <= 0) maxncolors = 20;
770  if (darkthresh <= 0) darkthresh = 20;
771  if (lightthresh <= 0) lightthresh = 244;
772  if (diffthresh <= 0) diffthresh = 15;
773  if (ncolor < maxncolors) {
774  L_WARNING("ncolor too small; setting to %d\n", procName, maxncolors);
775  ncolor = maxncolors;
776  }
777  if (ngray < maxncolors) {
778  L_WARNING("ngray too small; setting to %d\n", procName, maxncolors);
779  ngray = maxncolors;
780  }
781 
782  /* Estimate the color content and the number of colors required */
783  pixColorsForQuantization(pixs, 15, &ncolors, &iscolor, 0);
784 
785  /* Note that maxncolors applies to all colors required to quantize,
786  * both gray and colorful */
787  if (ncolors > maxncolors)
788  return (PIX *)ERROR_PTR("too many colors", procName, NULL);
789 
790  /* If no color, return quantized gray pix */
791  if (!iscolor) {
792  pixg = pixConvertTo8(pixs, 0);
793  pixd = pixThresholdOn8bpp(pixg, ngray, 1);
794  pixDestroy(&pixg);
795  return pixd;
796  }
797 
798  /* Use the mixed gray/color quantizer */
799  return pixMedianCutQuantMixed(pixs, ncolor, ngray, darkthresh,
800  lightthresh, diffthresh);
801 }
802 
803 
804 
805 /*------------------------------------------------------------------------*
806  * Median cut indexed histogram *
807  *------------------------------------------------------------------------*/
825 l_int32 *
827  l_int32 sigbits,
828  l_int32 subsample)
829 {
830 l_int32 i, j, w, h, wpl, rshift, index, histosize;
831 l_int32 *histo;
832 l_uint32 mask, pixel;
833 l_uint32 *data, *line;
834 
835  PROCNAME("pixMedianCutHisto");
836 
837  if (!pixs)
838  return (l_int32 *)ERROR_PTR("pixs not defined", procName, NULL);
839  if (pixGetDepth(pixs) != 32)
840  return (l_int32 *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
841  if (sigbits < 5 || sigbits > 6)
842  return (l_int32 *)ERROR_PTR("sigbits not 5 or 6", procName, NULL);
843  if (subsample <= 0)
844  return (l_int32 *)ERROR_PTR("subsample not > 0", procName, NULL);
845 
846  histosize = 1 << (3 * sigbits);
847  if ((histo = (l_int32 *)LEPT_CALLOC(histosize, sizeof(l_int32))) == NULL)
848  return (l_int32 *)ERROR_PTR("histo not made", procName, NULL);
849 
850  rshift = 8 - sigbits;
851  mask = 0xff >> rshift;
852  pixGetDimensions(pixs, &w, &h, NULL);
853  data = pixGetData(pixs);
854  wpl = pixGetWpl(pixs);
855  for (i = 0; i < h; i += subsample) {
856  line = data + i * wpl;
857  for (j = 0; j < w; j += subsample) {
858  pixel = line[j];
859  getColorIndexMedianCut(pixel, rshift, mask, sigbits, &index);
860  histo[index]++;
861  }
862  }
863 
864  return histo;
865 }
866 
867 
868 /*------------------------------------------------------------------------*
869  * Static helpers *
870  *------------------------------------------------------------------------*/
889 static PIXCMAP *
891  l_int32 depth,
892  l_int32 *histo,
893  l_int32 histosize,
894  l_int32 sigbits)
895 {
896 l_int32 i, index, shift, rval, gval, bval;
897 l_uint32 mask;
898 PIXCMAP *cmap;
899 
900  PROCNAME("pixcmapGenerateFromHisto");
901 
902  if (!pixs)
903  return (PIXCMAP *)ERROR_PTR("pixs not defined", procName, NULL);
904  if (pixGetDepth(pixs) != 32)
905  return (PIXCMAP *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
906  if (!histo)
907  return (PIXCMAP *)ERROR_PTR("histo not defined", procName, NULL);
908 
909  /* Capture the rgb values of each occupied cube in the histo,
910  * and re-label the histo value with the colormap index. */
911  cmap = pixcmapCreate(depth);
912  shift = 8 - sigbits;
913  mask = 0xff >> shift;
914  for (i = 0, index = 0; i < histosize; i++) {
915  if (histo[i]) {
916  rval = (i >> (2 * sigbits)) << shift;
917  gval = ((i >> sigbits) & mask) << shift;
918  bval = (i & mask) << shift;
919  pixcmapAddColor(cmap, rval, gval, bval);
920  histo[i] = index++;
921  }
922  }
923 
924  return cmap;
925 }
926 
927 
948 static PIX *
950  l_int32 ditherflag,
951  l_int32 outdepth,
952  PIXCMAP *cmap,
953  l_int32 *indexmap,
954  l_int32 mapsize,
955  l_int32 sigbits)
956 {
957 l_uint8 *bufu8r, *bufu8g, *bufu8b;
958 l_int32 i, j, w, h, wpls, wpld, rshift, index, cmapindex, success;
959 l_int32 rval, gval, bval, rc, gc, bc;
960 l_int32 dif, val1, val2, val3;
961 l_int32 *buf1r, *buf1g, *buf1b, *buf2r, *buf2g, *buf2b;
962 l_uint32 *datas, *datad, *lines, *lined;
963 l_uint32 mask, pixel;
964 PIX *pixd;
965 
966  PROCNAME("pixQuantizeWithColormap");
967 
968  if (!pixs || pixGetDepth(pixs) != 32)
969  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
970  if (!cmap)
971  return (PIX *)ERROR_PTR("cmap not defined", procName, NULL);
972  if (!indexmap)
973  return (PIX *)ERROR_PTR("indexmap not defined", procName, NULL);
974  if (ditherflag)
975  outdepth = 8;
976 
977  pixGetDimensions(pixs, &w, &h, NULL);
978  pixd = pixCreate(w, h, outdepth);
979  pixSetColormap(pixd, cmap);
980  pixCopyResolution(pixd, pixs);
981  pixCopyInputFormat(pixd, pixs);
982  datas = pixGetData(pixs);
983  datad = pixGetData(pixd);
984  wpls = pixGetWpl(pixs);
985  wpld = pixGetWpl(pixd);
986 
987  rshift = 8 - sigbits;
988  mask = 0xff >> rshift;
989  if (ditherflag == 0) {
990  for (i = 0; i < h; i++) {
991  lines = datas + i * wpls;
992  lined = datad + i * wpld;
993  if (outdepth == 1) {
994  for (j = 0; j < w; j++) {
995  pixel = lines[j];
996  getColorIndexMedianCut(pixel, rshift, mask,
997  sigbits, &index);
998  if (indexmap[index])
999  SET_DATA_BIT(lined, j);
1000  }
1001  } else if (outdepth == 2) {
1002  for (j = 0; j < w; j++) {
1003  pixel = lines[j];
1004  getColorIndexMedianCut(pixel, rshift, mask,
1005  sigbits, &index);
1006  SET_DATA_DIBIT(lined, j, indexmap[index]);
1007  }
1008  } else if (outdepth == 4) {
1009  for (j = 0; j < w; j++) {
1010  pixel = lines[j];
1011  getColorIndexMedianCut(pixel, rshift, mask,
1012  sigbits, &index);
1013  SET_DATA_QBIT(lined, j, indexmap[index]);
1014  }
1015  } else { /* outdepth == 8 */
1016  for (j = 0; j < w; j++) {
1017  pixel = lines[j];
1018  getColorIndexMedianCut(pixel, rshift, mask,
1019  sigbits, &index);
1020  SET_DATA_BYTE(lined, j, indexmap[index]);
1021  }
1022  }
1023  }
1024  } else { /* ditherflag == 1 */
1025  success = TRUE;
1026  bufu8r = bufu8g = bufu8b = NULL;
1027  buf1r = buf1g = buf1b = buf2r = buf2g = buf2b = NULL;
1028  bufu8r = (l_uint8 *)LEPT_CALLOC(w, sizeof(l_uint8));
1029  bufu8g = (l_uint8 *)LEPT_CALLOC(w, sizeof(l_uint8));
1030  bufu8b = (l_uint8 *)LEPT_CALLOC(w, sizeof(l_uint8));
1031  buf1r = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
1032  buf1g = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
1033  buf1b = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
1034  buf2r = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
1035  buf2g = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
1036  buf2b = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
1037  if (!bufu8r || !bufu8g || !bufu8b || !buf1r || !buf1g ||
1038  !buf1b || !buf2r || !buf2g || !buf2b) {
1039  L_ERROR("buffer not made\n", procName);
1040  success = FALSE;
1041  goto buffer_cleanup;
1042  }
1043 
1044  /* Start by priming buf2; line 1 is above line 2 */
1045  pixGetRGBLine(pixs, 0, bufu8r, bufu8g, bufu8b);
1046  for (j = 0; j < w; j++) {
1047  buf2r[j] = 64 * bufu8r[j];
1048  buf2g[j] = 64 * bufu8g[j];
1049  buf2b[j] = 64 * bufu8b[j];
1050  }
1051 
1052  for (i = 0; i < h - 1; i++) {
1053  /* Swap data 2 --> 1, and read in new line 2 */
1054  memcpy(buf1r, buf2r, 4 * w);
1055  memcpy(buf1g, buf2g, 4 * w);
1056  memcpy(buf1b, buf2b, 4 * w);
1057  pixGetRGBLine(pixs, i + 1, bufu8r, bufu8g, bufu8b);
1058  for (j = 0; j < w; j++) {
1059  buf2r[j] = 64 * bufu8r[j];
1060  buf2g[j] = 64 * bufu8g[j];
1061  buf2b[j] = 64 * bufu8b[j];
1062  }
1063 
1064  /* Dither */
1065  lined = datad + i * wpld;
1066  for (j = 0; j < w - 1; j++) {
1067  rval = buf1r[j] / 64;
1068  gval = buf1g[j] / 64;
1069  bval = buf1b[j] / 64;
1070  index = ((rval >> rshift) << (2 * sigbits)) +
1071  ((gval >> rshift) << sigbits) + (bval >> rshift);
1072  cmapindex = indexmap[index];
1073  SET_DATA_BYTE(lined, j, cmapindex);
1074  pixcmapGetColor(cmap, cmapindex, &rc, &gc, &bc);
1075 
1076  dif = buf1r[j] / 8 - 8 * rc;
1077  if (dif > DIF_CAP) dif = DIF_CAP;
1078  if (dif < -DIF_CAP) dif = -DIF_CAP;
1079  if (dif != 0) {
1080  val1 = buf1r[j + 1] + 3 * dif;
1081  val2 = buf2r[j] + 3 * dif;
1082  val3 = buf2r[j + 1] + 2 * dif;
1083  if (dif > 0) {
1084  buf1r[j + 1] = L_MIN(16383, val1);
1085  buf2r[j] = L_MIN(16383, val2);
1086  buf2r[j + 1] = L_MIN(16383, val3);
1087  } else {
1088  buf1r[j + 1] = L_MAX(0, val1);
1089  buf2r[j] = L_MAX(0, val2);
1090  buf2r[j + 1] = L_MAX(0, val3);
1091  }
1092  }
1093 
1094  dif = buf1g[j] / 8 - 8 * gc;
1095  if (dif > DIF_CAP) dif = DIF_CAP;
1096  if (dif < -DIF_CAP) dif = -DIF_CAP;
1097  if (dif != 0) {
1098  val1 = buf1g[j + 1] + 3 * dif;
1099  val2 = buf2g[j] + 3 * dif;
1100  val3 = buf2g[j + 1] + 2 * dif;
1101  if (dif > 0) {
1102  buf1g[j + 1] = L_MIN(16383, val1);
1103  buf2g[j] = L_MIN(16383, val2);
1104  buf2g[j + 1] = L_MIN(16383, val3);
1105  } else {
1106  buf1g[j + 1] = L_MAX(0, val1);
1107  buf2g[j] = L_MAX(0, val2);
1108  buf2g[j + 1] = L_MAX(0, val3);
1109  }
1110  }
1111 
1112  dif = buf1b[j] / 8 - 8 * bc;
1113  if (dif > DIF_CAP) dif = DIF_CAP;
1114  if (dif < -DIF_CAP) dif = -DIF_CAP;
1115  if (dif != 0) {
1116  val1 = buf1b[j + 1] + 3 * dif;
1117  val2 = buf2b[j] + 3 * dif;
1118  val3 = buf2b[j + 1] + 2 * dif;
1119  if (dif > 0) {
1120  buf1b[j + 1] = L_MIN(16383, val1);
1121  buf2b[j] = L_MIN(16383, val2);
1122  buf2b[j + 1] = L_MIN(16383, val3);
1123  } else {
1124  buf1b[j + 1] = L_MAX(0, val1);
1125  buf2b[j] = L_MAX(0, val2);
1126  buf2b[j + 1] = L_MAX(0, val3);
1127  }
1128  }
1129  }
1130 
1131  /* Get last pixel in row; no downward propagation */
1132  rval = buf1r[w - 1] / 64;
1133  gval = buf1g[w - 1] / 64;
1134  bval = buf1b[w - 1] / 64;
1135  index = ((rval >> rshift) << (2 * sigbits)) +
1136  ((gval >> rshift) << sigbits) + (bval >> rshift);
1137  SET_DATA_BYTE(lined, w - 1, indexmap[index]);
1138  }
1139 
1140  /* Get last row of pixels; no leftward propagation */
1141  lined = datad + (h - 1) * wpld;
1142  for (j = 0; j < w; j++) {
1143  rval = buf2r[j] / 64;
1144  gval = buf2g[j] / 64;
1145  bval = buf2b[j] / 64;
1146  index = ((rval >> rshift) << (2 * sigbits)) +
1147  ((gval >> rshift) << sigbits) + (bval >> rshift);
1148  SET_DATA_BYTE(lined, j, indexmap[index]);
1149  }
1150 
1151 buffer_cleanup:
1152  LEPT_FREE(bufu8r);
1153  LEPT_FREE(bufu8g);
1154  LEPT_FREE(bufu8b);
1155  LEPT_FREE(buf1r);
1156  LEPT_FREE(buf1g);
1157  LEPT_FREE(buf1b);
1158  LEPT_FREE(buf2r);
1159  LEPT_FREE(buf2g);
1160  LEPT_FREE(buf2b);
1161  if (!success) pixDestroy(&pixd);
1162  }
1163 
1164  return pixd;
1165 }
1166 
1167 
1184 static void
1185 getColorIndexMedianCut(l_uint32 pixel,
1186  l_int32 rshift,
1187  l_uint32 mask,
1188  l_int32 sigbits,
1189  l_int32 *pindex)
1190 {
1191 l_int32 rval, gval, bval;
1192 
1193  rval = pixel >> (24 + rshift);
1194  gval = (pixel >> (16 + rshift)) & mask;
1195  bval = (pixel >> (8 + rshift)) & mask;
1196  *pindex = (rval << (2 * sigbits)) + (gval << sigbits) + bval;
1197  return;
1198 }
1199 
1200 
1216 static L_BOX3D *
1218  l_int32 sigbits,
1219  l_int32 subsample)
1220 {
1221 l_int32 rmin, rmax, gmin, gmax, bmin, bmax, rval, gval, bval;
1222 l_int32 w, h, wpl, i, j, rshift;
1223 l_uint32 mask, pixel;
1224 l_uint32 *data, *line;
1225 
1226  PROCNAME("pixGetColorRegion");
1227 
1228  if (!pixs)
1229  return (L_BOX3D *)ERROR_PTR("pixs not defined", procName, NULL);
1230 
1231  rmin = gmin = bmin = 1000000;
1232  rmax = gmax = bmax = 0;
1233  rshift = 8 - sigbits;
1234  mask = 0xff >> rshift;
1235  pixGetDimensions(pixs, &w, &h, NULL);
1236  data = pixGetData(pixs);
1237  wpl = pixGetWpl(pixs);
1238  for (i = 0; i < h; i += subsample) {
1239  line = data + i * wpl;
1240  for (j = 0; j < w; j += subsample) {
1241  pixel = line[j];
1242  rval = pixel >> (24 + rshift);
1243  gval = (pixel >> (16 + rshift)) & mask;
1244  bval = (pixel >> (8 + rshift)) & mask;
1245  if (rval < rmin)
1246  rmin = rval;
1247  else if (rval > rmax)
1248  rmax = rval;
1249  if (gval < gmin)
1250  gmin = gval;
1251  else if (gval > gmax)
1252  gmax = gval;
1253  if (bval < bmin)
1254  bmin = bval;
1255  else if (bval > bmax)
1256  bmax = bval;
1257  }
1258  }
1259 
1260  return box3dCreate(rmin, rmax, gmin, gmax, bmin, bmax);
1261 }
1262 
1263 
1273 static l_int32
1274 medianCutApply(l_int32 *histo,
1275  l_int32 sigbits,
1276  L_BOX3D *vbox,
1277  L_BOX3D **pvbox1,
1278  L_BOX3D **pvbox2)
1279 {
1280 l_int32 i, j, k, sum, rw, gw, bw, maxw, index;
1281 l_int32 total, left, right;
1282 l_int32 partialsum[128];
1283 L_BOX3D *vbox1, *vbox2;
1284 
1285  PROCNAME("medianCutApply");
1286 
1287  if (pvbox1) *pvbox1 = NULL;
1288  if (pvbox2) *pvbox2 = NULL;
1289  if (!histo)
1290  return ERROR_INT("histo not defined", procName, 1);
1291  if (!vbox)
1292  return ERROR_INT("vbox not defined", procName, 1);
1293  if (!pvbox1 || !pvbox2)
1294  return ERROR_INT("&vbox1 and &vbox2 not both defined", procName, 1);
1295 
1296  if (vboxGetCount(vbox, histo, sigbits) == 0)
1297  return ERROR_INT("no pixels in vbox", procName, 1);
1298 
1299  /* If the vbox occupies just one element in color space, it can't
1300  * be split. Leave the 'sortparam' field at 0, so that it goes to
1301  * the tail of the priority queue and stays there, thereby avoiding
1302  * an infinite loop (take off, put back on the head) if it
1303  * happens to be the most populous box! */
1304  rw = vbox->r2 - vbox->r1 + 1;
1305  gw = vbox->g2 - vbox->g1 + 1;
1306  bw = vbox->b2 - vbox->b1 + 1;
1307  if (rw == 1 && gw == 1 && bw == 1) {
1308  *pvbox1 = box3dCopy(vbox);
1309  return 0;
1310  }
1311 
1312  /* Select the longest axis for splitting */
1313  maxw = L_MAX(rw, gw);
1314  maxw = L_MAX(maxw, bw);
1315 #if DEBUG_SPLIT_AXES
1316  if (rw == maxw)
1317  fprintf(stderr, "red split\n");
1318  else if (gw == maxw)
1319  fprintf(stderr, "green split\n");
1320  else
1321  fprintf(stderr, "blue split\n");
1322 #endif /* DEBUG_SPLIT_AXES */
1323 
1324  /* Find the partial sum arrays along the selected axis. */
1325  total = 0;
1326  if (maxw == rw) {
1327  for (i = vbox->r1; i <= vbox->r2; i++) {
1328  sum = 0;
1329  for (j = vbox->g1; j <= vbox->g2; j++) {
1330  for (k = vbox->b1; k <= vbox->b2; k++) {
1331  index = (i << (2 * sigbits)) + (j << sigbits) + k;
1332  sum += histo[index];
1333  }
1334  }
1335  total += sum;
1336  partialsum[i] = total;
1337  }
1338  } else if (maxw == gw) {
1339  for (i = vbox->g1; i <= vbox->g2; i++) {
1340  sum = 0;
1341  for (j = vbox->r1; j <= vbox->r2; j++) {
1342  for (k = vbox->b1; k <= vbox->b2; k++) {
1343  index = (i << sigbits) + (j << (2 * sigbits)) + k;
1344  sum += histo[index];
1345  }
1346  }
1347  total += sum;
1348  partialsum[i] = total;
1349  }
1350  } else { /* maxw == bw */
1351  for (i = vbox->b1; i <= vbox->b2; i++) {
1352  sum = 0;
1353  for (j = vbox->r1; j <= vbox->r2; j++) {
1354  for (k = vbox->g1; k <= vbox->g2; k++) {
1355  index = i + (j << (2 * sigbits)) + (k << sigbits);
1356  sum += histo[index];
1357  }
1358  }
1359  total += sum;
1360  partialsum[i] = total;
1361  }
1362  }
1363 
1364  /* Determine the cut planes, making sure that two vboxes
1365  * are always produced. Generate the two vboxes and compute
1366  * the sum in each of them. Choose the cut plane within
1367  * the greater of the (left, right) sides of the bin in which
1368  * the median pixel resides. Here's the surprise: go halfway
1369  * into that side. By doing that, you technically move away
1370  * from "median cut," but in the process a significant number
1371  * of low-count vboxes are produced, allowing much better
1372  * reproduction of low-count spot colors. */
1373  vbox1 = vbox2 = NULL;
1374  if (maxw == rw) {
1375  for (i = vbox->r1; i <= vbox->r2; i++) {
1376  if (partialsum[i] > total / 2) {
1377  vbox1 = box3dCopy(vbox);
1378  vbox2 = box3dCopy(vbox);
1379  left = i - vbox->r1;
1380  right = vbox->r2 - i;
1381  if (left <= right)
1382  vbox1->r2 = L_MIN(vbox->r2 - 1, i + right / 2);
1383  else /* left > right */
1384  vbox1->r2 = L_MAX(vbox->r1, i - 1 - left / 2);
1385  vbox2->r1 = vbox1->r2 + 1;
1386  break;
1387  }
1388  }
1389  } else if (maxw == gw) {
1390  for (i = vbox->g1; i <= vbox->g2; i++) {
1391  if (partialsum[i] > total / 2) {
1392  vbox1 = box3dCopy(vbox);
1393  vbox2 = box3dCopy(vbox);
1394  left = i - vbox->g1;
1395  right = vbox->g2 - i;
1396  if (left <= right)
1397  vbox1->g2 = L_MIN(vbox->g2 - 1, i + right / 2);
1398  else /* left > right */
1399  vbox1->g2 = L_MAX(vbox->g1, i - 1 - left / 2);
1400  vbox2->g1 = vbox1->g2 + 1;
1401  break;
1402  }
1403  }
1404  } else { /* maxw == bw */
1405  for (i = vbox->b1; i <= vbox->b2; i++) {
1406  if (partialsum[i] > total / 2) {
1407  vbox1 = box3dCopy(vbox);
1408  vbox2 = box3dCopy(vbox);
1409  left = i - vbox->b1;
1410  right = vbox->b2 - i;
1411  if (left <= right)
1412  vbox1->b2 = L_MIN(vbox->b2 - 1, i + right / 2);
1413  else /* left > right */
1414  vbox1->b2 = L_MAX(vbox->b1, i - 1 - left / 2);
1415  vbox2->b1 = vbox1->b2 + 1;
1416  break;
1417  }
1418  }
1419  }
1420  *pvbox1 = vbox1;
1421  *pvbox2 = vbox2;
1422  if (!vbox1)
1423  return ERROR_INT("vbox1 not made; shouldn't happen", procName, 1);
1424  if (!vbox2)
1425  return ERROR_INT("vbox2 not made; shouldn't happen", procName, 1);
1426  vbox1->npix = vboxGetCount(vbox1, histo, sigbits);
1427  vbox2->npix = vboxGetCount(vbox2, histo, sigbits);
1428  vbox1->vol = vboxGetVolume(vbox1);
1429  vbox2->vol = vboxGetVolume(vbox2);
1430 
1431  return 0;
1432 }
1433 
1434 
1453 static PIXCMAP *
1455  l_int32 *histo,
1456  l_int32 sigbits)
1457 {
1458 l_int32 index, rval, gval, bval;
1459 L_BOX3D *vbox;
1460 PIXCMAP *cmap;
1461 
1462  PROCNAME("pixcmapGenerateFromMedianCuts");
1463 
1464  if (!lh)
1465  return (PIXCMAP *)ERROR_PTR("lh not defined", procName, NULL);
1466  if (!histo)
1467  return (PIXCMAP *)ERROR_PTR("histo not defined", procName, NULL);
1468 
1469  rval = gval = bval = 0; /* make compiler happy */
1470  cmap = pixcmapCreate(8);
1471  index = 0;
1472  while (lheapGetCount(lh) > 0) {
1473  vbox = (L_BOX3D *)lheapRemove(lh);
1474  vboxGetAverageColor(vbox, histo, sigbits, index, &rval, &gval, &bval);
1475  pixcmapAddColor(cmap, rval, gval, bval);
1476  LEPT_FREE(vbox);
1477  index++;
1478  }
1479 
1480  return cmap;
1481 }
1482 
1483 
1509 static l_int32
1511  l_int32 *histo,
1512  l_int32 sigbits,
1513  l_int32 index,
1514  l_int32 *prval,
1515  l_int32 *pgval,
1516  l_int32 *pbval)
1517 {
1518 l_int32 i, j, k, ntot, mult, histoindex, rsum, gsum, bsum;
1519 
1520  PROCNAME("vboxGetAverageColor");
1521 
1522  if (!vbox)
1523  return ERROR_INT("vbox not defined", procName, 1);
1524  if (!histo)
1525  return ERROR_INT("histo not defined", procName, 1);
1526  if (!prval || !pgval || !pbval)
1527  return ERROR_INT("&p*val not all defined", procName, 1);
1528 
1529  *prval = *pgval = *pbval = 0;
1530  ntot = 0;
1531  mult = 1 << (8 - sigbits);
1532  rsum = gsum = bsum = 0;
1533  for (i = vbox->r1; i <= vbox->r2; i++) {
1534  for (j = vbox->g1; j <= vbox->g2; j++) {
1535  for (k = vbox->b1; k <= vbox->b2; k++) {
1536  histoindex = (i << (2 * sigbits)) + (j << sigbits) + k;
1537  ntot += histo[histoindex];
1538  rsum += (l_int32)(histo[histoindex] * (i + 0.5) * mult);
1539  gsum += (l_int32)(histo[histoindex] * (j + 0.5) * mult);
1540  bsum += (l_int32)(histo[histoindex] * (k + 0.5) * mult);
1541  if (index >= 0)
1542  histo[histoindex] = index;
1543  }
1544  }
1545  }
1546 
1547  if (ntot == 0) {
1548  *prval = mult * (vbox->r1 + vbox->r2 + 1) / 2;
1549  *pgval = mult * (vbox->g1 + vbox->g2 + 1) / 2;
1550  *pbval = mult * (vbox->b1 + vbox->b2 + 1) / 2;
1551  } else {
1552  *prval = rsum / ntot;
1553  *pgval = gsum / ntot;
1554  *pbval = bsum / ntot;
1555  }
1556 
1557 #if DEBUG_MC_COLORS
1558  fprintf(stderr, "ntot[%d] = %d: [%d, %d, %d], (%d, %d, %d)\n",
1559  index, ntot, vbox->r2 - vbox->r1 + 1,
1560  vbox->g2 - vbox->g1 + 1, vbox->b2 - vbox->b1 + 1,
1561  *prval, *pgval, *pbval);
1562 #endif /* DEBUG_MC_COLORS */
1563 
1564  return 0;
1565 }
1566 
1567 
1576 static l_int32
1578  l_int32 *histo,
1579  l_int32 sigbits)
1580 {
1581 l_int32 i, j, k, npix, index;
1582 
1583  PROCNAME("vboxGetCount");
1584 
1585  if (!vbox)
1586  return ERROR_INT("vbox not defined", procName, 0);
1587  if (!histo)
1588  return ERROR_INT("histo not defined", procName, 0);
1589 
1590  npix = 0;
1591  for (i = vbox->r1; i <= vbox->r2; i++) {
1592  for (j = vbox->g1; j <= vbox->g2; j++) {
1593  for (k = vbox->b1; k <= vbox->b2; k++) {
1594  index = (i << (2 * sigbits)) + (j << sigbits) + k;
1595  npix += histo[index];
1596  }
1597  }
1598  }
1599 
1600  return npix;
1601 }
1602 
1603 
1610 static l_int32
1612 {
1613  PROCNAME("vboxGetVolume");
1614 
1615  if (!vbox)
1616  return ERROR_INT("vbox not defined", procName, 0);
1617 
1618  return ((vbox->r2 - vbox->r1 + 1) * (vbox->g2 - vbox->g1 + 1) *
1619  (vbox->b2 - vbox->b1 + 1));
1620 }
1621 
1628 static L_BOX3D *
1629 box3dCreate(l_int32 r1,
1630  l_int32 r2,
1631  l_int32 g1,
1632  l_int32 g2,
1633  l_int32 b1,
1634  l_int32 b2)
1635 {
1636 L_BOX3D *vbox;
1637 
1638  vbox = (L_BOX3D *)LEPT_CALLOC(1, sizeof(L_BOX3D));
1639  vbox->r1 = r1;
1640  vbox->r2 = r2;
1641  vbox->g1 = g1;
1642  vbox->g2 = g2;
1643  vbox->b1 = b1;
1644  vbox->b2 = b2;
1645  return vbox;
1646 }
1647 
1648 
1660 static L_BOX3D *
1662 {
1663 L_BOX3D *vboxc;
1664 
1665  PROCNAME("box3dCopy");
1666 
1667  if (!vbox)
1668  return (L_BOX3D *)ERROR_PTR("vbox not defined", procName, NULL);
1669 
1670  vboxc = box3dCreate(vbox->r1, vbox->r2, vbox->g1, vbox->g2,
1671  vbox->b1, vbox->b2);
1672  vboxc->npix = vbox->npix;
1673  vboxc->vol = vbox->vol;
1674  return vboxc;
1675 }
l_ok lheapAdd(L_HEAP *lh, void *item)
lheapAdd()
Definition: heap.c:186
PIX * pixMedianCutQuantMixed(PIX *pixs, l_int32 ncolor, l_int32 ngray, l_int32 darkthresh, l_int32 lightthresh, l_int32 diffthresh)
pixMedianCutQuantMixed()
Definition: colorquant2.c:579
PIX * pixThresholdOn8bpp(PIX *pixs, l_int32 nlevels, l_int32 cmapflag)
pixThresholdOn8bpp()
Definition: grayquant.c:1632
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3041
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
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1624
void lheapDestroy(L_HEAP **plh, l_int32 freeflag)
lheapDestroy()
Definition: heap.c:145
static PIX * pixQuantizeWithColormap(PIX *pixs, l_int32 ditherflag, l_int32 outdepth, PIXCMAP *cmap, l_int32 *indexmap, l_int32 mapsize, l_int32 sigbits)
pixQuantizeWithColormap()
Definition: colorquant2.c:949
l_int32 * pixMedianCutHisto(PIX *pixs, l_int32 sigbits, l_int32 subsample)
pixMedianCutHisto()
Definition: colorquant2.c:826
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1573
static l_int32 medianCutApply(l_int32 *histo, l_int32 sigbits, L_BOX3D *vbox, L_BOX3D **pvbox1, L_BOX3D **pvbox2)
medianCutApply()
Definition: colorquant2.c:1274
static l_int32 vboxGetVolume(L_BOX3D *vbox)
vboxGetVolume()
Definition: colorquant2.c:1611
l_int32 lheapGetCount(L_HEAP *lh)
lheapGetCount()
Definition: heap.c:271
static L_BOX3D * pixGetColorRegion(PIX *pixs, l_int32 sigbits, l_int32 subsample)
pixGetColorRegion()
Definition: colorquant2.c:1217
PIX * pixFewColorsMedianCutQuantMixed(PIX *pixs, l_int32 ncolor, l_int32 ngray, l_int32 maxncolors, l_int32 darkthresh, l_int32 lightthresh, l_int32 diffthresh)
pixFewColorsMedianCutQuantMixed()
Definition: colorquant2.c:754
#define SET_DATA_DIBIT(pdata, n, val)
Definition: arrayaccess.h:149
l_ok pixColorsForQuantization(PIX *pixs, l_int32 thresh, l_int32 *pncolors, l_int32 *piscolor, l_int32 debug)
pixColorsForQuantization()
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:111
static L_BOX3D * box3dCreate(l_int32 r1, l_int32 r2, l_int32 g1, l_int32 g2, l_int32 b1, l_int32 b2)
box3dCreate()
Definition: colorquant2.c:1629
static l_int32 vboxGetAverageColor(L_BOX3D *vbox, l_int32 *histo, l_int32 sigbits, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
vboxGetAverageColor()
Definition: colorquant2.c:1510
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:751
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
L_HEAP * lheapCreate(l_int32 nalloc, l_int32 direction)
lheapCreate()
Definition: heap.c:102
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
void * lheapRemove(L_HEAP *lh)
lheapRemove()
Definition: heap.c:242
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
l_ok pixGetRGBLine(PIX *pixs, l_int32 row, l_uint8 *bufr, l_uint8 *bufg, l_uint8 *bufb)
pixGetRGBLine()
Definition: pix2.c:2816
static PIXCMAP * pixcmapGenerateFromHisto(PIX *pixs, l_int32 depth, l_int32 *histo, l_int32 histosize, l_int32 sigbits)
pixcmapGenerateFromHisto()
Definition: colorquant2.c:890
Definition: heap.h:77
l_ok pixcmapResetColor(PIXCMAP *cmap, l_int32 index, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapResetColor()
Definition: colormap.c:893
static l_int32 vboxGetCount(L_BOX3D *vbox, l_int32 *histo, l_int32 sigbits)
vboxGetCount()
Definition: colorquant2.c:1577
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
static L_BOX3D * box3dCopy(L_BOX3D *vbox)
box3dCopy()
Definition: colorquant2.c:1661
l_ok pixColorFraction(PIX *pixs, l_int32 darkthresh, l_int32 lightthresh, l_int32 diffthresh, l_int32 factor, l_float32 *ppixfract, l_float32 *pcolorfract)
pixColorFraction()
Definition: colorcontent.c:678
PIX * pixMedianCutQuantGeneral(PIX *pixs, l_int32 ditherflag, l_int32 outdepth, l_int32 maxcolors, l_int32 sigbits, l_int32 maxsub, l_int32 checkbw)
pixMedianCutQuantGeneral()
Definition: colorquant2.c:308
l_int32 pixcmapGetCount(PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:635
Definition: pix.h:134
PIX * pixCopy(PIX *pixd, PIX *pixs)
pixCopy()
Definition: pix1.c:628
PIX * pixMedianCutQuant(PIX *pixs, l_int32 ditherflag)
pixMedianCutQuant()
Definition: colorquant2.c:257
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:341
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2737
static void getColorIndexMedianCut(l_uint32 pixel, l_int32 rshift, l_uint32 mask, l_int32 sigbits, l_int32 *pindex)
getColorIndexMedianCut()
Definition: colorquant2.c:1185
#define SET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:127
l_ok pixcmapGetRankIntensity(PIXCMAP *cmap, l_float32 rankval, l_int32 *pindex)
pixcmapGetRankIntensity()
Definition: colormap.c:1158
static PIXCMAP * pixcmapGenerateFromMedianCuts(L_HEAP *lh, l_int32 *histo, l_int32 sigbits)
pixcmapGenerateFromMedianCuts()
Definition: colorquant2.c:1454