Получить средний цвет изображения с помощью Javascript - PullRequest
103 голосов
/ 30 марта 2010

Не уверен, что это возможно, но хочу написать скрипт, который бы возвращал среднее значение hex или rgb для изображения. Я знаю, что это можно сделать в AS, но хочу сделать это в JavaScript.

Ответы [ 12 ]

127 голосов
/ 30 марта 2010

AFAIK, единственный способ сделать это с помощью <canvas/> ...

DEMO V2 : http://jsfiddle.net/xLF38/818/

Обратите внимание, это будет работать только с изображениями в том же домене и в браузерах, которые поддерживают холст HTML5:

function getAverageRGB(imgEl) {

    var blockSize = 5, // only visit every 5 pixels
        defaultRGB = {r:0,g:0,b:0}, // for non-supporting envs
        canvas = document.createElement('canvas'),
        context = canvas.getContext && canvas.getContext('2d'),
        data, width, height,
        i = -4,
        length,
        rgb = {r:0,g:0,b:0},
        count = 0;

    if (!context) {
        return defaultRGB;
    }

    height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
    width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;

    context.drawImage(imgEl, 0, 0);

    try {
        data = context.getImageData(0, 0, width, height);
    } catch(e) {
        /* security error, img on diff domain */
        return defaultRGB;
    }

    length = data.data.length;

    while ( (i += blockSize * 4) < length ) {
        ++count;
        rgb.r += data.data[i];
        rgb.g += data.data[i+1];
        rgb.b += data.data[i+2];
    }

    // ~~ used to floor values
    rgb.r = ~~(rgb.r/count);
    rgb.g = ~~(rgb.g/count);
    rgb.b = ~~(rgb.b/count);

    return rgb;

}

Для IE, проверьте excanvas .

77 голосов
/ 07 декабря 2011

Думаю, я опубликую проект, с которым недавно столкнулся, чтобы получить доминирующий цвет:

Color Thief

Скрипт для захвата доминирующего цвета или типичной цветовой палитры с изображения. Использует JavaScript и холст.

Другие решения, упоминающие и предлагающие доминирующий цвет, никогда не отвечают на вопрос в надлежащем контексте («в javascript»). Надеюсь, этот проект поможет тем, кто хочет это сделать.

47 голосов
/ 30 марта 2010

«Доминантный цвет» сложно. Что вы хотите сделать, это сравнить расстояние между каждым пикселем и каждым другим пикселем в цветовом пространстве (евклидово расстояние), а затем найти пиксель, цвет которого ближе всего к любому другому цвету. Этот пиксель является доминирующим цветом. Средний цвет обычно будет грязным.

Хотелось бы, чтобы у меня был MathML, чтобы показать вам евклидово расстояние. Google это.

Я выполнил вышеупомянутое выполнение в цветовом пространстве RGB, используя PHP / GD здесь: https://gist.github.com/cf23f8bddb307ad4abd8

Это, однако, очень вычислительно дорого. Это приведет к сбою вашей системы на больших изображениях и обязательно приведет к сбою вашего браузера, если вы попробуете это в клиенте. Я работал над рефакторингом своего исполнения, чтобы: - сохранить результаты в таблице поиска для будущего использования в итерации по каждому пикселю. - разделить большие изображения на сетки размером 20 на 20 пикселей для локализованного доминирования. - использовать евклидово расстояние между x1y1 и x1y2, чтобы вычислить расстояние между x1y1 и x1y3.

Пожалуйста, дайте мне знать, если вы добьетесь прогресса в этом направлении. Я был бы счастлив увидеть это. Я сделаю то же самое.

Canvas - лучший способ сделать это на клиенте. SVG нет, SVG является векторным. После того, как я завершу выполнение, я хочу запустить его на холсте (возможно, с помощью веб-мастера для расчета общего расстояния каждого пикселя).

Еще одна вещь, о которой стоит подумать, это то, что RGB не является хорошим цветовым пространством для этого, потому что евклидово расстояние между цветами в пространстве RGB не очень близко к визуальному расстоянию. Лучшим цветовым пространством для этого может быть LUV, но я не нашел хорошей библиотеки для этого или каких-либо алгоритмов для преобразования RGB в LUV.

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

15 голосов
/ 30 марта 2010

Первое: это можно сделать без HTML5 Canvas или SVG.
Фактически, кто-то только что смог генерировать файлы PNG на стороне клиента, используя JavaScript , без canvas или SVG, используя схему URI данных .

Второе: вам может вообще не понадобиться Canvas, SVG или что-либо из перечисленного выше.
Если вам нужно только обрабатывать изображений на стороне клиента, без их изменения, все это не нужно.

Вы можете получить адрес источника из тега img на странице, сделать для него запрос XHR - он, скорее всего, будет поступать из кэша браузера - и обработать его как поток байтов из Javascript.
Вам нужно хорошее понимание формата изображения. (Приведенный выше генератор частично основан на исходных текстах libpng и может послужить хорошей отправной точкой.)

9 голосов
/ 30 марта 2010

Я бы сказал, через HTML-тэг canvas.

Вы можете найти здесь пост @Georg, в котором рассказывается о небольшом коде от Opera:

// Get the CanvasPixelArray from the given coordinates and dimensions.
var imgd = context.getImageData(x, y, width, height);
var pix = imgd.data;

// Loop over each pixel and invert the color.
for (var i = 0, n = pix.length; i < n; i += 4) {
    pix[i  ] = 255 - pix[i  ]; // red
    pix[i+1] = 255 - pix[i+1]; // green
    pix[i+2] = 255 - pix[i+2]; // blue
    // i+3 is alpha (the fourth element)
}

// Draw the ImageData at the given (x,y) coordinates.
context.putImageData(imgd, x, y);

Это инвертирует изображение, используя значения R, G и B каждого пикселя. Вы можете легко сохранить значения RGB, затем округлить массивы Red, Green и Blue и, наконец, преобразовать их обратно в HEX-код.

5 голосов
/ 18 мая 2016

Недавно я наткнулся на плагин jQuery, который делает то, что я изначально хотел https://github.com/briangonzalez/jquery.adaptive-backgrounds.js в отношении получения доминирующего цвета из изображения.

4 голосов
/ 30 марта 2010

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

1 голос
/ 03 мая 2018

Многофункциональное решение

Я бы лично объединил Color Thief вместе с этой модифицированной версией Назовите этот цвет , чтобы получить более чем достаточный массив доминирующих цветовых результатов для изображений.

Пример:

Рассмотрим следующее изображение:

enter image description here

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

let color_thief = new ColorThief();
let sample_image = new Image();

sample_image.onload = () => {
  let result = ntc.name('#' + color_thief.getColor(sample_image).map(x => {
    const hex = x.toString(16);
    return hex.length === 1 ? '0' + hex : hex;

  }).join(''));

  console.log(result[0]); // #f0c420     : Dominant HEX/RGB value of closest match
  console.log(result[1]); // Moon Yellow : Dominant specific color name of closest match
  console.log(result[2]); // #ffff00     : Dominant HEX/RGB value of shade of closest match
  console.log(result[3]); // Yellow      : Dominant color name of shade of closest match
  console.log(result[4]); // false       : True if exact color match
};

sample_image.crossOrigin = 'anonymous';
sample_image.src = document.getElementById('sample-image').src;
1 голос
/ 26 октября 2015

Речь идет о «квантовании цвета», которое имеет несколько подходов, таких как MMCQ (модифицированное квантование с медианным срезом) или OQ (квантование по октре). Другой подход использует K-Means для получения кластеров цветов.

Я соединил все это здесь, так как я нашел решение для tvOS, где есть подмножество XHTML, в котором нет элемента <canvas/>:

Создание доминирующих цветов для изображения RGB с XMLHttpRequest

0 голосов
/ 26 июня 2019

Как указывалось в других ответах, часто то, что вам действительно нужно, это доминирующий цвет, а не средний цвет, который обычно бывает коричневым. Я написал скрипт, который получает самый распространенный цвет, и разместил его в этом gist

...