Как получить основной цвет в изображении? - PullRequest
9 голосов
/ 30 марта 2010

Я хочу получить основной цвет в фоновом изображении в .NET.Возможно ли это?

Ответы [ 5 ]

6 голосов
/ 30 марта 2010

Вы можете пройтись по всем пикселям изображения и использовать метод getPixel для определения значения RGB. После этого вы можете получить словарь, в котором будет храниться значение ARGB и счетчик. Затем вы можете увидеть, какое значение ARGB присутствует на изображении чаще всего.

var list = new Dictionary<int, int>();
Bitmap myImage = (Bitmap)Bitmap.FromFile("C:/test.jpeg");
for (int x = 0; x < myImage.Width; x++)
{
    for (int y = 0; y < myImage.Height; y++)
    {
        int rgb = myImage.GetPixel(x, y).ToArgb();
        if (!list.ContainsKey(rgb))
            list.Add(rgb, 1);
        else
            list[rgb]++;
    }
}

Как указывалось, это не имеет никакого отношения к подобным цветам. Если вам нужен более «общий» цвет большинства, у вас может быть порог сходства. например а не:

if (!list.ContainsKey(rgb))
        list.Add(rgb, 1);
    else
        list[rgb]++;

Вы могли бы сделать:

var added = false;
for (int i = 0; i < 10; i++)
{
    if (list.ContainsKey(rgb+i))
    {
        list[rgb+i]++;
        added = true;
        break;
    }
    if (list.ContainsKey(rgb-i))
    {
        list[rgb-i]++;
        added = true;
        break;
    }
}
if(!added)
    list.Add(rgb, 1);

Вы можете поднять порог 10 до того, что вам нужно.

5 голосов
/ 30 марта 2010

Возвращает средний цвет изображения.

static Color AverageColor(string fileName)
{
    using (var bmp = new Bitmap(fileName))
    {
        int width = bmp.Width;
        int height = bmp.Height;
        int red = 0;
        int green = 0;
        int blue = 0;
        int alpha = 0;
        for (int x = 0; x < width; x++)
            for (int y = 0; y < height; y++)
            {
                var pixel = bmp.GetPixel(x, y);
                red += pixel.R;
                green += pixel.G;
                blue += pixel.B;
                alpha += pixel.A;
            }

        Func<int, int> avg = c => c / (width * height);

        red = avg(red);
        green = avg(green);
        blue = avg(blue);
        alpha = avg(alpha);

        var color = Color.FromArgb(alpha, red, green, blue);

        return color;
    }
}
5 голосов
/ 30 марта 2010

Вы также можете найти этот алгоритм испытаний на переполнение стека:

Задача алгоритма: создать цветовую схему из изображения

Также рассмотрите возможность создания гистограммы изображения и выбора цвета с наибольшим значением в качестве «основного цвета»: http://www.phpclasses.org/browse/file/15953.html

4 голосов
/ 30 марта 2010

Возвращает средний цвет изображения с использованием небезопасного доступа к указателю. Примечание: код адаптирован только для 24bppRgb, может быть адаптирован для других форматов пикселей.

    unsafe static Color GetColor(string filename)
    {
        using (var image = (Bitmap)Bitmap.FromFile(filename))
        {
            if (image.PixelFormat != PixelFormat.Format24bppRgb) throw new NotSupportedException(String.Format("Unsupported pixel format: {0}", image.PixelFormat));

            var pixelSize = 3;
            var bounds = new Rectangle(0, 0, image.Width, image.Height);
            var data = image.LockBits(bounds, ImageLockMode.ReadOnly, image.PixelFormat);

            long r = 0;
            long g = 0;
            long b = 0;

            for (int y = 0; y < data.Height; ++y)
            {
                byte* row = (byte*)data.Scan0 + (y * data.Stride);
                for (int x = 0; x < data.Width; ++x)
                {
                    var pos = x * pixelSize;
                    b += row[pos];
                    g += row[pos + 1];
                    r += row[pos + 2];
                }
            }

            r = r / (data.Width * data.Height);
            g = g / (data.Width * data.Height);
            b = b / (data.Width * data.Height);
            image.UnlockBits(data);

            return Color.FromArgb((int)r, (int)g, (int)b);
        }
    }

Суть: http://gist.github.com/349210

3 голосов
/ 30 марта 2010

Предполагая, что вы охарактеризуете цвет каждого пикселя, используя RGB (по сравнению, скажем, CMYK ), вы можете построить трехмерный массив (по одному измерению для R, G и B). Затем выберите количество ячеек, которое вы хотите иметь в каждом измерении - чем больше ячеек, тем больше различие вы проводите между похожими оттенками.

Как только это будет сделано, просто переберите растровое представление вашего изображения, суммируя # пикселей, попадающих в каждую из ячеек вашего трехмерного массива. Ячейка с наибольшей суммой будет преобладающим цветом.

Возможно, вы захотите сделать свой алгоритм легко настраиваемым для # бинов в каждом измерении, чтобы вы могли настроить, насколько он различает похожие цвета.

image = new Bitmap("C:\\test.bmp", true);
int x, y;
// Loop through the images pixels to product 3d histogram
for(x=0; x<image.Width; x++)
{
   for(y=0; y<image.Height; y++)
   {
      Color pixelColor = image.GetPixel(x, y);

      // Increment color count in appropriate cell of your 3d histogram here
      ...
   }
}
...