Last active
March 27, 2024 10:22
-
-
Save waffleau/6e074573d4bece3f7a007ed8536512b5 to your computer and use it in GitHub Desktop.
Extract dominant colours from an image in Ruby using MiniMagick
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def self.extract_dominant_colors(image_path, quantity=5, threshold=0.01) | |
image = MiniMagick::Image.open(image_path) | |
# Get image histogram | |
result = image.run_command('convert', image_path, '-format', '%c', '-colors', quantity, '-depth', 8, 'histogram:info:') | |
# Extract colors and frequencies from result | |
frequencies = result.scan(/([0-9]+)\:/).flatten.map { |m| m.to_f } | |
hex_values = result.scan(/(\#[0-9ABCDEF]{6,8})/).flatten | |
total_frequencies = frequencies.reduce(:+).to_f | |
# Create frequency/color pairs [frequency, hex], | |
# sort by frequency, | |
# ignore fully transparent colours | |
# select items over frequency threshold (1% by default), | |
# extract hex values, | |
# return desired quantity | |
frequencies | |
.map.with_index { |f, i| [f / total_frequencies, hex_values[i]] } | |
.sort { |r| r[0] } | |
.reject { |r| r[1].end_with?('FF') } | |
.select { |r| r[0] > threshold } | |
.map { |r| r[1][0..6] } | |
.slice(0, quantity) | |
end |
Shouldn't it reject values ending in 00
instead of FF
?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
hey @chridubois,
That line creates a histogram, which is a way of analyzing the colors present in an image. You can read more about it here, but the short explanation of that line is that it returns a list that describes how many pixels in the image are a particular color.
The
colors
argument should do what you're asking for. If you ask for fewer colors, it will group pixels that are similar. If you ask for more colors, it will give a more detailed breakdown.From my testing, it's unfortunately a bit hard to get things exactly right. For example, you might ask for 4 colors, and it will only return 3 — even though there are indeed 4 colors present in the image. I don't know enough about ImageMagick to understand why that would be. However I suspect there are ways to get around this issue — maybe you can posterize the image before getting a histogram.
Anyway, the tl;dr of it all is: adjust the
quantity
argument to be a smaller number.