kmeans.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. ** © 2011-2016 by Kornel Lesiński.
  3. ** See COPYRIGHT file for license.
  4. */
  5. #include "libimagequant.h"
  6. #include "pam.h"
  7. #include "kmeans.h"
  8. #include "nearest.h"
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #ifdef _OPENMP
  12. #include <omp.h>
  13. #else
  14. #define omp_get_max_threads() 1
  15. #define omp_get_thread_num() 0
  16. #endif
  17. /*
  18. * K-Means iteration: new palette color is computed from weighted average of colors that map to that palette entry.
  19. */
  20. LIQ_PRIVATE void kmeans_init(const colormap *map, const unsigned int max_threads, kmeans_state average_color[])
  21. {
  22. memset(average_color, 0, sizeof(average_color[0])*(KMEANS_CACHE_LINE_GAP+map->colors)*max_threads);
  23. }
  24. LIQ_PRIVATE void kmeans_update_color(const f_pixel acolor, const float value, const colormap *map, unsigned int match, const unsigned int thread, kmeans_state average_color[])
  25. {
  26. match += thread * (KMEANS_CACHE_LINE_GAP+map->colors);
  27. average_color[match].a += acolor.a * value;
  28. average_color[match].r += acolor.r * value;
  29. average_color[match].g += acolor.g * value;
  30. average_color[match].b += acolor.b * value;
  31. average_color[match].total += value;
  32. }
  33. LIQ_PRIVATE void kmeans_finalize(colormap *map, const unsigned int max_threads, const kmeans_state average_color[])
  34. {
  35. for (unsigned int i=0; i < map->colors; i++) {
  36. double a=0, r=0, g=0, b=0, total=0;
  37. // Aggregate results from all threads
  38. for(unsigned int t=0; t < max_threads; t++) {
  39. const unsigned int offset = (KMEANS_CACHE_LINE_GAP+map->colors) * t + i;
  40. a += average_color[offset].a;
  41. r += average_color[offset].r;
  42. g += average_color[offset].g;
  43. b += average_color[offset].b;
  44. total += average_color[offset].total;
  45. }
  46. if (total && !map->palette[i].fixed) {
  47. map->palette[i].acolor = (f_pixel){
  48. .a = a / total,
  49. .r = r / total,
  50. .g = g / total,
  51. .b = b / total,
  52. };
  53. map->palette[i].popularity = total;
  54. }
  55. }
  56. }
  57. LIQ_PRIVATE double kmeans_do_iteration(histogram *hist, colormap *const map, kmeans_callback callback)
  58. {
  59. const unsigned int max_threads = omp_get_max_threads();
  60. LIQ_ARRAY(kmeans_state, average_color, (KMEANS_CACHE_LINE_GAP+map->colors) * max_threads);
  61. kmeans_init(map, max_threads, average_color);
  62. struct nearest_map *const n = nearest_init(map);
  63. hist_item *const achv = hist->achv;
  64. const int hist_size = hist->size;
  65. double total_diff=0;
  66. #if __GNUC__ >= 9
  67. #pragma omp parallel for if (hist_size > 2000) \
  68. schedule(static) default(none) shared(achv,average_color,callback,hist_size,map,n) reduction(+:total_diff)
  69. #else
  70. #pragma omp parallel for if (hist_size > 2000) \
  71. schedule(static) default(none) shared(average_color,callback) reduction(+:total_diff)
  72. #endif
  73. for(int j=0; j < hist_size; j++) {
  74. float diff;
  75. unsigned int match = nearest_search(n, &achv[j].acolor, achv[j].tmp.likely_colormap_index, &diff);
  76. achv[j].tmp.likely_colormap_index = match;
  77. total_diff += diff * achv[j].perceptual_weight;
  78. kmeans_update_color(achv[j].acolor, achv[j].perceptual_weight, map, match, omp_get_thread_num(), average_color);
  79. if (callback) callback(&achv[j], diff);
  80. }
  81. nearest_free(n);
  82. kmeans_finalize(map, max_threads, average_color);
  83. return total_diff / hist->total_perceptual_weight;
  84. }