132 votes

Obtenir la couleur moyenne d'une image via Javascript

Je ne suis pas sûr que ce soit possible, mais je cherche à écrire un script qui renverrait la moyenne. hex o rgb pour une image. Je sais que cela peut être fait en AS mais je cherche à le faire en JavaScript.

24 votes

Mon ami Boaz a déjà emprunté cette voie (j'espère qu'il nous dira ce qu'il en pense) mais la moyenne vous laisse généralement avec une couleur semblable au vomi. Ce que vous voulez vraiment, c'est une "couleur dominante". Il y a plusieurs façons de l'obtenir (histogramme de la teinte avec répartition dynamique, etc.) mais je pense que c'est probablement plus précis pour le résultat que tu veux obtenir.

167voto

James Points 56229

AFAIK, la seule façon de le faire est avec <canvas/> ...

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

Attention, cela ne fonctionnera qu'avec des images situées sur le même domaine et dans les navigateurs qui prennent en charge le canvas 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 .

2 votes

Existe-t-il un moyen d'obtenir l'histogramme des couleurs d'une image située dans un autre domaine ?

2 votes

Dan : Je pense que vous rencontrez la restriction cross-origin si vous essayez d'accéder aux données d'une image d'un autre domaine. Ce qui est une déception.

9 votes

Je pense qu'il y a un mauvais placement pour la valeur bleue et verte, vous écrivez 'rgb('+rgb.r+','+rgb.b+','+rgb.g+')' et cela devrait être 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')' . c'est étrange quand la couleur dominante est le bleu mais que le résultat est le vert :).

94voto

J. Chase Points 493

Je me suis dit que j'allais poster un projet sur lequel je suis tombé récemment pour obtenir une couleur dominante :

Voleur de couleurs

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

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

60voto

La "couleur dominante" est délicate. Il s'agit de comparer la distance entre chaque pixel et tous les autres pixels dans l'espace couleur (distance euclidienne), puis de trouver le pixel dont la couleur est la plus proche de toutes les autres couleurs. Ce pixel est la couleur dominante. La couleur moyenne sera généralement la boue.

J'aimerais avoir du MathML ici pour vous montrer la distance euclidienne. Cherche sur Google.

J'ai réalisé l'exécution ci-dessus dans l'espace couleur RGB en utilisant PHP/GD ici : https://gist.github.com/cf23f8bddb307ad4abd8

Cette méthode est toutefois très coûteuse en termes de calcul. Elle fera planter votre système sur les grandes images, et fera planter votre navigateur si vous l'essayez dans le client. J'ai travaillé sur la refactorisation de mon exécution pour : - stocker les résultats dans une table de consultation pour une utilisation future dans l'itération sur chaque pixel. - diviser les grandes images en grilles de 20px 20px pour une dominance localisée. - utiliser la distance euclidienne entre x1y1 et x1y2 pour déterminer la distance entre x1y1 et x1y3.

Faites-moi savoir si vous progressez sur ce front. Je serais heureux de les voir. Je ferai de même.

Le canevas est certainement le meilleur moyen de le faire dans le client. SVG ne l'est pas, car il est basé sur les vecteurs. Une fois que j'aurai mis au point l'exécution, la prochaine chose que je veux faire est de la faire fonctionner dans le canevas (peut-être avec un webworker pour le calcul de la distance globale de chaque pixel).

Une autre chose à laquelle il faut penser est que l'espace RVB n'est pas un bon espace couleur pour faire cela, parce que la distance euclidienne entre les couleurs dans l'espace RVB n'est pas très proche de la distance visuelle. Un meilleur espace couleur pour cela pourrait être LUV, mais je n'ai pas trouvé de bonne bibliothèque pour cela, ni d'algorythme pour convertir RGB en LUV.

Une approche totalement différente consisterait à trier vos couleurs dans un arc-en-ciel, et à construire un histogramme avec une tolérance pour tenir compte des différentes nuances d'une couleur. Je n'ai pas encore essayé, car le tri des couleurs dans un arc-en-ciel est difficile, tout comme les histogrammes de couleurs. Je pourrais essayer cela la prochaine fois. Encore une fois, faites-moi savoir si vous faites des progrès ici.

6 votes

C'est une de ces réponses pour lesquelles j'aimerais pouvoir faire plus que +1 :-)

3 votes

Excellente réponse même si une solution claire n'a pas été rendue. Cela m'aidera à décider de ma prochaine étape...

0 votes

C'est une excellente réponse. J'ai écrit un module de quelques nœuds pour faire le calcul de la distance euclidienne non pas dans LUV, mais dans le module L a espace couleur b*. Voir github.com/zeke/color-namer y github.com/zeke/euclidean-distance

16voto

Andras Vass Points 8021

Premièrement, il est possible de le faire sans HTML5 Canvas ou SVG.
En fait, quelqu'un vient de réussir à générer des fichiers PNG côté client à l'aide de JavaScript , sans canvas ou SVG, en utilisant le schéma URI de données .

Deuxièmement, il se peut que vous n'ayez pas du tout besoin de Canvas, de SVG ou de tout ce qui précède.
Si vous avez seulement besoin de processus les images du côté client, sans les modifier, tout cela n'est pas nécessaire.

Vous pouvez obtenir l'adresse source à partir de la balise img sur la page, faire un XHR le demande - il proviendra très probablement du cache du navigateur - et le traite comme un flux d'octets à partir de Javascript.
Vous devrez avoir une bonne compréhension du format de l'image. (Le générateur ci-dessus est partiellement basé sur les sources de libpng et peut constituer un bon point de départ).

0 votes

+1 pour la solution bytestream. C'est une bonne solution si la seule option est de le faire sur l'application cliente.

11voto

rnaud Points 1460

Je dirais via la balise HTML canvas.

Vous pouvez trouver aquí un post de @Georg parlant d'un petit code par le dev d'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);

Ceci inverse l'image en utilisant la valeur R, G et B de chaque pixel. Vous pourriez facilement stocker les valeurs RVB, puis arrondir les tableaux de rouge, vert et bleu, et enfin les reconvertir en code HEX.

0 votes

Y a-t-il une chance qu'il existe une alternative IE à la solution de la toile ?

0 votes

@Ben4Himv : Il y a l'IE9 Platform Preview ;-) mais sérieusement, j'ai bien peur que non.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X