2010-03-29 23 views
86

No estoy seguro de que esto sea posible, pero busca escribir un script que devuelva el valor promedio de hex o rgb para una imagen. Sé que se puede hacer en AS pero buscando hacerlo en JavaScript.Obtener el color promedio de la imagen mediante Javascript

+12

mi amigo Boaz ha estado en este camino antes (con un poco de suerte suena) pero el promedio generalmente te deja con un color similar al vómito. Lo que realmente quieres es "color dominante".Hay algunas maneras de conseguir eso (histograma de huella con cubicación dinámica, etc.) pero creo que eso es probablemente más preciso para el resultado deseado. –

Respuesta

113

yo sepa, la única manera de hacerlo es con <canvas/> ...

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

Nota, esto sólo funcionará con imágenes en el mismo dominio y en los navegadores que soportan Lienzo de 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; 

} 

Para IE, consulte excanvas.

+0

¿Hay alguna manera de obtener el histograma de color para una imagen que se encuentra en un dominio diferente? –

+1

Dan: Creo que se encuentra con la restricción de origen cruzado si intenta acceder a los datos de imagen en una imagen de otro dominio. Que es un fastidio –

+7

creo que hay una colocación preocupante para el valor azul y verde, escribes ''rgb (' + rgb.r + ',' + rgb.b + ',' + rgb.g + ')' 'y eso debería ser'' rgb ('+ rgb.r +', '+ rgb.g +', '+ rgb.b +') ''. es extraño cuando el color dominante es azul pero el resultado es verde :). –

5

JavaScript no tiene acceso a los datos de color de píxeles individuales de una imagen. Al menos, tal vez no hasta html5 ... en cuyo caso es lógico que puedas dibujar una imagen en un lienzo y luego inspeccionar el lienzo (tal vez, nunca lo hice yo mismo).

8

Yo diría a través de la etiqueta de lona HTML.

puede encontrar here un mensaje por @Georg hablando de un pequeño código por el dev 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); 

Esta invertir la imagen mediante el uso de la R, G y B el valor de cada píxel. Puede almacenar fácilmente los valores RGB, luego redondear los arreglos Rojo, Verde y Azul, y finalmente convertirlos de nuevo en un código HEX.

+0

¿hay alguna posibilidad de que haya una alternativa de IE a la solución de lienzo? – bgreater

+0

@ Ben4Himv: está la vista previa de la plataforma IE9 ;-) pero en serio, me temo que no. –

13

Primero: se puede hacer sin HTML5 Canvas o SVG.
En realidad, alguien solo logró generate client-side PNG files using JavaScript, sin lienzo o SVG, utilizando el data URI scheme.

Segundo: es posible que en realidad no necesites Canvas, SVG o cualquiera de los anteriores.
Si solo necesita procesar imágenes en el lado del cliente, sin modificarlas, todo esto no es necesario.

Puede obtener la dirección de origen de la etiqueta img en la página, hacer una solicitud de XHR - probablemente provenga de la memoria caché del navegador - y procesarla como una secuencia de bytes de Javascript.
Necesitará una buena comprensión del formato de la imagen. (El generador anterior se basa parcialmente en fuentes libpng y podría proporcionar un buen punto de partida.)

+0

Awesome answer. – Plynx

+0

+1 para la solución bytestream. Esta es una buena opción si la única opción es hacerlo en la aplicación cliente. – loretoparisi

44

"Dominant Color" es complicado. Lo que quiere hacer es comparar la distancia entre cada píxel y cada otro píxel en el espacio de color (Distancia euclidiana), y luego buscar el píxel cuyo color está más cerca de cualquier otro color. Ese píxel es el color dominante. El color promedio generalmente será barro.

Ojalá tuviera MathML aquí para mostrarle la Distancia euclidiana. Buscalo en Google.

que he logrado la ejecución anterior en el espacio de color RGB usando PHP/GD aquí: https://gist.github.com/cf23f8bddb307ad4abd8

Sin embargo, esto es muy costoso computacionalmente.Se bloqueará su sistema en imágenes grandes, y definitivamente bloqueará su navegador si lo prueba en el cliente. He estado trabajando en la refacturación de mi ejecución para: - almacenar resultados en una tabla de búsqueda para su uso futuro en la iteración sobre cada píxel. - para dividir imágenes grandes en cuadrículas de 20px 20px para el dominio localizado. - para usar la distancia euclídea entre x1y1 y x1y2 para calcular la distancia entre x1y1 y x1y3.

Háganme saber si avanza en este frente. Me gustaría verlo Voy a hacer lo mismo.

La lona es definitivamente la mejor manera de hacer esto en el cliente. SVG no lo es, SVG está basado en vectores. Después de que baje la ejecución, lo siguiente que quiero hacer es ejecutar esto en el lienzo (tal vez con un webworker para el cálculo de la distancia global de cada píxel).

Otra cosa en que pensar es que RGB no es un buen espacio de color para hacer esto, porque la distancia euclidiana entre los colores en el espacio RGB no es muy cercana a la distancia visual. Un mejor espacio de color para hacer esto podría ser LUV, pero no he encontrado una buena biblioteca para esto, ni ningún algoritmo para convertir RGB a LUV.

Un enfoque completamente diferente sería ordenar los colores en un arcoiris, y construir un histograma con tolerancia para tener en cuenta los distintos tonos de un color. No he intentado esto, porque ordenar colores en un arco iris es difícil, y también lo son los histogramas de color. Podría intentar esto a continuación. De nuevo, avíseme si progresa aquí.

+2

Esta es una de esas respuestas por las que me gustaría poder hacer más que solo +1 :-) –

+3

Excelente respuesta aunque no se haya obtenido una solución clara. Esto me ayudará a decidir mi próximo paso ... – bgreater

+0

Esta es una gran respuesta. Escribí algunos módulos de nodos para hacer el cálculo de la distancia euclidiana no en LUV, sino en el espacio de color L * a * b *. Consulte https://github.com/zeke/color-namer y https://github.com/zeke/euclidean-distance – Zeke

69

Robusto que había puesto un proyecto Recientemente me encontré para conseguir el color dominante:

Color Thief

Un guión para agarrar el color dominante o una paleta de colores representativa de una imagen. Utiliza javascript y lienzo.

Las otras soluciones que mencionan y sugieren el color dominante nunca responden realmente la pregunta en el contexto adecuado ("en javascript"). Esperemos que este proyecto ayude a aquellos que quieren hacer precisamente eso.

1

Se trata de la "Cuantización del color" que tiene varios enfoques, como MMCQ (cuantificación de corte de mediana modificada) o OQ (cuantización de octário). Enfoque diferente use K-Means para obtener grupos de colores.

He putts todos juntos aquí, ya que estaba encontrando una solución para tvOS donde hay un subconjunto de XHTML, que no tiene <canvas/> elemento:

Generate the Dominant Colors for an RGB image with XMLHttpRequest

0

Hay una herramienta en línea pickimagecolor.com que le ayuda a encontrar el color medio o dominante de la imagen. Solo tiene que cargar una imagen desde su computadora y luego hacer clic en la imagen. Da el color promedio en HEX, RGB y HSV. También encuentra los tonos de color que coinciden con ese color para elegir. Lo he usado muchas veces

Cuestiones relacionadas