web-dev-qa-db-fra.com

Obtenir la couleur moyenne de l'image via Javascript

Pas sûr que ce soit possible, mais cherchez à écrire un script qui renverrait la valeur moyenne hex ou rgb d'une image Je sais que cela peut être fait en AS mais cherche à le faire en JavaScript. 

97
bgreater

Autant que je sache, le seul moyen de le faire est avec <canvas/>...

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

Notez que cela ne fonctionnera qu'avec les images du même domaine et dans les navigateurs prenant en charge le canevas 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;

}

Pour IE, consultez excanvas .

123
James

Je pensais publier un projet que je venais de rencontrer pour obtenir une couleur dominante:

Voleur de couleurs

Un script pour saisir la couleur dominante ou une palette de couleurs représentative à partir d'une image. Utilise javascript et canvas.

Les autres solutions mentionnant et suggérant une couleur dominante ne répondent jamais vraiment à la question dans un contexte approprié ("en javascript"). Espérons que ce projet aidera ceux qui le souhaitent.

73
J. Chase

"Couleur dominante" est délicate. Ce que vous voulez faire est de comparer la distance entre chaque pixel et tous les autres pixels de l'espace colorimétrique (Distance euclidienne), puis de trouver le pixel dont la couleur est la plus proche de chaque autre couleur. Ce pixel est la couleur dominante. La couleur moyenne sera habituellement de la boue.

J'aimerais avoir MathML ici pour vous montrer la distance euclidienne. Recherche le sur Google.

J'ai effectué l'exécution ci-dessus dans l'espace colorimétrique RVB avec PHP/Gd ici: https://Gist.github.com/cf23f8bddb307ad4abd8

Ceci est cependant très coûteux en calcul. Cela plantera votre système sur les grandes images, et bloquera votre navigateur si vous l'essayez dans le client. J'ai travaillé sur la refactorisation de mon exécution pour: - stocke les résultats dans une table de correspondance pour une utilisation future dans l'itération sur chaque pixel . - diviser les grandes images en grilles de 20 px 20 pixels pour une dominance localisée . - utiliser la distance euclidienne entre x1y1 et x1y2 pour calculer la distance entre x1y1 et x1y3.

S'il vous plaît laissez-moi savoir si vous faites des progrès sur ce front. Je serais heureux de le voir. Je vais faire la même chose.

Canvas est certainement le meilleur moyen de le faire chez le client. SVG n'est pas, SVG est vectoriel. Une fois que l'exécution est terminée, la prochaine chose que je veux faire est de l'exécuter dans le canevas (peut-être avec un webworker pour le calcul de la distance totale de chaque pixel).

Une autre chose à considérer est que le RVB n’est pas un bon espace colorimétrique, car la distance euclidienne entre les couleurs dans l’espace RVB n’est pas très proche de la distance visuelle. Le LUV est un meilleur espace colorimétrique pour le faire, mais je n’ai pas trouvé de bonne bibliothèque pour cela, ni aucun autre algorithme permettant de convertir RGB en LUV.

Une approche totalement différente consisterait à trier vos couleurs dans un arc-en-ciel et à créer un histogramme avec tolérance permettant de prendre en compte différentes nuances de couleur. Je n'ai pas essayé cela, car le tri des couleurs dans un arc-en-ciel est difficile, de même que les histogrammes de couleurs. Je pourrais essayer ceci ensuite. Encore une fois, laissez-moi savoir si vous faites des progrès ici.

46
user304736

Premièrement: cela peut être fait sans HTML5 Canvas ou SVG.
En fait, quelqu'un a simplement réussi à générer des fichiers PNG côté client à l'aide de JavaScript , sans canvas ou SVG, à l'aide du schéma d'URI data .

Deuxièmement: vous n’auriez peut-être pas besoin de Canvas, SVG ou de tout ce qui précède.
Si vous n'avez besoin que de traiter les images côté client, sans les modifier, tout cela n'est pas nécessaire. 

Vous pouvez obtenir l'adresse source à partir de la balise img de la page, en faire une requête XHR - elle viendra probablement du cache du navigateur - et la traitera comme un flux d'octets depuis Javascript.
Vous aurez besoin d’une bonne compréhension du format de l’image. (Le générateur ci-dessus est partiellement basé sur les sources de libpng et pourrait constituer un bon point de départ.)

15
Andras Vass

Je dirais via la balise HTML.

Vous pouvez trouver ici un message de @Georg qui parle d'un petit code écrit par Opera dev: 

// 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);

Ceci inverse l'image en utilisant les valeurs R, V et B de chaque pixel. Vous pouvez facilement stocker les valeurs RVB, puis arrondir les tableaux Rouge, Vert et Bleu, puis les reconvertir en code HEX.

9
rnaud

Je suis récemment tombé sur un plugin jQuery qui fait ce que je voulais au départ https://github.com/briangonzalez/jquery.adaptive-backgrounds.js en ce qui concerne l'obtention d'une couleur dominante à partir d'une image. 

5
bgreater

Javascript n'a pas accès aux données de couleur de pixel individuelles d'une image. Du moins, peut-être pas avant html5 ... il est alors raisonnable de penser que vous pourrez dessiner une image sur une toile, puis inspecter la toile (peut-être que je ne l'ai jamais faite moi-même).

4
Joel Martinez

Solution tout en un

Je combinerais personnellement Color Thief avec cette version modifiée de Name that Color pour obtenir un tableau plus que suffisant de résultats de couleurs dominantes pour les images.

Exemple:

Considérez l'image suivante:

 enter image description here

Vous pouvez utiliser le code suivant pour extraire des données d'image relatives à la couleur dominante:

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
Grant Miller

Il s’agit de la "quantification des couleurs" qui comporte plusieurs approches, telles que MMCQ (quantification de coupe médiane modifiée) ou OQ (quantification d’octree). Une approche différente utilise K-Means pour obtenir des groupes de couleurs.

J'ai tout mis ensemble ici, car je cherchais une solution pour tvOS où il existe un sous-ensemble de XHTML, qui n'a pas d'élément <canvas/>:

Génère les couleurs dominantes d'une image RVB avec XMLHttpRequest

1
loretoparisi

Comme indiqué dans d'autres réponses, vous voulez souvent ce que vous voulez vraiment de la couleur dominante par opposition à la couleur moyenne qui a tendance à être brune. J'ai écrit un script qui prend la couleur la plus commune et l'a posté sur ce Gist

0
dctalbot

Moyen moins précis mais plus rapide d'obtenir une couleur moyenne de l'image avec le support datauri:

function get_average_rgb(img) {
    var context = document.createElement('canvas').getContext('2d');
    if (typeof img == 'string') {
        var src = img;
        img = new Image;
        img.setAttribute('crossOrigin', ''); 
        img.src = src;
    }
    context.imageSmoothingEnabled = true;
    context.drawImage(img, 0, 0, 1, 1);
    return context.getImageData(1, 1, 1, 1).data.slice(0,3);
}
0
350D

Il existe un outil en ligne pickimagecolor.com qui vous aide à trouver la couleur moyenne ou dominante d’une image. Il donne la couleur moyenne en HEX, RGB et HSV. Il trouve également les nuances de couleurs correspondant à cette couleur. Je l'ai utilisé plusieurs fois.

0
shubham agrawal