The code section below is an example of how to calculate the dominant color in a bitmap. The code uses euclidean distance calculations for each color channel in each pixel. Then it sorts the pixels to find the color which is the closest to all other colors.
To improve the output I take to top %2 of colors and average them. Also the Alpha channel is treated differently though it could be changed to use the same distance logic.
The results are much better than the average color calculation. Though it is more computationally expensive so it will take longer to complete.
<code> public static Color CalculateDominantColor(BitmapSource source) { if (source.Format.BitsPerPixel != 32 || source.Format != PixelFormats.Bgra32) throw new ApplicationException("expected 32bit image"); Dictionary<Color, double> colorDist = new Dictionary<Color, double>(); System.Windows.Size sz = new System.Windows.Size(source.PixelWidth, source.PixelHeight); //read bitmap int pixelsSz = (int)sz.Width * (int)sz.Height * (source.Format.BitsPerPixel / 8); int stride = ((int)sz.Width * source.Format.BitsPerPixel + 7) / 8; int pixelBytes = (source.Format.BitsPerPixel / 8); byte[] pixels = new byte[pixelsSz]; source.CopyPixels(pixels, stride, 0); const int alphaThershold = 10; UInt64 pixelCount = 0; UInt64 avgAlpha = 0; for (int y = 0; y < sz.Height; y++) { for (int x = 0; x < sz.Width; x++) { int index = (int)((y * sz.Width) + x) * (pixelBytes); byte r1, g1, b1, a1; r1 = g1 = b1 = a1 = 0; a1 = pixels[index + 3]; r1 = pixels[index + 2]; g1 = pixels[index + 1]; b1 = pixels[index]; if (a1 <= alphaThershold) continue; //ignore pixelCount++; avgAlpha += (UInt64)a1; Color cl = Color.FromArgb(0, r1, g1, b1); double dist = 0; if (!colorDist.ContainsKey(cl)) { colorDist.Add(cl, 0); for (int y2 = 0; y2 < sz.Height; y2++) { for (int x2 = 0; x2 < sz.Width; x2++) { int index2 = (int)(y2 * sz.Width) + x2; byte r2, g2, b2, a2; r2 = g2 = b2 = a2 = 0; a2 = pixels[index2 + 3]; r2 = pixels[index2 + 2]; g2 = pixels[index2 + 1]; b2 = pixels[index2]; if (a2 <= alphaThershold) continue; //ignore dist += Math.Sqrt(Math.Pow(r2 - r1, 2) + Math.Pow(g2 - g1, 2) + Math.Pow(b2 - b1, 2)); } } colorDist[cl] = dist; } } } //clamp alpha avgAlpha = avgAlpha / pixelCount; if (avgAlpha >= (255 - alphaThershold)) avgAlpha = 255; //take weighted average of top 2% of colors var clrs = (from entry in colorDist orderby entry.Value ascending select new { Color = entry.Key, Dist = 1.0/Math.Max(1,entry.Value) }).ToList().Take( Math.Max(1, (int)(colorDist.Count * 0.02)) ); double sumDist = clrs.Sum(x => x.Dist); Color result = Color.FromArgb((byte)avgAlpha, (byte)(clrs.Sum(x => x.Color.R * x.Dist) / sumDist), (byte)(clrs.Sum(x => x.Color.G * x.Dist) / sumDist), (byte)(clrs.Sum(x => x.Color.B * x.Dist) / sumDist)); return result; } </code>