Rust图像处理库kmeans_colors的使用:高效K均值聚类算法实现图像色彩量化与调色板生成

Rust图像处理库kmeans_colors的使用:高效K均值聚类算法实现图像色彩量化与调色板生成

kmeans-colors是一个使用k-means++初始化的k-means聚类算法来计算图像中k种平均颜色的Rust库。

基本用法

k-means聚类的工作原理是从图像中随机猜测k种颜色(称为质心)开始。对于每个步骤,遍历图像中的每个像素以找到颜色最接近它的质心。然后,质心计算所有接近它们的颜色的平均值并移动到该颜色。这个过程重复进行,直到质心停止移动或达到最大步数。

kmeans_colors -i gfx/pink.jpg -k 2 -o pink2

调色板生成

kmeans_colors -i gfx/mountains.jpg --no-file --palette
kmeans_colors -i gfx/pink.jpg --no-file --palette --proportional
kmeans_colors -i gfx/flowers.jpg --no-file --palette --proportional --sort

完整示例代码

use kmeans_colors::{get_kmeans, Kmeans, Sort};
use palette::{Lab, Pixel, Srgb};
use image::{open, RgbImage};

fn main() {
    // 打开图像文件
    let img = open("input.jpg").unwrap().to_rgb8();
    
    // 将图像像素转换为Lab颜色空间
    let lab: Vec<Lab> = img.pixels()
        .map(|p| Srgb::new(
            p[0] as f32 / 255.0,
            p[1] as f32 / 255.0,
            p[2] as f32 / 255.0
        ).into())
        .collect();

    // 设置k-means参数
    let k = 8; // 要提取的颜色数量
    let max_iter = 20; // 最大迭代次数
    let converge = 1.0; // 收敛因子
    let runs = 3; // 运行次数

    // 执行k-means聚类
    let kmeans = get_kmeans(
        &lab,
        k,
        max_iter,
        converge,
        runs,
        0 // 随机种子
    );

    // 获取聚类结果
    let result = kmeans.result;
    let dominant_colors = result.centroids;
    
    // 按颜色频率排序
    let sorted = Sort::sort_indexed_colors(&result.indices, &dominant_colors);
    
    // 打印主要颜色
    for (i, color) in sorted.centroids.iter().enumerate() {
        let rgb: Srgb = Srgb::from(*color);
        let pixel = rgb.into_format().into_raw();
        println!(
            "Color {}: #{:02x}{:02x}{:02x} - {:.2}%",
            i+1,
            (pixel[0] * 255.0) as u8,
            (pixel[1] * 255.0) as u8,
            (pixel[2] * 255.0) as u8,
            sorted.percentage[i] * 100.0
        );
    }
    
    // 生成量化图像
    let mut quantized = RgbImage::new(img.width(), img.height());
    for (i, &idx) in result.indices.iter().enumerate() {
        let rgb: Srgb = Srgb::from(dominant_colors[idx]);
        let pixel = rgb.into_format().into_raw();
        let x = i as u32 % img.width();
        let y = i as u32 / img.width();
        quantized.put_pixel(x, y, image::Rgb([
            (pixel[0] * 255.0) as u8,
            (pixel[1] * 255.0) as u8,
            (pixel[2] * 255.0) as u8
        ]));
    }
    
    // 保存结果
    quantized.save("quantized.png").unwrap();
}

特性

  • 从图像创建调色板
  • Lab色彩空间或RGB色彩空间计算
  • 查找与输入颜色最接近的颜色
  • 用自定义颜色替换颜色
  • 可调整的迭代次数和重复次数
  • 打印平均颜色
  • 打印图像中每种颜色的百分比
  • 透明度支持
  • kmeans++中心初始化
  • 支持多图像输入进行批量处理
  • 指定随机种子以获得可重现的结果

安装

在Cargo.toml中添加:

[dependencies.kmeans_colors]
version = "0.6"
default-features = false

许可证

MIT或Apache-2.0


1 回复

Rust图像处理库kmeans_colors的使用:高效K均值聚类算法实现图像色彩量化与调色板生成

kmeans_colors是一个基于Rust的高效图像处理库,专门用于实现K均值聚类算法进行图像色彩量化和调色板生成。该库提供了简单易用的API,能够帮助开发者快速实现图像色彩压缩、主题色提取等功能。

主要特性

  • 高效的K均值聚类算法实现
  • 支持多种色彩空间(RGB, Lab等)
  • 并行处理加速计算
  • 可定制的聚类参数
  • 轻量级且无依赖

安装方法

在Cargo.toml中添加依赖:

[dependencies]
kmeans_colors = "0.5"
image = "0.24"  # 用于图像加载和保存

基本使用方法

1. 从图像中提取调色板

use kmeans_colors::{get_kmeans, Kmeans, Calculate};
use image::{io::Reader, RgbImage};

fn main() {
    // 加载图像
    let img = Reader::open("input.jpg")
        .unwrap()
        .decode()
        .unwrap()
        .into_rgb8();
    
    // 将图像像素转换为Vec<[f32;3]>
    let pixels: Vec<[f32; 3]> = img.pixels()
        .map(|p| [p[0] as f32, p[1] as f32, p[2] as f32])
        .collect();
    
    // 运行K均值聚类算法
    let k = 8; // 聚类数量
    let max_iter = 20; // 最大迭代次数
    let converge = 1.0; // 收敛阈值
    
    let kmeans = get_kmeans(
        &pixels,
        k,
        max_iter,
        converge,
        Kmeans::init_kmeanplusplus,
        &Calculate::default(),
    );
    
    // 获取聚类中心(调色板)
    let palette = kmeans.centroids;
    
    println!("提取的调色板颜色:");
    for color in palette {
        println!("RGB: {:?}", color);
    }
}

2. 图像色彩量化

use kmeans_colors::{get_kmeans, Kmeans, Calculate};
use image::{io::Reader, RgbImage, Rgb};

fn main() {
    // 加载图像
    let mut img = Reader::open("input.jpg")
        .unwrap()
        .decode()
        .unwrap()
        .into_rgb8();
    
    let pixels: Vec<[f32; 3]> = img.pixels()
        .map(|p| [p[0] as f32, p[1] as f32, p[2] as f32])
        .collect();
    
    let k = 8;
    let kmeans = get_kmeans(
        &pixels,
        k,
        20,
        1.0,
        Kmeans::init_kmeanplusplus,
        &Calculate::default(),
    );
    
    // 将每个像素替换为最近的聚类中心颜色
    let result = kmeans.map_to極d(&pixels);
    
    // 更新图像
    for (i, pixel) in img.pixels_mut().enumerate() {
        let rgb = result[i];
        *pixel = Rgb([
            rgb[0] as u8,
            rgb[1] as u8,
            rgb[2] as u8,
        ]);
    }
    
    // 保存结果
    img.save("output.jpg").unwrap();
}

3. 使用Lab色彩空间获得更准确的结果

use kmeans_colors::{get_kmeans_hsv, Kmeans, Calculate};
use palette::{Srgb, IntoColor};

fn main() {
    // 假设我们已经有了像素数据
    let pixels: Vec<[f32; 3]> = /* ... */;
    
    // 转换为Lab色彩空间
    let lab_pixels: Vec<_> = pixels.iter()
        .map(|&rgb| {
            let srgb = Srgb::new(rgb[0], rgb[1], rgb[2]);
            srgb.into_color::<palette::Lab>().to_components()
        })
        .collect();
    
    let k = 5;
    let kmeans = get_kmeans(
        &lab_pixels,
        k,
        20,
        1.0,
        Kmeans::init_kmeanplusplus,
        &Calculate::default(),
    );
    
    // 处理结果...
}

高级用法

自定义初始化方法

use kmeans_colors::{get_kmeans, Kmeans, Calculate};

fn custom_init(pixels: &[[f32; 3]], k: usize) -> Vec<[f32; 3]> {
    // 实现自定义的聚类中心初始化逻辑
    // 例如随机选择k个像素作为初始中心
    use rand::seq::SliceRandom;
    let mut rng = rand::thread_rng();
    pixels.choose_multiple(&mut rng, k)
        .cloned()
        .collect()
}

let kmeans = get_kmeans(
    &pixels,
    k,
    max_iter,
    converge,
    custom_init,
    &Calculate::default(),
);

并行处理加速

use kmeans_colors::{get_kmeans_par, Kmeans, Calculate};

let kmeans = get_kmeans_par(  // 注意这里使用_par版本
    &pixels,
    k,
    max_iter,
    converge,
    Kmeans::init_kmeanplusplus,
    &Calculate::default(),
);

性能优化建议

  1. 对于大图像,可以先缩小图像尺寸再进行聚类
  2. 调整max_iterconverge参数平衡速度与精度
  3. 使用Lab色彩空间可能获得更符合人眼感知的结果
  4. 启用并行处理加速计算

kmeans_colors库为Rust开发者提供了强大而高效的图像色彩处理能力,特别适合需要图像主题色提取、色彩压缩等功能的场景。

完整示例代码

下面是一个完整的示例,展示了如何使用kmeans_colors库从图像中提取调色板并进行色彩量化:

use kmeans_colors::{get_kmeans_par, Kmeans, Calculate};
use image::{io::Reader, RgbImage, Rgb};
use palette::{Srgb, IntoColor};
use std::time::Instant;

fn main() {
    // 1. 加载图像
    let start = Instant::now();
    let mut img = Reader::open("input.jpg")
        .expect("无法打开图像文件")
        .decode()
        .expect("无法解码图像")
        .into_rgb8();
    println!("图像加载耗时: {:?}", start.elapsed());

    // 2. 准备像素数据
    let pixels: Vec<[f32; 3]> = img.pixels()
        .map(|p| [p[0] as f32, p[1] as f32, p[2] as f32])
        .collect();

    // 3. 转换为Lab色彩空间(更符合人眼感知)
    let lab_start = Instant::now();
    let lab_pixels: Vec<_> = pixels.iter()
        .map(|&rgb| {
            Srgb::new(rgb[0], rgb[1], rgb[2])
                .into_color::<palette::Lab>()
                .to_components()
        })
        .collect();
    println!("色彩空间转换耗时: {:?}", lab_start.elapsed());

    // 4. 运行K均值聚类算法
    let k = 8; // 要提取的颜色数量
    let max_iter = 20; // 最大迭代次数
    let converge = 1.0; // 收敛阈值
    
    let kmeans_start = Instant::now();
    let kmeans = get_kmeans_par(
        &lab_pixels,
        k,
        max_iter,
        converge,
        Kmeans::init_kmeanplusplus,
        &Calculate::default(),
    );
    println!("K均值聚类耗时: {:?}", kmeans_start.elapsed());

    // 5. 获取调色板(RGB格式)
    let palette = kmeans.centroids.iter()
        .map(|&lab| {
            let lab = palette::Lab::from_components(lab);
            let rgb = Srgb::from_color(lab);
            [rgb.red, rgb.green, rgb.blue]
        })
        .collect::<Vec<_>>();

    println!("\n提取的调色板颜色(RGB):");
    for (i, color) in palette.iter().enumerate() {
        println!("颜色{}: [{:.1}, {:.1}, {:.1}]", i+1, color[0], color[1], color[2]);
    }

    // 6. 图像色彩量化
    let quant_start = Instant::now();
    let result = kmeans.map_to_centroids(&lab_pixels);
    
    // 更新图像像素
    for (i, pixel) in img.pixels_mut().enumerate() {
        let rgb = palette[result[i].cluster as usize];
        *pixel = Rgb([
            (rgb[0] * 255.0).round() as u8,
            (rgb[1] * 255.0).round() as u8,
            (rgb[2] * 255.0).round() as u8,
        ]);
    }
    println!("色彩量化耗时: {:?}", quant_start.elapsed());

    // 7. 保存结果
    img.save("output.png").expect("无法保存图像");
    println!("\n总耗时: {:?}", start.elapsed());
}

这个完整示例包含了以下功能:

  1. 图像加载与预处理
  2. RGB到Lab色彩空间的转换
  3. 使用并行K均值聚类算法提取调色板
  4. 将结果转换回RGB色彩空间
  5. 图像色彩量化处理
  6. 性能计时和结果输出

你可以根据需要调整聚类数量k、最大迭代次数等参数来获得不同的效果。

回到顶部