Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Free Pascal, Pascal ABC и другие _ RGB --> 256

Автор: compiler 11.08.2007 19:58

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

заранее благодарен

Автор: Neznaika 11.08.2007 21:15

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

Пусть элемент палитры описывается типом
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 11.08.2007 21:34

Что-то я не совсем понял...

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

Вобще, как я понял, приведенная программа совершает обратные действия wink.gif
Но если бы действитель была бы функция Distance, то задача бы сильно бы упростилась бы...

Автор: volvo 11.08.2007 22:00

Ты для каких режимов хочешь это делать? Если у тебя Win-приложение, то есть http://msdn2.microsoft.com/en-us/library/ms532650.aspx

Автор: compiler 11.08.2007 22:09

Цитата(volvo @ 11.08.2007 18:00) *
Ты для каких режимов хочешь это делать? Если у тебя Win-приложение, то есть http://msdn2.microsoft.com/en-us/library/ms532650.aspx
а где можна посмотреть примеры по использованию?

Автор: Neznaika 11.08.2007 22:34

Цитата

нужна функция на ФП которая получая 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 11.08.2007 22:48

Цитата
где можна посмотреть примеры по использованию?

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

Ну, конечно, если тебе больше нравится создавать велосипеды самому - нет проблем...

Автор: Neznaika 11.08.2007 23:45

По-моему самый простой(и наглядный) пример использования это:
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 12.08.2007 17:00

Ответ-велосипед. Функция, которая требовалась изначально.
Все комментарии были написаны раньше.


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;


Автор: Archon 12.08.2007 22:02

http://www.enlight.ru/demo/faq/smth.phtml?query=alg_clr_near