Dominant Image Color Algorithms

View on Github

This is just a playground for testing out different algorithms for extracting dominant colors from images. I've tried various techniques for improving optimization, including downsampling, shifting certain color space channels, and eliminating Lab luminance altogether. Difficult to beat the speed of the MMCQ algorithm, though.

K-means clustering using the ml-kmeans and node-kmeans libraries. MMCQ (modified median cut quantization) algorithm from Leptonica library in colorquant2.c, later implemented in the quantize Javascript package. (quantize is the code used in the Color Thief library.) node-vibrant also uses MMCQ. Huge shoutout to the original author of MMCQ as implemented in Leptonica, Dan Bloomberg.

Naive Hierarchical Clustering (5.27s)

Naive Mean Shift Clustering (0.29s)

K-means RGB (node-kmeans) (13.98s)

K-means RGB sampled 1/4 (node-kmeans) (10.39s)

K-means RGB sampled 1/16 (node-kmeans) (2.61s)

K-means RGB sampled 1/64 (node-kmeans) (0.76s)

K-means HSV sampled 1/16 (node-kmeans) (1.59s)

K-means Lab sampled 1/16 (node-kmeans) (1.58s)

MMCQ (0.2s)

2 step: MMCQ then K-means (0.21s)

2 step: MMCQ then Hierarchical Clustering (0.22s)

My implementation with node-kmeans (0.24s)

Vibrant (0.25s)

Naive Hierarchical Clustering (11.62s)

Naive Mean Shift Clustering (0.5s)

K-means RGB (node-kmeans) (49.1s)

K-means RGB sampled 1/4 (node-kmeans) (7.01s)

K-means RGB sampled 1/16 (node-kmeans) (2.77s)

K-means RGB sampled 1/64 (node-kmeans) (0.38s)

K-means HSV sampled 1/16 (node-kmeans) (1.43s)

K-means Lab sampled 1/16 (node-kmeans) (1.52s)

MMCQ (0.2s)

2 step: MMCQ then K-means (0.18s)

2 step: MMCQ then Hierarchical Clustering (0.17s)

My implementation with node-kmeans (0.22s)

Vibrant (0.2s)

Naive Hierarchical Clustering (5.53s)

Naive Mean Shift Clustering (0.33s)

K-means RGB (node-kmeans) (75.49s)

K-means RGB sampled 1/4 (node-kmeans) (13.43s)

K-means RGB sampled 1/16 (node-kmeans) (2.08s)

K-means RGB sampled 1/64 (node-kmeans) (0.37s)

K-means HSV sampled 1/16 (node-kmeans) (1.07s)

K-means Lab sampled 1/16 (node-kmeans) (1.9s)

MMCQ (0.24s)

2 step: MMCQ then K-means (0.23s)

2 step: MMCQ then Hierarchical Clustering (0.25s)

My implementation with node-kmeans (0.26s)

Vibrant (0.27s)

Naive Hierarchical Clustering (9.95s)

Naive Mean Shift Clustering (0.41s)

K-means RGB (node-kmeans) (136.87s)

K-means RGB sampled 1/4 (node-kmeans) (38.73s)

K-means RGB sampled 1/16 (node-kmeans) (7.45s)

K-means RGB sampled 1/64 (node-kmeans) (0.71s)

K-means HSV sampled 1/16 (node-kmeans) (1.37s)

K-means Lab sampled 1/16 (node-kmeans) (2.86s)

MMCQ (0.3s)

2 step: MMCQ then K-means (0.27s)

2 step: MMCQ then Hierarchical Clustering (0.29s)

My implementation with node-kmeans (0.41s)

Vibrant (0.31s)

Naive Hierarchical Clustering (10.65s)

Naive Mean Shift Clustering (0.85s)

K-means RGB (node-kmeans) (111.18s)

K-means RGB sampled 1/4 (node-kmeans) (33.16s)

K-means RGB sampled 1/16 (node-kmeans) (9.43s)

K-means RGB sampled 1/64 (node-kmeans) (2s)

K-means HSV sampled 1/16 (node-kmeans) (2s)

K-means Lab sampled 1/16 (node-kmeans) (2.86s)

MMCQ (0.34s)

2 step: MMCQ then K-means (0.32s)

2 step: MMCQ then Hierarchical Clustering (0.27s)

My implementation with node-kmeans (0.44s)

Vibrant (0.34s)

Naive Hierarchical Clustering (14.75s)

Naive Mean Shift Clustering (0.29s)

K-means RGB (node-kmeans) (44.07s)

K-means RGB sampled 1/4 (node-kmeans) (8.32s)

K-means RGB sampled 1/16 (node-kmeans) (1.13s)

K-means RGB sampled 1/64 (node-kmeans) (0.26s)

K-means HSV sampled 1/16 (node-kmeans) (0.51s)

K-means Lab sampled 1/16 (node-kmeans) (0.67s)

MMCQ (0.12s)

2 step: MMCQ then K-means (0.11s)

2 step: MMCQ then Hierarchical Clustering (0.11s)

My implementation with node-kmeans (0.41s)

Vibrant (0.14s)

Naive Hierarchical Clustering (3.49s)

Naive Mean Shift Clustering (0.23s)

K-means RGB (node-kmeans) (35.14s)

K-means RGB sampled 1/4 (node-kmeans) (16.42s)

K-means RGB sampled 1/16 (node-kmeans) (5.02s)

K-means RGB sampled 1/64 (node-kmeans) (0.32s)

K-means HSV sampled 1/16 (node-kmeans) (1.29s)

K-means Lab sampled 1/16 (node-kmeans) (1.89s)

MMCQ (0.17s)

2 step: MMCQ then K-means (0.16s)

2 step: MMCQ then Hierarchical Clustering (0.17s)

My implementation with node-kmeans (0.27s)

Vibrant (0.18s)

Naive Hierarchical Clustering (4.34s)

Naive Mean Shift Clustering (0.32s)

K-means RGB (node-kmeans) (30.74s)

K-means RGB sampled 1/4 (node-kmeans) (9.78s)

K-means RGB sampled 1/16 (node-kmeans) (1.75s)

K-means RGB sampled 1/64 (node-kmeans) (0.55s)

K-means HSV sampled 1/16 (node-kmeans) (2.05s)

K-means Lab sampled 1/16 (node-kmeans) (2.29s)

MMCQ (0.27s)

2 step: MMCQ then K-means (0.29s)

2 step: MMCQ then Hierarchical Clustering (0.28s)

My implementation with node-kmeans (0.38s)

Vibrant (0.23s)

Naive Hierarchical Clustering (4.7s)

Naive Mean Shift Clustering (0.32s)

K-means RGB (node-kmeans) (49.9s)

K-means RGB sampled 1/4 (node-kmeans) (27.36s)

K-means RGB sampled 1/16 (node-kmeans) (4.5s)

K-means RGB sampled 1/64 (node-kmeans) (0.45s)

K-means HSV sampled 1/16 (node-kmeans) (0.92s)

K-means Lab sampled 1/16 (node-kmeans) (0.99s)

MMCQ (0.18s)

2 step: MMCQ then K-means (0.18s)

2 step: MMCQ then Hierarchical Clustering (0.21s)

My implementation with node-kmeans (0.32s)

Vibrant (0.2s)

Naive Hierarchical Clustering (1.37s)

Naive Mean Shift Clustering (0.1s)

K-means RGB (node-kmeans) (11.51s)

K-means RGB sampled 1/4 (node-kmeans) (2.08s)

K-means RGB sampled 1/16 (node-kmeans) (0.46s)

K-means RGB sampled 1/64 (node-kmeans) (0.14s)

K-means HSV sampled 1/16 (node-kmeans) (0.44s)

K-means Lab sampled 1/16 (node-kmeans) (0.73s)

MMCQ (0.07s)

2 step: MMCQ then K-means (0.08s)

2 step: MMCQ then Hierarchical Clustering (0.08s)

My implementation with node-kmeans (0.1s)

Vibrant (0.09s)

Naive Hierarchical Clustering (10.76s)

Naive Mean Shift Clustering (0.37s)

K-means RGB (node-kmeans) (32.73s)

K-means RGB sampled 1/4 (node-kmeans) (9.2s)

K-means RGB sampled 1/16 (node-kmeans) (3.55s)

K-means RGB sampled 1/64 (node-kmeans) (0.69s)

K-means HSV sampled 1/16 (node-kmeans) (1.95s)

K-means Lab sampled 1/16 (node-kmeans) (1.78s)

MMCQ (0.23s)

2 step: MMCQ then K-means (0.26s)

2 step: MMCQ then Hierarchical Clustering (0.28s)

My implementation with node-kmeans (0.36s)

Vibrant (0.27s)