Leptonica  1.77.0
Image processing and image analysis suite
colorquant1.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 
117 #include <string.h>
118 #include "allheaders.h"
119 
120 
121 /*
122  * <pre>
123  * This data structure is used for pixOctreeColorQuant(),
124  * a color octree that adjusts to the color distribution
125  * in the image that is being quantized. The best settings
126  * are with CQ_NLEVELS = 6 and DITHERING set on.
127  *
128  * Notes:
129  * (1) the CTE (color table entry) index is sequentially
130  * assigned as the tree is pruned back
131  * (2) if 'bleaf' == 1, all pixels in that cube have been
132  * assigned to one or more CTEs. But note that if
133  * all 8 subcubes have 'bleaf' == 1, it will have no
134  * pixels left for assignment and will not be a CTE.
135  * (3) 'nleaves', the number of leaves contained at the next
136  * lower level is some number between 0 and 8, inclusive.
137  * If it is zero, it means that all colors within this cube
138  * are part of a single growing cluster that has not yet
139  * been set aside as a leaf. If 'nleaves' > 0, 'bleaf'
140  * will be set to 1 and all pixels not assigned to leaves
141  * at lower levels will be assigned to a CTE here.
142  * (However, as described above, if all pixels are already
143  * assigned, we set 'bleaf' = 1 but do not create a CTE
144  * at this level.)
145  * (4) To keep the maximum color error to a minimum, we
146  * prune the tree back to level 2, and require that
147  * all 64 level 2 cells are CTEs.
148  * (5) We reserve an extra set of colors to prevent running out
149  * of colors during the assignment of the final 64 level 2 cells.
150  * This is more likely to happen with small images.
151  * (6) When we run out of colors, the dithered image can be very
152  * poor, so we additionally prevent dithering if the image
153  * is small.
154  * (7) The color content of the image is measured, and if there
155  * is very little color, it is quantized in grayscale.
156  * </pre>
157  */
159 {
160  l_int32 rc, gc, bc; /* center values */
161  l_int32 n; /* number of samples in this cell */
162  l_int32 index; /* CTE (color table entry) index */
163  l_int32 nleaves; /* # of leaves contained at next lower level */
164  l_int32 bleaf; /* boolean: 0 if not a leaf, 1 if so */
165 };
166 typedef struct ColorQuantCell CQCELL;
167 
168  /* Constants for pixOctreeColorQuant() */
169 static const l_int32 CQ_NLEVELS = 5; /* only 4, 5 and 6 are allowed */
170 static const l_int32 CQ_RESERVED_COLORS = 64; /* to allow for level 2 */
171  /* remainder CTEs */
172 static const l_int32 EXTRA_RESERVED_COLORS = 25; /* to avoid running out */
173 static const l_int32 TREE_GEN_WIDTH = 350; /* big enough for good stats */
174 static const l_int32 MIN_DITHER_SIZE = 250; /* don't dither if smaller */
175 
176 
177 /*
178  * <pre>
179  * This data structure is used for pixOctreeQuantNumColors(),
180  * a color octree that adjusts in a simple way to the to the color
181  * distribution in the image that is being quantized. It outputs
182  * colormapped images, either 4 bpp or 8 bpp, depending on the
183  * max number of colors and the compression desired.
184  *
185  * The number of samples is saved as a float in the first location,
186  * because this is required to use it as the key that orders the
187  * cells in the priority queue.
188  * </pre>
189  * */
191 {
192  l_float32 n; /* number of samples in this cell */
193  l_int32 octindex; /* octcube index */
194  l_int32 rcum, gcum, bcum; /* cumulative values */
195  l_int32 rval, gval, bval; /* average values */
196 };
197 typedef struct OctcubeQuantCell OQCELL;
198 
199 
200 /*
201  * <pre>
202  * This data structure is using for heap sorting octcubes
203  * by population. Sort order is decreasing.
204  * </pre>
205  */
207 {
208  l_float32 npix; /* parameter on which to sort */
209  l_int32 index; /* octcube index at assigned level */
210  l_int32 rval; /* mean red value of pixels in octcube */
211  l_int32 gval; /* mean green value of pixels in octcube */
212  l_int32 bval; /* mean blue value of pixels in octcube */
213 };
214 typedef struct L_OctcubePop L_OCTCUBE_POP;
215 
216 /*
217  * <pre>
218  * In pixDitherOctindexWithCmap(), we use these default values.
219  To get the max value of 'dif' in the dithering color transfer,
220  divide these "DIF_CAP" values by 8. However, a value of
221  0 means that there is no cap (infinite cap). A very small
222  value is used for POP_DIF_CAP because dithering on the population
223  generated colormap can be unstable without a tight cap.
224  * </pre>
225  */
226 
227 static const l_int32 FIXED_DIF_CAP = 0;
228 static const l_int32 POP_DIF_CAP = 40;
229 
230 
231  /* Static octree helper function */
232 static l_int32 octreeFindColorCell(l_int32 octindex, CQCELL ***cqcaa,
233  l_int32 *pindex, l_int32 *prval,
234  l_int32 *pgval, l_int32 *pbval);
235 
236  /* Static cqcell functions */
237 static CQCELL ***octreeGenerateAndPrune(PIX *pixs, l_int32 colors,
238  l_int32 reservedcolors,
239  PIXCMAP **pcmap);
240 static PIX *pixOctreeQuantizePixels(PIX *pixs, CQCELL ***cqcaa,
241  l_int32 ditherflag);
242 static CQCELL ***cqcellTreeCreate(void);
243 static void cqcellTreeDestroy(CQCELL ****pcqcaa);
244 
245  /* Static helper octcube index functions */
246 static void getRGBFromOctcube(l_int32 cubeindex, l_int32 level,
247  l_int32 *prval, l_int32 *pgval, l_int32 *pbval);
248 static l_int32 getOctcubeIndices(l_int32 rgbindex, l_int32 level,
249  l_int32 *pbindex, l_int32 *psindex);
250 static l_int32 octcubeGetCount(l_int32 level, l_int32 *psize);
251 
252  /* Static function to perform octcube-indexed dithering */
253 static l_int32 pixDitherOctindexWithCmap(PIX *pixs, PIX *pixd, l_uint32 *rtab,
254  l_uint32 *gtab, l_uint32 *btab,
255  l_int32 *carray, l_int32 difcap);
256 
257  /* Static function to perform octcube-based quantizing from colormap */
258 static PIX *pixOctcubeQuantFromCmapLUT(PIX *pixs, PIXCMAP *cmap,
259  l_int32 mindepth, l_int32 *cmaptab,
260  l_uint32 *rtab, l_uint32 *gtab,
261  l_uint32 *btab);
262 
263 #ifndef NO_CONSOLE_IO
264 #define DEBUG_COLORQUANT 0
265 #define DEBUG_OCTINDEX 0
266 #define DEBUG_OCTCUBE_CMAP 0
267 #define DEBUG_POP 0
268 #define DEBUG_FEW_COLORS 0
269 #define PRINT_OCTCUBE_STATS 0
270 #endif /* ~NO_CONSOLE_IO */
271 
272 
273 /*-------------------------------------------------------------------------*
274  * Two-pass adaptive octree color quantization *
275  *-------------------------------------------------------------------------*/
534 PIX *
536  l_int32 colors,
537  l_int32 ditherflag)
538 {
539  PROCNAME("pixOctreeColorQuant");
540 
541  if (!pixs)
542  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
543  if (pixGetDepth(pixs) != 32)
544  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
545  if (colors < 128 || colors > 240) /* further restricted */
546  return (PIX *)ERROR_PTR("colors must be in [128, 240]", procName, NULL);
547 
548  return pixOctreeColorQuantGeneral(pixs, colors, ditherflag, 0.01, 0.01);
549 }
550 
551 
600 PIX *
602  l_int32 colors,
603  l_int32 ditherflag,
604  l_float32 validthresh,
605  l_float32 colorthresh)
606 {
607 l_int32 w, h, minside, factor, index, rval, gval, bval;
608 l_float32 scalefactor;
609 l_float32 pixfract; /* fraction neither near white nor black */
610 l_float32 colorfract; /* fraction with color of the pixfract population */
611 CQCELL ***cqcaa;
612 PIX *pixd, *pixsub;
613 PIXCMAP *cmap;
614 
615  PROCNAME("pixOctreeColorQuantGeneral");
616 
617  if (!pixs)
618  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
619  if (pixGetDepth(pixs) != 32)
620  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
621  if (colors < 128 || colors > 240)
622  return (PIX *)ERROR_PTR("colors must be in [128, 240]", procName, NULL);
623 
624  /* Determine if the image has sufficient color content for
625  * octree quantization, based on the input thresholds.
626  * If pixfract << 1, most pixels are close to black or white.
627  * If colorfract << 1, the pixels that are not near
628  * black or white have very little color.
629  * If with insufficient color, quantize with a grayscale colormap. */
630  pixGetDimensions(pixs, &w, &h, NULL);
631  if (validthresh > 0.0 && colorthresh > 0.0) {
632  minside = L_MIN(w, h);
633  factor = L_MAX(1, minside / 400);
634  pixColorFraction(pixs, 20, 244, 20, factor, &pixfract, &colorfract);
635  if (pixfract * colorfract < validthresh * colorthresh) {
636  L_INFO("\n Pixel fraction neither white nor black = %6.3f"
637  "\n Color fraction of those pixels = %6.3f"
638  "\n Quantizing to 8 bpp gray\n",
639  procName, pixfract, colorfract);
640  return pixConvertTo8(pixs, 1);
641  }
642  } else {
643  L_INFO("\n Process in color by default\n", procName);
644  }
645 
646  /* Conditionally subsample to speed up the first pass */
647  if (w > TREE_GEN_WIDTH) {
648  scalefactor = (l_float32)TREE_GEN_WIDTH / (l_float32)w;
649  pixsub = pixScaleBySampling(pixs, scalefactor, scalefactor);
650  } else {
651  pixsub = pixClone(pixs);
652  }
653 
654  /* Drop the number of requested colors if image is very small */
655  if (w < MIN_DITHER_SIZE && h < MIN_DITHER_SIZE)
656  colors = L_MIN(colors, 220);
657 
658  /* Make the pruned octree */
659  cqcaa = octreeGenerateAndPrune(pixsub, colors, CQ_RESERVED_COLORS, &cmap);
660  if (!cqcaa) {
661  pixDestroy(&pixsub);
662  return (PIX *)ERROR_PTR("tree not made", procName, NULL);
663  }
664 #if DEBUG_COLORQUANT
665  L_INFO(" Colors requested = %d\n", procName, colors);
666  L_INFO(" Actual colors = %d\n", procName, cmap->n);
667 #endif /* DEBUG_COLORQUANT */
668 
669  /* Do not dither if image is very small */
670  if (w < MIN_DITHER_SIZE && h < MIN_DITHER_SIZE && ditherflag == 1) {
671  L_INFO("Small image: dithering turned off\n", procName);
672  ditherflag = 0;
673  }
674 
675  /* Traverse tree from root, looking for lowest cube
676  * that is a leaf, and set dest pix value to its
677  * colortable index */
678  if ((pixd = pixOctreeQuantizePixels(pixs, cqcaa, ditherflag)) == NULL) {
679  pixDestroy(&pixsub);
680  cqcellTreeDestroy(&cqcaa);
681  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
682  }
683 
684  /* Attach colormap and copy res */
685  pixSetColormap(pixd, cmap);
686  pixCopyResolution(pixd, pixs);
687  pixCopyInputFormat(pixd, pixs);
688 
689  /* Force darkest color to black if each component <= 4 */
690  pixcmapGetRankIntensity(cmap, 0.0, &index);
691  pixcmapGetColor(cmap, index, &rval, &gval, &bval);
692  if (rval < 5 && gval < 5 && bval < 5)
693  pixcmapResetColor(cmap, index, 0, 0, 0);
694 
695  /* Force lightest color to white if each component >= 252 */
696  pixcmapGetRankIntensity(cmap, 1.0, &index);
697  pixcmapGetColor(cmap, index, &rval, &gval, &bval);
698  if (rval > 251 && gval > 251 && bval > 251)
699  pixcmapResetColor(cmap, index, 255, 255, 255);
700 
701  cqcellTreeDestroy(&cqcaa);
702  pixDestroy(&pixsub);
703  return pixd;
704 }
705 
706 
723 static CQCELL ***
725  l_int32 colors,
726  l_int32 reservedcolors,
727  PIXCMAP **pcmap)
728 {
729 l_int32 rval, gval, bval, cindex;
730 l_int32 level, ncells, octindex;
731 l_int32 w, h, wpls;
732 l_int32 i, j, isub;
733 l_int32 npix; /* number of remaining pixels to be assigned */
734 l_int32 ncolor; /* number of remaining color cells to be used */
735 l_int32 ppc; /* ave number of pixels left for each color cell */
736 l_int32 rv, gv, bv;
737 l_float32 thresholdFactor[] = {0.01f, 0.01f, 1.0f, 1.0f, 1.0f, 1.0f};
738 l_float32 thresh; /* factor of ppc for this level */
739 l_uint32 *datas, *lines;
740 l_uint32 *rtab, *gtab, *btab;
741 CQCELL ***cqcaa; /* one array for each octree level */
742 CQCELL **cqca, **cqcasub;
743 CQCELL *cqc, *cqcsub;
744 PIXCMAP *cmap;
745 NUMA *nat; /* accumulates levels for threshold cells */
746 NUMA *nar; /* accumulates levels for residual cells */
747 
748  PROCNAME("octreeGenerateAndPrune");
749 
750  if (!pixs)
751  return (CQCELL ***)ERROR_PTR("pixs not defined", procName, NULL);
752  if (pixGetDepth(pixs) != 32)
753  return (CQCELL ***)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
754  if (colors < 128 || colors > 256)
755  return (CQCELL ***)ERROR_PTR("colors not in [128,256]", procName, NULL);
756  if (!pcmap)
757  return (CQCELL ***)ERROR_PTR("&cmap not defined", procName, NULL);
758 
759  if ((cqcaa = cqcellTreeCreate()) == NULL)
760  return (CQCELL ***)ERROR_PTR("cqcaa not made", procName, NULL);
761 
762  /* Make the canonical index tables */
763  rtab = gtab = btab = NULL;
764  makeRGBToIndexTables(&rtab, &gtab, &btab, CQ_NLEVELS);
765 
766  /* Generate an 8 bpp cmap (max size 256) */
767  cmap = pixcmapCreate(8);
768  *pcmap = cmap;
769 
770  pixGetDimensions(pixs, &w, &h, NULL);
771  npix = w * h; /* initialize to all pixels */
772  ncolor = colors - reservedcolors - EXTRA_RESERVED_COLORS;
773  ppc = npix / ncolor;
774  datas = pixGetData(pixs);
775  wpls = pixGetWpl(pixs);
776 
777  /* Accumulate the centers of each cluster at level CQ_NLEVELS */
778  ncells = 1 << (3 * CQ_NLEVELS);
779  cqca = cqcaa[CQ_NLEVELS];
780  for (i = 0; i < h; i++) {
781  lines = datas + i * wpls;
782  for (j = 0; j < w; j++) {
783  extractRGBValues(lines[j], &rval, &gval, &bval);
784  octindex = rtab[rval] | gtab[gval] | btab[bval];
785  cqc = cqca[octindex];
786  cqc->n++;
787  }
788  }
789 
790  /* Arrays for storing statistics */
791  nat = numaCreate(0);
792  nar = numaCreate(0);
793 
794  /* Prune back from the lowest level and generate the colormap */
795  for (level = CQ_NLEVELS - 1; level >= 2; level--) {
796  thresh = thresholdFactor[level];
797  cqca = cqcaa[level];
798  cqcasub = cqcaa[level + 1];
799  ncells = 1 << (3 * level);
800  for (i = 0; i < ncells; i++) { /* i is octindex at level */
801  cqc = cqca[i];
802  for (j = 0; j < 8; j++) { /* check all subnodes */
803  isub = 8 * i + j; /* isub is octindex at level+1 */
804  cqcsub = cqcasub[isub];
805  if (cqcsub->bleaf == 1) { /* already a leaf? */
806  cqc->nleaves++; /* count the subcube leaves */
807  continue;
808  }
809  if (cqcsub->n >= thresh * ppc) { /* make it a true leaf? */
810  cqcsub->bleaf = 1;
811  if (cmap->n < 256) {
812  cqcsub->index = cmap->n; /* assign the color index */
813  getRGBFromOctcube(isub, level + 1, &rv, &gv, &bv);
814  pixcmapAddColor(cmap, rv, gv, bv);
815 #if 1 /* save values */
816  cqcsub->rc = rv;
817  cqcsub->gc = gv;
818  cqcsub->bc = bv;
819 #endif
820  } else {
821  /* This doesn't seem to happen. Do something. */
822  L_ERROR("assigning pixels to wrong color\n", procName);
823  pixcmapGetNearestIndex(cmap, 128, 128, 128, &cindex);
824  cqcsub->index = cindex; /* assign to the nearest */
825  pixcmapGetColor(cmap, cindex, &rval, &gval, &bval);
826  cqcsub->rc = rval;
827  cqcsub->gc = gval;
828  cqcsub->bc = bval;
829  }
830  cqc->nleaves++;
831  npix -= cqcsub->n;
832  ncolor--;
833  if (ncolor > 0)
834  ppc = npix / ncolor;
835  else if (ncolor + reservedcolors > 0)
836  ppc = npix / (ncolor + reservedcolors);
837  else
838  ppc = 1000000; /* make it big */
839  numaAddNumber(nat, level + 1);
840 
841 #if DEBUG_OCTCUBE_CMAP
842  fprintf(stderr, "Exceeds threshold: colors used = %d, colors remaining = %d\n",
843  cmap->n, ncolor + reservedcolors);
844  fprintf(stderr, " cell with %d pixels, npix = %d, ppc = %d\n",
845  cqcsub->n, npix, ppc);
846  fprintf(stderr, " index = %d, level = %d, subindex = %d\n",
847  i, level, j);
848  fprintf(stderr, " rv = %d, gv = %d, bv = %d\n", rv, gv, bv);
849 #endif /* DEBUG_OCTCUBE_CMAP */
850 
851  }
852  }
853  if (cqc->nleaves > 0 || level == 2) { /* make the cube a leaf now */
854  cqc->bleaf = 1;
855  if (cqc->nleaves < 8) { /* residual CTE cube: acquire the
856  * remaining pixels */
857  for (j = 0; j < 8; j++) { /* check all subnodes */
858  isub = 8 * i + j;
859  cqcsub = cqcasub[isub];
860  if (cqcsub->bleaf == 0) /* absorb */
861  cqc->n += cqcsub->n;
862  }
863  if (cmap->n < 256) {
864  cqc->index = cmap->n; /* assign the color index */
865  getRGBFromOctcube(i, level, &rv, &gv, &bv);
866  pixcmapAddColor(cmap, rv, gv, bv);
867 #if 1 /* save values */
868  cqc->rc = rv;
869  cqc->gc = gv;
870  cqc->bc = bv;
871 #endif
872  } else {
873  L_WARNING("possibly assigned pixels to wrong color\n",
874  procName);
875  /* This is very bad. It will only cause trouble
876  * with dithering, and we try to avoid it with
877  * EXTRA_RESERVED_PIXELS. */
878  pixcmapGetNearestIndex(cmap, rv, gv, bv, &cindex);
879  cqc->index = cindex; /* assign to the nearest */
880  pixcmapGetColor(cmap, cindex, &rval, &gval, &bval);
881  cqc->rc = rval;
882  cqc->gc = gval;
883  cqc->bc = bval;
884  }
885  npix -= cqc->n;
886  ncolor--;
887  if (ncolor > 0)
888  ppc = npix / ncolor;
889  else if (ncolor + reservedcolors > 0)
890  ppc = npix / (ncolor + reservedcolors);
891  else
892  ppc = 1000000; /* make it big */
893  numaAddNumber(nar, level);
894 
895 #if DEBUG_OCTCUBE_CMAP
896  fprintf(stderr, "By remainder: colors used = %d, colors remaining = %d\n",
897  cmap->n, ncolor + reservedcolors);
898  fprintf(stderr, " cell with %d pixels, npix = %d, ppc = %d\n",
899  cqc->n, npix, ppc);
900  fprintf(stderr, " index = %d, level = %d\n", i, level);
901  fprintf(stderr, " rv = %d, gv = %d, bv = %d\n", rv, gv, bv);
902 #endif /* DEBUG_OCTCUBE_CMAP */
903 
904  }
905  } else { /* absorb all the subpixels but don't make it a leaf */
906  for (j = 0; j < 8; j++) { /* absorb from all subnodes */
907  isub = 8 * i + j;
908  cqcsub = cqcasub[isub];
909  cqc->n += cqcsub->n;
910  }
911  }
912  }
913  }
914 
915 #if PRINT_OCTCUBE_STATS
916 {
917 l_int32 tc[] = {0, 0, 0, 0, 0, 0, 0};
918 l_int32 rc[] = {0, 0, 0, 0, 0, 0, 0};
919 l_int32 nt, nr, ival;
920 
921  nt = numaGetCount(nat);
922  nr = numaGetCount(nar);
923  for (i = 0; i < nt; i++) {
924  numaGetIValue(nat, i, &ival);
925  tc[ival]++;
926  }
927  for (i = 0; i < nr; i++) {
928  numaGetIValue(nar, i, &ival);
929  rc[ival]++;
930  }
931  fprintf(stderr, " Threshold cells formed: %d\n", nt);
932  for (i = 1; i < CQ_NLEVELS + 1; i++)
933  fprintf(stderr, " level %d: %d\n", i, tc[i]);
934  fprintf(stderr, "\n Residual cells formed: %d\n", nr);
935  for (i = 0; i < CQ_NLEVELS ; i++)
936  fprintf(stderr, " level %d: %d\n", i, rc[i]);
937 }
938 #endif /* PRINT_OCTCUBE_STATS */
939 
940  numaDestroy(&nat);
941  numaDestroy(&nar);
942  LEPT_FREE(rtab);
943  LEPT_FREE(gtab);
944  LEPT_FREE(btab);
945 
946  return cqcaa;
947 }
948 
949 
973 static PIX *
975  CQCELL ***cqcaa,
976  l_int32 ditherflag)
977 {
978 l_uint8 *bufu8r, *bufu8g, *bufu8b;
979 l_int32 rval, gval, bval;
980 l_int32 octindex, index;
981 l_int32 val1, val2, val3, dif;
982 l_int32 w, h, wpls, wpld, i, j, success;
983 l_int32 rc, gc, bc;
984 l_int32 *buf1r, *buf1g, *buf1b, *buf2r, *buf2g, *buf2b;
985 l_uint32 *rtab, *gtab, *btab;
986 l_uint32 *datas, *datad, *lines, *lined;
987 PIX *pixd;
988 
989  PROCNAME("pixOctreeQuantizePixels");
990 
991  if (!pixs)
992  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
993  if (pixGetDepth(pixs) != 32)
994  return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
995  if (!cqcaa)
996  return (PIX *)ERROR_PTR("cqcaa not defined", procName, NULL);
997 
998  /* Make output 8 bpp palette image */
999  pixGetDimensions(pixs, &w, &h, NULL);
1000  datas = pixGetData(pixs);
1001  wpls = pixGetWpl(pixs);
1002  if ((pixd = pixCreate(w, h, 8)) == NULL)
1003  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1004  pixCopyResolution(pixd, pixs);
1005  pixCopyInputFormat(pixd, pixs);
1006  datad = pixGetData(pixd);
1007  wpld = pixGetWpl(pixd);
1008 
1009  /* Make the canonical index tables */
1010  rtab = gtab = btab = NULL;
1011  makeRGBToIndexTables(&rtab, &gtab, &btab, CQ_NLEVELS);
1012 
1013  /* Traverse tree from root, looking for lowest cube
1014  * that is a leaf, and set dest pix to its
1015  * colortable index value. The results are far
1016  * better when dithering to get a more accurate
1017  * average color. */
1018  if (ditherflag == 0) { /* no dithering */
1019  for (i = 0; i < h; i++) {
1020  lines = datas + i * wpls;
1021  lined = datad + i * wpld;
1022  for (j = 0; j < w; j++) {
1023  extractRGBValues(lines[j], &rval, &gval, &bval);
1024  octindex = rtab[rval] | gtab[gval] | btab[bval];
1025  octreeFindColorCell(octindex, cqcaa, &index, &rc, &gc, &bc);
1026  SET_DATA_BYTE(lined, j, index);
1027  }
1028  }
1029  } else { /* Dither */
1030  success = TRUE;
1031  bufu8r = bufu8g = bufu8b = NULL;
1032  buf1r = buf1g = buf1b = buf2r = buf2g = buf2b = NULL;
1033  bufu8r = (l_uint8 *)LEPT_CALLOC(w, sizeof(l_uint8));
1034  bufu8g = (l_uint8 *)LEPT_CALLOC(w, sizeof(l_uint8));
1035  bufu8b = (l_uint8 *)LEPT_CALLOC(w, sizeof(l_uint8));
1036  buf1r = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
1037  buf1g = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
1038  buf1b = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
1039  buf2r = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
1040  buf2g = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
1041  buf2b = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
1042  if (!bufu8r || !bufu8g || !bufu8b || !buf1r || !buf1g ||
1043  !buf1b || !buf2r || !buf2g || !buf2b) {
1044  L_ERROR("buffer not made\n", procName);
1045  success = FALSE;
1046  goto buffer_cleanup;
1047  }
1048 
1049  /* Start by priming buf2; line 1 is above line 2 */
1050  pixGetRGBLine(pixs, 0, bufu8r, bufu8g, bufu8b);
1051  for (j = 0; j < w; j++) {
1052  buf2r[j] = 64 * bufu8r[j];
1053  buf2g[j] = 64 * bufu8g[j];
1054  buf2b[j] = 64 * bufu8b[j];
1055  }
1056 
1057  for (i = 0; i < h - 1; i++) {
1058  /* Swap data 2 --> 1, and read in new line 2 */
1059  memcpy(buf1r, buf2r, 4 * w);
1060  memcpy(buf1g, buf2g, 4 * w);
1061  memcpy(buf1b, buf2b, 4 * w);
1062  pixGetRGBLine(pixs, i + 1, bufu8r, bufu8g, bufu8b);
1063  for (j = 0; j < w; j++) {
1064  buf2r[j] = 64 * bufu8r[j];
1065  buf2g[j] = 64 * bufu8g[j];
1066  buf2b[j] = 64 * bufu8b[j];
1067  }
1068 
1069  /* Dither */
1070  lined = datad + i * wpld;
1071  for (j = 0; j < w - 1; j++) {
1072  rval = buf1r[j] / 64;
1073  gval = buf1g[j] / 64;
1074  bval = buf1b[j] / 64;
1075  octindex = rtab[rval] | gtab[gval] | btab[bval];
1076  octreeFindColorCell(octindex, cqcaa, &index, &rc, &gc, &bc);
1077  SET_DATA_BYTE(lined, j, index);
1078 
1079  dif = buf1r[j] / 8 - 8 * rc;
1080  if (dif != 0) {
1081  val1 = buf1r[j + 1] + 3 * dif;
1082  val2 = buf2r[j] + 3 * dif;
1083  val3 = buf2r[j + 1] + 2 * dif;
1084  if (dif > 0) {
1085  buf1r[j + 1] = L_MIN(16383, val1);
1086  buf2r[j] = L_MIN(16383, val2);
1087  buf2r[j + 1] = L_MIN(16383, val3);
1088  } else {
1089  buf1r[j + 1] = L_MAX(0, val1);
1090  buf2r[j] = L_MAX(0, val2);
1091  buf2r[j + 1] = L_MAX(0, val3);
1092  }
1093  }
1094 
1095  dif = buf1g[j] / 8 - 8 * gc;
1096  if (dif != 0) {
1097  val1 = buf1g[j + 1] + 3 * dif;
1098  val2 = buf2g[j] + 3 * dif;
1099  val3 = buf2g[j + 1] + 2 * dif;
1100  if (dif > 0) {
1101  buf1g[j + 1] = L_MIN(16383, val1);
1102  buf2g[j] = L_MIN(16383, val2);
1103  buf2g[j + 1] = L_MIN(16383, val3);
1104  } else {
1105  buf1g[j + 1] = L_MAX(0, val1);
1106  buf2g[j] = L_MAX(0, val2);
1107  buf2g[j + 1] = L_MAX(0, val3);
1108  }
1109  }
1110 
1111  dif = buf1b[j] / 8 - 8 * bc;
1112  if (dif != 0) {
1113  val1 = buf1b[j + 1] + 3 * dif;
1114  val2 = buf2b[j] + 3 * dif;
1115  val3 = buf2b[j + 1] + 2 * dif;
1116  if (dif > 0) {
1117  buf1b[j + 1] = L_MIN(16383, val1);
1118  buf2b[j] = L_MIN(16383, val2);
1119  buf2b[j + 1] = L_MIN(16383, val3);
1120  } else {
1121  buf1b[j + 1] = L_MAX(0, val1);
1122  buf2b[j] = L_MAX(0, val2);
1123  buf2b[j + 1] = L_MAX(0, val3);
1124  }
1125  }
1126  }
1127 
1128  /* Get last pixel in row; no downward propagation */
1129  rval = buf1r[w - 1] / 64;
1130  gval = buf1g[w - 1] / 64;
1131  bval = buf1b[w - 1] / 64;
1132  octindex = rtab[rval] | gtab[gval] | btab[bval];
1133  octreeFindColorCell(octindex, cqcaa, &index, &rc, &gc, &bc);
1134  SET_DATA_BYTE(lined, w - 1, index);
1135  }
1136 
1137  /* Get last row of pixels; no leftward propagation */
1138  lined = datad + (h - 1) * wpld;
1139  for (j = 0; j < w; j++) {
1140  rval = buf2r[j] / 64;
1141  gval = buf2g[j] / 64;
1142  bval = buf2b[j] / 64;
1143  octindex = rtab[rval] | gtab[gval] | btab[bval];
1144  octreeFindColorCell(octindex, cqcaa, &index, &rc, &gc, &bc);
1145  SET_DATA_BYTE(lined, j, index);
1146  }
1147 
1148 buffer_cleanup:
1149  LEPT_FREE(bufu8r);
1150  LEPT_FREE(bufu8g);
1151  LEPT_FREE(bufu8b);
1152  LEPT_FREE(buf1r);
1153  LEPT_FREE(buf1g);
1154  LEPT_FREE(buf1b);
1155  LEPT_FREE(buf2r);
1156  LEPT_FREE(buf2g);
1157  LEPT_FREE(buf2b);
1158  if (!success) pixDestroy(&pixd);
1159  }
1160 
1161  LEPT_FREE(rtab);
1162  LEPT_FREE(gtab);
1163  LEPT_FREE(btab);
1164  return pixd;
1165 }
1166 
1167 
1189 static l_int32
1190 octreeFindColorCell(l_int32 octindex,
1191  CQCELL ***cqcaa,
1192  l_int32 *pindex,
1193  l_int32 *prval,
1194  l_int32 *pgval,
1195  l_int32 *pbval)
1196 {
1197 l_int32 level;
1198 l_int32 baseindex, subindex;
1199 CQCELL *cqc, *cqcsub;
1200 
1201  /* Use rgb values stored in the cubes; a little faster */
1202  for (level = 2; level < CQ_NLEVELS; level++) {
1203  getOctcubeIndices(octindex, level, &baseindex, &subindex);
1204  cqc = cqcaa[level][baseindex];
1205  cqcsub = cqcaa[level + 1][subindex];
1206  if (cqcsub->bleaf == 0) { /* use cell at level above */
1207  *pindex = cqc->index;
1208  *prval = cqc->rc;
1209  *pgval = cqc->gc;
1210  *pbval = cqc->bc;
1211  break;
1212  } else if (level == CQ_NLEVELS - 1) { /* reached the bottom */
1213  *pindex = cqcsub->index;
1214  *prval = cqcsub->rc;
1215  *pgval = cqcsub->gc;
1216  *pbval = cqcsub->bc;
1217  break;
1218  }
1219  }
1220 
1221 #if 0
1222  /* Generate rgb values for each cube on the fly; slower */
1223  for (level = 2; level < CQ_NLEVELS; level++) {
1224  l_int32 rv, gv, bv;
1225  getOctcubeIndices(octindex, level, &baseindex, &subindex);
1226  cqc = cqcaa[level][baseindex];
1227  cqcsub = cqcaa[level + 1][subindex];
1228  if (cqcsub->bleaf == 0) { /* use cell at level above */
1229  getRGBFromOctcube(baseindex, level, &rv, &gv, &bv);
1230  *pindex = cqc->index;
1231  *prval = rv;
1232  *pgval = gv;
1233  *pbval = bv;
1234  break;
1235  } else if (level == CQ_NLEVELS - 1) { /* reached the bottom */
1236  getRGBFromOctcube(subindex, level + 1, &rv, &gv, &bv);
1237  *pindex = cqcsub->index;
1238  *prval = rv;
1239  *pgval = gv;
1240  *pbval = bv;
1241  break;
1242  }
1243  }
1244 #endif
1245 
1246  return 0;
1247 }
1248 
1249 
1250 
1251 /*------------------------------------------------------------------*
1252  * Helper cqcell functions *
1253  *------------------------------------------------------------------*/
1259 static CQCELL ***
1261 {
1262 l_int32 level, ncells, i;
1263 CQCELL ***cqcaa;
1264 CQCELL **cqca; /* one array for each octree level */
1265 
1266  PROCNAME("cqcellTreeCreate");
1267 
1268  /* Make array of accumulation cell arrays from levels 1 to 5 */
1269  if ((cqcaa = (CQCELL ***)LEPT_CALLOC(CQ_NLEVELS + 1, sizeof(CQCELL **)))
1270  == NULL)
1271  return (CQCELL ***)ERROR_PTR("cqcaa not made", procName, NULL);
1272  for (level = 0; level <= CQ_NLEVELS; level++) {
1273  ncells = 1 << (3 * level);
1274  if ((cqca = (CQCELL **)LEPT_CALLOC(ncells, sizeof(CQCELL *))) == NULL) {
1275  cqcellTreeDestroy(&cqcaa);
1276  return (CQCELL ***)ERROR_PTR("cqca not made", procName, NULL);
1277  }
1278  cqcaa[level] = cqca;
1279  for (i = 0; i < ncells; i++) {
1280  if ((cqca[i] = (CQCELL *)LEPT_CALLOC(1, sizeof(CQCELL))) == NULL) {
1281  cqcellTreeDestroy(&cqcaa);
1282  return (CQCELL ***)ERROR_PTR("cqc not made", procName, NULL);
1283  }
1284  }
1285  }
1286 
1287  return cqcaa;
1288 }
1289 
1290 
1296 static void
1298 {
1299 l_int32 level, ncells, i;
1300 CQCELL ***cqcaa;
1301 CQCELL **cqca;
1302 
1303  PROCNAME("cqcellTreeDestroy");
1304 
1305  if (pcqcaa == NULL) {
1306  L_WARNING("ptr address is NULL\n", procName);
1307  return;
1308  }
1309 
1310  if ((cqcaa = *pcqcaa) == NULL)
1311  return;
1312 
1313  for (level = 0; level <= CQ_NLEVELS; level++) {
1314  cqca = cqcaa[level];
1315  ncells = 1 << (3 * level);
1316  for (i = 0; i < ncells; i++)
1317  LEPT_FREE(cqca[i]);
1318  LEPT_FREE(cqca);
1319  }
1320  LEPT_FREE(cqcaa);
1321  *pcqcaa = NULL;
1322 
1323  return;
1324 }
1325 
1326 
1327 
1328 /*------------------------------------------------------------------*
1329  * Helper index functions *
1330  *------------------------------------------------------------------*/
1360 l_ok
1361 makeRGBToIndexTables(l_uint32 **prtab,
1362  l_uint32 **pgtab,
1363  l_uint32 **pbtab,
1364  l_int32 cqlevels)
1365 {
1366 l_int32 i;
1367 l_uint32 *rtab, *gtab, *btab;
1368 
1369  PROCNAME("makeRGBToIndexTables");
1370 
1371  if (cqlevels < 1 || cqlevels > 6)
1372  return ERROR_INT("cqlevels must be in {1,...6}", procName, 1);
1373 
1374  if (!prtab || !pgtab || !pbtab)
1375  return ERROR_INT("not all &tabs defined", procName, 1);
1376  rtab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1377  gtab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1378  btab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1379  if (!rtab || !gtab || !btab)
1380  return ERROR_INT("calloc fail for tab", procName, 1);
1381  *prtab = rtab;
1382  *pgtab = gtab;
1383  *pbtab = btab;
1384 
1385  switch (cqlevels)
1386  {
1387  case 1:
1388  for (i = 0; i < 256; i++) {
1389  rtab[i] = (i >> 5) & 0x0004;
1390  gtab[i] = (i >> 6) & 0x0002;
1391  btab[i] = (i >> 7);
1392  }
1393  break;
1394  case 2:
1395  for (i = 0; i < 256; i++) {
1396  rtab[i] = ((i >> 2) & 0x0020) | ((i >> 4) & 0x0004);
1397  gtab[i] = ((i >> 3) & 0x0010) | ((i >> 5) & 0x0002);
1398  btab[i] = ((i >> 4) & 0x0008) | ((i >> 6) & 0x0001);
1399  }
1400  break;
1401  case 3:
1402  for (i = 0; i < 256; i++) {
1403  rtab[i] = ((i << 1) & 0x0100) | ((i >> 1) & 0x0020) |
1404  ((i >> 3) & 0x0004);
1405  gtab[i] = (i & 0x0080) | ((i >> 2) & 0x0010) |
1406  ((i >> 4) & 0x0002);
1407  btab[i] = ((i >> 1) & 0x0040) | ((i >> 3) & 0x0008) |
1408  ((i >> 5) & 0x0001);
1409  }
1410  break;
1411  case 4:
1412  for (i = 0; i < 256; i++) {
1413  rtab[i] = ((i << 4) & 0x0800) | ((i << 2) & 0x0100) |
1414  (i & 0x0020) | ((i >> 2) & 0x0004);
1415  gtab[i] = ((i << 3) & 0x0400) | ((i << 1) & 0x0080) |
1416  ((i >> 1) & 0x0010) | ((i >> 3) & 0x0002);
1417  btab[i] = ((i << 2) & 0x0200) | (i & 0x0040) |
1418  ((i >> 2) & 0x0008) | ((i >> 4) & 0x0001);
1419  }
1420  break;
1421  case 5:
1422  for (i = 0; i < 256; i++) {
1423  rtab[i] = ((i << 7) & 0x4000) | ((i << 5) & 0x0800) |
1424  ((i << 3) & 0x0100) | ((i << 1) & 0x0020) |
1425  ((i >> 1) & 0x0004);
1426  gtab[i] = ((i << 6) & 0x2000) | ((i << 4) & 0x0400) |
1427  ((i << 2) & 0x0080) | (i & 0x0010) |
1428  ((i >> 2) & 0x0002);
1429  btab[i] = ((i << 5) & 0x1000) | ((i << 3) & 0x0200) |
1430  ((i << 1) & 0x0040) | ((i >> 1) & 0x0008) |
1431  ((i >> 3) & 0x0001);
1432  }
1433  break;
1434  case 6:
1435  for (i = 0; i < 256; i++) {
1436  rtab[i] = ((i << 10) & 0x20000) | ((i << 8) & 0x4000) |
1437  ((i << 6) & 0x0800) | ((i << 4) & 0x0100) |
1438  ((i << 2) & 0x0020) | (i & 0x0004);
1439  gtab[i] = ((i << 9) & 0x10000) | ((i << 7) & 0x2000) |
1440  ((i << 5) & 0x0400) | ((i << 3) & 0x0080) |
1441  ((i << 1) & 0x0010) | ((i >> 1) & 0x0002);
1442  btab[i] = ((i << 8) & 0x8000) | ((i << 6) & 0x1000) |
1443  ((i << 4) & 0x0200) | ((i << 2) & 0x0040) |
1444  (i & 0x0008) | ((i >> 2) & 0x0001);
1445  }
1446  break;
1447  default:
1448  ERROR_INT("cqlevels not in [1...6]", procName, 1);
1449  break;
1450  }
1451 
1452  return 0;
1453 }
1454 
1455 
1469 void
1471  l_int32 gval,
1472  l_int32 bval,
1473  l_uint32 *rtab,
1474  l_uint32 *gtab,
1475  l_uint32 *btab,
1476  l_uint32 *pindex)
1477 {
1478  *pindex = rtab[rval] | gtab[gval] | btab[bval];
1479  return;
1480 }
1481 
1482 
1515 static void
1516 getRGBFromOctcube(l_int32 cubeindex,
1517  l_int32 level,
1518  l_int32 *prval,
1519  l_int32 *pgval,
1520  l_int32 *pbval)
1521 {
1522 l_int32 rgbindex;
1523 
1524  /* Bring to format in 21 bits: (r7 g7 b7 r6 g6 b6 ...) */
1525  /* This is valid for levels from 0 to 6 */
1526  rgbindex = cubeindex << (3 * (7 - level)); /* upper corner of cube */
1527  rgbindex |= (0x7 << (3 * (6 - level))); /* index to center of cube */
1528 
1529  /* Extract separate pieces */
1530  *prval = ((rgbindex >> 13) & 0x80) |
1531  ((rgbindex >> 11) & 0x40) |
1532  ((rgbindex >> 9) & 0x20) |
1533  ((rgbindex >> 7) & 0x10) |
1534  ((rgbindex >> 5) & 0x08) |
1535  ((rgbindex >> 3) & 0x04) |
1536  ((rgbindex >> 1) & 0x02);
1537  *pgval = ((rgbindex >> 12) & 0x80) |
1538  ((rgbindex >> 10) & 0x40) |
1539  ((rgbindex >> 8) & 0x20) |
1540  ((rgbindex >> 6) & 0x10) |
1541  ((rgbindex >> 4) & 0x08) |
1542  ((rgbindex >> 2) & 0x04) |
1543  (rgbindex & 0x02);
1544  *pbval = ((rgbindex >> 11) & 0x80) |
1545  ((rgbindex >> 9) & 0x40) |
1546  ((rgbindex >> 7) & 0x20) |
1547  ((rgbindex >> 5) & 0x10) |
1548  ((rgbindex >> 3) & 0x08) |
1549  ((rgbindex >> 1) & 0x04) |
1550  ((rgbindex << 1) & 0x02);
1551 
1552  return;
1553 }
1554 
1555 
1592 static l_int32
1593 getOctcubeIndices(l_int32 rgbindex,
1594  l_int32 level,
1595  l_int32 *pbindex,
1596  l_int32 *psindex)
1597 {
1598  PROCNAME("getOctcubeIndex");
1599 
1600  if (level < 0 || level > CQ_NLEVELS - 1)
1601  return ERROR_INT("level must be in e.g., [0 ... 5]", procName, 1);
1602  if (!pbindex)
1603  return ERROR_INT("&bindex not defined", procName, 1);
1604  if (!psindex)
1605  return ERROR_INT("&sindex not defined", procName, 1);
1606 
1607  *pbindex = rgbindex >> (3 * (CQ_NLEVELS - level));
1608  *psindex = rgbindex >> (3 * (CQ_NLEVELS - 1 - level));
1609  return 0;
1610 }
1611 
1612 
1626 static l_int32
1627 octcubeGetCount(l_int32 level,
1628  l_int32 *psize)
1629 {
1630  PROCNAME("octcubeGetCount");
1631 
1632  if (!psize)
1633  return ERROR_INT("&size not defined", procName, 1);
1634  if (level < 1 || level > 6)
1635  return ERROR_INT("invalid level", procName, 1);
1636 
1637  *psize = 1 << (3 * level);
1638  return 0;
1639 }
1640 
1641 
1642 /*---------------------------------------------------------------------------*
1643  * Adaptive octree quantization based on population at a fixed level *
1644  *---------------------------------------------------------------------------*/
1700 PIX *
1702  l_int32 level,
1703  l_int32 ditherflag)
1704 {
1705 l_int32 w, h, wpls, wpld, i, j, depth, size, ncolors, index;
1706 l_int32 rval, gval, bval;
1707 l_int32 *rarray, *garray, *barray, *narray, *iarray;
1708 l_uint32 octindex, octindex2;
1709 l_uint32 *rtab, *gtab, *btab, *rtab2, *gtab2, *btab2;
1710 l_uint32 *lines, *lined, *datas, *datad;
1711 L_OCTCUBE_POP *opop;
1712 L_HEAP *lh;
1713 PIX *pixd;
1714 PIXCMAP *cmap;
1715 
1716  PROCNAME("pixOctreeQuantByPopulation");
1717 
1718  if (!pixs)
1719  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1720  if (pixGetDepth(pixs) != 32)
1721  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1722  if (level == 0) level = 4;
1723  if (level < 3 || level > 4)
1724  return (PIX *)ERROR_PTR("level not in {3,4}", procName, NULL);
1725 
1726  /* Do not dither if image is very small */
1727  pixGetDimensions(pixs, &w, &h, NULL);
1728  if (w < MIN_DITHER_SIZE && h < MIN_DITHER_SIZE && ditherflag == 1) {
1729  L_INFO("Small image: dithering turned off\n", procName);
1730  ditherflag = 0;
1731  }
1732 
1733  if (octcubeGetCount(level, &size)) /* array size = 2 ** (3 * level) */
1734  return (PIX *)ERROR_PTR("size not returned", procName, NULL);
1735  rtab = gtab = btab = NULL;
1736  makeRGBToIndexTables(&rtab, &gtab, &btab, level);
1737 
1738  pixd = NULL;
1739  narray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
1740  rarray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
1741  garray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
1742  barray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
1743  if (!narray || !rarray || !garray || !barray)
1744  goto array_cleanup;
1745 
1746  /* Place the pixels in octcube leaves. */
1747  datas = pixGetData(pixs);
1748  wpls = pixGetWpl(pixs);
1749  for (i = 0; i < h; i++) {
1750  lines = datas + i * wpls;
1751  for (j = 0; j < w; j++) {
1752  extractRGBValues(lines[j], &rval, &gval, &bval);
1753  octindex = rtab[rval] | gtab[gval] | btab[bval];
1754  narray[octindex]++;
1755  rarray[octindex] += rval;
1756  garray[octindex] += gval;
1757  barray[octindex] += bval;
1758  }
1759  }
1760 
1761  /* Find the number of different colors */
1762  for (i = 0, ncolors = 0; i < size; i++) {
1763  if (narray[i] > 0)
1764  ncolors++;
1765  }
1766  if (ncolors <= 4)
1767  depth = 2;
1768  else if (ncolors <= 16)
1769  depth = 4;
1770  else
1771  depth = 8;
1772  pixd = pixCreate(w, h, depth);
1773  datad = pixGetData(pixd);
1774  wpld = pixGetWpl(pixd);
1775  pixCopyResolution(pixd, pixs);
1776  pixCopyInputFormat(pixd, pixs);
1777  cmap = pixcmapCreate(depth);
1778  pixSetColormap(pixd, cmap);
1779 
1780  /* Average the colors in each octcube leaf. */
1781  for (i = 0; i < size; i++) {
1782  if (narray[i] > 0) {
1783  rarray[i] /= narray[i];
1784  garray[i] /= narray[i];
1785  barray[i] /= narray[i];
1786  }
1787  }
1788 
1789  /* If ncolors <= 256, finish immediately. Do not dither.
1790  * Re-use narray to hold the colormap index + 1 */
1791  if (ncolors <= 256) {
1792  for (i = 0, index = 0; i < size; i++) {
1793  if (narray[i] > 0) {
1794  pixcmapAddColor(cmap, rarray[i], garray[i], barray[i]);
1795  narray[i] = index + 1; /* to avoid storing 0 */
1796  index++;
1797  }
1798  }
1799 
1800  /* Set the cmap indices for each pixel */
1801  for (i = 0; i < h; i++) {
1802  lines = datas + i * wpls;
1803  lined = datad + i * wpld;
1804  for (j = 0; j < w; j++) {
1805  extractRGBValues(lines[j], &rval, &gval, &bval);
1806  octindex = rtab[rval] | gtab[gval] | btab[bval];
1807  switch (depth)
1808  {
1809  case 8:
1810  SET_DATA_BYTE(lined, j, narray[octindex] - 1);
1811  break;
1812  case 4:
1813  SET_DATA_QBIT(lined, j, narray[octindex] - 1);
1814  break;
1815  case 2:
1816  SET_DATA_DIBIT(lined, j, narray[octindex] - 1);
1817  break;
1818  default:
1819  L_WARNING("shouldn't get here\n", procName);
1820  }
1821  }
1822  }
1823  goto array_cleanup;
1824  }
1825 
1826  /* More complicated. Sort by decreasing population */
1827  lh = lheapCreate(500, L_SORT_DECREASING);
1828  for (i = 0; i < size; i++) {
1829  if (narray[i] > 0) {
1830  opop = (L_OCTCUBE_POP *)LEPT_CALLOC(1, sizeof(L_OCTCUBE_POP));
1831  opop->npix = (l_float32)narray[i];
1832  opop->index = i;
1833  opop->rval = rarray[i];
1834  opop->gval = garray[i];
1835  opop->bval = barray[i];
1836  lheapAdd(lh, opop);
1837  }
1838  }
1839 
1840  /* Take the top 192. These will form the first 192 colors
1841  * in the cmap. iarray[i] holds the index into the cmap. */
1842  iarray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
1843  for (i = 0; i < 192; i++) {
1844  opop = (L_OCTCUBE_POP*)lheapRemove(lh);
1845  if (!opop) break;
1846  pixcmapAddColor(cmap, opop->rval, opop->gval, opop->bval);
1847  iarray[opop->index] = i + 1; /* +1 to avoid storing 0 */
1848 
1849 #if DEBUG_POP
1850  fprintf(stderr, "i = %d, n = %6.0f, (r,g,b) = (%d %d %d)\n",
1851  i, opop->npix, opop->rval, opop->gval, opop->bval);
1852 #endif /* DEBUG_POP */
1853 
1854  LEPT_FREE(opop);
1855  }
1856 
1857  /* Make the octindex tables for level 2, and reuse rarray, etc. */
1858  rtab2 = gtab2 = btab2 = NULL;
1859  makeRGBToIndexTables(&rtab2, &gtab2, &btab2, 2);
1860  for (i = 0; i < 64; i++) {
1861  narray[i] = 0;
1862  rarray[i] = 0;
1863  garray[i] = 0;
1864  barray[i] = 0;
1865  }
1866 
1867  /* Take the rest of the occupied octcubes, assigning the pixels
1868  * to these new colormap indices. iarray[] is addressed
1869  * by %level octcube indices, and it now holds the
1870  * colormap indices for all pixels in pixs. */
1871  for (i = 192; i < size; i++) {
1872  opop = (L_OCTCUBE_POP*)lheapRemove(lh);
1873  if (!opop) break;
1874  rval = opop->rval;
1875  gval = opop->gval;
1876  bval = opop->bval;
1877  octindex2 = rtab2[rval] | gtab2[gval] | btab2[bval];
1878  narray[octindex2] += (l_int32)opop->npix;
1879  rarray[octindex2] += (l_int32)opop->npix * rval;
1880  garray[octindex2] += (l_int32)opop->npix * gval;
1881  barray[octindex2] += (l_int32)opop->npix * bval;
1882  iarray[opop->index] = 192 + octindex2 + 1; /* +1 to avoid storing 0 */
1883  LEPT_FREE(opop);
1884  }
1885  lheapDestroy(&lh, TRUE);
1886 
1887  /* To span the full color space, which is necessary for dithering,
1888  * set each iarray element whose value is still 0 at the input
1889  * level octcube leaves (because there were no pixels in those
1890  * octcubes) to the colormap index corresponding to its level 2
1891  * octcube. */
1892  if (ditherflag) {
1893  for (i = 0; i < size; i++) {
1894  if (iarray[i] == 0) {
1895  getRGBFromOctcube(i, level, &rval, &gval, &bval);
1896  octindex2 = rtab2[rval] | gtab2[gval] | btab2[bval];
1897  iarray[i] = 192 + octindex2 + 1;
1898  }
1899  }
1900  }
1901  LEPT_FREE(rtab2);
1902  LEPT_FREE(gtab2);
1903  LEPT_FREE(btab2);
1904 
1905  /* Average the colors from the residuals in each level 2 octcube,
1906  * and add these 64 values to the colormap. */
1907  for (i = 0; i < 64; i++) {
1908  if (narray[i] > 0) {
1909  rarray[i] /= narray[i];
1910  garray[i] /= narray[i];
1911  barray[i] /= narray[i];
1912  } else { /* no pixels in this octcube; use center value */
1913  getRGBFromOctcube(i, 2, &rarray[i], &garray[i], &barray[i]);
1914  }
1915  pixcmapAddColor(cmap, rarray[i], garray[i], barray[i]);
1916  }
1917 
1918  /* Set the cmap indices for each pixel. Subtract 1 from
1919  * the value in iarray[] because we added 1 earlier. */
1920  if (ditherflag == 0) {
1921  for (i = 0; i < h; i++) {
1922  lines = datas + i * wpls;
1923  lined = datad + i * wpld;
1924  for (j = 0; j < w; j++) {
1925  extractRGBValues(lines[j], &rval, &gval, &bval);
1926  octindex = rtab[rval] | gtab[gval] | btab[bval];
1927  SET_DATA_BYTE(lined, j, iarray[octindex] - 1);
1928  }
1929  }
1930  } else { /* dither */
1931  pixDitherOctindexWithCmap(pixs, pixd, rtab, gtab, btab,
1932  iarray, POP_DIF_CAP);
1933  }
1934 
1935 #if DEBUG_POP
1936  for (i = 0; i < size / 16; i++) {
1937  l_int32 j;
1938  for (j = 0; j < 16; j++)
1939  fprintf(stderr, "%d ", iarray[16 * i + j]);
1940  fprintf(stderr, "\n");
1941  }
1942 #endif /* DEBUG_POP */
1943 
1944  LEPT_FREE(iarray);
1945 
1946 array_cleanup:
1947  LEPT_FREE(narray);
1948  LEPT_FREE(rarray);
1949  LEPT_FREE(garray);
1950  LEPT_FREE(barray);
1951  LEPT_FREE(rtab);
1952  LEPT_FREE(gtab);
1953  LEPT_FREE(btab);
1954 
1955  return pixd;
1956 }
1957 
1958 
1991 static l_int32
1993  PIX *pixd,
1994  l_uint32 *rtab,
1995  l_uint32 *gtab,
1996  l_uint32 *btab,
1997  l_int32 *indexmap,
1998  l_int32 difcap)
1999 {
2000 l_uint8 *bufu8r, *bufu8g, *bufu8b;
2001 l_int32 i, j, w, h, wpld, octindex, cmapindex, success;
2002 l_int32 rval, gval, bval, rc, gc, bc;
2003 l_int32 dif, val1, val2, val3;
2004 l_int32 *buf1r, *buf1g, *buf1b, *buf2r, *buf2g, *buf2b;
2005 l_uint32 *datad, *lined;
2006 PIXCMAP *cmap;
2007 
2008  PROCNAME("pixDitherOctindexWithCmap");
2009 
2010  if (!pixs || pixGetDepth(pixs) != 32)
2011  return ERROR_INT("pixs undefined or not 32 bpp", procName, 1);
2012  if (!pixd || pixGetDepth(pixd) != 8)
2013  return ERROR_INT("pixd undefined or not 8 bpp", procName, 1);
2014  if ((cmap = pixGetColormap(pixd)) == NULL)
2015  return ERROR_INT("pixd not cmapped", procName, 1);
2016  if (!rtab || !gtab || !btab || !indexmap)
2017  return ERROR_INT("not all 4 tables defined", procName, 1);
2018  pixGetDimensions(pixs, &w, &h, NULL);
2019  if (pixGetWidth(pixd) != w || pixGetHeight(pixd) != h)
2020  return ERROR_INT("pixs and pixd not same size", procName, 1);
2021 
2022  success = TRUE;
2023  bufu8r = bufu8g = bufu8b = NULL;
2024  buf1r = buf1g = buf1b = buf2r = buf2g = buf2b = NULL;
2025  bufu8r = (l_uint8 *)LEPT_CALLOC(w, sizeof(l_uint8));
2026  bufu8g = (l_uint8 *)LEPT_CALLOC(w, sizeof(l_uint8));
2027  bufu8b = (l_uint8 *)LEPT_CALLOC(w, sizeof(l_uint8));
2028  buf1r = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
2029  buf1g = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
2030  buf1b = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
2031  buf2r = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
2032  buf2g = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
2033  buf2b = (l_int32 *)LEPT_CALLOC(w, sizeof(l_int32));
2034  if (!bufu8r || !bufu8g || !bufu8b || !buf1r || !buf1g ||
2035  !buf1b || !buf2r || !buf2g || !buf2b) {
2036  L_ERROR("buffer not made\n", procName);
2037  success = FALSE;
2038  goto buffer_cleanup;
2039  }
2040 
2041  /* Start by priming buf2; line 1 is above line 2 */
2042  pixGetRGBLine(pixs, 0, bufu8r, bufu8g, bufu8b);
2043  for (j = 0; j < w; j++) {
2044  buf2r[j] = 64 * bufu8r[j];
2045  buf2g[j] = 64 * bufu8g[j];
2046  buf2b[j] = 64 * bufu8b[j];
2047  }
2048 
2049  datad = pixGetData(pixd);
2050  wpld = pixGetWpl(pixd);
2051  for (i = 0; i < h - 1; i++) {
2052  /* Swap data 2 --> 1, and read in new line 2 */
2053  memcpy(buf1r, buf2r, 4 * w);
2054  memcpy(buf1g, buf2g, 4 * w);
2055  memcpy(buf1b, buf2b, 4 * w);
2056  pixGetRGBLine(pixs, i + 1, bufu8r, bufu8g, bufu8b);
2057  for (j = 0; j < w; j++) {
2058  buf2r[j] = 64 * bufu8r[j];
2059  buf2g[j] = 64 * bufu8g[j];
2060  buf2b[j] = 64 * bufu8b[j];
2061  }
2062 
2063  /* Dither */
2064  lined = datad + i * wpld;
2065  for (j = 0; j < w - 1; j++) {
2066  rval = buf1r[j] / 64;
2067  gval = buf1g[j] / 64;
2068  bval = buf1b[j] / 64;
2069  octindex = rtab[rval] | gtab[gval] | btab[bval];
2070  cmapindex = indexmap[octindex] - 1;
2071  SET_DATA_BYTE(lined, j, cmapindex);
2072  pixcmapGetColor(cmap, cmapindex, &rc, &gc, &bc);
2073 
2074  dif = buf1r[j] / 8 - 8 * rc;
2075  if (difcap > 0) {
2076  if (dif > difcap) dif = difcap;
2077  if (dif < -difcap) dif = -difcap;
2078  }
2079  if (dif != 0) {
2080  val1 = buf1r[j + 1] + 3 * dif;
2081  val2 = buf2r[j] + 3 * dif;
2082  val3 = buf2r[j + 1] + 2 * dif;
2083  if (dif > 0) {
2084  buf1r[j + 1] = L_MIN(16383, val1);
2085  buf2r[j] = L_MIN(16383, val2);
2086  buf2r[j + 1] = L_MIN(16383, val3);
2087  } else {
2088  buf1r[j + 1] = L_MAX(0, val1);
2089  buf2r[j] = L_MAX(0, val2);
2090  buf2r[j + 1] = L_MAX(0, val3);
2091  }
2092  }
2093 
2094  dif = buf1g[j] / 8 - 8 * gc;
2095  if (difcap > 0) {
2096  if (dif > difcap) dif = difcap;
2097  if (dif < -difcap) dif = -difcap;
2098  }
2099  if (dif != 0) {
2100  val1 = buf1g[j + 1] + 3 * dif;
2101  val2 = buf2g[j] + 3 * dif;
2102  val3 = buf2g[j + 1] + 2 * dif;
2103  if (dif > 0) {
2104  buf1g[j + 1] = L_MIN(16383, val1);
2105  buf2g[j] = L_MIN(16383, val2);
2106  buf2g[j + 1] = L_MIN(16383, val3);
2107  } else {
2108  buf1g[j + 1] = L_MAX(0, val1);
2109  buf2g[j] = L_MAX(0, val2);
2110  buf2g[j + 1] = L_MAX(0, val3);
2111  }
2112  }
2113 
2114  dif = buf1b[j] / 8 - 8 * bc;
2115  if (difcap > 0) {
2116  if (dif > difcap) dif = difcap;
2117  if (dif < -difcap) dif = -difcap;
2118  }
2119  if (dif != 0) {
2120  val1 = buf1b[j + 1] + 3 * dif;
2121  val2 = buf2b[j] + 3 * dif;
2122  val3 = buf2b[j + 1] + 2 * dif;
2123  if (dif > 0) {
2124  buf1b[j + 1] = L_MIN(16383, val1);
2125  buf2b[j] = L_MIN(16383, val2);
2126  buf2b[j + 1] = L_MIN(16383, val3);
2127  } else {
2128  buf1b[j + 1] = L_MAX(0, val1);
2129  buf2b[j] = L_MAX(0, val2);
2130  buf2b[j + 1] = L_MAX(0, val3);
2131  }
2132  }
2133  }
2134 
2135  /* Get last pixel in row; no downward propagation */
2136  rval = buf1r[w - 1] / 64;
2137  gval = buf1g[w - 1] / 64;
2138  bval = buf1b[w - 1] / 64;
2139  octindex = rtab[rval] | gtab[gval] | btab[bval];
2140  cmapindex = indexmap[octindex] - 1;
2141  SET_DATA_BYTE(lined, w - 1, cmapindex);
2142  }
2143 
2144  /* Get last row of pixels; no leftward propagation */
2145  lined = datad + (h - 1) * wpld;
2146  for (j = 0; j < w; j++) {
2147  rval = buf2r[j] / 64;
2148  gval = buf2g[j] / 64;
2149  bval = buf2b[j] / 64;
2150  octindex = rtab[rval] | gtab[gval] | btab[bval];
2151  cmapindex = indexmap[octindex] - 1;
2152  SET_DATA_BYTE(lined, j, cmapindex);
2153  }
2154 
2155 buffer_cleanup:
2156  LEPT_FREE(bufu8r);
2157  LEPT_FREE(bufu8g);
2158  LEPT_FREE(bufu8b);
2159  LEPT_FREE(buf1r);
2160  LEPT_FREE(buf1g);
2161  LEPT_FREE(buf1b);
2162  LEPT_FREE(buf2r);
2163  LEPT_FREE(buf2g);
2164  LEPT_FREE(buf2b);
2165 
2166  return (success) ? 0 : 1;
2167 }
2168 
2169 
2170 /*---------------------------------------------------------------------------*
2171  * Adaptive octree quantization to 4 and 8 bpp with max colors *
2172  *---------------------------------------------------------------------------*/
2262 PIX *
2264  l_int32 maxcolors,
2265  l_int32 subsample)
2266 {
2267 l_int32 w, h, minside, bpp, wpls, wpld, i, j, actualcolors;
2268 l_int32 rval, gval, bval, nbase, nextra, maxlevel, ncubes, val;
2269 l_int32 *lut1, *lut2;
2270 l_uint32 index;
2271 l_uint32 *lines, *lined, *datas, *datad, *pspixel;
2272 l_uint32 *rtab, *gtab, *btab;
2273 OQCELL *oqc;
2274 OQCELL **oqca;
2275 L_HEAP *lh;
2276 PIX *pixd;
2277 PIXCMAP *cmap;
2278 
2279  PROCNAME("pixOctreeQuantNumColors");
2280 
2281  if (!pixs)
2282  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2283  if (pixGetDepth(pixs) != 32)
2284  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
2285  if (maxcolors < 8) {
2286  L_WARNING("max colors < 8; setting to 8\n", procName);
2287  maxcolors = 8;
2288  }
2289  if (maxcolors > 256) {
2290  L_WARNING("max colors > 256; setting to 256\n", procName);
2291  maxcolors = 256;
2292  }
2293 
2294  pixGetDimensions(pixs, &w, &h, NULL);
2295  datas = pixGetData(pixs);
2296  wpls = pixGetWpl(pixs);
2297  minside = L_MIN(w, h);
2298  if (subsample <= 0) {
2299  subsample = L_MAX(1, minside / 200);
2300  }
2301 
2302  if (maxcolors <= 16) {
2303  bpp = 4;
2304  pixd = pixCreate(w, h, bpp);
2305  maxlevel = 2;
2306  ncubes = 64; /* 2^6 */
2307  nbase = 8;
2308  nextra = maxcolors - nbase;
2309  } else if (maxcolors <= 64) {
2310  bpp = 8;
2311  pixd = pixCreate(w, h, bpp);
2312  maxlevel = 2;
2313  ncubes = 64; /* 2^6 */
2314  nbase = 8;
2315  nextra = maxcolors - nbase;
2316  } else { /* maxcolors <= 256 */
2317  bpp = 8;
2318  pixd = pixCreate(w, h, bpp);
2319  maxlevel = 3;
2320  ncubes = 512; /* 2^9 */
2321  nbase = 64;
2322  nextra = maxcolors - nbase;
2323  }
2324 
2325  pixCopyResolution(pixd, pixs);
2326  pixCopyInputFormat(pixd, pixs);
2327 
2328  /*----------------------------------------------------------*
2329  * If we're using the minimum number of colors, it is *
2330  * much simpler. We just use 'nbase' octcubes. *
2331  * For this case, we don't eliminate any extra colors. *
2332  *----------------------------------------------------------*/
2333  if (nextra == 0) {
2334  /* prepare the OctcubeQuantCell array */
2335  if ((oqca = (OQCELL **)LEPT_CALLOC(nbase, sizeof(OQCELL *))) == NULL) {
2336  pixDestroy(&pixd);
2337  return (PIX *)ERROR_PTR("oqca not made", procName, NULL);
2338  }
2339  for (i = 0; i < nbase; i++) {
2340  oqca[i] = (OQCELL *)LEPT_CALLOC(1, sizeof(OQCELL));
2341  oqca[i]->n = 0.0;
2342  }
2343 
2344  rtab = gtab = btab = NULL;
2345  makeRGBToIndexTables(&rtab, &gtab, &btab, maxlevel - 1);
2346 
2347  /* Go through the entire image, gathering statistics and
2348  * assigning pixels to their quantized value */
2349  datad = pixGetData(pixd);
2350  wpld = pixGetWpl(pixd);
2351  for (i = 0; i < h; i++) {
2352  lines = datas + i * wpls;
2353  lined = datad + i * wpld;
2354  for (j = 0; j < w; j++) {
2355  pspixel = lines + j;
2356  extractRGBValues(*pspixel, &rval, &gval, &bval);
2357  getOctcubeIndexFromRGB(rval, gval, bval,
2358  rtab, gtab, btab, &index);
2359 /* fprintf(stderr, "rval = %d, gval = %d, bval = %d,"
2360  " index = %d\n", rval, gval, bval, index); */
2361  if (bpp == 4)
2362  SET_DATA_QBIT(lined, j, index);
2363  else /* bpp == 8 */
2364  SET_DATA_BYTE(lined, j, index);
2365  oqca[index]->n += 1.0;
2366  oqca[index]->rcum += rval;
2367  oqca[index]->gcum += gval;
2368  oqca[index]->bcum += bval;
2369  }
2370  }
2371 
2372  /* Compute average color values in each octcube, and
2373  * generate colormap */
2374  cmap = pixcmapCreate(bpp);
2375  pixSetColormap(pixd, cmap);
2376  for (i = 0; i < nbase; i++) {
2377  oqc = oqca[i];
2378  if (oqc->n != 0) {
2379  oqc->rval = (l_int32)(oqc->rcum / oqc->n);
2380  oqc->gval = (l_int32)(oqc->gcum / oqc->n);
2381  oqc->bval = (l_int32)(oqc->bcum / oqc->n);
2382  } else {
2383  getRGBFromOctcube(i, maxlevel - 1, &oqc->rval,
2384  &oqc->gval, &oqc->bval);
2385  }
2386  pixcmapAddColor(cmap, oqc->rval, oqc->gval, oqc->bval);
2387  }
2388 
2389  for (i = 0; i < nbase; i++)
2390  LEPT_FREE(oqca[i]);
2391  LEPT_FREE(oqca);
2392  LEPT_FREE(rtab);
2393  LEPT_FREE(gtab);
2394  LEPT_FREE(btab);
2395  return pixd;
2396  }
2397 
2398  /*------------------------------------------------------------*
2399  * General case: we will use colors in octcubes at maxlevel. *
2400  * We also remove any colors that are not populated from *
2401  * the colormap. *
2402  *------------------------------------------------------------*/
2403  /* Prepare the OctcubeQuantCell array */
2404  if ((oqca = (OQCELL **)LEPT_CALLOC(ncubes, sizeof(OQCELL *))) == NULL) {
2405  pixDestroy(&pixd);
2406  return (PIX *)ERROR_PTR("oqca not made", procName, NULL);
2407  }
2408  for (i = 0; i < ncubes; i++) {
2409  oqca[i] = (OQCELL *)LEPT_CALLOC(1, sizeof(OQCELL));
2410  oqca[i]->n = 0.0;
2411  }
2412 
2413  /* Make the tables to map color to the octindex,
2414  * of which there are 'ncubes' at 'maxlevel' */
2415  rtab = gtab = btab = NULL;
2416  makeRGBToIndexTables(&rtab, &gtab, &btab, maxlevel);
2417 
2418  /* Estimate the color distribution; we want to find the
2419  * most popular nextra colors at 'maxlevel' */
2420  for (i = 0; i < h; i += subsample) {
2421  lines = datas + i * wpls;
2422  for (j = 0; j < w; j += subsample) {
2423  pspixel = lines + j;
2424  extractRGBValues(*pspixel, &rval, &gval, &bval);
2425  getOctcubeIndexFromRGB(rval, gval, bval, rtab, gtab, btab, &index);
2426  oqca[index]->n += 1.0;
2427  oqca[index]->octindex = index;
2428  oqca[index]->rcum += rval;
2429  oqca[index]->gcum += gval;
2430  oqca[index]->bcum += bval;
2431  }
2432  }
2433 
2434  /* Transfer the OQCELL from the array, and order in a heap */
2435  lh = lheapCreate(512, L_SORT_DECREASING);
2436  for (i = 0; i < ncubes; i++)
2437  lheapAdd(lh, oqca[i]);
2438  LEPT_FREE(oqca); /* don't need this array */
2439 
2440  /* Prepare a new OctcubeQuantCell array, with maxcolors cells */
2441  oqca = (OQCELL **)LEPT_CALLOC(maxcolors, sizeof(OQCELL *));
2442  for (i = 0; i < nbase; i++) { /* make nbase cells */
2443  oqca[i] = (OQCELL *)LEPT_CALLOC(1, sizeof(OQCELL));
2444  oqca[i]->n = 0.0;
2445  }
2446 
2447  /* Remove the nextra most populated ones, and put them in the array */
2448  for (i = 0; i < nextra; i++) {
2449  oqc = (OQCELL *)lheapRemove(lh);
2450  oqc->n = 0.0; /* reinit */
2451  oqc->rcum = 0;
2452  oqc->gcum = 0;
2453  oqc->bcum = 0;
2454  oqca[nbase + i] = oqc; /* store it in the array */
2455  }
2456 
2457  /* Destroy the heap and its remaining contents */
2458  lheapDestroy(&lh, TRUE);
2459 
2460  /* Generate a lookup table from octindex at maxlevel
2461  * to color table index */
2462  lut1 = (l_int32 *)LEPT_CALLOC(ncubes, sizeof(l_int32));
2463  for (i = 0; i < nextra; i++)
2464  lut1[oqca[nbase + i]->octindex] = nbase + i;
2465  for (index = 0; index < ncubes; index++) {
2466  if (lut1[index] == 0) /* not one of the extras; need to assign */
2467  lut1[index] = index >> 3; /* remove the least significant bits */
2468 /* fprintf(stderr, "lut1[%d] = %d\n", index, lut1[index]); */
2469  }
2470 
2471  /* Go through the entire image, gathering statistics and
2472  * assigning pixels to their quantized value */
2473  datad = pixGetData(pixd);
2474  wpld = pixGetWpl(pixd);
2475  for (i = 0; i < h; i++) {
2476  lines = datas + i * wpls;
2477  lined = datad + i * wpld;
2478  for (j = 0; j < w; j++) {
2479  pspixel = lines + j;
2480  extractRGBValues(*pspixel, &rval, &gval, &bval);
2481  getOctcubeIndexFromRGB(rval, gval, bval, rtab, gtab, btab, &index);
2482 /* fprintf(stderr, "rval = %d, gval = %d, bval = %d, index = %d\n",
2483  rval, gval, bval, index); */
2484  val = lut1[index];
2485  switch (bpp) {
2486  case 4:
2487  SET_DATA_QBIT(lined, j, val);
2488  break;
2489  case 8:
2490  SET_DATA_BYTE(lined, j, val);
2491  break;
2492  default:
2493  LEPT_FREE(oqca);
2494  LEPT_FREE(lut1);
2495  return (PIX *)ERROR_PTR("bpp not 4 or 8!", procName, NULL);
2496  break;
2497  }
2498  oqca[val]->n += 1.0;
2499  oqca[val]->rcum += rval;
2500  oqca[val]->gcum += gval;
2501  oqca[val]->bcum += bval;
2502  }
2503  }
2504 
2505  /* Compute averages, set up a colormap, and make a second
2506  * lut that converts from the color values currently in
2507  * the image to a minimal set */
2508  lut2 = (l_int32 *)LEPT_CALLOC(ncubes, sizeof(l_int32));
2509  cmap = pixcmapCreate(bpp);
2510  pixSetColormap(pixd, cmap);
2511  for (i = 0, index = 0; i < maxcolors; i++) {
2512  oqc = oqca[i];
2513  lut2[i] = index;
2514  if (oqc->n == 0) /* no occupancy; don't bump up index */
2515  continue;
2516  oqc->rval = (l_int32)(oqc->rcum / oqc->n);
2517  oqc->gval = (l_int32)(oqc->gcum / oqc->n);
2518  oqc->bval = (l_int32)(oqc->bcum / oqc->n);
2519  pixcmapAddColor(cmap, oqc->rval, oqc->gval, oqc->bval);
2520  index++;
2521  }
2522 /* pixcmapWriteStream(stderr, cmap); */
2523  actualcolors = pixcmapGetCount(cmap);
2524 /* fprintf(stderr, "Number of different colors = %d\n", actualcolors); */
2525 
2526  /* Last time through the image; use the lookup table to
2527  * remap the pixel value to the minimal colormap */
2528  if (actualcolors < maxcolors) {
2529  for (i = 0; i < h; i++) {
2530  lined = datad + i * wpld;
2531  for (j = 0; j < w; j++) {
2532  switch (bpp) {
2533  case 4:
2534  val = GET_DATA_QBIT(lined, j);
2535  SET_DATA_QBIT(lined, j, lut2[val]);
2536  break;
2537  case 8:
2538  val = GET_DATA_BYTE(lined, j);
2539  SET_DATA_BYTE(lined, j, lut2[val]);
2540  break;
2541  }
2542  }
2543  }
2544  }
2545 
2546  if (oqca) {
2547  for (i = 0; i < maxcolors; i++)
2548  LEPT_FREE(oqca[i]);
2549  }
2550  LEPT_FREE(oqca);
2551  LEPT_FREE(lut1);
2552  LEPT_FREE(lut2);
2553  LEPT_FREE(rtab);
2554  LEPT_FREE(gtab);
2555  LEPT_FREE(btab);
2556  return pixd;
2557 }
2558 
2559 
2560 /*-------------------------------------------------------------------------*
2561  * Mixed color/gray quantization with specified number of colors *
2562  *-------------------------------------------------------------------------*/
2592 PIX *
2594  l_int32 depth,
2595  l_int32 graylevels,
2596  l_int32 delta)
2597 {
2598 l_int32 w, h, wpls, wpld, i, j, size, octlevels;
2599 l_int32 rval, gval, bval, del, val, midval;
2600 l_int32 *carray, *rarray, *garray, *barray;
2601 l_int32 *tabval;
2602 l_uint32 octindex;
2603 l_uint32 *rtab, *gtab, *btab;
2604 l_uint32 *lines, *lined, *datas, *datad;
2605 PIX *pixd;
2606 PIXCMAP *cmap;
2607 
2608  PROCNAME("pixOctcubeQuantMixedWithGray");
2609 
2610  if (!pixs)
2611  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2612  if (pixGetDepth(pixs) != 32)
2613  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
2614  if (graylevels < 2)
2615  return (PIX *)ERROR_PTR("invalid graylevels", procName, NULL);
2616  if (depth == 4) {
2617  octlevels = 1;
2618  size = 8; /* 2 ** 3 */
2619  if (graylevels > 8)
2620  return (PIX *)ERROR_PTR("max 8 gray levels", procName, NULL);
2621  } else if (depth == 8) {
2622  octlevels = 2;
2623  size = 64; /* 2 ** 6 */
2624  if (graylevels > 192)
2625  return (PIX *)ERROR_PTR("max 192 gray levels", procName, NULL);
2626  } else {
2627  return (PIX *)ERROR_PTR("output depth not 4 or 8 bpp", procName, NULL);
2628  }
2629 
2630  pixd = NULL;
2631 
2632  /* Make octcube index tables */
2633  rtab = gtab = btab = NULL;
2634  makeRGBToIndexTables(&rtab, &gtab, &btab, octlevels);
2635 
2636  /* Make octcube arrays for storing points in each cube */
2637  carray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
2638  rarray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
2639  garray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
2640  barray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
2641 
2642  /* Make lookup table, using computed thresholds */
2643  tabval = makeGrayQuantIndexTable(graylevels);
2644  if (!rtab || !gtab || !btab ||
2645  !carray || !rarray || !garray || !barray || !tabval) {
2646  L_ERROR("calloc fail for an array\n", procName);
2647  goto array_cleanup;
2648  }
2649 
2650  /* Make colormapped output pixd */
2651  pixGetDimensions(pixs, &w, &h, NULL);
2652  if ((pixd = pixCreate(w, h, depth)) == NULL) {
2653  L_ERROR("pixd not made\n", procName);
2654  goto array_cleanup;
2655  }
2656  pixCopyResolution(pixd, pixs);
2657  pixCopyInputFormat(pixd, pixs);
2658  cmap = pixcmapCreate(depth);
2659  for (j = 0; j < size; j++) /* reserve octcube colors */
2660  pixcmapAddColor(cmap, 1, 1, 1); /* a color that won't be used */
2661  for (j = 0; j < graylevels; j++) { /* set grayscale colors */
2662  val = (255 * j) / (graylevels - 1);
2663  pixcmapAddColor(cmap, val, val, val);
2664  }
2665  pixSetColormap(pixd, cmap);
2666  wpld = pixGetWpl(pixd);
2667  datad = pixGetData(pixd);
2668 
2669  /* Go through src image: assign dest pixels to colormap values
2670  * and compute average colors in each occupied octcube */
2671  datas = pixGetData(pixs);
2672  wpls = pixGetWpl(pixs);
2673  for (i = 0; i < h; i++) {
2674  lines = datas + i * wpls;
2675  lined = datad + i * wpld;
2676  for (j = 0; j < w; j++) {
2677  extractRGBValues(lines[j], &rval, &gval, &bval);
2678  if (rval > gval) {
2679  if (gval > bval) { /* r > g > b */
2680  del = rval - bval;
2681  midval = gval;
2682  } else if (rval > bval) { /* r > b > g */
2683  del = rval - gval;
2684  midval = bval;
2685  } else { /* b > r > g */
2686  del = bval - gval;
2687  midval = rval;
2688  }
2689  } else { /* gval >= rval */
2690  if (rval > bval) { /* g > r > b */
2691  del = gval - bval;
2692  midval = rval;
2693  } else if (gval > bval) { /* g > b > r */
2694  del = gval - rval;
2695  midval = bval;
2696  } else { /* b > g > r */
2697  del = bval - rval;
2698  midval = gval;
2699  }
2700  }
2701  if (del > delta) { /* assign to color */
2702  octindex = rtab[rval] | gtab[gval] | btab[bval];
2703  carray[octindex]++;
2704  rarray[octindex] += rval;
2705  garray[octindex] += gval;
2706  barray[octindex] += bval;
2707  if (depth == 4)
2708  SET_DATA_QBIT(lined, j, octindex);
2709  else /* depth == 8 */
2710  SET_DATA_BYTE(lined, j, octindex);
2711  } else { /* assign to grayscale */
2712  val = size + tabval[midval];
2713  if (depth == 4)
2714  SET_DATA_QBIT(lined, j, val);
2715  else /* depth == 8 */
2716  SET_DATA_BYTE(lined, j, val);
2717  }
2718  }
2719  }
2720 
2721  /* Average the colors in each bin and reset the colormap */
2722  for (i = 0; i < size; i++) {
2723  if (carray[i] > 0) {
2724  rarray[i] /= carray[i];
2725  garray[i] /= carray[i];
2726  barray[i] /= carray[i];
2727  pixcmapResetColor(cmap, i, rarray[i], garray[i], barray[i]);
2728  }
2729  }
2730 
2731 array_cleanup:
2732  LEPT_FREE(carray);
2733  LEPT_FREE(rarray);
2734  LEPT_FREE(garray);
2735  LEPT_FREE(barray);
2736  LEPT_FREE(rtab);
2737  LEPT_FREE(gtab);
2738  LEPT_FREE(btab);
2739  LEPT_FREE(tabval);
2740 
2741  return pixd;
2742 }
2743 
2744 
2745 /*-------------------------------------------------------------------------*
2746  * Fixed partition octcube quantization with 256 cells *
2747  *-------------------------------------------------------------------------*/
2811 PIX *
2813  l_int32 ditherflag)
2814 {
2815 l_uint8 index;
2816 l_int32 rval, gval, bval;
2817 l_int32 w, h, wpls, wpld, i, j, cindex;
2818 l_uint32 *rtab, *gtab, *btab;
2819 l_int32 *itab;
2820 l_uint32 *datas, *datad, *lines, *lined;
2821 PIX *pixd;
2822 PIXCMAP *cmap;
2823 
2824  PROCNAME("pixFixedOctcubeQuant256");
2825 
2826  if (!pixs)
2827  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2828  if (pixGetDepth(pixs) != 32)
2829  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
2830 
2831  /* Do not dither if image is very small */
2832  pixGetDimensions(pixs, &w, &h, NULL);
2833  if (w < MIN_DITHER_SIZE && h < MIN_DITHER_SIZE && ditherflag == 1) {
2834  L_INFO("Small image: dithering turned off\n", procName);
2835  ditherflag = 0;
2836  }
2837 
2838  /* Find the centers of the 256 cells, each of which represents
2839  * the 3 MSBits of the red and green components, and the
2840  * 2 MSBits of the blue component. This gives a mapping
2841  * from a "cube index" to the rgb values. Save all 256
2842  * rgb values of these centers in a colormap.
2843  * For example, to get the red color of the cell center,
2844  * you take the 3 MSBits of to the index and add the
2845  * offset to the center of the cell, which is 0x10. */
2846  cmap = pixcmapCreate(8);
2847  for (cindex = 0; cindex < 256; cindex++) {
2848  rval = (cindex & 0xe0) | 0x10;
2849  gval = ((cindex << 3) & 0xe0) | 0x10;
2850  bval = ((cindex << 6) & 0xc0) | 0x20;
2851  pixcmapAddColor(cmap, rval, gval, bval);
2852  }
2853 
2854  /* Make output 8 bpp palette image */
2855  datas = pixGetData(pixs);
2856  wpls = pixGetWpl(pixs);
2857  if ((pixd = pixCreate(w, h, 8)) == NULL) {
2858  pixcmapDestroy(&cmap);
2859  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2860  }
2861  pixSetColormap(pixd, cmap);
2862  pixCopyResolution(pixd, pixs);
2863  pixCopyInputFormat(pixd, pixs);
2864  datad = pixGetData(pixd);
2865  wpld = pixGetWpl(pixd);
2866 
2867  /* Set dest pix values to colortable indices */
2868  if (ditherflag == 0) { /* no dithering */
2869  for (i = 0; i < h; i++) {
2870  lines = datas + i * wpls;
2871  lined = datad + i * wpld;
2872  for (j = 0; j < w; j++) {
2873  extractRGBValues(lines[j], &rval, &gval, &bval);
2874  index = (rval & 0xe0) | ((gval >> 3) & 0x1c) | (bval >> 6);
2875  SET_DATA_BYTE(lined, j, index);
2876  }
2877  }
2878  } else { /* ditherflag == 1 */
2879  /* Set up conversion tables from rgb directly to the colormap
2880  * index. However, the dithering function expects these tables
2881  * to generate an octcube index (+1), and the table itab[] to
2882  * convert to the colormap index. So we make a trivial
2883  * itab[], that simply compensates for the -1 in
2884  * pixDitherOctindexWithCmap(). No cap is required on
2885  * the propagated difference. */
2886  rtab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
2887  gtab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
2888  btab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
2889  itab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
2890  if (!rtab || !gtab || !btab || !itab) {
2891  pixDestroy(&pixd);
2892  return (PIX *)ERROR_PTR("calloc fail for table", procName, NULL);
2893  }
2894  for (i = 0; i < 256; i++) {
2895  rtab[i] = i & 0xe0;
2896  gtab[i] = (i >> 3) & 0x1c;
2897  btab[i] = i >> 6;
2898  itab[i] = i + 1;
2899  }
2900  pixDitherOctindexWithCmap(pixs, pixd, rtab, gtab, btab, itab,
2901  FIXED_DIF_CAP);
2902  LEPT_FREE(rtab);
2903  LEPT_FREE(gtab);
2904  LEPT_FREE(btab);
2905  LEPT_FREE(itab);
2906  }
2907 
2908  return pixd;
2909 }
2910 
2911 
2912 /*---------------------------------------------------------------------------*
2913  * Nearly exact quantization for images with few colors *
2914  *---------------------------------------------------------------------------*/
2945 PIX *
2947  l_int32 level)
2948 {
2949 l_int32 w, h, wpls, wpld, i, j, depth, size, ncolors, index;
2950 l_int32 rval, gval, bval;
2951 l_int32 *carray, *rarray, *garray, *barray;
2952 l_uint32 octindex;
2953 l_uint32 *rtab, *gtab, *btab;
2954 l_uint32 *lines, *lined, *datas, *datad, *pspixel;
2955 PIX *pixd;
2956 PIXCMAP *cmap;
2957 
2958  PROCNAME("pixFewColorsOctcubeQuant1");
2959 
2960  if (!pixs)
2961  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2962  if (pixGetDepth(pixs) != 32)
2963  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
2964  if (level < 1 || level > 6)
2965  return (PIX *)ERROR_PTR("invalid level", procName, NULL);
2966 
2967  pixd = NULL;
2968 
2969  if (octcubeGetCount(level, &size)) /* array size = 2 ** (3 * level) */
2970  return (PIX *)ERROR_PTR("size not returned", procName, NULL);
2971  rtab = gtab = btab = NULL;
2972  makeRGBToIndexTables(&rtab, &gtab, &btab, level);
2973 
2974  carray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
2975  rarray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
2976  garray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
2977  barray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32));
2978  if (!carray || !rarray || !garray || !barray) {
2979  L_ERROR("calloc fail for an array\n", procName);
2980  goto array_cleanup;
2981  }
2982 
2983  /* Place the pixels in octcube leaves. */
2984  pixGetDimensions(pixs, &w, &h, NULL);
2985  datas = pixGetData(pixs);
2986  wpls = pixGetWpl(pixs);
2987  for (i = 0; i < h; i++) {
2988  lines = datas + i * wpls;
2989  for (j = 0; j < w; j++) {
2990  pspixel = lines + j;
2991  extractRGBValues(*pspixel, &rval, &gval, &bval);
2992  octindex = rtab[rval] | gtab[gval] | btab[bval];
2993  carray[octindex]++;
2994  rarray[octindex] += rval;
2995  garray[octindex] += gval;
2996  barray[octindex] += bval;
2997  }
2998  }
2999 
3000  /* Find the number of different colors */
3001  for (i = 0, ncolors = 0; i < size; i++) {
3002  if (carray[i] > 0)
3003  ncolors++;
3004  }
3005  if (ncolors > 256) {
3006  L_WARNING("%d colors found; more than 256\n", procName, ncolors);
3007  goto array_cleanup;
3008  }
3009  if (ncolors <= 4)
3010  depth = 2;
3011  else if (ncolors <= 16)
3012  depth = 4;
3013  else
3014  depth = 8;
3015 
3016  /* Average the colors in each octcube leaf and add to colormap table;
3017  * then use carray to hold the colormap index + 1 */
3018  cmap = pixcmapCreate(depth);
3019  for (i = 0, index = 0; i < size; i++) {
3020  if (carray[i] > 0) {
3021  rarray[i] /= carray[i];
3022  garray[i] /= carray[i];
3023  barray[i] /= carray[i];
3024  pixcmapAddColor(cmap, rarray[i], garray[i], barray[i]);
3025  carray[i] = index + 1; /* to avoid storing 0 */
3026  index++;
3027  }
3028  }
3029 
3030  pixd = pixCreate(w, h, depth);
3031  pixSetColormap(pixd, cmap);
3032  pixCopyResolution(pixd, pixs);
3033  pixCopyInputFormat(pixd, pixs);
3034  datad = pixGetData(pixd);
3035  wpld = pixGetWpl(pixd);
3036  for (i = 0; i < h; i++) {
3037  lines = datas + i * wpls;
3038  lined = datad + i * wpld;
3039  for (j = 0; j < w; j++) {
3040  pspixel = lines + j;
3041  extractRGBValues(*pspixel, &rval, &gval, &bval);
3042  octindex = rtab[rval] | gtab[gval] | btab[bval];
3043  switch (depth)
3044  {
3045  case 2:
3046  SET_DATA_DIBIT(lined, j, carray[octindex] - 1);
3047  break;
3048  case 4:
3049  SET_DATA_QBIT(lined, j, carray[octindex] - 1);
3050  break;
3051  case 8:
3052  SET_DATA_BYTE(lined, j, carray[octindex] - 1);
3053  break;
3054  default:
3055  L_WARNING("shouldn't get here\n", procName);
3056  }
3057  }
3058  }
3059 
3060 array_cleanup:
3061  LEPT_FREE(carray);
3062  LEPT_FREE(rarray);
3063  LEPT_FREE(garray);
3064  LEPT_FREE(barray);
3065  LEPT_FREE(rtab);
3066  LEPT_FREE(gtab);
3067  LEPT_FREE(btab);
3068  return pixd;
3069 }
3070 
3071 
3115 PIX *
3117  l_int32 level,
3118  NUMA *na,
3119  l_int32 ncolors,
3120  l_int32 *pnerrors)
3121 {
3122 l_int32 w, h, wpls, wpld, i, j, nerrors;
3123 l_int32 ncubes, depth, cindex, oval;
3124 l_int32 rval, gval, bval;
3125 l_int32 *octarray;
3126 l_uint32 octindex;
3127 l_uint32 *rtab, *gtab, *btab;
3128 l_uint32 *lines, *lined, *datas, *datad, *ppixel;
3129 l_uint32 *colorarray;
3130 PIX *pixd;
3131 PIXCMAP *cmap;
3132 
3133  PROCNAME("pixFewColorsOctcubeQuant2");
3134 
3135  if (!pixs)
3136  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3137  if (pixGetDepth(pixs) != 32)
3138  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
3139  if (level < 3 || level > 6)
3140  return (PIX *)ERROR_PTR("level not in {4, 5, 6}", procName, NULL);
3141  if (ncolors > 256)
3142  return (PIX *)ERROR_PTR("ncolors > 256", procName, NULL);
3143  if (pnerrors)
3144  *pnerrors = UNDEF;
3145 
3146  pixd = NULL;
3147 
3148  /* Represent the image with a set of leaf octcubes
3149  * at 'level', one for each color. */
3150  rtab = gtab = btab = NULL;
3151  makeRGBToIndexTables(&rtab, &gtab, &btab, level);
3152 
3153  /* The octarray will give a ptr from the octcube to the colorarray */
3154  ncubes = numaGetCount(na);
3155  octarray = (l_int32 *)LEPT_CALLOC(ncubes, sizeof(l_int32));
3156 
3157  /* The colorarray will hold the colors of the first pixel
3158  * that lands in the leaf octcube. After filling, it is
3159  * used to generate the colormap. */
3160  colorarray = (l_uint32 *)LEPT_CALLOC(ncolors + 1, sizeof(l_uint32));
3161  if (!octarray || !colorarray) {
3162  L_ERROR("octarray or colorarray not made\n", procName);
3163  goto cleanup_arrays;
3164  }
3165 
3166  /* Determine the output depth from the number of colors */
3167  pixGetDimensions(pixs, &w, &h, NULL);
3168  datas = pixGetData(pixs);
3169  wpls = pixGetWpl(pixs);
3170  if (ncolors <= 4)
3171  depth = 2;
3172  else if (ncolors <= 16)
3173  depth = 4;
3174  else /* ncolors <= 256 */
3175  depth = 8;
3176 
3177  if ((pixd = pixCreate(w, h, depth)) == NULL) {
3178  L_ERROR("pixd not made\n", procName);
3179  goto cleanup_arrays;
3180  }
3181  pixCopyResolution(pixd, pixs);
3182  pixCopyInputFormat(pixd, pixs);
3183  datad = pixGetData(pixd);
3184  wpld = pixGetWpl(pixd);
3185 
3186  /* For each pixel, get the octree index for its leaf octcube.
3187  * Check if a pixel has already been found in this octcube.
3188  * ~ If not yet found, save that color in the colorarray
3189  * and save the cindex in the octarray.
3190  * ~ If already found, compare the pixel color with the
3191  * color in the colorarray, and note if it differs.
3192  * Then set the dest pixel value to the cindex - 1, which
3193  * will be the cmap index for this color. */
3194  cindex = 1; /* start with 1 */
3195  nerrors = 0;
3196  for (i = 0; i < h; i++) {
3197  lines = datas + i * wpls;
3198  lined = datad + i * wpld;
3199  for (j = 0; j < w; j++) {
3200  ppixel = lines + j;
3201  extractRGBValues(*ppixel, &rval, &gval, &bval);
3202  octindex = rtab[rval] | gtab[gval] | btab[bval];
3203  oval = octarray[octindex];
3204  if (oval == 0) {
3205  octarray[octindex] = cindex;
3206  colorarray[cindex] = *ppixel;
3207  setPixelLow(lined, j, depth, cindex - 1);
3208  cindex++;
3209  } else { /* already have seen this color; is it unique? */
3210  setPixelLow(lined, j, depth, oval - 1);
3211  if (colorarray[oval] != *ppixel)
3212  nerrors++;
3213  }
3214  }
3215  }
3216  if (pnerrors)
3217  *pnerrors = nerrors;
3218 
3219 #if DEBUG_FEW_COLORS
3220  fprintf(stderr, "ncubes = %d, ncolors = %d\n", ncubes, ncolors);
3221  for (i = 0; i < ncolors; i++)
3222  fprintf(stderr, "color[%d] = %x\n", i, colorarray[i + 1]);
3223 #endif /* DEBUG_FEW_COLORS */
3224 
3225  /* Make the colormap. */
3226  cmap = pixcmapCreate(depth);
3227  for (i = 0; i < ncolors; i++) {
3228  ppixel = colorarray + i + 1;
3229  extractRGBValues(*ppixel, &rval, &gval, &bval);
3230  pixcmapAddColor(cmap, rval, gval, bval);
3231  }
3232  pixSetColormap(pixd, cmap);
3233 
3234 cleanup_arrays:
3235  LEPT_FREE(octarray);
3236  LEPT_FREE(colorarray);
3237  LEPT_FREE(rtab);
3238  LEPT_FREE(gtab);
3239  LEPT_FREE(btab);
3240 
3241  return pixd;
3242 }
3243 
3244 
3304 PIX *
3306  l_int32 level,
3307  l_int32 darkthresh,
3308  l_int32 lightthresh,
3309  l_int32 diffthresh,
3310  l_float32 minfract,
3311  l_int32 maxspan)
3312 {
3313 l_int32 i, j, w, h, wplc, wplm, wpld, ncolors, index;
3314 l_int32 rval, gval, bval, val, minval, maxval;
3315 l_int32 *lut;
3316 l_uint32 *datac, *datam, *datad, *linec, *linem, *lined;
3317 PIX *pixc, *pixm, *pixg, *pixd;
3318 PIXCMAP *cmap, *cmapd;
3319 
3320  PROCNAME("pixFewColorsOctcubeQuantMixed");
3321 
3322  if (!pixs || pixGetDepth(pixs) != 32)
3323  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
3324  if (level <= 0) level = 3;
3325  if (level > 6)
3326  return (PIX *)ERROR_PTR("invalid level", procName, NULL);
3327  if (darkthresh <= 0) darkthresh = 20;
3328  if (lightthresh <= 0) lightthresh = 244;
3329  if (diffthresh <= 0) diffthresh = 20;
3330  if (minfract <= 0.0) minfract = 0.05;
3331  if (maxspan <= 2) maxspan = 15;
3332 
3333  /* Start with a simple fixed octcube quantizer. */
3334  if ((pixc = pixFewColorsOctcubeQuant1(pixs, level)) == NULL)
3335  return (PIX *)ERROR_PTR("too many colors", procName, NULL);
3336 
3337  /* Identify and save color entries in the colormap. Set up a LUT
3338  * that returns -1 for any gray pixel. */
3339  cmap = pixGetColormap(pixc);
3340  ncolors = pixcmapGetCount(cmap);
3341  cmapd = pixcmapCreate(8);
3342  lut = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
3343  for (i = 0; i < 256; i++)
3344  lut[i] = -1;
3345  for (i = 0, index = 0; i < ncolors; i++) {
3346  pixcmapGetColor(cmap, i, &rval, &gval, &bval);
3347  minval = L_MIN(rval, gval);
3348  minval = L_MIN(minval, bval);
3349  if (minval > lightthresh) /* near white */
3350  continue;
3351  maxval = L_MAX(rval, gval);
3352  maxval = L_MAX(maxval, bval);
3353  if (maxval < darkthresh) /* near black */
3354  continue;
3355 
3356  /* Use the max diff between components to test for color */
3357  if (maxval - minval >= diffthresh) {
3358  pixcmapAddColor(cmapd, rval, gval, bval);
3359  lut[i] = index;
3360  index++;
3361  }
3362  }
3363 
3364  /* Generate dest pix with just the color pixels set to their
3365  * colormap indices. At the same time, make a 1 bpp mask
3366  * of the non-color pixels */
3367  pixGetDimensions(pixs, &w, &h, NULL);
3368  pixd = pixCreate(w, h, 8);
3369  pixSetColormap(pixd, cmapd);
3370  pixm = pixCreate(w, h, 1);
3371  datac = pixGetData(pixc);
3372  datam = pixGetData(pixm);
3373  datad = pixGetData(pixd);
3374  wplc = pixGetWpl(pixc);
3375  wplm = pixGetWpl(pixm);
3376  wpld = pixGetWpl(pixd);
3377  for (i = 0; i < h; i++) {
3378  linec = datac + i * wplc;
3379  linem = datam + i * wplm;
3380  lined = datad + i * wpld;
3381  for (j = 0; j < w; j++) {
3382  val = GET_DATA_BYTE(linec, j);
3383  if (lut[val] == -1)
3384  SET_DATA_BIT(linem, j);
3385  else
3386  SET_DATA_BYTE(lined, j, lut[val]);
3387  }
3388  }
3389 
3390  /* Fill in the gray values. Use a grayscale version of pixs
3391  * as input, along with the mask over the actual gray pixels. */
3392  pixg = pixConvertTo8(pixs, 0);
3393  pixGrayQuantFromHisto(pixd, pixg, pixm, minfract, maxspan);
3394 
3395  LEPT_FREE(lut);
3396  pixDestroy(&pixc);
3397  pixDestroy(&pixm);
3398  pixDestroy(&pixg);
3399  return pixd;
3400 }
3401 
3402 
3403 /*---------------------------------------------------------------------------*
3404  * Fixed partition octcube quantization with RGB output *
3405  *---------------------------------------------------------------------------*/
3422 PIX *
3424  l_int32 level)
3425 {
3426 l_int32 w, h, wpls, wpld, i, j;
3427 l_int32 rval, gval, bval;
3428 l_uint32 octindex;
3429 l_uint32 *rtab, *gtab, *btab;
3430 l_uint32 *lines, *lined, *datas, *datad;
3431 PIX *pixd;
3432 
3433  PROCNAME("pixFixedOctcubeQuantGenRGB");
3434 
3435  if (!pixs)
3436  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3437  if (pixGetDepth(pixs) != 32)
3438  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
3439  if (level < 1 || level > 6)
3440  return (PIX *)ERROR_PTR("level not in {1,...6}", procName, NULL);
3441 
3442  if (makeRGBToIndexTables(&rtab, &gtab, &btab, level))
3443  return (PIX *)ERROR_PTR("tables not made", procName, NULL);
3444 
3445  pixGetDimensions(pixs, &w, &h, NULL);
3446  pixd = pixCreate(w, h, 32);
3447  pixCopyResolution(pixd, pixs);
3448  pixCopyInputFormat(pixd, pixs);
3449  datad = pixGetData(pixd);
3450  wpld = pixGetWpl(pixd);
3451  datas = pixGetData(pixs);
3452  wpls = pixGetWpl(pixs);
3453  for (i = 0; i < h; i++) {
3454  lines = datas + i * wpls;
3455  lined = datad + i * wpld;
3456  for (j = 0; j < w; j++) {
3457  extractRGBValues(lines[j], &rval, &gval, &bval);
3458  octindex = rtab[rval] | gtab[gval] | btab[bval];
3459  getRGBFromOctcube(octindex, level, &rval, &gval, &bval);
3460  composeRGBPixel(rval, gval, bval, lined + j);
3461  }
3462  }
3463 
3464  LEPT_FREE(rtab);
3465  LEPT_FREE(gtab);
3466  LEPT_FREE(btab);
3467  return pixd;
3468 }
3469 
3470 
3471 /*------------------------------------------------------------------*
3472  * Color quantize RGB image using existing colormap *
3473  *------------------------------------------------------------------*/
3495 PIX *
3497  PIXCMAP *cmap,
3498  l_int32 mindepth,
3499  l_int32 level,
3500  l_int32 metric)
3501 {
3502 l_int32 d;
3503 
3504  PROCNAME("pixQuantFromCmap");
3505 
3506  if (!pixs)
3507  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3508  if (mindepth != 2 && mindepth != 4 && mindepth != 8)
3509  return (PIX *)ERROR_PTR("invalid mindepth", procName, NULL);
3510  d = pixGetDepth(pixs);
3511  if (d == 8)
3512  return pixGrayQuantFromCmap(pixs, cmap, mindepth);
3513  else if (d == 32)
3514  return pixOctcubeQuantFromCmap(pixs, cmap, mindepth,
3515  level, metric);
3516  else
3517  return (PIX *)ERROR_PTR("d not 8 or 32 bpp", procName, NULL);
3518 }
3519 
3520 
3521 
3584 PIX *
3586  PIXCMAP *cmap,
3587  l_int32 mindepth,
3588  l_int32 level,
3589  l_int32 metric)
3590 {
3591 l_int32 *cmaptab;
3592 l_uint32 *rtab, *gtab, *btab;
3593 PIX *pixd;
3594 
3595  PROCNAME("pixOctcubeQuantFromCmap");
3596 
3597  if (!pixs)
3598  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3599  if (pixGetDepth(pixs) != 32)
3600  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
3601  if (!cmap)
3602  return (PIX *)ERROR_PTR("cmap not defined", procName, NULL);
3603  if (mindepth != 2 && mindepth != 4 && mindepth != 8)
3604  return (PIX *)ERROR_PTR("invalid mindepth", procName, NULL);
3605  if (level < 1 || level > 6)
3606  return (PIX *)ERROR_PTR("level not in {1...6}", procName, NULL);
3607  if (metric != L_MANHATTAN_DISTANCE && metric != L_EUCLIDEAN_DISTANCE)
3608  return (PIX *)ERROR_PTR("invalid metric", procName, NULL);
3609 
3610  /* Set up the tables to map rgb to the nearest colormap index */
3611  rtab = gtab = btab = NULL;
3612  makeRGBToIndexTables(&rtab, &gtab, &btab, level);
3613  cmaptab = pixcmapToOctcubeLUT(cmap, level, metric);
3614 
3615  pixd = pixOctcubeQuantFromCmapLUT(pixs, cmap, mindepth,
3616  cmaptab, rtab, gtab, btab);
3617 
3618  LEPT_FREE(cmaptab);
3619  LEPT_FREE(rtab);
3620  LEPT_FREE(gtab);
3621  LEPT_FREE(btab);
3622  return pixd;
3623 }
3624 
3625 
3650 static PIX *
3652  PIXCMAP *cmap,
3653  l_int32 mindepth,
3654  l_int32 *cmaptab,
3655  l_uint32 *rtab,
3656  l_uint32 *gtab,
3657  l_uint32 *btab)
3658 {
3659 l_int32 i, j, w, h, depth, wpls, wpld;
3660 l_int32 rval, gval, bval, index;
3661 l_uint32 octindex;
3662 l_uint32 *lines, *lined, *datas, *datad;
3663 PIX *pixd;
3664 PIXCMAP *cmapc;
3665 
3666  PROCNAME("pixOctcubeQuantFromCmapLUT");
3667 
3668  if (!pixs)
3669  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3670  if (pixGetDepth(pixs) != 32)
3671  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
3672  if (!cmap)
3673  return (PIX *)ERROR_PTR("cmap not defined", procName, NULL);
3674  if (mindepth != 2 && mindepth != 4 && mindepth != 8)
3675  return (PIX *)ERROR_PTR("invalid mindepth", procName, NULL);
3676  if (!rtab || !gtab || !btab || !cmaptab)
3677  return (PIX *)ERROR_PTR("tables not all defined", procName, NULL);
3678 
3679  /* Init dest pix (with minimum bpp depending on cmap) */
3680  pixcmapGetMinDepth(cmap, &depth);
3681  depth = L_MAX(depth, mindepth);
3682  pixGetDimensions(pixs, &w, &h, NULL);
3683  if ((pixd = pixCreate(w, h, depth)) == NULL)
3684  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
3685  cmapc = pixcmapCopy(cmap);
3686  pixSetColormap(pixd, cmapc);
3687  pixCopyResolution(pixd, pixs);
3688  pixCopyInputFormat(pixd, pixs);
3689 
3690  /* Insert the colormap index of the color nearest to the input pixel */
3691  datas = pixGetData(pixs);
3692  datad = pixGetData(pixd);
3693  wpls = pixGetWpl(pixs);
3694  wpld = pixGetWpl(pixd);
3695  for (i = 0; i < h; i++) {
3696  lines = datas + i * wpls;
3697  lined = datad + i * wpld;
3698  for (j = 0; j < w; j++) {
3699  extractRGBValues(lines[j], &rval, &gval, &bval);
3700  /* Map from rgb to octcube index */
3701  getOctcubeIndexFromRGB(rval, gval, bval, rtab, gtab, btab,
3702  &octindex);
3703  /* Map from octcube index to nearest colormap index */
3704  index = cmaptab[octindex];
3705  if (depth == 2)
3706  SET_DATA_DIBIT(lined, j, index);
3707  else if (depth == 4)
3708  SET_DATA_QBIT(lined, j, index);
3709  else /* depth == 8 */
3710  SET_DATA_BYTE(lined, j, index);
3711  }
3712  }
3713 
3714  return pixd;
3715 }
3716 
3717 
3718 /*---------------------------------------------------------------------------*
3719  * Generation of octcube histogram *
3720  *---------------------------------------------------------------------------*/
3734 NUMA *
3736  l_int32 level,
3737  l_int32 *pncolors)
3738 {
3739 l_int32 size, i, j, w, h, wpl, ncolors, val;
3740 l_int32 rval, gval, bval;
3741 l_uint32 octindex;
3742 l_uint32 *rtab, *gtab, *btab;
3743 l_uint32 *data, *line;
3744 l_float32 *array;
3745 NUMA *na;
3746 
3747  PROCNAME("pixOctcubeHistogram");
3748 
3749  if (pncolors) *pncolors = 0;
3750  if (!pixs)
3751  return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
3752  if (pixGetDepth(pixs) != 32)
3753  return (NUMA *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
3754 
3755  pixGetDimensions(pixs, &w, &h, NULL);
3756  wpl = pixGetWpl(pixs);
3757  data = pixGetData(pixs);
3758 
3759  if (octcubeGetCount(level, &size)) /* array size = 2 ** (3 * level) */
3760  return (NUMA *)ERROR_PTR("size not returned", procName, NULL);
3761  rtab = gtab = btab = NULL;
3762  makeRGBToIndexTables(&rtab, &gtab, &btab, level);
3763 
3764  if ((na = numaCreate(size)) == NULL) {
3765  L_ERROR("na not made\n", procName);
3766  goto cleanup_arrays;
3767  }
3768  numaSetCount(na, size);
3769  array = numaGetFArray(na, L_NOCOPY);
3770 
3771  for (i = 0; i < h; i++) {
3772  line = data + i * wpl;
3773  for (j = 0; j < w; j++) {
3774  extractRGBValues(line[j], &rval, &gval, &bval);
3775  octindex = rtab[rval] | gtab[gval] | btab[bval];
3776 #if DEBUG_OCTINDEX
3777  if ((level == 1 && octindex > 7) ||
3778  (level == 2 && octindex > 63) ||
3779  (level == 3 && octindex > 511) ||
3780  (level == 4 && octindex > 4097) ||
3781  (level == 5 && octindex > 32783) ||
3782  (level == 6 && octindex > 262271)) {
3783  fprintf(stderr, "level = %d, octindex = %d, index error!\n",
3784  level, octindex);
3785  continue;
3786  }
3787 #endif /* DEBUG_OCTINDEX */
3788  array[octindex] += 1.0;
3789  }
3790  }
3791 
3792  if (pncolors) {
3793  for (i = 0, ncolors = 0; i < size; i++) {
3794  numaGetIValue(na, i, &val);
3795  if (val > 0)
3796  ncolors++;
3797  }
3798  *pncolors = ncolors;
3799  }
3800 
3801 cleanup_arrays:
3802  LEPT_FREE(rtab);
3803  LEPT_FREE(gtab);
3804  LEPT_FREE(btab);
3805  return na;
3806 }
3807 
3808 
3809 /*------------------------------------------------------------------*
3810  * Get filled octcube table from colormap *
3811  *------------------------------------------------------------------*/
3857 l_int32 *
3859  l_int32 level,
3860  l_int32 metric)
3861 {
3862 l_int32 i, k, size, ncolors, mindist, dist, mincolor, index;
3863 l_int32 rval, gval, bval; /* color at center of the octcube */
3864 l_int32 *rmap, *gmap, *bmap, *tab;
3865 
3866  PROCNAME("pixcmapToOctcubeLUT");
3867 
3868  if (!cmap)
3869  return (l_int32 *)ERROR_PTR("cmap not defined", procName, NULL);
3870  if (level < 1 || level > 6)
3871  return (l_int32 *)ERROR_PTR("level not in {1...6}", procName, NULL);
3872  if (metric != L_MANHATTAN_DISTANCE && metric != L_EUCLIDEAN_DISTANCE)
3873  return (l_int32 *)ERROR_PTR("invalid metric", procName, NULL);
3874 
3875  if (octcubeGetCount(level, &size)) /* array size = 2 ** (3 * level) */
3876  return (l_int32 *)ERROR_PTR("size not returned", procName, NULL);
3877  if ((tab = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32))) == NULL)
3878  return (l_int32 *)ERROR_PTR("tab not allocated", procName, NULL);
3879 
3880  ncolors = pixcmapGetCount(cmap);
3881  pixcmapToArrays(cmap, &rmap, &gmap, &bmap, NULL);
3882 
3883  /* Assign based on the closest octcube center to the cmap color */
3884  for (i = 0; i < size; i++) {
3885  getRGBFromOctcube(i, level, &rval, &gval, &bval);
3886  mindist = 1000000;
3887  mincolor = 0; /* irrelevant init */
3888  for (k = 0; k < ncolors; k++) {
3889  if (metric == L_MANHATTAN_DISTANCE) {
3890  dist = L_ABS(rval - rmap[k]) + L_ABS(gval - gmap[k]) +
3891  L_ABS(bval - bmap[k]);
3892  } else { /* L_EUCLIDEAN_DISTANCE */
3893  dist = (rval - rmap[k]) * (rval - rmap[k]) +
3894  (gval - gmap[k]) * (gval - gmap[k]) +
3895  (bval - bmap[k]) * (bval - bmap[k]);
3896  }
3897  if (dist < mindist) {
3898  mindist = dist;
3899  mincolor = k;
3900  }
3901  }
3902  tab[i] = mincolor;
3903  }
3904 
3905  /* Reset black and white if available in the colormap.
3906  * The darkest octcube is at octindex 0.
3907  * The lightest octcube is at the max octindex. */
3908  pixcmapGetNearestIndex(cmap, 0, 0, 0, &index);
3909  pixcmapGetColor(cmap, index, &rval, &gval, &bval);
3910  if (rval < 7 && gval < 7 && bval < 7) {
3911  tab[0] = index;
3912  }
3913  pixcmapGetNearestIndex(cmap, 255, 255, 255, &index);
3914  pixcmapGetColor(cmap, index, &rval, &gval, &bval);
3915  if (rval > 248 && gval > 248 && bval > 248) {
3916  tab[(1 << (3 * level)) - 1] = index;
3917  }
3918 
3919  LEPT_FREE(rmap);
3920  LEPT_FREE(gmap);
3921  LEPT_FREE(bmap);
3922  return tab;
3923 }
3924 
3925 
3926 /*------------------------------------------------------------------*
3927  * Strip out unused elements in colormap *
3928  *------------------------------------------------------------------*/
3943 l_ok
3945 {
3946 l_int32 i, j, w, h, d, nc, wpls, val, newval, index, zerofound;
3947 l_int32 rval, gval, bval;
3948 l_uint32 *datas, *lines;
3949 l_int32 *histo, *map1, *map2;
3950 PIXCMAP *cmap, *cmapd;
3951 
3952  PROCNAME("pixRemoveUnusedColors");
3953 
3954  if (!pixs)
3955  return ERROR_INT("pixs not defined", procName, 1);
3956  if ((cmap = pixGetColormap(pixs)) == NULL)
3957  return 0;
3958 
3959  d = pixGetDepth(pixs);
3960  if (d != 2 && d != 4 && d != 8)
3961  return ERROR_INT("d not in {2, 4, 8}", procName, 1);
3962 
3963  /* Find which indices are actually used */
3964  nc = pixcmapGetCount(cmap);
3965  if ((histo = (l_int32 *)LEPT_CALLOC(nc, sizeof(l_int32))) == NULL)
3966  return ERROR_INT("histo not made", procName, 1);
3967  pixGetDimensions(pixs, &w, &h, NULL);
3968  wpls = pixGetWpl(pixs);
3969  datas = pixGetData(pixs);
3970  for (i = 0; i < h; i++) {
3971  lines = datas + i * wpls;
3972  for (j = 0; j < w; j++) {
3973  switch (d)
3974  {
3975  case 2:
3976  val = GET_DATA_DIBIT(lines, j);
3977  break;
3978  case 4:
3979  val = GET_DATA_QBIT(lines, j);
3980  break;
3981  case 8:
3982  val = GET_DATA_BYTE(lines, j);
3983  break;
3984  default:
3985  LEPT_FREE(histo);
3986  return ERROR_INT("switch ran off end!", procName, 1);
3987  }
3988  if (val >= nc) {
3989  L_WARNING("cmap index out of bounds!\n", procName);
3990  continue;
3991  }
3992  histo[val]++;
3993  }
3994  }
3995 
3996  /* Check if there are any zeroes. If none, quit. */
3997  zerofound = FALSE;
3998  for (i = 0; i < nc; i++) {
3999  if (histo[i] == 0) {
4000  zerofound = TRUE;
4001  break;
4002  }
4003  }
4004  if (!zerofound) {
4005  LEPT_FREE(histo);
4006  return 0;
4007  }
4008 
4009  /* Generate mapping tables between indices */
4010  map1 = (l_int32 *)LEPT_CALLOC(nc, sizeof(l_int32));
4011  map2 = (l_int32 *)LEPT_CALLOC(nc, sizeof(l_int32));
4012  index = 0;
4013  for (i = 0; i < nc; i++) {
4014  if (histo[i] != 0) {
4015  map1[index] = i; /* get old index from new */
4016  map2[i] = index; /* get new index from old */
4017  index++;
4018  }
4019  }
4020 
4021  /* Generate new colormap and attach to pixs */
4022  cmapd = pixcmapCreate(d);
4023  for (i = 0; i < index; i++) {
4024  pixcmapGetColor(cmap, map1[i], &rval, &gval, &bval);
4025  pixcmapAddColor(cmapd, rval, gval, bval);
4026  }
4027  pixSetColormap(pixs, cmapd);
4028 
4029  /* Map pixel (index) values to new cmap */
4030  for (i = 0; i < h; i++) {
4031  lines = datas + i * wpls;
4032  for (j = 0; j < w; j++) {
4033  switch (d)
4034  {
4035  case 2:
4036  val = GET_DATA_DIBIT(lines, j);
4037  newval = map2[val];
4038  SET_DATA_DIBIT(lines, j, newval);
4039  break;
4040  case 4:
4041  val = GET_DATA_QBIT(lines, j);
4042  newval = map2[val];
4043  SET_DATA_QBIT(lines, j, newval);
4044  break;
4045  case 8:
4046  val = GET_DATA_BYTE(lines, j);
4047  newval = map2[val];
4048  SET_DATA_BYTE(lines, j, newval);
4049  break;
4050  default:
4051  LEPT_FREE(histo);
4052  LEPT_FREE(map1);
4053  LEPT_FREE(map2);
4054  return ERROR_INT("switch ran off end!", procName, 1);
4055  }
4056  }
4057  }
4058 
4059  LEPT_FREE(histo);
4060  LEPT_FREE(map1);
4061  LEPT_FREE(map2);
4062  return 0;
4063 }
4064 
4065 
4066 /*------------------------------------------------------------------*
4067  * Find number of occupied octcubes at the specified level *
4068  *------------------------------------------------------------------*/
4089 l_ok
4091  l_int32 level,
4092  l_int32 mincount,
4093  l_float32 minfract,
4094  l_int32 *pncolors)
4095 {
4096 l_int32 i, j, w, h, d, wpl, ncolors, size, octindex;
4097 l_int32 rval, gval, bval;
4098 l_int32 *carray;
4099 l_uint32 *data, *line, *rtab, *gtab, *btab;
4100 
4101  PROCNAME("pixNumberOccupiedOctcubes");
4102 
4103  if (!pncolors)
4104  return ERROR_INT("&ncolors not defined", procName, 1);
4105  *pncolors = 0;
4106  if (!pix)
4107  return ERROR_INT("pix not defined", procName, 1);
4108  pixGetDimensions(pix, &w, &h, &d);
4109  if (d != 32)
4110  return ERROR_INT("pix not 32 bpp", procName, 1);
4111  if (level < 1 || level > 6)
4112  return ERROR_INT("invalid level", procName, 1);
4113  if ((mincount < 0 && minfract < 0) || (mincount >= 0.0 && minfract >= 0.0))
4114  return ERROR_INT("invalid mincount/minfract", procName, 1);
4115  if (mincount == 0 || minfract == 0.0)
4116  mincount = 1;
4117  else if (minfract > 0.0)
4118  mincount = L_MIN(1, (l_int32)(minfract * w * h));
4119 
4120  if (octcubeGetCount(level, &size)) /* array size = 2 ** (3 * level) */
4121  return ERROR_INT("size not returned", procName, 1);
4122  rtab = gtab = btab = NULL;
4123  makeRGBToIndexTables(&rtab, &gtab, &btab, level);
4124  if ((carray = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32))) == NULL) {
4125  L_ERROR("carray not made\n", procName);
4126  goto cleanup_arrays;
4127  }
4128 
4129  /* Mark the occupied octcube leaves */
4130  data = pixGetData(pix);
4131  wpl = pixGetWpl(pix);
4132  for (i = 0; i < h; i++) {
4133  line = data + i * wpl;
4134  for (j = 0; j < w; j++) {
4135  extractRGBValues(line[j], &rval, &gval, &bval);
4136  octindex = rtab[rval] | gtab[gval] | btab[bval];
4137  carray[octindex]++;
4138  }
4139  }
4140 
4141  /* Count them */
4142  for (i = 0, ncolors = 0; i < size; i++) {
4143  if (carray[i] >= mincount)
4144  ncolors++;
4145  }
4146  *pncolors = ncolors;
4147 
4148 cleanup_arrays:
4149  LEPT_FREE(carray);
4150  LEPT_FREE(rtab);
4151  LEPT_FREE(gtab);
4152  LEPT_FREE(btab);
4153  return 0;
4154 }
PIX * pixOctreeColorQuant(PIX *pixs, l_int32 colors, l_int32 ditherflag)
pixOctreeColorQuant()
Definition: colorquant1.c:535
PIX * pixFewColorsOctcubeQuantMixed(PIX *pixs, l_int32 level, l_int32 darkthresh, l_int32 lightthresh, l_int32 diffthresh, l_float32 minfract, l_int32 maxspan)
pixFewColorsOctcubeQuantMixed()
Definition: colorquant1.c:3305
static PIX * pixOctcubeQuantFromCmapLUT(PIX *pixs, PIXCMAP *cmap, l_int32 mindepth, l_int32 *cmaptab, l_uint32 *rtab, l_uint32 *gtab, l_uint32 *btab)
pixOctcubeQuantFromCmapLUT()
Definition: colorquant1.c:3651
l_ok lheapAdd(L_HEAP *lh, void *item)
lheapAdd()
Definition: heap.c:186
l_int32 * pixcmapToOctcubeLUT(PIXCMAP *cmap, l_int32 level, l_int32 metric)
pixcmapToOctcubeLUT()
Definition: colorquant1.c:3858
l_ok pixcmapGetMinDepth(PIXCMAP *cmap, l_int32 *pmindepth)
pixcmapGetMinDepth()
Definition: colormap.c:692
l_int32 n
Definition: pix.h:160
NUMA * pixOctcubeHistogram(PIX *pixs, l_int32 level, l_int32 *pncolors)
pixOctcubeHistogram()
Definition: colorquant1.c:3735
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:473
Definition: pix.h:716
PIX * pixGrayQuantFromHisto(PIX *pixd, PIX *pixs, PIX *pixm, l_float32 minfract, l_int32 maxsize)
pixGrayQuantFromHisto()
Definition: grayquant.c:2341
void setPixelLow(l_uint32 *line, l_int32 x, l_int32 depth, l_uint32 val)
setPixelLow()
Definition: pix2.c:600
l_ok pixcmapGetNearestIndex(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapGetNearestIndex()
Definition: colormap.c:1209
static PIX * pixOctreeQuantizePixels(PIX *pixs, CQCELL ***cqcaa, l_int32 ditherflag)
pixOctreeQuantizePixels()
Definition: colorquant1.c:974
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3041
PIX * pixFixedOctcubeQuant256(PIX *pixs, l_int32 ditherflag)
pixFixedOctcubeQuant256()
Definition: colorquant1.c:2812
l_ok makeRGBToIndexTables(l_uint32 **prtab, l_uint32 **pgtab, l_uint32 **pbtab, l_int32 cqlevels)
makeRGBToIndexTables()
Definition: colorquant1.c:1361
static void cqcellTreeDestroy(CQCELL ****pcqcaa)
cqcellTreeDestroy()
Definition: colorquant1.c:1297
static l_int32 octcubeGetCount(l_int32 level, l_int32 *psize)
octcubeGetCount()
Definition: colorquant1.c:1627
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:302
l_ok pixNumberOccupiedOctcubes(PIX *pix, l_int32 level, l_int32 mincount, l_float32 minfract, l_int32 *pncolors)
pixNumberOccupiedOctcubes()
Definition: colorquant1.c:4090
#define SET_DATA_QBIT(pdata, n, val)
Definition: arrayaccess.h:168
void pixcmapDestroy(PIXCMAP **pcmap)
pixcmapDestroy()
Definition: colormap.c:265
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:187
l_int32 * makeGrayQuantIndexTable(l_int32 nlevels)
makeGrayQuantIndexTable()
Definition: grayquant.c:1843
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1624
l_ok numaSetCount(NUMA *na, l_int32 newcount)
numaSetCount()
Definition: numabasic.c:658
void lheapDestroy(L_HEAP **plh, l_int32 freeflag)
lheapDestroy()
Definition: heap.c:145
PIX * pixScaleBySampling(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBySampling()
Definition: scale1.c:1338
PIX * pixFewColorsOctcubeQuant2(PIX *pixs, l_int32 level, NUMA *na, l_int32 ncolors, l_int32 *pnerrors)
pixFewColorsOctcubeQuant2()
Definition: colorquant1.c:3116
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1573
static l_int32 pixDitherOctindexWithCmap(PIX *pixs, PIX *pixd, l_uint32 *rtab, l_uint32 *gtab, l_uint32 *btab, l_int32 *carray, l_int32 difcap)
pixDitherOctindexWithCmap()
Definition: colorquant1.c:1992
#define SET_DATA_DIBIT(pdata, n, val)
Definition: arrayaccess.h:149
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:111
static CQCELL *** cqcellTreeCreate(void)
cqcellTreeCreate()
Definition: colorquant1.c:1260
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:727
Definition: array.h:59
PIX * pixOctcubeQuantFromCmap(PIX *pixs, PIXCMAP *cmap, l_int32 mindepth, l_int32 level, l_int32 metric)
pixOctcubeQuantFromCmap()
Definition: colorquant1.c:3585
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:631
l_ok pixcmapToArrays(PIXCMAP *cmap, l_int32 **prmap, l_int32 **pgmap, l_int32 **pbmap, l_int32 **pamap)
pixcmapToArrays()
Definition: colormap.c:1856
void getOctcubeIndexFromRGB(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *rtab, l_uint32 *gtab, l_uint32 *btab, l_uint32 *pindex)
getOctcubeIndexFromRGB()
Definition: colorquant1.c:1470
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
#define GET_DATA_QBIT(pdata, n)
Definition: arrayaccess.h:164
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
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:515
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
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
PIX * pixFewColorsOctcubeQuant1(PIX *pixs, l_int32 level)
pixFewColorsOctcubeQuant1()
Definition: colorquant1.c:2946
PIX * pixGrayQuantFromCmap(PIX *pixs, PIXCMAP *cmap, l_int32 mindepth)
pixGrayQuantFromCmap()
Definition: grayquant.c:2564
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:360
static void getRGBFromOctcube(l_int32 cubeindex, l_int32 level, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
getRGBFromOctcube()
Definition: colorquant1.c:1516
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
PIX * pixFixedOctcubeQuantGenRGB(PIX *pixs, l_int32 level)
pixFixedOctcubeQuantGenRGB()
Definition: colorquant1.c:3423
PIX * pixOctreeColorQuantGeneral(PIX *pixs, l_int32 colors, l_int32 ditherflag, l_float32 validthresh, l_float32 colorthresh)
pixOctreeColorQuantGeneral()
Definition: colorquant1.c:601
PIX * pixOctreeQuantNumColors(PIX *pixs, l_int32 maxcolors, l_int32 subsample)
pixOctreeQuantNumColors()
Definition: colorquant1.c:2263
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
l_float32 * numaGetFArray(NUMA *na, l_int32 copyflag)
numaGetFArray()
Definition: numabasic.c:865
#define GET_DATA_DIBIT(pdata, n)
Definition: arrayaccess.h:145
static l_int32 octreeFindColorCell(l_int32 octindex, CQCELL ***cqcaa, l_int32 *pindex, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
octreeFindColorCell()
Definition: colorquant1.c:1190
l_ok pixRemoveUnusedColors(PIX *pixs)
pixRemoveUnusedColors()
Definition: colorquant1.c:3944
l_int32 pixcmapGetCount(PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:635
Definition: pix.h:134
static l_int32 getOctcubeIndices(l_int32 rgbindex, l_int32 level, l_int32 *pbindex, l_int32 *psindex)
getOctcubeIndices()
Definition: colorquant1.c:1593
PIX * pixOctreeQuantByPopulation(PIX *pixs, l_int32 level, l_int32 ditherflag)
pixOctreeQuantByPopulation()
Definition: colorquant1.c:1701
PIX * pixOctcubeQuantMixedWithGray(PIX *pixs, l_int32 depth, l_int32 graylevels, l_int32 delta)
pixOctcubeQuantMixedWithGray()
Definition: colorquant1.c:2593
static CQCELL *** octreeGenerateAndPrune(PIX *pixs, l_int32 colors, l_int32 reservedcolors, PIXCMAP **pcmap)
octreeGenerateAndPrune()
Definition: colorquant1.c:724
PIXCMAP * pixcmapCopy(PIXCMAP *cmaps)
pixcmapCopy()
Definition: colormap.c:234
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2671
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
PIX * pixQuantFromCmap(PIX *pixs, PIXCMAP *cmap, l_int32 mindepth, l_int32 level, l_int32 metric)
pixQuantFromCmap()
Definition: colorquant1.c:3496
#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