Помощь - Поиск - Пользователи - Календарь
Полная версия: RGB --> 256
Форум «Всё о Паскале» > Pascal, Object Pascal > 32 битные компиляторы
compiler
Добрый день!
Собственно нужна функция на ФП которая получая RGB-параметры возвращала бы номер этого(или максимально близкого к этому цвету) в стандартной палитре. [ RGBToP(const r, g, b:word):word; ]
Желательно БЕЗ использования асм.
Поиск особых результатов не дал(кроме не к чему не ведущей темы 2003-года)

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

Пусть элемент палитры описывается типом
type TRGB = record Red, Green, Blue : Byte end;
Палитра состоит из 256 элементов TRGB:
type TRGBPalette = array[0..255] of TRGB;

Можно рассуждать следующим образом.
Есть цветовое пространство RGB. Нам нужен его первый октант, то есть та часть(тот куб),
в котором координаты по осям R, G и B изменяются от 0 до 255(тип Byte для Red, Green и Blue в TRGB).
Соответственно переменная типа TRGB будет с одной стороны задавать цвет, а с другой(то что нам и нужно)
координаты в первом октанте RGB-пространства. Вся палитра будет соответственно задавать набор
точек в RGB-пространстве. Остается решить задачу на нахождение минимального расстояния от заданной
точки до точек из палитры(в цветовом пространстве RGB).
Пусть функция вычисляющая расстояние между двумя точками A и B объявлена как
function Distance( A, B : TRGB ) : Real;
тогда найти минимальное расстояние (и нужный нам ближайший цвет) можно следующим образом:
 
var
RGBPalette : TRGBPalette; { Палитра <чужая>. }
X : TRGB; { Цвет <из нашей палитры>. }
MinDistance : Real;
Index : Integer; { Номер цвета из чужой палитры, который наиболее близок к нашему цвету. }
I : Integer;
begin
Index := 0;
MinDistance := Distance(X,RGBPalette[Index]);
for I := 1 to 255 do
if MinDistance > Distance(X,RGBPalette[I]) then
begin
MinDistance := Distance(X,RGBPalette[I]);
Index := I
end;
end;



Тогда цвет RGBPalette[Index] наиболее "похож" на цвет X.

P.S.
Игрушки я не разрабатывал.
compiler
Что-то я не совсем понял...

Итак разбиваем всю палитру RGB на 256 цветов(ибо больше нам все равно не понадобится) //каким образом мы будем отсеивать цвета?
Затем сравниваем все цвета RGB с неким цветом //каким образом будет происходить сравнение(тоесть где взять функцию Distance)?

Вобще, как я понял, приведенная программа совершает обратные действия wink.gif
Но если бы действитель была бы функция Distance, то задача бы сильно бы упростилась бы...
volvo
Ты для каких режимов хочешь это делать? Если у тебя Win-приложение, то есть GetNearestPaletteIndex
compiler
Цитата(volvo @ 11.08.2007 18:00) *
Ты для каких режимов хочешь это делать? Если у тебя Win-приложение, то есть GetNearestPaletteIndex
а где можна посмотреть примеры по использованию?
Neznaika
Цитата

нужна функция на ФП которая получая RGB-параметры возвращала бы номер этого(или максимально близкого к этому цвету) в стандартной палитре. [ RGBToP(const r, g, b:word):word; ]


стандартная палитра - это наверно VGA-палитра. Тогда в ней 256 цветов. Я её объявил как RGBPalette.
Если это не так, то нужно просто поменять верхний диапазон для массива TRGBPalette и для цикла for.
В любом случае массив RGBPalette необходимо каким-либо образом инициализировать(например считать из файла).

Самое главное нужно понять, что три компоненты цвета можно соотнести с тремя координатами пространства.
Можно попробовать на бумаге нарисовать систему координат с тремя осями, только вместо X, Y и Z написать
Red, Green и Blue. Так как компоненты цвета больше или равны нулю(принимают значения от 0 до 255),
то рассматривать придётся только один октант(1/8) RGB-пространства: Red - 0..255; Green - 0..255; Blue - 0..255.
Все цвета(и цвета "стандартной" палитры и цвет, передаваемый в функцию) - это ТОЧКИ RGB-пространства,
а компоненты цвета(Red, Green и Blue) - это КООРДИНАТЫ ЭТИХ ТОЧЕК. Массив RGBPalette - это 256 разноцветных точек в кубе RGB-пространства, цвет, передаваемый в функцию, - ещё одна цветная точка в этом кубе(я задал её переменной X). Точки с ПОХОЖИМ цветом находятся БЛИЖЕ ДРУГ К ДРУГУ. То есть нужно просто находить расстояния в RGB-пространстве(оно ТРЁХМЕРНОЕ - Red,Green,Blue) от точки X до точек RGBPalette и выбрать из них наименьшее. Этим и занимается ранее приведённый фрагмент кода.

Как вычисляются расстояния в N-мерных пространствах?
Точки A и B с координатами (X1,X2,...,XN).
Одно измеренние - одна координата(X1). S = Abs(A.X1 - B.X1).
Два измерения - две координаты(X1,X2). S = Sqrt( Sqr(A.X1 - B.X1) + Sqr(A.X2 - B.X2) ).
Три измерения - три координаты(X1,X2.X3). S = Sqrt( Sqr(A.X1 - B.X1) + Sqr(A.X2 - B.X2) + Sqr(A.X3 - B.X3)).
Тьфу, уже не помню в каком классе средней школы это проходят. Без обид.
P.S.
Ну, можно сказать, что эти формулы основаны на теореме Пифагора.
Не знаю, что ещё написать по этому поводу.
volvo
Цитата
где можна посмотреть примеры по использованию?

Обычное использование: сначала создается палитра с помощью CreatePalette(), пример есть в DRKB... Потом - из значений компонент собирается цвет, индекс которого будешь искать, и наконец, находим индекс через GetNearestPaletteIndex(палитра, цвет)...

Ну, конечно, если тебе больше нравится создавать велосипеды самому - нет проблем...
Neznaika
По-моему самый простой(и наглядный) пример использования это:
1) Создать 2 различных BMP-файла(с палитрой из 256 цветов) - A.BMP и B.BMP.
Например два пейзажа: море(A.BMP) и пустыня(B.BMP).
2) Из файла A.BMP взять палитру: APalette.RGB.
3) Заменить значения цвета всех пикселей для B.BMP на ближайшие похожие в APalette.RGB.
Палитра APalette.RGB заменит исходную палитру B.BMP.
4) Посмотреть на результат(изменённый B.BMP) и *** smile.gif
Хорошо, что сейчас палитры не используются!
Neznaika
Ответ-велосипед. Функция, которая требовалась изначально.
Все комментарии были написаны раньше.

const
MAX_PALETTE_INDEX = 255;
type
TRGB = record
Red, Green, Blue : Byte
end;
TRGBPalette = array[0..MAX_PALETTE_INDEX] of TRGB;

function GetNearestPaletteIndex( RGBPalette : TRGBPalette; X : TRGB ) : Integer;
var
DD, MinDD : LongInt;
I, Index : Integer;
begin
Index := 0;
MinDD :=
Sqr(LongInt(X.Red) - RGBPalette[Index].Red) +
Sqr(LongInt(X.Green) - RGBPalette[Index].Green) +
Sqr(LongInt(X.Blue) - RGBPalette[Index].Blue);
for I := 1 to MAX_PALETTE_INDEX do
begin
DD :=
Sqr(LongInt(X.Red) - RGBPalette[I].Red) +
Sqr(LongInt(X.Green) - RGBPalette[I].Green) +
Sqr(LongInt(X.Blue) - RGBPalette[I].Blue);
if MinDD > DD then
begin
MinDD := DD;
Index := I
end
end;
GetNearestPaletteIndex := Index
end;

Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.