Извлечь «доминирующие» цвета из модели HSV? (не от модели RGB)

Я ищу цветовую палитру из изображения.

я мог бы получить данные RGB из изображения

getRgbData() {
    this.canvas = window.document.createElement('canvas')
    this.context = this.canvas.getContext('2d')
    this.width = this.canvas.width = image.width || image.naturalWidth
    this.height = this.canvas.height = image.height || image.naturalHeight
    this.context.drawImage(image, 0, 0, this.width, this.height)
    return this.context.getImageData(0, 0, this.width, this.height)
}

и преобразовать значения RGB в модель HSV (метод rgbToHsv написан из https://gist.github.com/mjackson/5311256#file-color-conversion-algorithms-js-L1)

getHsvData() {
    const { data, width, height } = this.getRgbData()
    const pixcel = width * height
    const q = 1
    const array = []
    for (var i = 0, r, g, b, offset; i < pixcel; i = i + q) {
        offset = i * 4
        r = data[offset + 0]
        g = data[offset + 1]
        b = data[offset + 2]
        array.push({ r, g, b })
    }

    return array.map(l => this.rgbToHsv(l.r, l.g, l.b))
} 

получается вот так (это преобразованные данные из RGB 24bit)

[
   {h: 0.6862745098039215, s: 0.7727272727272727, v: 0.17254901960784313},
   {h: 0.676470588235294, s: 0.723404255319149, v: 0.1843137254901961},
   .....
]

color-thief и vibrant.js получает доминирующий цвет из модели RGB, но я хочу получить доминирующий цвет из преобразованной модели HSV. (я слышал, что извлечение цвета из hsv больше подходит для человеческого глаза. Это правда?)

как я могу извлечь цвет из модели HSV ..?


person highalps    schedule 16.03.2018    source источник
comment
Взгляните на tinycolor — я использовал его в одном из своих проектов. Отлично работает, прост в использовании.   -  person SaganRitual    schedule 16.03.2018
comment
@GreatBigBore Я хочу знать, как извлечь доминирующий цвет из этих значений :( (я думаю, это связано с квантованием цвета)   -  person highalps    schedule 16.03.2018
comment
Это возможно или это?   -  person SaganRitual    schedule 16.03.2018
comment
Ваш оттенок - ваш доминирующий цвет... Не знаю, о чем вы спрашиваете....   -  person Get Off My Lawn    schedule 16.03.2018
comment
@GetOffMyLawn, но при преобразовании модели RGB в HSV появляется много оттенков. правильно? (тысячи независимых значений)   -  person highalps    schedule 16.03.2018
comment
Да... Вы пытаетесь получить доминирующее значение всего изображения?   -  person Get Off My Lawn    schedule 16.03.2018
comment
@GetOffMyLawn правильно :)   -  person highalps    schedule 16.03.2018
comment
@GreatBigBore извините, мне это не помогло :( это просто рассказывает, как использовать библиотеку Matlab ...   -  person highalps    schedule 16.03.2018


Ответы (2)


Первое, что нам нужно сделать, это получить средний цвет изображения. Мы можем сделать это, добавив каждый цветовой канал отдельно, а затем разделив его на высоту и ширину холста.

function channelAverages(data, width, height) {
  let r = 0, g = 0, b = 0
  let totalPixels = width * height
  for (let i = 0, l = data.data.length; i < l; i += 4) {
    r += data.data[i]
    g += data.data[i + 1]
    b += data.data[i + 2]
  }
  return {
    r: Math.floor(r / totalPixels),
    g: Math.floor(g / totalPixels),
    b: Math.floor(b / totalPixels)
  }
}

Далее мы хотим преобразовать среднее значение возвращенного цвета в HSL, мы можем сделать это с помощью этой функции (на которую вы также ссылаетесь выше).

function rgbToHsl(r, g, b) {
  r /= 255, g /= 255, b /= 255;
  var max = Math.max(r, g, b), min = Math.min(r, g, b);
  var h, s, l = (max + min) / 2;

  if (max == min) {
    h = s = 0; // achromatic
  } else {
    var d = max - min;
    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
    switch (max) {
      case r: h = (g - b) / d + (g < b ? 6 : 0); break;
      case g: h = (b - r) / d + 2; break;
      case b: h = (r - g) / d + 4; break;
    }
    h /= 6;
  }
  return [h, s, l];
}

Итак, чтобы получить наш вывод, мы можем сделать это:

let data = ctx.getImageData(0, 0, canvas.width, canvas.height)
let avg = channelAverages(data, width, height)
console.log(rgbToHsl(avg.r, avg.g, avg.b))

Если нам нужны числа, которые мы можем использовать в редакторе (например, PhotoShop или Gimp) для проверки наших результатов, нам просто нужно умножить каждое:

h = h * 360 
    Example: 0.08 * 360 = 28.8

s = s * 100 
    Example: 0.85 * 100 = 85

l = l * 100 
    Example: 0.32 * 100 = 32
person Get Off My Lawn    schedule 16.03.2018
comment
Спасибо за ответ! у меня есть еще один вопрос, это отличается от извлечения цвета с использованием алгоритма MMCQ из модели RGB? (например, библиотека color-thief и яркая.js выше) - person highalps; 16.03.2018
comment
Извините, я не уверен. - person Get Off My Lawn; 16.03.2018

Существует библиотека под названием Kleur.js, которую вы можете использовать для получения изображений, но помните, что она дает случайную цветовую палитру каждый раз. Но доминирующий цвет останется одним и тем же в каждой цветовой палитре.

// Create the Kleur Object
Kleur = new Kleur();

// Set the image link to get the palette from
imageObj = Kleur.init(imgLink);

// Wait for the image to load
imageObj.onload = function(e) {

    // get the color array from the image
    let colorArr = Kleur.getPixelArray(imageObj);

    // pass the array to generate the color array
    let array_of_pixels = Kleur.generateColorArray(colorArr);

    // you can get the dominant color from the image
    const dominant = Kleur.getDominant(array_of_pixels);

    // log the light colors and the dominant color
    console.log(light, dominant)
}

если вы хотите увидеть пример использования этого кода, посетите codepen

И если вам нужны все доминирующие цвета, которые, я думаю, являются цветами с наибольшим количеством пикселей, вы можете получить доступ к array_of_pixels, поэтому вы можете сделать

// for first five dominant color
for(let x = 0; x < 5; x++){
    console.log(array_of_pixels[x].hsv);
}

// for the dominant colors hsv value
console.log(dominant.hsv)

это зарегистрирует значения hsv для пяти наиболее доминирующих цветов в изображении (обычно доминирующие цвета действительно похожи, поэтому следите за этим)

Kleur js возвращает цвета в различном цветовом пространстве

  • RGB
  • Шестнадцатеричный
  • ВПГ
  • XYZ
  • ЛАБОРАТОРИЯ
  • ЛЧ

он также возвращает count, который представляет собой количество пикселей, имеющих цвет

person miri    schedule 19.04.2020