static void AssignSegments(VP8Encoder* const enc, const int alphas[MAX_ALPHA + 1]) { const int nb = enc->segment_hdr_.num_segments_; int centers[NUM_MB_SEGMENTS]; int weighted_average = 0; int map[MAX_ALPHA + 1]; int a, n, k; int min_a = 0, max_a = MAX_ALPHA, range_a; // 'int' type is ok for histo, and won't overflow int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS]; // bracket the input for (n = 0; n <= MAX_ALPHA && alphas[n] == 0; ++n) {} min_a = n; for (n = MAX_ALPHA; n > min_a && alphas[n] == 0; --n) {} max_a = n; range_a = max_a - min_a; // Spread initial centers evenly for (n = 1, k = 0; n < 2 * nb; n += 2) { centers[k++] = min_a + (n * range_a) / (2 * nb); } for (k = 0; k < MAX_ITERS_K_MEANS; ++k) { // few iters are enough int total_weight; int displaced; // Reset stats for (n = 0; n < nb; ++n) { accum[n] = 0; dist_accum[n] = 0; } // Assign nearest center for each 'a' n = 0; // track the nearest center for current 'a' for (a = min_a; a <= max_a; ++a) { if (alphas[a]) { while (n < nb - 1 && abs(a - centers[n + 1]) < abs(a - centers[n])) { n++; } map[a] = n; // accumulate contribution into best centroid dist_accum[n] += a * alphas[a]; accum[n] += alphas[a]; } } // All point are classified. Move the centroids to the // center of their respective cloud. displaced = 0; weighted_average = 0; total_weight = 0; for (n = 0; n < nb; ++n) { if (accum[n]) { const int new_center = (dist_accum[n] + accum[n] / 2) / accum[n]; displaced += abs(centers[n] - new_center); centers[n] = new_center; weighted_average += new_center * accum[n]; total_weight += accum[n]; } } weighted_average = (weighted_average + total_weight / 2) / total_weight; if (displaced < 5) break; // no need to keep on looping... } // Map each original value to the closest centroid for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { VP8MBInfo* const mb = &enc->mb_info_[n]; const int alpha = mb->alpha_; mb->segment_ = map[alpha]; mb->alpha_ = centers[map[alpha]]; // for the record. } if (nb > 1) { const int smooth = (enc->config_->preprocessing & 1); if (smooth) SmoothSegmentMap(enc); } SetSegmentAlphas(enc, centers, weighted_average); // pick some alphas. }
static void AssignSegments(VP8Encoder* const enc, const int alphas[MAX_ALPHA + 1]) { const int nb = enc->segment_hdr_.num_segments_; int centers[NUM_MB_SEGMENTS]; int weighted_average = 0; int map[MAX_ALPHA + 1]; int a, n, k; int min_a = 0, max_a = MAX_ALPHA, range_a; int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS]; for (n = 0; n <= MAX_ALPHA && alphas[n] == 0; ++n) {} min_a = n; for (n = MAX_ALPHA; n > min_a && alphas[n] == 0; --n) {} max_a = n; range_a = max_a - min_a; for (n = 1, k = 0; n < 2 * nb; n += 2) { centers[k++] = min_a + (n * range_a) / (2 * nb); } for (k = 0; k < MAX_ITERS_K_MEANS; ++k) { int total_weight; int displaced; for (n = 0; n < nb; ++n) { accum[n] = 0; dist_accum[n] = 0; } n = 0; for (a = min_a; a <= max_a; ++a) { if (alphas[a]) { while (n < nb - 1 && abs(a - centers[n + 1]) < abs(a - centers[n])) { n++; } map[a] = n; dist_accum[n] += a * alphas[a]; accum[n] += alphas[a]; } } displaced = 0; weighted_average = 0; total_weight = 0; for (n = 0; n < nb; ++n) { if (accum[n]) { const int new_center = (dist_accum[n] + accum[n] / 2) / accum[n]; displaced += abs(centers[n] - new_center); centers[n] = new_center; weighted_average += new_center * accum[n]; total_weight += accum[n]; } } weighted_average = (weighted_average + total_weight / 2) / total_weight; if (displaced < 5) break; } for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { VP8MBInfo* const mb = &enc->mb_info_[n]; const int alpha = mb->alpha_; mb->segment_ = map[alpha]; mb->alpha_ = centers[map[alpha]]; } if (nb > 1) { const int smooth = (enc->config_->preprocessing & 1); if (smooth) SmoothSegmentMap(enc); } SetSegmentAlphas(enc, centers, weighted_average); }