Добрый день! Собственно нужна функция на ФП которая получая RGB-параметры возвращала бы номер этого(или максимально близкого к этому цвету) в стандартной палитре. [ RGBToP(const r, g, b:word):word; ] Желательно БЕЗ использования асм. Поиск особых результатов не дал(кроме не к чему не ведущей темы 2003-года)
Оооо, я когда-то решал эту задачу. Её нужно было решать всем разработчикам игрушек с палитровой графикой для подгонки например цветов текстур/спрайтов с оригинальной палитрой к цветовой палитре игры.
Пусть элемент палитры описывается типом 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.
Итак разбиваем всю палитру RGB на 256 цветов(ибо больше нам все равно не понадобится) //каким образом мы будем отсеивать цвета? Затем сравниваем все цвета RGB с неким цветом //каким образом будет происходить сравнение(тоесть где взять функцию Distance)?
Вобще, как я понял, приведенная программа совершает обратные действия Но если бы действитель была бы функция Distance, то задача бы сильно бы упростилась бы...
нужна функция на ФП которая получая 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. Ну, можно сказать, что эти формулы основаны на теореме Пифагора. Не знаю, что ещё написать по этому поводу.
Обычное использование: сначала создается палитра с помощью CreatePalette(), пример есть в DRKB... Потом - из значений компонент собирается цвет, индекс которого будешь искать, и наконец, находим индекс через GetNearestPaletteIndex(палитра, цвет)...
Ну, конечно, если тебе больше нравится создавать велосипеды самому - нет проблем...
По-моему самый простой(и наглядный) пример использования это: 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) и *** Хорошо, что сейчас палитры не используются!
Ответ-велосипед. Функция, которая требовалась изначально. Все комментарии были написаны раньше.
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;