Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
获取图片主颜色
/* 算法一:k-means 加 euclidean */
/*
* This portion was created by referencing the article
* "Using python and k-means to find the dominant colors in images"
*/
// You can see the Python version of this in Charles Leifer's article
function euclidean (point1, point2) {
let s = 0
for (let i = 0, l = point1.length; i < l; i++) {
s += Math.pow(point1[i] - point2[i], 2)
}
return Math.sqrt(s)
}
// There are letious ways to convert rgb to hex, I found this on Stack Overflow.
function rgbToHex (rgb) {
function toHex (c) {
let hex = parseInt(c).toString(16)
return hex.length == 1 ? '0' + hex : hex
}
return '#' + toHex(rgb[0]) + toHex(rgb[1]) + toHex(rgb[2])
}
function calculateCenter (points, n) {
let values = []
// Here we're populating the values array with 0s just so we know what size it should be (n)
for (let i = 0; i < n; i++) {
values.push(0)
}
let plength = 0
for (let i = 0, l = points.length; i < l; i++) {
plength++
for (let j = 0; j < n; j++) {
values[j] += points[i][j]
}
}
// Using the average to get the centers
for (let i = 0; i < n; i++) {
values[i] = values[i] / plength
}
return values
}
// I basically just took this from Charles Leifer.
function k_mean (points, k, min_diff) {
let plength = points.length
let colorGroup = []
let seen = []
while (colorGroup.length < k) {
let idx = parseInt(Math.random() * plength)
let found = false
for (let i = 0; i < seen.length; i++) {
if (idx === seen[i]) {
found = true
break
}
}
if (!found) {
seen.push(idx)
let isValidColor = points[idx].reduce((score, value) => {
return score + (value !== 0 && value !== 255) ? 1 : 0
}, 0) > 0
if (!isValidColor) {
continue
}
colorGroup.push([points[idx], [points[idx]]])
}
}
while (true) {
let plists = []
for (let i = 0; i < k; i++) {
plists.push([])
}
for (let j = 0; j < plength; j++) {
let p = points[j]
let smallest_distance = 10000000
let idx = 0
for (let i = 0; i < k; i++) {
let distance = euclidean(p, colorGroup[i][0])
if (distance < smallest_distance) {
smallest_distance = distance
idx = i
}
}
plists[idx].push(p)
}
let diff = 0
for (let i = 0; i < k; i++) {
let old = colorGroup[i]
let list = plists[i]
let center = calculateCenter(list, 3)
let new_cluster = [center, (list)]
let dist = euclidean(old[0], center)
colorGroup[i] = new_cluster
diff = diff > dist ? diff : dist
}
if (isNaN(diff)) {
break
}
if (diff < min_diff) {
break
}
}
return colorGroup
}
// Here's where we to actual interaction with the webpage
function processimg (img, canvaselement) {
let points = []
// Drawing the given image onto a canvas 250x250 in size
canvaselement.drawImage(img, 0, 0, 250, 250)
// Getting data from said canvas. This *DOES* get every pixel in the image.
// Luckily, it's fast.
let dataCanvas = canvaselement.getImageData(0, 0, 250, 250).data
// Populating the points array with colors from the image
for (let i = 0, l = dataCanvas.length; i < l; i += 4) {
let r = dataCanvas[i]
let g = dataCanvas[i + 1]
let b = dataCanvas[i + 2]
points.push([r, g, b])
}
let totals = k_mean(points, 3, 1)
let hex = []
// If you try and convert the RGB to Hex directly here, it takes FOREVER,
// but if you have the helper method above, it works fast. Strange.
for (let i = 0; i < totals.length; i++) {
hex.push(rgbToHex(totals[i][0]))
}
return hex
}
// Execute
const colors = processimg(image, document.createElement('canvas').getContext('2d'))
/* 算法二:使用 rgbquant.sample 统计画板值 */
import RgbQuant from 'rgbquant'
import { get, map, sortBy, isArray } from 'lodash'
function rgbToHex (rgb) {
function toHex (c) {
let hex = parseInt(c).toString(16)
return hex.length == 1 ? '0' + hex : hex
}
return '#' + toHex(rgb[0]) + toHex(rgb[1]) + toHex(rgb[2])
}
function analyse (img) {
// quantify
let quant = new RgbQuant({
colors: 10,
})
quant.sample(img)
let pal = quant.palette(true)
let hist = {}
let indices = []
for (let i = 0, len = pal.length; i < len; i++) {
hist[i] = 0
indices.push(i)
}
// show the result
let result = quant.reduce(img, 2) // eslint-disable-line
for (let i = 0, len = result.length; i < len; i++) {
hist[result[i]] += 1
}
let total = 0
for (let i = 0, len = pal.length; i < len; i++) {
total += hist[i]
}
for (let i = 0, len = pal.length; i < len; i++) {
hist[i] = hist[i] * 100 / total
}
// sort for indices (reverse order)
indices.sort(function (a, b) {
return hist[a] < hist[b] ? 1 : (hist[a] > hist[b] ? -1 : 0)
})
return map(indices, index => {
return {
color: rgbToHex(pal[index]),
hist: hist[index],
}
})
}
// Execute
let colors = analyse(image)
/* 算法三:使用 color-thief 的 color quantization */
/* 查看 MMCQ https://gist.github.com/nrabinowitz/1104622 */
// import ColorThief from '@mariotacke/color-thief'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.