* @brief Pick some initial kmeans cluster centers. * * @param blk The image block color data to compress. * @param texel_count The number of texels in the block. * @param partition_count The number of partitions in the block. * @param[out] cluster_centers The initial partition cluster center colors. */
| 58 | * @param[out] cluster_centers The initial partition cluster center colors. |
| 59 | */ |
| 60 | static void kmeans_init( |
| 61 | const image_block& blk, |
| 62 | unsigned int texel_count, |
| 63 | unsigned int partition_count, |
| 64 | vfloat4 cluster_centers[BLOCK_MAX_PARTITIONS] |
| 65 | ) { |
| 66 | promise(texel_count > 0); |
| 67 | promise(partition_count > 0); |
| 68 | |
| 69 | unsigned int clusters_selected = 0; |
| 70 | float distances[BLOCK_MAX_TEXELS]; |
| 71 | |
| 72 | // Pick a random sample as first cluster center; 145897 from random.org |
| 73 | unsigned int sample = 145897 % texel_count; |
| 74 | vfloat4 center_color = blk.texel(sample); |
| 75 | cluster_centers[clusters_selected] = center_color; |
| 76 | clusters_selected++; |
| 77 | |
| 78 | // Compute the distance to the first cluster center |
| 79 | float distance_sum = 0.0f; |
| 80 | for (unsigned int i = 0; i < texel_count; i++) |
| 81 | { |
| 82 | vfloat4 color = blk.texel(i); |
| 83 | vfloat4 diff = color - center_color; |
| 84 | float distance = dot_s(diff * diff, blk.channel_weight); |
| 85 | distance_sum += distance; |
| 86 | distances[i] = distance; |
| 87 | } |
| 88 | |
| 89 | // More numbers from random.org for weighted-random center selection |
| 90 | const float cluster_cutoffs[9] { |
| 91 | 0.626220f, 0.932770f, 0.275454f, |
| 92 | 0.318558f, 0.240113f, 0.009190f, |
| 93 | 0.347661f, 0.731960f, 0.156391f |
| 94 | }; |
| 95 | |
| 96 | unsigned int cutoff = (clusters_selected - 1) + 3 * (partition_count - 2); |
| 97 | |
| 98 | // Pick the remaining samples as needed |
| 99 | while (true) |
| 100 | { |
| 101 | // Pick the next center in a weighted-random fashion. |
| 102 | float summa = 0.0f; |
| 103 | float distance_cutoff = distance_sum * cluster_cutoffs[cutoff++]; |
| 104 | for (sample = 0; sample < texel_count; sample++) |
| 105 | { |
| 106 | summa += distances[sample]; |
| 107 | if (summa >= distance_cutoff) |
| 108 | { |
| 109 | break; |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | // Clamp to a valid range and store the selected cluster center |
| 114 | sample = astc::min(sample, texel_count - 1); |
| 115 | |
| 116 | center_color = blk.texel(sample); |
| 117 | cluster_centers[clusters_selected++] = center_color; |
no test coverage detected