So, I\'m working on a fresh iteration of a web app. And, we\'ve found that our users are obsessed with being lazy. Really lazy. In fact, the more wor
Similar to McWafflestix's solution, the specifics will need to be tweaked, but my general approach would be...
(I agree that HSV is the right space)
Grab a histogram of the image, filter it to smooth the noise, and find the highest score where V and S are in a (possibly dynamic) gamut of likely "subject" colors. A red bird on a blue sky will require that we be smart enough not to base our scheme on the blue, but on the red. This may require some guesses about photo composition, like "centered in the frame" and "rule of thirds" analysis could give you a probability of a color being relevant. Regardless, this is our the base color.
Along the lines of Kuler, calculate colors that compliment the base by moving around the color wheel. Extra points for a calculated compliment if it also appeared prominently in the histogram from step 1.
Use the base color and calculated compliments to derive pleasing adjunct colors, such as lighter and darker versions of each, more or less saturated, etc.
I'm a bit late to this, but I would implement a Kohonen Map (http://en.wikipedia.org/wiki/Self-organizing_map) in a 3d colour space. The number of points on the map would be the number of distinct colours you wanted for your palette, then train your map using all of the pixels from the image. I've not tried this myself but I'm sure someone else has thought of it already.
I do this to find the palette used for images (of artwork).
I start with imagemagick and resize a large image down to a workable size (i.e. 400 px on largest dimension.) This actually helps convert subtle local color differences into fewer pixels with an average of those colors.
Loop through each pixel present in the resized image, reading the RGB values for each pixel, convert the RGB to HSB and store the HSB values to an array.
For each pixel color found, I then divide the Hue range (0,255) by 16, the Saturation range (0,100) by 10, and Brightness range (0,100) by 10. Round the result up or down to an integer. This helps group pixels into categories of similar colors.
So a pixel with HSB of 223,64,76 would be in the category 14,6,8
Within each category, you can still find the exact color of each pixel, but for the most part the categories themselves are a close color match to the source image.
Choose to divide the HSB into finer divisions if you want better color replication from the categories. ie. divide each H,S,B by 8,5,5 instead of 16,10,10.
Count up the most prevalent color categories, sort and display. I discard color categories with very few pixel counts.
Note: This is really designed for artwork that has very few pixels with identical color values (i.e. paintings with shadows and gradients.)
For the most part, an HTML page probably has more pixels that exactly match a specific color value (i.e. background color, text color, etc. are all going to be the same color wherever they appear.)
You can take a look at:
https://github.com/dcollien/Dreamcoat
which does this in CoffeeScript (literate coffee, so it's well documented)
Demo here: http://dcollien.github.io/Dreamcoat/test.html
It has both a colour quantization approach, and a KMeans approach which are combined.
There are already a lot of good suggestion how to find the primary colors and I would try similar approaches. For finding the text color, I have another suggestion.
Calculate the histogram for each line in the image from top to bottom. Every time you reach the base line of a line there should be a strong drop in the frequency of the text color. The frequency will remain low until you reach the upper case letters of the next line followd by a second step when you reach the lower case letters.
If there is another strong peak that becomes even larger when you hit the base line, you have found the background color. A gradient background will smooth this peak and the changes of the peaks - when you enter or leave a new line - will be smoothed by antialiasing.
To find the primary X colors, screencap the app. Run a color histogram on the image. The top X colors in the histogram are the theme. Edit: if gradients are used, you'll want to pick distinct "peaks" of colors; that is, you may have a whole bunch of colors right around "orange" if orange is one of the main colors used in the gradients. Effectively, just enforce a certain amount of distance between your colors chosen from the histogram.
Tweaking the color scheme can best be done in HSV space; convert your colors to HSV space, and if the users want it to be "Brighter", increase the Value, if they want it to be more "Colorful", increase the Saturation, etc.
Determining the text color can best be done by characterizing areas of high variability (high frequency in Fourier space). Within those areas, you should have either: two colors, text and background, in which case your text is the lesser-used color; or you'll have several colors, text and background image colors, in which case the text color is the most common color.