Скорее всего, в любом насыщенном изображении большинство ваших цветов будут в некотором роде уникальными. Из этого следует, что получение различных цветов, скорее всего, не поможет вам в достижении вашей цели.
Я рекомендую проверять значения HSV для каждого пикселя вашего изображения. Я оставлю вам бесчисленное количество онлайн-примеров получения изображений в виде массивов значений HSV.
С вашими значениями 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]);
}
}
Я не пытался отфильтровать, какие оттенки выбрать. Возможно, вам придется рассмотреть некоторые эвристические методы, а не слепо выбирать такое большое количество значений, потому что вы, вероятно, захотите выбрать оттенки, которые несколько разделены в цветовом спектре. У меня нет времени исследовать это дальше, но я надеюсь, что это дает некоторое представление о стратегии, которую вы можете рассмотреть.
person
kbrimington
schedule
28.04.2011