void unit_tests() { int a[4] = {1, 2, 3, 4}; insertion_sort(a, 4); test_sorted(a, 4); int b[4] = {10, 20, 40, 30}; insertion_sort(b, 4); test_sorted(b, 4); int c[4] = {10, 4000, 20, 300}; insertion_sort(c, 4); test_sorted(c, 4); int d[4] = {3000, 40000, 20000, 10000}; insertion_sort(d, 4); test_sorted(d, 4); }
static int split(BoxNode *node) { unsigned char rl,rh,gl,gh,bl,bh; int f[3]; int best,axis; int i; PixelList *heads[2][3]; PixelList *tails[2][3]; uint32_t newCounts[2]; BoxNode *left,*right; rh=node->head[0]->p.c.r; rl=node->tail[0]->p.c.r; gh=node->head[1]->p.c.g; gl=node->tail[1]->p.c.g; bh=node->head[2]->p.c.b; bl=node->tail[2]->p.c.b; #ifdef TEST_SPLIT printf ("splitting node [%d %d %d] [%d %d %d] ",rl,gl,bl,rh,gh,bh); #endif f[0]=(rh-rl)*77; f[1]=(gh-gl)*150; f[2]=(bh-bl)*29; best=f[0]; axis=0; for (i=1;i<3;i++) { if (best<f[i]) { best=f[i]; axis=i; } } #ifdef TEST_SPLIT printf ("along axis %d\n",axis+1); #endif #ifdef TEST_SPLIT { PixelList *_prevTest,*_nextTest; int _i,_nextCount[3],_prevCount[3]; for (_i=0;_i<3;_i++) { if (node->tail[_i]->next[_i]) { printf ("tail is not tail\n"); printf ("node->tail[%d]->next[%d]=%p\n",_i,_i,node->tail[_i]->next[_i]); } if (node->head[_i]->prev[_i]) { printf ("head is not head\n"); printf ("node->head[%d]->prev[%d]=%p\n",_i,_i,node->head[_i]->prev[_i]); } } for (_i=0;_i<3;_i++) { for (_nextCount[_i]=0,_nextTest=node->head[_i];_nextTest&&_nextTest->next[_i];_nextTest=_nextTest->next[_i],_nextCount[_i]++); for (_prevCount[_i]=0,_prevTest=node->tail[_i];_prevTest&&_prevTest->prev[_i];_prevTest=_prevTest->prev[_i],_prevCount[_i]++); if (_nextTest!=node->tail[_i]) { printf ("next-list of axis %d does not end at tail\n",_i); } if (_prevTest!=node->head[_i]) { printf ("prev-list of axis %d does not end at head\n",_i); } for (;_nextTest&&_nextTest->prev[_i];_nextTest=_nextTest->prev[_i]); for (;_prevTest&&_prevTest->next[_i];_prevTest=_prevTest->next[_i]); if (_nextTest!=node->head[_i]) { printf ("next-list of axis %d does not loop back to head\n",_i); } if (_prevTest!=node->tail[_i]) { printf ("prev-list of axis %d does not loop back to tail\n",_i); } } for (_i=1;_i<3;_i++) { if (_prevCount[_i]!=_prevCount[_i-1] || _nextCount[_i]!=_nextCount[_i-1] || _prevCount[_i]!=_nextCount[_i]) { printf ("{%d %d %d} {%d %d %d}\n", _prevCount[0], _prevCount[1], _prevCount[2], _nextCount[0], _nextCount[1], _nextCount[2]); } } } #endif node->axis=axis; if (!splitlists(node->head, node->tail, heads, tails, newCounts, axis, node->pixelCount)) { #ifndef NO_OUTPUT printf ("list split failed.\n"); #endif return 0; } #ifdef TEST_SPLIT if (!test_sorted(heads[0])) { printf ("bug in split"); exit(1); } if (!test_sorted(heads[1])) { printf ("bug in split"); exit(1); } #endif /* malloc check ok, small constant allocation */ left=malloc(sizeof(BoxNode)); right=malloc(sizeof(BoxNode)); if (!left||!right) { return 0; } for(i=0;i<3;i++) { left->head[i]=heads[0][i]; left->tail[i]=tails[0][i]; right->head[i]=heads[1][i]; right->tail[i]=tails[1][i]; node->head[i]=NULL; node->tail[i]=NULL; } #ifdef TEST_SPLIT if (left->head[0]) { rh=left->head[0]->p.c.r; rl=left->tail[0]->p.c.r; gh=left->head[1]->p.c.g; gl=left->tail[1]->p.c.g; bh=left->head[2]->p.c.b; bl=left->tail[2]->p.c.b; printf (" left node [%3d %3d %3d] [%3d %3d %3d]\n",rl,gl,bl,rh,gh,bh); } if (right->head[0]) { rh=right->head[0]->p.c.r; rl=right->tail[0]->p.c.r; gh=right->head[1]->p.c.g; gl=right->tail[1]->p.c.g; bh=right->head[2]->p.c.b; bl=right->tail[2]->p.c.b; printf (" right node [%3d %3d %3d] [%3d %3d %3d]\n",rl,gl,bl,rh,gh,bh); } #endif left->l=left->r=NULL; right->l=right->r=NULL; left->axis=right->axis=-1; left->volume=right->volume=-1; left->pixelCount=newCounts[0]; right->pixelCount=newCounts[1]; node->l=left; node->r=right; return 1; }
int quantize(Pixel *pixelData, uint32_t nPixels, uint32_t nQuantPixels, Pixel **palette, uint32_t *paletteLength, uint32_t **quantizedPixels, int kmeans) { PixelList *hl[3]; HashTable *h; BoxNode *root; uint32_t i; uint32_t *qp; uint32_t nPaletteEntries; uint32_t *avgDist; uint32_t **avgDistSortKey; Pixel *p; #ifndef NO_OUTPUT uint32_t timer,timer2; #endif #ifndef NO_OUTPUT timer2=clock(); printf ("create hash table..."); fflush(stdout); timer=clock(); #endif h=create_pixel_hash(pixelData,nPixels); #ifndef NO_OUTPUT printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); #endif if (!h) { goto error_0; } #ifndef NO_OUTPUT printf ("create lists from hash table..."); fflush(stdout); timer=clock(); #endif hl[0]=hl[1]=hl[2]=NULL; hashtable_foreach(h,hash_to_list,hl); #ifndef NO_OUTPUT printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); #endif if (!hl[0]) { goto error_1; } #ifndef NO_OUTPUT printf ("mergesort lists..."); fflush(stdout); timer=clock(); #endif for(i=0;i<3;i++) { hl[i]=mergesort_pixels(hl[i],i); } #ifdef TEST_MERGESORT if (!test_sorted(hl)) { printf ("bug in mergesort\n"); goto error_1; } #endif #ifndef NO_OUTPUT printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); #endif #ifndef NO_OUTPUT printf ("median cut..."); fflush(stdout); timer=clock(); #endif root=median_cut(hl,nPixels,nQuantPixels); #ifndef NO_OUTPUT printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); #endif if (!root) { goto error_1; } nPaletteEntries=0; #ifndef NO_OUTPUT printf ("median cut tree to hash table..."); fflush(stdout); timer=clock(); #endif annotate_hash_table(root,h,&nPaletteEntries); #ifndef NO_OUTPUT printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); #endif #ifndef NO_OUTPUT printf ("compute palette...\n"); fflush(stdout); timer=clock(); #endif if (!compute_palette_from_median_cut(pixelData,nPixels,h,&p,nPaletteEntries)) { goto error_3; } #ifndef NO_OUTPUT printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); #endif free_box_tree(root); root=NULL; /* malloc check ok, using calloc for overflow */ qp=calloc(nPixels, sizeof(uint32_t)); if (!qp) { goto error_4; } if (nPaletteEntries > UINT32_MAX / nPaletteEntries ) { goto error_5; } /* malloc check ok, using calloc for overflow, check of n*n above */ avgDist=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t)); if (!avgDist) { goto error_5; } /* malloc check ok, using calloc for overflow, check of n*n above */ avgDistSortKey=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t *)); if (!avgDistSortKey) { goto error_6; } if (!build_distance_tables(avgDist,avgDistSortKey,p,nPaletteEntries)) { goto error_7; } if (!map_image_pixels_from_median_box(pixelData,nPixels,p,nPaletteEntries,h,avgDist,avgDistSortKey,qp)) { goto error_7; } #ifdef TEST_NEAREST_NEIGHBOUR #include <math.h> { uint32_t bestmatch,bestdist,dist; HashTable *h2; printf ("nearest neighbour search (full search)..."); fflush(stdout); timer=clock(); h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp); for (i=0;i<nPixels;i++) { if (hashtable_lookup(h2,pixelData[i],&paletteEntry)) { bestmatch=paletteEntry; } else { bestmatch=0; bestdist= _SQR(pixelData[i].c.r-p[0].c.r)+ _SQR(pixelData[i].c.g-p[0].c.g)+ _SQR(pixelData[i].c.b-p[0].c.b); for (j=1;j<nPaletteEntries;j++) { dist= _SQR(pixelData[i].c.r-p[j].c.r)+ _SQR(pixelData[i].c.g-p[j].c.g)+ _SQR(pixelData[i].c.b-p[j].c.b); if (dist==bestdist && j==qp[i]) { bestmatch=j; } if (dist<bestdist) { bestdist=dist; bestmatch=j; } } hashtable_insert(h2,pixelData[i],bestmatch); } if (qp[i]!=bestmatch ) { printf ("discrepancy in matching algorithms pixel %d [%d %d] %f %f\n", i,qp[i],bestmatch, sqrt((double)(_SQR(pixelData[i].c.r-p[qp[i]].c.r)+ _SQR(pixelData[i].c.g-p[qp[i]].c.g)+ _SQR(pixelData[i].c.b-p[qp[i]].c.b))), sqrt((double)(_SQR(pixelData[i].c.r-p[bestmatch].c.r)+ _SQR(pixelData[i].c.g-p[bestmatch].c.g)+ _SQR(pixelData[i].c.b-p[bestmatch].c.b))) ); } } hashtable_free(h2); } #endif #ifndef NO_OUTPUT printf ("k means...\n"); fflush(stdout); timer=clock(); #endif if (kmeans) k_means(pixelData,nPixels,p,nPaletteEntries,qp,kmeans-1); #ifndef NO_OUTPUT printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); #endif *quantizedPixels=qp; *palette=p; *paletteLength=nPaletteEntries; #ifndef NO_OUTPUT printf ("cleanup..."); fflush(stdout); timer=clock(); #endif if (avgDist) free(avgDist); if (avgDistSortKey) free(avgDistSortKey); destroy_pixel_hash(h); #ifndef NO_OUTPUT printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); printf ("-----\ntotal time %f\n",(clock()-timer2)/(double)CLOCKS_PER_SEC); #endif return 1; error_7: if (avgDistSortKey) free(avgDistSortKey); error_6: if (avgDist) free(avgDist); error_5: if (qp) free(qp); error_4: if (p) free(p); error_3: if (root) free_box_tree(root); error_1: destroy_pixel_hash(h); error_0: *quantizedPixels=NULL; *paletteLength=0; *palette=NULL; return 0; }