Skip to content

Instantly share code, notes, and snippets.

@floriankapaun
Created December 24, 2020 08:55
Show Gist options
  • Save floriankapaun/d73722474d309932bce5c50f0d382420 to your computer and use it in GitHub Desktop.
Save floriankapaun/d73722474d309932bce5c50f0d382420 to your computer and use it in GitHub Desktop.
Calculate "colorfulness" of image in JavaScript
/**
* Returns the colorfulness (0-1) of an image.
*
* Example implementation: https://codepen.io/flo__/pen/GRjMaWJ
*
* 'img' is a 1d array containing rgba values for each pixel as retrieved by ctx.getImageData()
*/
const calculateColorfulness = (img) => {
const R_OFFSET = 0;
const G_OFFSET = 1;
const B_OFFSET = 2;
const rg = [];
const yb = [];
for (let x = 0; x < img.width; x++) {
for (let y = 0; y < img.height; y++) {
const r = getPixelValue(img, x, y, R_OFFSET);
const g = getPixelValue(img, x, y, G_OFFSET);
const b = getPixelValue(img, x, y, B_OFFSET);
rg.push(byteToUnitInterval(Math.abs(r - g)));
yb.push(byteToUnitInterval(Math.abs(0.5 * (r + g) - b)));
}
}
// Compute the mean and standard deviation of both 'rg' and 'yb'img,
const rgMean = getMean(rg);
const ybMean = getMean(yb);
const rgStandardDeviation = getStandardDeviation(rg);
const ybStandardDeviation = getStandardDeviation(yb);
// Combine the mean and standard deviations
const rootStandardDeviation = Math.sqrt(Math.pow(rgStandardDeviation, 2) + Math.pow(ybStandardDeviation, 2));
const rootMean = Math.sqrt(Math.pow(rgMean, 2) + Math.pow(ybMean, 2));
// Return "colorfulness"
return rootStandardDeviation + (0.3 * rootMean);
}
/**
* Utility Functions
*/
// Given the x, y index, return what position it should be in a 1d array containing rgba values
const getPixelIndex = (img, x, y) => (x + y * img.width) * 4;
// Returns the value of x, y indexed pixel
const getPixelValue = (img, x, y, offset) => {
const index = getPixelIndex(img, x, y) + offset;
return img.data[index];
};
// Converts Byte (0 - 255) to UnitInterval (0 - 1)
const byteToUnitInterval = (byteValue) => byteValue / 256;
const getMean = (array) => (array.reduce((a, b) => a + b)) / array.length;
const getStandardDeviation = (array) => {
const mean = getMean(array);
return Math.sqrt(getMean(array.map((x) => Math.pow(x - mean, 2))));
};
/**
* Example usage:
* 1. Setup canvas
* 2. Get image data from it
* 3. Calculate its "colorfulness"
*/
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// Draw something on the canvas
ctx.beginPath();
ctx.rect(0, 0, 150, 300);
ctx.fillStyle = "red";
ctx.fill();
ctx.beginPath();
ctx.rect(150, 0, 150, 300);
ctx.fillStyle = "blue";
ctx.fill();
// Get image from canvas
const img = ctx.getImageData(0, 0, canvas.width, canvas.height);
// Calculate its colorfulness
const colorfulness = calculateColorfulness(img);
@floriankapaun
Copy link
Author

Check out the underlying article on pyimagesearch for a deeper insight and detailed explanation of the calculations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment