#![allow(dead_code)]
#![allow(clippy::needless_range_loop)]
extern crate alloc;
use alloc::vec;
use super::{MAX_ALPHA, NUM_SEGMENTS};
const MAX_ITERS_K_MEANS: usize = 6;
pub fn assign_segments_kmeans(
alphas: &[u32; 256],
num_segments: usize,
) -> ([u8; NUM_SEGMENTS], [u8; 256], i32) {
let num_segments = num_segments.min(NUM_SEGMENTS);
let mut centers = [0u8; NUM_SEGMENTS];
let mut map = [0u8; 256];
let mut min_a = 0usize;
let mut max_a = MAX_ALPHA as usize;
for (n, &count) in alphas.iter().enumerate() {
if count > 0 {
min_a = n;
break;
}
}
for n in (min_a..=MAX_ALPHA as usize).rev() {
if alphas[n] > 0 {
max_a = n;
break;
}
}
let range_a = max_a.saturating_sub(min_a);
for (k, center) in centers.iter_mut().enumerate().take(num_segments) {
let n = 1 + 2 * k;
*center = (min_a + (n * range_a) / (2 * num_segments)) as u8;
}
let mut accum = [0u32; NUM_SEGMENTS];
let mut dist_accum = [0u32; NUM_SEGMENTS];
let mut weighted_average = 0i32;
let mut total_weight = 0u32;
for _ in 0..MAX_ITERS_K_MEANS {
for i in 0..num_segments {
accum[i] = 0;
dist_accum[i] = 0;
}
let mut current_center = 0usize;
for a in min_a..=max_a {
if alphas[a] > 0 {
while current_center + 1 < num_segments {
let d_curr = (a as i32 - centers[current_center] as i32).abs();
let d_next = (a as i32 - centers[current_center + 1] as i32).abs();
if d_next < d_curr {
current_center += 1;
} else {
break;
}
}
map[a] = current_center as u8;
dist_accum[current_center] += a as u32 * alphas[a];
accum[current_center] += alphas[a];
}
}
let mut displaced = 0i32;
weighted_average = 0;
total_weight = 0;
for n in 0..num_segments {
if accum[n] > 0 {
let new_center = ((dist_accum[n] + accum[n] / 2) / accum[n]) as u8;
displaced += (centers[n] as i32 - new_center as i32).abs();
centers[n] = new_center;
weighted_average += new_center as i32 * accum[n] as i32;
total_weight += accum[n];
}
}
if displaced < 5 {
break;
}
}
if total_weight > 0 {
weighted_average = (weighted_average + total_weight as i32 / 2) / total_weight as i32;
} else {
weighted_average = 128;
}
for i in num_segments..NUM_SEGMENTS {
centers[i] = centers[num_segments - 1];
}
(centers, map, weighted_average)
}
use crate::encoder::fast_math::quality_to_compression;
pub fn compute_segment_quant(quality: u8, segment_alpha: i32, sns_strength: u8) -> u8 {
const SNS_TO_DQ: f64 = 0.9;
let amp = SNS_TO_DQ * (sns_strength as f64) / 100.0 / 128.0;
let expn = 1.0 - amp * (segment_alpha as f64);
if expn <= 0.0 {
let c = quality_to_compression(quality);
let q = crate::encoder::fast_math::round(127.0 * (1.0 - c)) as i32;
return q.clamp(0, 127) as u8;
}
let c_base = quality_to_compression(quality);
let c = crate::encoder::fast_math::pow(c_base, expn);
let q = (127.0 * (1.0 - c)) as i32;
q.clamp(0, 127) as u8
}
pub fn smooth_segment_map(segment_map: &mut [u8], mb_w: usize, mb_h: usize) {
if mb_w < 3 || mb_h < 3 {
return; }
const MAJORITY_THRESHOLD: u8 = 5;
let mut tmp = vec![0u8; mb_w * mb_h];
tmp.copy_from_slice(segment_map);
for y in 1..mb_h - 1 {
for x in 1..mb_w - 1 {
let idx = x + y * mb_w;
let mut counts = [0u8; NUM_SEGMENTS];
let current_seg = segment_map[idx];
counts[segment_map[idx - mb_w - 1] as usize] += 1; counts[segment_map[idx - mb_w] as usize] += 1; counts[segment_map[idx - mb_w + 1] as usize] += 1; counts[segment_map[idx - 1] as usize] += 1; counts[segment_map[idx + 1] as usize] += 1; counts[segment_map[idx + mb_w - 1] as usize] += 1; counts[segment_map[idx + mb_w] as usize] += 1; counts[segment_map[idx + mb_w + 1] as usize] += 1;
let mut majority_seg = current_seg;
for (seg, &count) in counts.iter().enumerate() {
if count >= MAJORITY_THRESHOLD {
majority_seg = seg as u8;
break;
}
}
tmp[idx] = majority_seg;
}
}
segment_map.copy_from_slice(&tmp);
}