Created
December 24, 2020 08:55
-
-
Save floriankapaun/d73722474d309932bce5c50f0d382420 to your computer and use it in GitHub Desktop.
Calculate "colorfulness" of image in JavaScript
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
/** | |
* 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); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Check out the underlying article on pyimagesearch for a deeper insight and detailed explanation of the calculations.