Вход

Просмотр полной версии : Привести цвет к одному из двух основных



tae1980
21.01.2019, 12:31
Такая задачка.

Есть два цвета принятые как основные. Палитра 8bpp (rrrgggbb).
Нужно привести (приравнять) третий цвет к одному из основных цветов, который больше всего подходит.

Может кто подскажет алгоритм или направление куда рыть?

Shiny
21.01.2019, 12:56
как вариант -покурить сырки bmp2scr или другого продвинутого конвертера. или, как вариант, почитать про квантизацию цветов например.

tae1980
21.01.2019, 14:13
Ответ найден (но ещё не тестировал). Поиск ближайшего цвета в палитре. (http://algolist.manual.ru/graphics/find_col.php)

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

Введем обозначения:

(R0,G0,B0) - цвет, аналог которого нужно найти в палитре.
(Ri,Gi,Bi) - i-тый цвет в палитре.

Различие цветов будем оценивать с помощью следующей функции:
fi = 30*(Ri-R0)2+59*(Gi-G0)2+11*(Bi-B0)2.

Множители 30;59;11 - отражают различную чувствительность человеческого глаза к красному,зеленому и синему цветам соответственно. Далее мы поочереди перебираем все цвета палитры и ищем цвет, для которого fi принимает минимальное значение. Это и будет искомый цвет.


// структуры
typedef struct RGB_type
{
char r,g,b;
} RGB;

typedef struct Pal_type
{
int n; // число цветов в палитре
RGB* C;
} Pal;

// это подпрограмма поиска
// P - палитра
// С - цвет, который требуется найти
// Возвращаемое значение - индекс цвета в палитре
int FindColor(Pal *P,RGB *C)
{
int i, fi, best_color, f_min=1000000;
for(i=0;i<P->n,i++)
{
fi=30*(P->C.r-C->r)*(P->C.r-C->r)+
59*(P->C.g-C->g)*(P->C.g-C->g)+
11*(P->C.b-C->b)*(P->C.b-C->b);
if(fi<f_min){best_color=i,f_min=fi;}
}
return(best_color); }

Ynicky
21.01.2019, 19:31
У меня была задача преобразовать полноцветные картинки RGB888
в палитру для Spec256. В палитре - 256 цветов в кодировке RGB888.
В картинках, где преобладал синий цвет, поиск минимума отличий
был лучше по формуле 1R+1G+1B вместо 3R+6G+1B.
В других наоборот.
67771
67772
67773
67774
67775
67776

Lethargeek
21.01.2019, 20:01
Множители 30;59;11 - отражают различную чувствительность человеческого глаза к красному,зеленому и синему цветам соответственно...
...отображаемым на устройстве древнего стандарта NTSC. Для других стандартов другие пр0центы:
http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html (в матрицах смотреть на вторую строку)

tae1980
22.01.2019, 00:42
Lethargeek, И что лучше взять для Профи 5.06, палитра 16 из 256 (rrrgggbb) с выводом на жк монитор?
Я не спец по графике, можно для таких ткнуть пальцем? Была бы одна матрица, а там целый веер.

Lethargeek
22.01.2019, 16:26
tae1980, лучше - знать, на какой стандарт рассчитывал автор пикчи :)
да не парься, просто напиши конвертер с выводом кучи вариантов всех сразу
просматривай потом результаты и выбирай каждый раз один на свой вкус

tae1980
23.01.2019, 16:13
В продолжении темы.
В текущей версии конвектора изображения под экран Profi реализованы две схемы выборки цветов для байта:
1. Находим два самых частых цвета, остальные приводим к ним.
2. То же, но если по краям находятся два самых светлых или самых темных цвета, приводом все цвета к ним.

Начитался про квантизацию изображений, но тут не много другая задача. Не вижу возможности применить её здесь. Или я не прав?

Вопрос: можно ли улучшить качество? Будут ли советы, рекомендации?

Вот два примера:
http://www.imageup.ru/img172/3266730/2019-01-23_15-44-58.png (http://www.imageup.ru/img172/3266730/2019-01-23_15-44-58.png.html)
http://www.imageup.ru/img172/3266731/2019-01-23_16-03-15.png (http://www.imageup.ru/img172/3266731/2019-01-23_16-03-15.png.html)

marinovsoft
23.01.2019, 17:06
Про дизеринг напомнить?
https://ru.wikipedia.org/wiki/Дизеринг

tae1980
23.01.2019, 17:28
marinovsoft, думал о нем. Но для меня это сложно.
Поступаю так в фотошопе сначала индексирую цвет к 256 в палитре Профи. Потом делаю цвет снова 24 битным. После привожу к 16 цветам. Такая последовательность, так как фотошоп не позволяет привести к 16 цветам если загружена палитра 256 цветов.
если я правильно понимаю, то квантизацию и дизеринг изображения делает при этих манипуляциях фотошоп.

Я же беря подготовленный файл, привожу палитру 24bpp к палитре Профи и объединяю последовательность из 8 точек в байт. Так как у Профи 2 цвета на 8 точек. Для чего нужно выкинуть до 6 цветов, приведя их к двум основным (правила их выбора из 8 возможных описал выше). От сюда и вылазит "размазывание" картинок.

Думаю дизеринг в данной ситуации мог бы помочь "сгладить" изображение. Но вот как его организовать я не пойму.

Lethargeek
24.01.2019, 18:31
ну какбэ https://en.wikipedia.org/wiki/Dither

- - - Добавлено - - -

и далее по ссылкам под картинками, например
https://en.wikipedia.org/wiki/Floyd–Steinberg_dithering
формулы простые совсем

tae1980
24.01.2019, 19:06
Lethargeek, формулы может и просты, только вот хорошо бы ещё и разбираться в теме, с чем у меня туго, так как от графики и разных художеств я очень далёк. Мозги заточены под другое. Тут просто выхода иного нет :)
Теорию уже немного начитался. Тут вот в чём вопрос: все статьи относятся к картинкам где у каждого пикселя свой цвет. На Профи же два цвета на 8 точек. То есть понятие "левый"/"нижний" пиксель не очевидное. Если пиксель в начале байта, какой пиксель считать "слева", тот который в этом байте или тот который уже в следующем байте?
Как теорию подтянуть под наши реали?
Изначально картинки готовятся во внешних программах, они всё это проделывают сами. "Размытие" получается уже после адаптации к экрану Профи. Когда применять теорию и какую? Не пойму как в теории перейти от цвета на точку, к двум цветам на байт.
Применять что-то после адаптации уже поздно, многие детали утеряны. Применять до - так оно как бы уже применялась (во внешних программах). ИМХО тут вопрос посложнее да же приведения к двум цветам. Тут как нужно и цвета сохранить, и пиксели встроить так что бы сохранить детали.
Мне не хватает теоретически-практических знаний. То что для художника очевидно, для меня темный лес.
Есть мысль сделать два прохода. На первом приводим как сейчас. На втором каждый пиксель результата сравниваем с оригиналом, если он стал темнее/светлее более чем на некий порядок, меняем его значение.

Lethargeek
24.01.2019, 19:27
при распределении ошибки попробуй выбирать внизу ближайший цвет из доступных двух
для начала сделай в один проход

tae1980
24.01.2019, 21:20
Извини, если достал.

при распределении ошибки попробуй выбирать внизу ближайший цвет из доступных двух
для начала сделай в один проход
На первом этапе нет двух цветов на байт, у каждого пикселя свой цвет.
Нужно сначала привести всю картинку к двум цветам на байт? Но тогда теряются детали.
Или берем первые 8 точек, приводим их к двум цветам, и полученную общую ошибка на байт распределяем так же на 8 точек? А что делать с "деталями" в первом байте? Мы их теряем?
А может так, берем за основу два крайних цвета в байте, а для средних 6 из сочетания цвета и пикселей (дизеринга) пытаемся найти оптимальную комбинацию?
С одной стороны не вижу необходимости двигаться по вертикали, так как две соседние по вертикали точки могут иметь разные цвета и они уже обработаны по внешних программах.
С другой стороны, учет (и влияние) вертикальных соседей даст возможность применять более хитрые пиксельные маски (забыл правильно название) для цвета.
Нужна некая комбинация из методов поучения двухцветных и 16 цветных картинок. Когда часть цветов эмулирются плотностью пикселей с учетом деления на байты. Возможно стоит работать с исходными файлами с числом цветов более 16. Но от одной мысли об этом у меня начинаются головные боли.

Lethargeek
25.01.2019, 02:56
ну тогда переводи построчно в два цвета, а ошибку вниз сноси попиксельно
потом переходишь к этой уже изменённой нижней строке и повторяешь