Identifying the most dominant color in an image

Hi,
I developed an algorithm that identifies the most dominant color in an image.
The input is a URL to the target image and the output is the dominant color.
The algorithm reads all the pixels of the bitmap and maps them into a dictionary.
Then, it builds a graph of similar colors by a pre-defined threshold.
While building the graph, the algorithm maintains the most dominant color by the node that has the largest amount of pixels combined with its' adjacent nodes.


public class ColorsGraph
{
    private const int _similarityThreshhold = 30;
    private readonly Dictionary<Color, int> _colorsMapping;
    private Dictionary<ColorNode, List<ColorNode>> _colorsGraph;
    private KeyValuePair<ColorNode, List<ColorNode>> _mostDominantColor;

    public ColorsGraph(string imageUrl)
    {
        _colorsMapping = new Dictionary<Color, int>();

        var request = WebRequest.Create(imageUrl);
        using (var response = request.GetResponse())
        using (var stream = response.GetResponseStream())
        using (var image = Bitmap.FromStream(stream) as Bitmap)
        {
            BuildColorsMapping(image);
        }

        BuildColorsGraph();
    }

    public Color GetMostDominantColor()
    {
        return _mostDominantColor.Key.Color;
    }

    public Color GetMostDominantColorAverage()
    {
        var nodes = new[] { _mostDominantColor.Key }.Union(_mostDominantColor.Value).ToList();
        return Color.FromArgb(
            nodes.Sum(x => x.Color.A) / nodes.Count,
            nodes.Sum(x => x.Color.R) / nodes.Count,
            nodes.Sum(x => x.Color.G) / nodes.Count,
            nodes.Sum(x => x.Color.B) / nodes.Count);
    }

    private void BuildColorsMapping(Bitmap aBitmap)
    {
        for (var x = 0; x < aBitmap.Height; ++x)
        {
            for (var y = 0; y < aBitmap.Width; ++y)
            {
                var color = aBitmap.GetPixel(x, y);
                if (_colorsMapping.ContainsKey(color))
                {
                    ++_colorsMapping[color];
                }
                else
                {
                    _colorsMapping.Add(color, 1);
                }
            }
        }
    }

    private void BuildColorsGraph()
    {
        _colorsGraph = _colorsMapping.ToDictionary(x => new ColorNode(x.Key, x.Value), x => new List<ColorNode>());
        _mostDominantColor = _colorsGraph.OrderByDescending(x => x.Key.TotalPixelsCount).First();

        foreach (var sourceColor in _colorsGraph.Keys)
        {
            foreach (var targetColor in _colorsGraph)
            {
                if (sourceColor != targetColor.Key && AreSimilar(sourceColor.Color, targetColor.Key.Color))
                {
                    targetColor.Value.Add(sourceColor);
                    targetColor.Key.TotalPixelsCount += sourceColor.PixelsCount;
                    if (targetColor.Key.TotalPixelsCount > _mostDominantColor.Key.TotalPixelsCount)
                    {
                        _mostDominantColor = targetColor;
                    }
                }
            }
        }
    }

    private bool AreSimilar(Color aSource, Color aTarget)
    {
        return
            Math.Abs(aSource.B - aTarget.B) < _similarityThreshhold &&
            Math.Abs(aSource.R - aTarget.R) < _similarityThreshhold &&
            Math.Abs(aSource.G - aTarget.G) < _similarityThreshhold;
    }

    private class ColorNode
    {
        public ColorNode(Color color, int pixelsCount)
        {
            Color = color;
            PixelsCount = pixelsCount;
            TotalPixelsCount = pixelsCount;
        }

        public Color Color { get; private set; }
        public int PixelsCount { get; private set; }
        public int TotalPixelsCount { get; set; }
        public override bool Equals(object obj)
        {
            return ((ColorNode)obj).Color == Color;
        }

        public override int GetHashCode()
        {
            return Color.GetHashCode();
        }
    }
}

Feel free to play with the threshold to optimize your results!

Good luck!

Comments

Popular posts from this blog

Impersonating CurrentUser from SYSTEM

Add Styles & Scripts Dynamically to head tag in ASP .NET MVC

Json To Dictionary generic model binder