home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------
- * split up color space for quantize program
- *----------------------------------------------------------------------
- */
-
- #include <stdio.h>
- #include <std.h>
- #include "quantize.h"
-
- /* Pick your choice of algorithm: */
- /* MIDPOINT_CUT or POPULARITY */
- /* (Choose in makefile) */
-
- #ifdef MIDPOINT_CUT
-
- typedef unsigned int color_index_t;
-
- /* My method here is to allocate a clist array big enough for all the
- * possible colors, and then recursively split it. Since the recursion
- * is depth-first and we're building a LIST, not a TREE of boxes, we can
- * scramble the colors within a parent box because that parent won't be used
- * any more. We end up with a list of boxes into which all the existing
- * colors are partitioned, as described in Heckbert's paper.
- */
- struct Box {
- struct Box *next;
- int rmin, rmax, gmin, gmax, bmin, bmax;
- color_index_t *clist; /* an array of color indices */
- int clist_len; /* how many cindexes in the list */
- };
-
- static int nboxes, maxboxes; /* number of boxes so far and max needed */
-
- MakeCmap(hist, cmap, cmaplen)
- unsigned int *hist;
- cmap_t *cmap;
- int cmaplen;
- {
- register int i;
- struct Box *box;
- nboxes = 1;
- maxboxes = cmaplen;
- NEW(box, struct Box, 1);
- dbug0("Making color boxes.\n");
- MakeTopBox(box, hist); /* Make the first (top-level) box */
- while (nboxes < maxboxes)
- SplitBoxes(box);
- FindColors(box, cmap, cmaplen);
- }
-
- MakeTopBox(box, hist) /* Make the top box from the histogram */
- struct Box *box;
- color_index_t *hist;
- {
- register int i;
- ASSERT(box != NULL);
- ASSERT(hist != NULL);
-
- /* Allocate enough color cells to hold all the colors */
- NEW(box->clist, color_index_t, HIST_SIZE);
- box->clist_len = 0;
- box->next = NULL;
- /* For each possible rgb color */
- for (i = 0; i < HIST_SIZE; i++)
- {
- if (hist[i] > 0) /* if any pixels are that color, */
- box->clist[box->clist_len++] = i;
- }
- Compact(box);
- fprintf(stderr,"Top box at 0x%x: %d colors, R (%d -> %d) G (%d -> %d) B (%d -> %d)\n",
- box, box->clist_len,
- box->rmin, box->rmax, box->gmin, box->gmax, box->bmin, box->bmax);
- }
-
- /* Shrink the box limits until it just encloses the points within it. */
- Compact(box)
- struct Box *box;
- {
- register int i;
- ASSERT(box != NULL);
- box->rmin = 256;
- box->gmin = 256;
- box->bmin = 256; /* Greater than any value */
- box->rmax = -1;
- box->gmax = -1;
- box->bmax = -1; /* Less than any rgb value */
- for (i = box->clist_len-1; i >= 0; i--)
- {
- int r = (box->clist[i] >> 10) & 0x1f; /* colors associated with 'i' */
- int g = (box->clist[i] >> 5) & 0x1f;
- int b = (box->clist[i]) & 0x1f;
- /* Expand the box until it just fits the colors tightly */
- if (r < box->rmin) box->rmin = r;
- if (g < box->gmin) box->gmin = g;
- if (b < box->bmin) box->bmin = b;
- if (r > box->rmax) box->rmax = r;
- if (g > box->gmax) box->gmax = g;
- if (b > box->bmax) box->bmax = b;
- }
- }
-
- /* Split all the boxes once each, stop if we've got enough */
- SplitBoxes(box)
- struct Box *box;
- {
- struct Box *nextbox;
- dbug1("Splitting all the boxes with %d done so far.\n", nboxes);
- while (box != NULL && nboxes < maxboxes)
- {
- nextbox = box->next;
- SplitBox(box); /* SplitBox changes box->next! */
- box = nextbox;
- }
- }
-
- static char longdim; /* char representing the longest dimension */
-
- int
- CompareColors(c1, c2)
- color_index_t *c1, *c2;
- {
- switch (longdim)
- {
- case 'r':
- return ((*c1 >> 10 & 0x1f) - (*c2 >> 10 & 0x1f));
- case 'g':
- return ((*c1 >> 5 & 0x1f) - (*c2 >> 5 & 0x1f));
- case 'b':
- return ((*c1 & 0x1f) - (*c2 & 0x1f));
- default:
- fprintf(stderr,"Illegal longdim 0x%x in CompareColors.\n", longdim);
- exit(1);
- }
- }
-
- /* Divide the box across its longest dimension at its median point
- * This is NOT recursive - we split all the boxes once, then if there's
- * more colors to be assigned we split all of them again, and so on. */
- SplitBox(box)
- struct Box *box;
- {
- struct Box *newbox; /* the 'other half' of the split box */
- ASSERT(box != NULL);
- if (nboxes > maxboxes) return;
- if (box->clist_len <= 1) return;
- nboxes++;
- if (box->rmax - box->rmin >= box->gmax - box->gmin &&
- box->rmax - box->rmin >= box->bmax - box->bmin)
- longdim = 'r';
- else
- if (box->gmax - box->gmin >= box->rmax - box->rmin &&
- box->gmax - box->gmin >= box->bmax - box->bmin)
- longdim = 'g';
- else
- if (box->bmax - box->bmin >= box->gmax - box->gmin &&
- box->bmax - box->bmin >= box->rmax - box->rmin)
- longdim = 'b';
- else
- {
- fprintf(stderr,"No longest dimension in SplitBox??!\n");
- fprintf(stderr,"This box: R (%d -> %d) G (%d -> %d) B (%d -> %d)\n",
- box->rmin, box->rmax, box->gmin, box->gmax, box->bmin, box->bmax);
- exit(1);
- }
- qsort(box->clist, box->clist_len, sizeof(color_index_t), CompareColors);
- /* Set up the new box and put it after the old box */
- NEW(newbox, struct Box, 1);
- newbox->next = box->next;
- box->next = newbox;
- /* If len is odd, put the extra one in the old box */
- newbox->clist_len = box->clist_len / 2;
- box->clist_len -= newbox->clist_len;
- newbox->clist = box->clist + box->clist_len;
- Compact(box);
- Compact(newbox);
- }
-
- /* Find the representative color in each box and put it into cmap. */
- FindColors(box, cmap, cmaplen) /* here box is a list of boxes */
- struct Box *box;
- cmap_t *cmap;
- int cmaplen;
- {
- register int r, g, b;
- register int i;
- int cml = 0;
- while (box != NULL)
- {
- r = 0, g = 0, b = 0;
- for (i=0; i < box->clist_len; i++)
- {
- r += (box->clist[i] >> 10 & 0x1f) << 3;
- g += (box->clist[i] >> 5 & 0x1f) << 3;
- b += (box->clist[i] & 0x1f) << 3;
- }
- ASSERT(r/box->clist_len < 256);
- ASSERT(g/box->clist_len < 256);
- ASSERT(b/box->clist_len < 256);
- cmap[cml*3] = r / box->clist_len;
- cmap[cml*3+1] = g / box->clist_len;
- cmap[cml*3+2] = b / box->clist_len;
- box = box->next;
- cml++;
- }
- ASSERT(cmaplen == cml); /* since there should be 'cmaplen' boxes */
- for (i = 0; i < cmaplen*3; i+=3)
- {
- printf("Cmap[%4d] = %3d, %3d, %3d\n",
- i/3, cmap[i], cmap[i+1], cmap[i+2]);
- }
- }
-
- #endif
-
- #ifdef POPULARITY
- static unsigned int *HiSt;
-
- CompareHist(v1, v2)
- int *v1, *v2;
- {
- return (HiSt[*v2] - HiSt[*v1]);
- }
-
- MakeCmap(hist, cmap, cmaplen)
- unsigned int *hist;
- cmap_t *cmap;
- int cmaplen;
- {
- register int i;
- unsigned int *hptrs;
- /* This is the popularity algorithm (Boyle & Lippman, Archmac, 1978) */
- /* First we sort the histogram: set up a bunch of pointers and sort them */
- dbug1("Getting %d ints for hptrs...", HIST_SIZE);
- /* NEW(hptrs, unsigned int, HIST_SIZE);*/
- hptrs = (unsigned int *)quant_image; /* use existing storage temporarily */
- dbug0("initting it...");
- for (i = 0; i < HIST_SIZE; i++) hptrs[i] = i;
- HiSt = hist;
- dbug0("Sorting...");
- qsort (hptrs, HIST_SIZE, sizeof(unsigned int), CompareHist);
- dbug0("making color map...");
- for (i = 0; i < cmaplen; i++)
- {
- cmap[3*i] = hptrs[i] >> 10 << 3;
- cmap[3*i+1] = (hptrs[i] >> 5 & 0x1f) << 3;
- cmap[3*i+2] = (hptrs[i] & 0x1f) << 3;
- }
- dbug0("done.\n");
- dbug1("Max pixels in one bucket: %d.\n", hist[hptrs[0]]);
- }
- #endif POPULARITY
-