Как я могу создать палитру выдающихся цветов с изображения?

StackOverflow https://stackoverflow.com/questions/5823854

Вопрос

Я пытаюсь выяснить, как попробовать все пиксели на изображении и генерировать из него палитру цветов, что -то вроде это или же это. Анкет Я понятия не имею, с чего начать. Может кто-то указать мне верное направление?

__РЕДАКТИРОВАТЬ: __

Это то, с чем я оказался до сих пор:

Я использовал это Пикселат Функция для получения больших блоков, таких как Joe_coolish. Он работает отлично и дает мне довольно хороший образец цветов для работы (это из Windows Sample Merall Fish Picture):

Теперь, если кто -то сможет помочь мне получить 5 самых разных цветов (самый темный синий, самый светлый синий, оранжевый, серый и персиковый (?)), Я бы любил вас навсегда. Я действительно не понимаю, как средний или же добавлять цвета вместе. Я также не могу выяснить, как определить, является ли цвет, похожий на программно, в вас есть несколько чисел и переменных, которые я теряюсь, пытаясь выяснить, что делать, к чему.

Это было полезно?

Решение

Ответы с участием кода показывают, как получить полную палитру. Если вы хотите получить обычные цвета, как на веб -сайтах, которые вы разместили, я бы это сделал.

Изображение источника:

Source

Во -первых, я бы усреднял цвета, нанеся фильтр низкого уровня (что -то вроде гауссового размытия)

enter image description here

Таким образом, вы ограничиваете общую палитру. Оттуда я разделил бы экран на n блоков (n - это общее количество пикселей, которые вы хотите в своей палитре)

enter image description here

Оттуда нацелены на каждый блок и перечислите по каждому пикселю, получите средний пиксель для этого блока и добавьте его в свой палитра. Результат - что -то вроде этого:

enter image description here

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

Другие советы

Сначала возьмите пиксели на картинке: (предполагает using System.Drawing.Imaging; а также using System.Runtime.InteropServices)

Bitmap b = new Bitmap(myImage);
BitmapData bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, ImageFormat.Format32Bpp);
int[] arr = new int[bd.Width * bd.Height - 1];
Marshal.Copy(bd.Scan0, arr, 0, arr.Length);
b.UnlockBits(bd);

Тогда вы можете создать свою палитру:

var distinctColors = arr.Distinct();

Необязательно: Устраните похожие цвета, пока у вас не появится предпочтительный размер палитры. Вот как вы могли бы это сделать (хотя это определенно не самый эффективный или точный способ, просто самый простой):

var dc = distinctColors.toArray(); // int dc[] = distinctColors.toArray() is what it used to be
int cmIndex1 = -1;
int cmIndex2 = -1;
int cmDiff = -1;
for (int i = 0; i < dc.length; i++) {
    Color c1 = Color.FromArgb(dc[i]);
    for (int j = i + 1; j < dc.length; j++) {
        Color c2 = Color.FromArgb(dc[j]);
        // Note: you might want to include alpha below
        int diff = Math.Abs(c1.R - c2.R) + Math.Abs(c1.G - c2.G) + Math.Abs(c1.B - c2.B);
        if (cmDiff < 0 || diff < cmDiff) {
            cmIndex1 = i;
            cmIndex2 = j;
            cmDiff = diff;
        }
    }
}
// Remove the colors, replace with average, repeat until you have the desired number of colors

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

Я рекомендую осмотреть значения HSV для каждого пикселя на вашем изображении. Я оставлю вас в бесчисленных онлайн -примерах получения изображений в качестве массивов значений ВПГ.

С вашими значениями ВПГ вы можете рассчитать кластеры выдающихся оттенков, создав целочисленное массив 256 оттенков, вычисляя гистограмму оттенков в данных изображения. Вы можете определить заметные оттенки, найдя кластеры 4-6 последовательных оттенков с высокой суммой.

После выбора нескольких выдающихся оттенков подразделение пикселей этих оттенков в другую гистограмму, измеряющую насыщение, и выберите выдающиеся кластеры и так далее.

Грубный пример

Приведенный ниже код представляет некоторую попытку помочь определить выдающиеся оттенки. Скорее всего, есть другие потрясающие способы сделать это; Однако это может дать некоторые идеи.

Во -первых, я получаю все цвета изображения как массив Color Объекты, как так:

private static Color[] GetImageData(Image image)
{
    using (var b = new Bitmap(image))
    {
        var bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
        byte[] arr = new byte[bd.Width * bd.Height * 3];
        Color[] colors = new Color[bd.Width * bd.Height];
        Marshal.Copy(bd.Scan0, arr, 0, arr.Length);
        b.UnlockBits(bd);

        for (int i = 0; i < colors.Length; i++)
        {
            var start = i*3;
            colors[i] = Color.FromArgb(arr[start], arr[start + 1], arr[start + 2]);
        }

        return colors;
    }
}

Вы можете рассмотреть вопрос о том, чтобы я получил заказ RGB в Color.FromArgb Метод вызов в правильном порядке.

Далее я придерживался метода утилиты для преобразования в HSV. В моем примере я буду работать только с оттенками, но вот полный рабочий пример конверсии:

private static void ColorToHSV(Color color, out int hue, out int saturation, out int value)
{
    int max = Math.Max(color.R, Math.Max(color.G, color.B));
    int min = Math.Min(color.R, Math.Min(color.G, color.B));

    hue = (int)(color.GetHue() * 256f / 360f);
    saturation = (max == 0) ? 0 : (int)(1d - (1d * min / max));
    value = (int)(max / 255d);
}

Наконец, я строю гистограмму оттенка, определяю ширину оттенков (скажем, 9 оттенков), в которой можно объединить счет, а затем сообщаю об подсчете консоли.

private static void ProcessImage(Color[] imagecolors)
{
    var hues = new int[256];
    var hueclusters = new int[256];
    int hue, saturation, value;

    // build hue histogram.
    foreach (var color in imagecolors) {
        ColorToHSV(color, out hue, out saturation, out value);
        hues[hue]++;
    }

    // calculate counts for clusters of colors.
    for (int i = 0; i < 256; i++) {
        int huecluster = 0;
        for (int count = 0, j = i; count < 9; count++, j++) {
            huecluster += hues[j % 256];
        }

        hueclusters[(i + 5) % 256] = huecluster;
    }

    // Print clusters on the console
    for (int i = 0; i < 256; i++) {
        Console.WriteLine("Hue {0}, Score {1}.", i, hueclusters[i]);
    }
}

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

Я начал здесь:

System.Drawing.Image img = System.Drawing.Bitmap.FromFile("file");
System.Drawing.Imaging.ColorPalette palette = img.Palette;
foreach (Color color in palette.Entries)
{
  //...
}

Я собираюсь описать лучший подход на очень высоком уровне.

Сначала вы создаете гистограмму цветов на картинке и их частоте.

Вы получите список всех цветов на изображении, вы можете использовать кластеризацию данных, чтобы найти цвета кандидатов для слияния. Цвета, которые объединяются в средневзвешенное среднее значение, на основе частоты исходных цветов.

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

После того, как у вас появится палитра, вы перерабатываете картинку, используя ближайший соседский цвет, который находится в палитре.

А K-средние Алгоритм кластеризации хорошо работает для этой проблемы. Он делает большую работу по извлечению центроидов цветных кластеров изображения, но имейте в виду, что его нетерминирование затрудняет определение фактической известности каждого кластера.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top