[][src]Crate kmeans_colors

Calculate the k-means colors of an image.

The library should be used with default-features = false. Image examples and demonstrations of parameters can be seen on the README page.

Overview

This crate provides methods for k-means calculation using the Lab color space or RGB color space. Each space has advantages and disadvantages due to the characteristics of the color space.

The Lab calculation produces more perceptually accurate results at a slightly slower runtime. RGB calculation will converge faster than Lab but the results may not visually correlate as well to the original image. Overall, properly converged results should not differ that drastically except at lower k counts. At k=1, the average color of an image, results should match almost exactly.

The binary located in src/bin/kmeans_colors shows some examples of crate functionality. The crate uses palette for its Lab and Srgb color types.

Note: If k-means calculation is taking too long, try scaling down the image size. A full-size image is not required for calculating the color palette or dominant color.

Calculating k-means

A basic workflow consists of reading a pixel buffer in, converting it into a flat array, then using that array with the k-means functions. The following example converts an array of u8 into Lab colors then finds the k-means. To find the k-means in RGB, convert the colors into Srgb then call the corresponding functions.

use palette::{Lab, Pixel, Srgb};
use kmeans_colors::{get_kmeans_lab, map_indices_to_colors_lab, KmeansLab};

// An image buffer of one black pixel and one white pixel
let img_vec = [0u8, 0, 0, 255, 255, 255];

// Convert RGB [u8] buffer to Lab for k-means
let lab: Vec<Lab> = Srgb::from_raw_slice(&img_vec)
    .iter()
    .map(|x| x.into_format().into())
    .collect();

// Iterate over amount of runs keeping best results
let mut result = KmeansLab::new();
(0..runs).for_each(|i| {
    let run_result = get_kmeans_lab(
        k,
        max_iter,
        converge,
        verbose,
        &lab,
        seed + i as u64,
    );
    if run_result.score < result.score {
        result = run_result;
    }
});

// Convert indexed colors back to RGB [u8] for output
buffer = map_indices_to_colors_lab(&result.centroids, &result.indices);

Because the initial seeds are random, the k-means calculation should be run multiple times in order to assure that the best result has been found. The algorithm may find itself in local minima that is not the optimal result. This is especially so for Lab but RGB may only need one run.

The binary uses 8 as the default k. The iteration limit is set to 20, RGB usually converges in under 10 iterations depending on the k. The convergence factor defaults to 8.0 for Lab and 0.0025 for RGB. The number of runs defaults to 3 for one of the binary subcommands. Through testing, these numbers were found to be an adequate tradeoff between performance and accuracy. If the results do not appear correct, raise the iteration limit as convergence was probably not met.

Getting the dominant color

After k-means calculation, the dominant color can be found by sorting the results and taking the contents of the first vector. By default, the sort_indexed_colors_* functions sort from darkest to lightest color. The functions return a tuple of the form (Color, f32, u8): a color, the percentage of its presence in the buffer, and the centroid index to which it corresponds.

use kmeans_colors::sort_indexed_colors_lab;

// Using result from k-means example, sort by percentage
let mut res = sort_indexed_colors_lab(&result.centroids, &result.indices);
res.sort_unstable_by(|a, b| (b.1).partial_cmp(&a.1).unwrap());

// The most appearing color will be the first element of the vec
let dominant_color = res.first().unwrap().0;

Structs

KmeansLab

Result of k-means operation in Lab space.

KmeansRgb

Result of k-means operation in RGB space.

Functions

get_closest_centroid_lab

Find a pixel's nearest centroid color in Lab, index the pixel with that centroid.

get_closest_centroid_rgb

Find a pixel's nearest centroid color in RGB, index the pixel with that centroid.

get_kmeans_lab

Find the k-means colors of a buffer in Lab space. max_iter and converge are useed together to determine when the k-means calculation has converged. When the score is less than converge or the number of iterations reaches max_iter, the calculation is complete.

get_kmeans_rgb

Find the k-means colors of a buffer in RGB space. max_iter and converge are useed together to determine when the k-means calculation has converged. When the score is less than converge or the number of iterations reaches max_iter, the calculation is complete.

map_indices_to_colors_lab

Map pixel indices to centroid colors for output as an Srgb u8 buffer.

map_indices_to_colors_rgb

Map pixel indices to centroid colors for output as an Srgb u8 buffer.

sort_indexed_colors_lab

Sorts the Lab centroids by luminosity and calculates the percentage of each color in the buffer. Returns a vector of tuples sorted from darkest to lightest holding a centroid, its percentage, and the index of the centroid.

sort_indexed_colors_rgb

Sorts the RGB centroids by luminosity and calculates the percentage of each color in the buffer. Returns a vector of tuples sorted from darkest to lightest holding a centroid, its percentage, and the index of the centroid.