Alec Barton
Alec Barton

Reputation: 237

Mathematically calculate "Vibrancy" of a color

Im writing a program that analyzes a picture and returns the most prominent color. Its simple to get the most frequently occurring color but I've found that very often this color is a dark black/gray/brown or a white and not the "color" you would associate with the image. So I'd like to get the top 5 colors and compare them based on some metric to determine which color is most "Vibrant/Colorful" and return that color.

Saturation wont work in this case because a saturated black will be ranked above a lighter pink and Brightness/Luminance wont work because a white will be ranked about a darker red. Im want to know what metric I can use to judge this. I recognize this is kind of an obtuse question but I know of other programs that do similar things so I assume there must be some way to calculate "Vibrancy/Colorfulness". It doesn't need to be perfect just work most of the time

For what its worth I'm working in javascript but the actual code is not the issue, I just need the equation I can use and then I can implement it


Edit with Solution:

After trying several different formulas I had the most success with the following

let colorfulness = ((max+ min) * (max-min))/max

where max & min are the highest and lowest RGB values, respectively. This page has a more detailed explanation of the formula itself.

This will return a value between 0 and 255 with 0 being least colorful and 255 being most. From running this on a bunch of different colors, I found that for my application any value above 50 was colorful enough, thought you can adjust this.

My final code is as follows

function getColorFromImage(image) {
    //gets the three most commonly occuring, distinct colors in an image as RGB values, in order of their frequency
    let palette = getPaletteFromImage(image, 3)

    for (let color of palette){
        var colorfulness = 0

        //(0,0,0) will return NAN if used in the formula, if (0,0,0) leave colorfulness as its default 0
        if (color != [0,0,0]){
            //get min & max values
            let min = Math.min(color)
            let max = Math.max(color)

            //calculate colorfulness of color
            colorfulness = ((max+ min) * (max-min))/max
        }

        //compare color's colorfulness against a threshold to determine if color is "colorful" enough
        //ive found 50 is a good threshold but adjust as needed
        if (colorfulness >= 50.0){
            return color
        }
    }

    //if none of the colors are deemed to be sufficiently colorful, just return the most common
    return palette[0]
}

Upvotes: 2

Views: 1475

Answers (3)

Omiod
Omiod

Reputation: 11643

Vibrance is not an attribuite of a single color like saturation, it instead considers the image globally. Increasing the vibrance of an image (as usually found in many photo editing software) means increasing the saturation of the less saturated colors to match the already saturated ones.

Upvotes: 1

Peter O.
Peter O.

Reputation: 32898

There is no common way to define "vibrancy" of a color. Thus, you can try combining multiple metrics such as "saturation", "brightness", and "luminance". The lower the overall metric is, the better. The following is an example in pseudocode.

// Compare metrics to "ideal"
var deltaSat = Saturation(thisColor) - idealSat;
var deltaBright = Brightness(thisColor) - idealBrightness;
var deltaLum = Luminance(thisColor) - idealLum;
// Calculate overall distance from ideal; the lower
// the better.
var dist = sqrt((deltaSat*deltaSat) +
   (deltaBright*deltaBright) +
   (deltaLum*deltaLum))

(If your issue is merely that you're having trouble calculating a metric for a given color, see my page on color topics for programmers.)

If your criteria for "vibrancy" are complex enough, you should consider using machine learning techniques such as classification algorithms. In machine learning in general:

  • You train a model to recognize different categories (such as "vibrant" and "non-vibrant" colors in this case).
  • You test the model to check how well it performs.
  • Once the model works well, you deploy the model and use it to predict whether a color is "vibrant" or "non-vibrant".

Machine learning is quite complex, however, so you should try the simpler method given earlier in this answer.

Upvotes: 1

Alec Barton
Alec Barton

Reputation: 237

After trying several different formulas I had the most success with the following

let colorfulness = ((max+ min) * (max-min))/max

where max & min are the highest and lowest RGB values, respectively. This page has a more detailed explanation of the formula itself.

This will return a value between 0 and 255 with 0 being least colorful and 255 being most. From running this on a bunch of different colors, I found that for my application any value above 50 was colorful enough, thought you can adjust this.

My final code is as follows

function getColorFromImage(image) {
    //gets the three most commonly occuring, distinct colors in an image as RGB values, in order of their frequency
    let palette = getPaletteFromImage(image, 3)

    for (let color of palette){
        var colorfulness = 0

        //(0,0,0) will return NAN if used in the formula, if (0,0,0) leave colorfulness as its default 0
        if (color != [0,0,0]){
            //get min & max values
            let min = Math.min(color)
            let max = Math.max(color)

            //calculate colorfulness of color
            colorfulness = ((max+ min) * (max-min))/max
        }

        //compare color's colorfulness against a threshold to determine if color is "colorful" enough
        //ive found 50 is a good threshold but adjust as needed
        if (colorfulness >= 50.0){
            return color
        }
    }

    //if none of the colors are deemed to be sufficiently colorful, just return the most common
    return palette[0]
}

Upvotes: 1

Related Questions