Цветовая сегментация - PullRequest
4 голосов
/ 29 июля 2011

Мне нужно сегментировать изображение по 7 цветам (красный, оранжевый, желтый, зеленый, голубой, синий, фиолетовый), как в радуге.Ты знаешь как это сделать?Любые документы или алгоритмы могут быть.Например, это можно сделать, назначив каждой тройке (r, g, b) цвет.Но это не эффективно, поскольку мы получили 255 ^ 3 комбинаций.

Ответы [ 5 ]

4 голосов
/ 29 июля 2011

Компонент "H" в цветовом пространстве HSV http://en.wikipedia.org/wiki/HSL_and_HSV, даст вам разумное число, представляющее положение (непрерывной) радуги.

Тогда достаточно просто разделить это непрерывное пространство на семь сегментов по вашему выбору.

1 голос
/ 29 июля 2011

Если цвета предопределены, то решение состоит в том, чтобы просто зациклить каждый пиксель и заменить ближайшим представителем.Как сказал carlosdc , преобразование цветового пространства может дать лучший результат, чем просто (r1-r2)**2 + (g1-g2)**2 + (b1-b2)**2.

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

// Initialize the cache to 255
std::vector<unsigned char> cache(256*256*256, 255);

for (int y=0; y<h; y++)
{
    unsigned char *pixel = img + y*w*3 + x;
    for int (x=0; x<w; x++, pixel+=3)
    {
        int r = pixel[0], g = pixel[1], b = pixel[2];
        int key = r + (g<<8) + (b<<16);
        int converted = cache[key];
        if (converted == 255)
        {
            ... find closest representative ...
            cache[key] = converted;
        }
        pixel[0] = red[converted];
        pixel[1] = green[converted];
        pixel[2] = blue[converted];
    }
}

Если количество цветов мало, вы можете использовать меньше памяти.Например, чтобы ограничить число представителей до 15, вам нужно всего 4 бита на запись цвета (половина пробела), и что-то вроде следующего сделает это:

std::vector<unsigned char> cache(256*256*256/2, 255);

...
int converted = (key&1) ? (cache[key>>1] >> 4) : (cache[key>>1] & 0x0F);
if (converted == 15) // Empty slot
{
    ...
    cache[key>>1] ^= (key & 1) ? ((converted << 4)^0xF0) : (converted^0x0F);
}
...

Если на противоположной стороне вы знаете, что число возможныхвходные цвета будут небольшими, а число представителей будет большим, тогда стандартная std::map может быть допустимой альтернативой.

1 голос
/ 29 июля 2011

Поскольку у вас уже есть 7 нужных вам цветов, вам не нужно использовать кластеризацию. Разумной отправной точкой будет: для каждого пикселя изображения найдите, какой из 7 цветов находится ближе всего к нему (используя расстояние L2 на RGB), и назначьте этот ближайший цвет этому пикселю. Возможно, вам удастся получить более качественные (более схожи по восприятию) результаты, если сначала преобразовать их в другое цветовое пространство, например CIE XYZ, однако это потребует экспериментов.

0 голосов
/ 29 июля 2011

Если вы хотите, чтобы он выглядел хорошо, вы должны использовать дизеринг, например, дизеринг Флойда Стейнберга: http://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering

0 голосов
/ 29 июля 2011

Почему бы вам не использовать один из методов (алгоритмов) кластеризации? Например, алгоритм k-средних. В противном случае, Google "сегментация изображения по цветам".

...