¿Cómo encontrar el color promedio de una imagen en Python con OpenCV?

He intentado este código:

import cv2 image = cv2.imread("sample.jpg") pixel = image[200, 550] print pixel 

Pero estoy recibiendo error como:

‘Nonetype’ sin atributos error getitem

Este error se muestra después de ejecutar la tercera línea de código.

Como arreglar el error

Hay dos causas potenciales para que este error ocurra:

  1. El nombre del archivo está mal escrito.
  2. El archivo de imagen no está en el directorio de trabajo actual.

Para solucionar este problema, debe asegurarse de que el nombre del archivo esté correctamente escrito (haga una comprobación de mayúsculas y minúsculas en el caso) y que el archivo de imagen esté en el directorio de trabajo actual (hay dos opciones aquí: puede cambiar el directorio de trabajo actual en su IDE o especifique la ruta completa del archivo).

Color promedio vs. color dominante

Luego, para calcular el “color promedio” tienes que decidir qué quieres decir con eso. En una imagen en escala de grises es simplemente la media de los niveles de gris en toda la imagen, pero con los colores no existe el “promedio”. De hecho, los colores generalmente se representan a través de vectores tridimensionales, mientras que los niveles de gris son escalares. Está bien promediar los escalares, pero no tiene sentido promediar los vectores.

Separar la imagen en sus componentes cromáticos y tomar el promedio de cada componente es una forma posible de hacerlo. Sin embargo, este enfoque puede producir un color sin sentido. Lo que realmente podría querer es un color dominante en lugar de un color promedio.

Implementación

Vayamos por el código lentamente. Comenzamos importando los módulos necesarios y leyendo la imagen:

 import cv2 import numpy as np from skimage import io img = io.imread('https://i.stack.imgur.com/DNM65.png')[:, :, :-1] 

Luego podemos calcular la media de cada canal cromático siguiendo un método análogo al propuesto por @Ruan B .:

 average = img.mean(axis=0).mean(axis=0) 

A continuación, aplicamos la agrupación de k-means para crear una paleta con los colores más representativos de la imagen (en este ejemplo de juguete, n_colors se configuró en 5 ).

 pixels = np.float32(img.reshape(-1, 3)) n_colors = 5 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 200, .1) flags = cv2.KMEANS_RANDOM_CENTERS _, labels, palette = cv2.kmeans(pixels, n_colors, None, criteria, 10, flags) _, counts = np.unique(labels, return_counts=True) 

Y finalmente, el color dominante es el color de la paleta que aparece con mayor frecuencia en la imagen cuantificada:

 dominant = palette[np.argmax(counts)] 

Comparacion de resultados

Para ilustrar las diferencias entre ambos enfoques, he usado la siguiente imagen de muestra:

Lego

Los valores obtenidos para el color promedio, es decir, un color cuyos componentes son las medias de los tres canales cromáticos, y el color dominante calculado a través de la agrupación de k-means son bastante diferentes:

 In [30]: average Out[30]: array([91.63179156, 69.30190754, 58.11971896]) In [31]: dominant Out[31]: array([179.3999 , 27.341282, 2.294441], dtype=float32) 

Veamos cómo se ven esos colores para comprender mejor las diferencias entre ambos enfoques. En la parte izquierda de la figura debajo se muestra el color promedio. Es evidente que el color promedio calculado no describe correctamente el contenido de color de la imagen original. De hecho, no hay un solo píxel con ese color en la imagen original. La parte derecha de la figura muestra los cinco colores más representativos ordenados de arriba a abajo en orden descendente de importancia (frecuencia de aparición). Esta paleta hace evidente que el color dominante es el rojo, lo que es consistente con el hecho de que la región más grande de color uniforme en la imagen original corresponde a la pieza roja de Lego.

Resultados

Este es el código utilizado para generar la figura anterior:

 import matplotlib.pyplot as plt avg_patch = np.ones(shape=img.shape, dtype=np.uint8)*np.uint8(average) indices = np.argsort(counts)[::-1] freqs = np.cumsum(np.hstack([[0], counts[indices]/counts.sum()])) rows = np.int_(img.shape[0]*freqs) dom_patch = np.zeros(shape=img.shape, dtype=np.uint8) for i in range(len(rows) - 1): dom_patch[rows[i]:rows[i + 1], :, :] += np.uint8(palette[indices[i]]) fig, (ax0, ax1) = plt.subplots(1, 2, figsize=(12,6)) ax0.imshow(avg_patch) ax0.set_title('Average color') ax0.axis('off') ax1.imshow(dom_patch) ax1.set_title('Dominant colors') ax1.axis('off') plt.show(fig) 

TL; respuesta DR

En resumen, a pesar de que el cálculo del color promedio, como se propuso en la respuesta de @Ruan B., es técnicamente correcto desde un punto de vista matemático, es posible que el resultado obtenido no represente adecuadamente el contenido de color de la imagen. Un enfoque más sensato es el de determinar el color dominante a través de la cuantificación vectorial (agrupación).

Pude obtener el color promedio usando lo siguiente:

 import cv2 import numpy myimg = cv2.imread('image.jpg') avg_color_per_row = numpy.average(myimg, axis=0) avg_color = numpy.average(avg_color_per_row, axis=0) print(avg_color) 

Resultado:

 [ 197.53434769 217.88439451 209.63799938] 

Gran recurso al que hice referencia