utiliza usar una tiene texto tener qué que puedo profundidad para modos mapa jpg imágenes impresa imagenes imagen hace fijas factores dispositivo digitalizar digitalización digitalizacion digitaliza denomina debo cómo cuenta cuantos cuando como colores color c# colors rgb imaging channel

c# - usar - Cómo calcular los valores de color rgb promedio de un mapa de bits



profundidad de color 8 16 o 32 bits (3)

En mi aplicación C # (3.5) necesito obtener los valores de color promedio para los canales rojo, verde y azul de un mapa de bits. Preferiblemente sin utilizar una biblioteca externa. Se puede hacer esto? ¿Si es así, cómo? Gracias por adelantado.

Intentando que las cosas sean un poco más precisas: cada píxel en el mapa de bits tiene un cierto valor de color RGB. Me gustaría obtener los valores RGB promedio para todos los píxeles de la imagen.


Aquí hay una manera mucho más simple:

Bitmap bmp = new Bitmap(1, 1); Bitmap orig = (Bitmap)Bitmap.FromFile("path"); using (Graphics g = Graphics.FromImage(bmp)) { // updated: the Interpolation mode needs to be set to // HighQualityBilinear or HighQualityBicubic or this method // doesn''t work at all. With either setting, the results are // slightly different from the averaging method. g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.DrawImage(orig, new Rectangle(0, 0, 1, 1)); } Color pixel = bmp.GetPixel(0, 0); // pixel will contain average values for entire orig Bitmap byte avgR = pixel.R; // etc.

Básicamente, utiliza DrawImage para copiar el mapa de bits original en un mapa de bits de 1 píxel. Los valores RGB de ese píxel representarán los promedios para todo el original. GetPixel es relativamente lento, pero solo cuando lo usas en un mapa de bits grande, píxel por píxel. Llamarlo una vez aquí no es gran cosa.

El uso de LockBits es realmente rápido, pero algunos usuarios de Windows tienen políticas de seguridad que impiden la ejecución del código "inseguro". Menciono esto porque este hecho solo me mordió por detrás recientemente.

Actualización : con InterpolationMode configurado en HighQualityBicubic, este método lleva aproximadamente el doble de tiempo que el promedio con LockBits; con HighQualityBilinear, toma solo un poco más que LockBits. Entonces, a menos que sus usuarios tengan una política de seguridad que prohíba el código unsafe , definitivamente no use mi método.

Actualización 2: con el paso del tiempo, ahora me doy cuenta de por qué este enfoque no funciona en absoluto. Incluso los algoritmos de interpolación de la más alta calidad incorporan solo unos pocos píxeles adyacentes, por lo que hay un límite de cuánto se puede aplastar una imagen sin perder información. Y reducir una imagen a un píxel supera este límite, sin importar qué algoritmo utilice.

La única forma de hacer esto sería reducir la imagen en pasos (tal vez reducirla a la mitad cada vez) hasta que llegue al tamaño de un píxel. No puedo expresar con meras palabras lo que sería una completa pérdida de tiempo escribir algo así, así que me alegro de haberme detenido cuando lo pensé. :)

Por favor, nadie más vote por esta respuesta, podría ser mi idea más estúpida.


Este tipo de cosas funcionará, pero puede que no sea lo suficientemente rápido como para ser tan útil.

public static Color getDominantColor(Bitmap bmp) { //Used for tally int r = 0; int g = 0; int b = 0; int total = 0; for (int x = 0; x < bmp.Width; x++) { for (int y = 0; y < bmp.Height; y++) { Color clr = bmp.GetPixel(x, y); r += clr.R; g += clr.G; b += clr.B; total++; } } //Calculate average r /= total; g /= total; b /= total; return Color.FromArgb(r, g, b); }


La forma más rápida es mediante el uso de código inseguro:

BitmapData srcData = bm.LockBits( new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); int stride = srcData.Stride; IntPtr Scan0 = srcData.Scan0; long[] totals = new long[] {0,0,0}; int width = bm.Width; int height = bm.Height; unsafe { byte* p = (byte*) (void*) Scan0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { for (int color = 0; color < 3; color++) { int idx = (y*stride) + x*4 + color; totals[color] += p[idx]; } } } } int avgB = totals[0] / (width*height); int avgG = totals[1] / (width*height); int avgR = totals[2] / (width*height);

Cuidado: no probé este código ... (es posible que haya cortado algunas esquinas)

Este código también asume una imagen de 32 bits. Para imágenes de 24 bits. Cambia el x * 4 a x * 3