ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/closest.c
Revision: 1.3
Committed: Fri Apr 7 16:36:15 1989 UTC (35 years, 1 month ago) by ph
Content type: text/plain
Branch: MAIN
Changes since 1.2: +10 -7 lines
Log Message:
ciq() now calls initializeclosest() fixing a bug, also error clamping

File Contents

# Content
1 /* Copyright 1988 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 CLOSEST - nearest-color lookup by locally ordered search
9 we use distance in rgb space as color metric
10
11 fillbucket subroutine makes trimmed, sorted lists of
12 possible closest colors to speed the closest searching.
13 About 6 times faster than exhaustive.
14
15 Paul Heckbert
16 */
17
18 #include "ciq.h"
19
20 #define inf 3*256*256
21 #define key(r,g,b) (((r)&0xe0)<<1|((g)&0xe0)>>2|((b)&0xe0)>>5)
22 /* 9-bit hash key: rrrgggbbb */
23
24 static struct thing {int mindist,pv;} space[512*257],*next,*bucket[512];
25 /* sorted lists of colors */
26
27 static int nfill,tests,calls;
28 static char filled[512]; /* has bucket[key] been filled yet? */
29 static int sq[511];
30
31 initializeclosest() { /* reset the buckets */
32 int k;
33 nfill = tests = calls = 0;
34 for (k=0; k<512; k++) filled[k] = 0;
35 next = space;
36 }
37
38 closest(r,g,b) /* find pv of colormap color closest to (r,g,b) */
39 int r,g,b;
40 {
41 register struct thing *p;
42 register int *rsq,*gsq,*bsq,dist,min;
43 int best,k;
44 struct thing *p0;
45
46 k = key(r,g,b);
47 if (!filled[k]) fillbucket(k);
48 min = inf;
49 rsq = sq+255-r;
50 gsq = sq+255-g;
51 bsq = sq+255-b;
52
53 /* stop looking when best is closer than next could be */
54 for (p0=p=bucket[k]; min>p->mindist; p++) {
55 dist = rsq[color[0][p->pv]] + gsq[color[1][p->pv]] +
56 bsq[color[2][p->pv]];
57 if (dist<min) {
58 best = p->pv;
59 min = dist;
60 }
61 }
62 tests += p-p0;
63 calls++;
64 return best;
65 }
66
67 #define H 16 /* half-width of a bucket */
68
69 compare(a,b)
70 register struct thing *a,*b;
71 {
72 return a->mindist-b->mindist;
73 }
74
75 fillbucket(k) /* make list of colormap colors which could be closest */
76 int k; /* matches for colors in bucket #k */
77 {
78 register int r,g,b,j,dist,*rsq,*gsq,*bsq,min,best;
79 struct thing *p,*q;
80
81 if (!sq[0]) for (j= -255; j<256; j++) sq[j+255] = j*j;
82
83 r = k>>1&0xe0|H; /* center of 32x32x32 cubical bucket */
84 g = k<<2&0xe0|H;
85 b = k<<5&0xe0|H;
86 rsq = sq+255-r;
87 gsq = sq+255-g;
88 bsq = sq+255-b;
89 bucket[k] = p = next;
90 min = inf;
91
92 for (j=0; j<n; j++, p++) {
93 p->pv = j;
94 dist = 0; /* compute distance from cube surface */
95 if (color[0][j]< r-H) dist += rsq[color[0][j]+H];
96 else if (color[0][j]>=r+H) dist += rsq[color[0][j]-H+1];
97 if (color[1][j]< g-H) dist += gsq[color[1][j]+H];
98 else if (color[1][j]>=g+H) dist += gsq[color[1][j]-H+1];
99 if (color[2][j]< b-H) dist += bsq[color[2][j]+H];
100 else if (color[2][j]>=b+H) dist += bsq[color[2][j]-H+1];
101 p->mindist = dist; /* for termination test in closest */
102 dist = rsq[color[0][j]]+gsq[color[1][j]]+bsq[color[2][j]];
103 if (dist<min) { /* find color closest to cube center */
104 best = j;
105 min = dist;
106 }
107 }
108
109 dist = rsq[color[0][best]+(color[0][best]<r?1-H:H)] +
110 gsq[color[1][best]+(color[1][best]<g?1-H:H)] +
111 bsq[color[2][best]+(color[2][best]<b?1-H:H)];
112 /* dist is an upper bound on mindist: maximum possible distance */
113 /* between a color in the bucket and its nearest neighbor */
114
115 /* eliminate colors which couldn't be closest */
116 for (p=q=next, j=0; j<n; j++, p++)
117 if (p->mindist<dist) {
118 q->mindist = p->mindist;
119 q->pv = p->pv;
120 q++;
121 }
122 if (q<=next) fprintf(stderr,"ERROR: empty bucket!\n");
123
124 /* and sort the list by mindist */
125 qsort(next,q-next,sizeof(struct thing),compare);
126 q->mindist = inf; /* list terminator */
127 next = q+1;
128 filled[k] = 1;
129 nfill++;
130 }
131
132 /*endclosest() {
133 printf("filled %d buckets, averaging %d colors per list, %d of which were tested\n",
134 nfill,(next-space-nfill)/nfill,tests/calls);
135 }*/