static int k_means(Pixel *pixelData, uint32_t nPixels, Pixel *paletteData, uint32_t nPaletteEntries, uint32_t *qp, int threshold) { uint32_t *avg[3]; uint32_t *count; uint32_t i; uint32_t *avgDist; uint32_t **avgDistSortKey; int changes; int built=0; if (nPaletteEntries > UINT32_MAX / (sizeof(uint32_t))) { return 0; } /* malloc check ok, using calloc */ if (!(count=calloc(nPaletteEntries, sizeof(uint32_t)))) { return 0; } for(i=0;i<3;i++) { avg[i]=NULL; } for(i=0;i<3;i++) { /* malloc check ok, using calloc */ if (!(avg[i]=calloc(nPaletteEntries, sizeof(uint32_t)))) { goto error_1; } } /* this is enough of a check, since the multiplication n*size is done above */ if (nPaletteEntries > UINT32_MAX / nPaletteEntries) { goto error_1; } /* malloc check ok, using calloc, checking n*n above */ avgDist=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t)); if (!avgDist) { goto error_1; } /* malloc check ok, using calloc, checking n*n above */ avgDistSortKey=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t *)); if (!avgDistSortKey) { goto error_2; } #ifndef NO_OUTPUT printf("[");fflush(stdout); #endif while (1) { if (!built) { compute_palette_from_quantized_pixels(pixelData,nPixels,paletteData,nPaletteEntries,avg,count,qp); build_distance_tables(avgDist,avgDistSortKey,paletteData,nPaletteEntries); built=1; } else { recompute_palette_from_averages(paletteData,nPaletteEntries,avg,count); resort_distance_tables(avgDist,avgDistSortKey,paletteData,nPaletteEntries); } changes=map_image_pixels_from_quantized_pixels(pixelData, nPixels, paletteData, nPaletteEntries, avgDist, avgDistSortKey, qp, avg, count); if (changes<0) { goto error_3; } #ifndef NO_OUTPUT printf (".(%d)",changes);fflush(stdout); #endif if (changes<=threshold) break; } #ifndef NO_OUTPUT printf("]\n"); #endif if (avgDistSortKey) free(avgDistSortKey); if (avgDist) free(avgDist); for(i=0;i<3;i++) if (avg[i]) free (avg[i]); if (count) free(count); return 1; error_3: if (avgDistSortKey) free(avgDistSortKey); error_2: if (avgDist) free(avgDist); error_1: for(i=0;i<3;i++) if (avg[i]) free (avg[i]); if (count) free(count); return 0; }
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; }
static int k_means(Pixel *pixelData, unsigned long nPixels, Pixel *paletteData, unsigned long nPaletteEntries, unsigned long *qp, int threshold) { unsigned long *avg[3]; unsigned long *count; unsigned long i; unsigned long *avgDist; unsigned long **avgDistSortKey; int changes; int built=0; if (!(count=malloc(sizeof(unsigned long)*nPaletteEntries))) { return 0; } for(i=0;i<3;i++) { avg[i]=NULL; } for(i=0;i<3;i++) { if (!(avg[i]=malloc(sizeof(unsigned long)*nPaletteEntries))) { goto error_1; } } avgDist=malloc(sizeof(unsigned long)*nPaletteEntries*nPaletteEntries); if (!avgDist) { goto error_1; } avgDistSortKey=malloc(sizeof(unsigned long *)*nPaletteEntries*nPaletteEntries); if (!avgDistSortKey) { goto error_2; } #ifndef NO_OUTPUT printf("[");fflush(stdout); #endif while (1) { if (!built) { compute_palette_from_quantized_pixels(pixelData,nPixels,paletteData,nPaletteEntries,avg,count,qp); build_distance_tables(avgDist,avgDistSortKey,paletteData,nPaletteEntries); built=1; } else { recompute_palette_from_averages(paletteData,nPaletteEntries,avg,count); resort_distance_tables(avgDist,avgDistSortKey,paletteData,nPaletteEntries); } changes=map_image_pixels_from_quantized_pixels(pixelData, nPixels, paletteData, nPaletteEntries, avgDist, avgDistSortKey, qp, avg, count); if (changes<0) { goto error_3; } #ifndef NO_OUTPUT printf (".(%d)",changes);fflush(stdout); #endif if (changes<=threshold) break; } #ifndef NO_OUTPUT printf("]\n"); #endif if (avgDistSortKey) free(avgDistSortKey); if (avgDist) free(avgDist); for(i=0;i<3;i++) if (avg[i]) free (avg[i]); if (count) free(count); return 1; error_3: if (avgDistSortKey) free(avgDistSortKey); error_2: if (avgDist) free(avgDist); error_1: for(i=0;i<3;i++) if (avg[i]) free (avg[i]); if (count) free(count); return 0; }