LIQ_PRIVATE double viter_do_iteration(histogram *hist, colormap *const map, const float min_opaque_val, viter_callback callback, const bool fast_palette) { const unsigned int max_threads = omp_get_max_threads(); // viter_state average_color[(VITER_CACHE_LINE_GAP+map->colors) * max_threads]; viter_state *average_color = (viter_state *)malloc((VITER_CACHE_LINE_GAP+map->colors) * max_threads); viter_init(map, max_threads, average_color); struct nearest_map *const n = nearest_init(map, fast_palette); hist_item *const achv = hist->achv; const int hist_size = hist->size; double total_diff=0; #pragma omp parallel for if (hist_size > 3000) \ schedule(static) default(none) shared(average_color,callback) reduction(+:total_diff) for(int j=0; j < hist_size; j++) { float diff; unsigned int match = nearest_search(n, achv[j].acolor, achv[j].likely_colormap_index, min_opaque_val, &diff); achv[j].likely_colormap_index = match; total_diff += diff * achv[j].perceptual_weight; viter_update_color(achv[j].acolor, achv[j].perceptual_weight, map, match, omp_get_thread_num(), average_color); if (callback) callback(&achv[j], diff); } nearest_free(n); viter_finalize(map, max_threads, average_color); free(average_color); return total_diff / hist->total_perceptual_weight; }
void viter_finalize(colormap *map, const int max_threads, const viter_state average_color[]) { for (int i=0; i < map->colors; i++) { double a=0, r=0, g=0, b=0, total=0; // Aggregate results from all threads for(int t=0; t < max_threads; t++) { const int offset = map->colors * t + i; a += average_color[offset].a; r += average_color[offset].r; g += average_color[offset].g; b += average_color[offset].b; total += average_color[offset].total; } if (total) { map->palette[i].acolor = (f_pixel){ .a = a / total, .r = r / total, .g = g / total, .b = b / total, }; } map->palette[i].popularity = total; } } double viter_do_iteration(histogram *hist, colormap *const map, const float min_opaque_val, viter_callback callback) { const int max_threads = omp_get_max_threads(); viter_state average_color[map->colors * max_threads]; viter_init(map, max_threads, average_color); struct nearest_map *const n = nearest_init(map); hist_item *const achv = hist->achv; const int hist_size = hist->size; double total_diff=0; #pragma omp parallel for if (hist_size > 3000) \ default(none) shared(average_color,callback) reduction(+:total_diff) for(int j=0; j < hist_size; j++) { float diff; int match = nearest_search(n, achv[j].acolor, min_opaque_val, &diff); total_diff += diff * achv[j].perceptual_weight; viter_update_color(achv[j].acolor, achv[j].perceptual_weight, map, match, omp_get_thread_num(), average_color); if (callback) callback(&achv[j], diff); } nearest_free(n); viter_finalize(map, max_threads, average_color); return total_diff / hist->total_perceptual_weight; }
void viter_finalize(colormap *map, f_pixel *average_color, float *average_color_count) { for (int i=0; i < map->colors; i++) { if (average_color_count[i]) { map->palette[i].acolor = (f_pixel){ .a = (average_color[i].a) / average_color_count[i], .r = (average_color[i].r) / average_color_count[i], .g = (average_color[i].g) / average_color_count[i], .b = (average_color[i].b) / average_color_count[i], }; } map->palette[i].popularity = average_color_count[i]; } } double viter_do_iteration(const hist *hist, colormap *map, float min_opaque_val) { f_pixel average_color[map->colors]; float average_color_count[map->colors]; hist_item *achv = hist->achv; viter_init(map, average_color,average_color_count); struct nearest_map *n = nearest_init(map); double total_diff=0; for(int j=0; j < hist->size; j++) { float diff; int match = nearest_search(n, achv[j].acolor, min_opaque_val, &diff); total_diff += diff * achv[j].perceptual_weight; viter_update_color(achv[j].acolor, achv[j].perceptual_weight, map, match, average_color,average_color_count); } nearest_free(n); viter_finalize(map, average_color,average_color_count); return total_diff / hist->total_perceptual_weight; }