![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Отобразить картинку в оттенках определенного цвета (Colorize) [D4, WinXP]
Tahion2 © (2004-07-07 10:01:00)Мне нужно отобразить картинку в оттернах определенного цвета. Выглядеть должно так, вроде ты смотришь на картинку через стекло заданого цвета.
Общий смысл процедуры таков: пробегаем по каждому пикселю битмапа, RGB -> HLS, и затем замена H и S на нужные нам, а L оставляем нетронутым.
Все, вроде, работает, но на темных цветах происходят непонятные "срывы". См. иллюстрацию (Правый результат): http://www.rudnik.com.ua/Example.gif
Вопрос: Что не так я делаю. Где ошибка?
Вот код, который я использую:
procedure RGBtoHLS(R, G, B: Integer; var H, L, S: Integer);
{ H-оттенок, L-яркость, S-насыщенность }
Var
cMax, cMin: Integer;
Rdelta, Gdelta, Bdelta: single;
Begin
cMax:=max(max(R, G), B);
cMin:=min(min(R, G), B);
L:=Round((((cMax+cMin)*HLSMAX)+RGBMAX)/(2*RGBMAX));
if (cMax=cMin) then
begin
S:=0; H:=UNDEFINED;
end
else
begin
if (L<=(HLSMAX/2)) then
S:=Round((((cMax-cMin)*HLSMAX)+((cMax+cMin)/2))/(cMax+cMin))
else
S:=Round((((cMax-cMin)*HLSMAX)+((2*RGBMAX-cMax-cMin)/2))
/(2*RGBMAX-cMax-cMin));
Rdelta:=(((cMax-R)*(HLSMAX/6))+((cMax-cMin)/2))/(cMax-cMin);
Gdelta:=(((cMax-G)*(HLSMAX/6))+((cMax-cMin)/2))/(cMax-cMin);
Bdelta:=(((cMax-B)*(HLSMAX/6))+((cMax-cMin)/2))/(cMax-cMin);
if (R=cMax) then
H:=Round(Bdelta-Gdelta)
else if (G=cMax) then
H:=Round((HLSMAX/3)+Rdelta-Bdelta)
else
H:=Round(((2*HLSMAX)/3)+Gdelta-Rdelta);
if (H<0) then H:=H+HLSMAX;
if (H>HLSMAX) then H:=H-HLSMAX;
end;
if S<0 then S:=0; if S>HLSMAX then S:=HLSMAX;
if L<0 then L:=0; if L>HLSMAX then L:=HLSMAX;
end;
procedure HLStoRGB(H, L, S: Integer; var R, G, B: Integer);
Var
Magic1, Magic2: single;
function HueToRGB(n1, n2, hue: single): single;
begin
if (hue<0) then hue:=hue+HLSMAX;
if (hue>HLSMAX) then hue:=hue-HLSMAX;
if (hue<(HLSMAX/6)) then
Result:=(n1+(((n2-n1)*hue+(HLSMAX/12))/(HLSMAX/6)))
else if (hue<(HLSMAX/2)) then
Result:=n2
else if (hue<((HLSMAX*2)/3)) then
Result:=(n1+(((n2-n1)*(((HLSMAX*2)/3)-hue)+(HLSMAX/12))/(HLSMAX/6)))
else
Result:=(n1);
end;
begin
if (S=0) then
begin
B:=Round((L*RGBMAX)/HLSMAX); R:=B; G:=B;
end
else
begin
if (L<=(HLSMAX/2)) then
Magic2:=(L*(HLSMAX+S)+(HLSMAX/2))/HLSMAX
else
Magic2:=L+S-((L*S)+(HLSMAX/2))/HLSMAX;
Magic1:=2*L-Magic2;
R:=Round((HueToRGB(Magic1, Magic2, H+(HLSMAX/3))*RGBMAX+(HLSMAX/2))/HLSMAX);
G:=Round((HueToRGB(Magic1, Magic2, H)*RGBMAX+(HLSMAX/2))/HLSMAX);
B:=Round((HueToRGB(Magic1, Magic2, H-(HLSMAX/3))*RGBMAX+(HLSMAX/2))/HLSMAX);
end;
if R<0 then R:=0; if R>RGBMAX then R:=RGBMAX;
if G<0 then G:=0; if G>RGBMAX then G:=RGBMAX;
if B<0 then B:=0; if B>RGBMAX then B:=RGBMAX;
end;
procedure ColorizeColor(R,G,B :integer; Color: TColor; var OutR, OutG, OutB:Byte);
//Колоризирует один пиксель цветом Color
var h1, s1, l1, h, s, l : integer;
InColor, OutColor : TColor;
R1,B1,G1:integer;
begin
InColor := RGB(R,G,B);
RGBtoHLS(R, G, B, h, l, s);
RGBtoHLS(GetRValue(Color), GetGValue(Color), GetBValue(Color), h1, l1, s1);
HLStoRGB(h1,l,s1, r1,g1,b1);
OutColor:= RGB(r1,g1,b1);
OutR:=GetRValue(OutColor);
OutG:=GetGValue(OutColor);
OutB:=GetBValue(OutColor);
end;
//Next here's a code to make a loop on an image (called Podglad, size is 32*32):
//В данном случае происходит раскраска красным цветом.
var OutR, OutG, OutB:Byte;
Col:TColor;
begin
for y := 0 to 31 do
for x := 0 to 31 do
begin
Col:=Podglad.Picture.Bitmap.Canvas.Pixels[x, y];
ColorizeColor(GetRValue(Col),GetGValue(Col),GetBValue(Col), clRed, OutR, OutG, OutB);
Podglad.Picture.Bitmap.Canvas.Pixels[x, y]:=RGB(OutR, OutG, OutB);
end;
end;
Tahion2 (2004-07-08 00:26:00) [21]Да. Уже неплохо. :)
Вот только здается мне, что алгоритм с RGB -> HLS и заменой Н и S правильный, вот только еще что-то нужно делать с L. Вот только что?
Огромное Кулясищще (2004-07-07 22:25:00) [22]Первый блин. Комочки большие, но всё же.
http://www.hot.ee/mvps17/exampel2.png
Tahion2 (2004-07-07 22:09:00) [23]Ждем-с
Огромное Кулясищще (2004-07-07 20:39:00) [24]Щас, ты погодь. Сваяю что-нить, раз Fenik плохой алгоритм сделал :)
Tahion2 (2004-07-07 15:30:00) [25]Эта функция глючит еще сильнее. То что в результатах на картинке
http://www.rudnik.com.ua/Example.gif
слева - это после работы именно этой ф-ции.
Огромное Кулясищще (2004-07-07 14:37:00) [26]http://delphibase.endimus.ru/?action=viewfunc&topic=mediaimg&id=10178
Tahion2 (2004-07-07 13:47:00) [27]Может кто чего подсказать?
Tahion2 (2004-07-07 11:39:00) [28]>Ты алгоритм сам изобрел? Если ты знаешь критерий неправильности, то знаешь и как правильно. Осталось сравнить.
Нет, не сам. В этом все и дело.
А как правильно я знаю из-за того, что есть программы, которые алгоритм уже реализуют (ПРАВИЛЬНО). Сравинивая их и мои результаты получаю ответ: правильно или нет
REA (2004-07-07 11:10:00) [29]Ты алгоритм сам изобрел? Если ты знаешь критерий неправильности, то знаешь и как правильно. Осталось сравнить.
Модуль GraphUtil:
procedure ColorRGBToHLS(clrRGB: COLORREF; var Hue, Luminance, Saturation: Word);
{ Calculates a color given Hue, Luminance and Saturation values }
function ColorHLSToRGB(Hue, Luminance, Saturation: Word): TColorRef;
Если версия Delphi старая, то могу кинуть целиком функции
Tahion2 (2004-07-07 10:49:00) [30]Что значит "Локализуй неверный пиксел"? они при определенных цветах все неверные.
Юпросчитай значение вручную
Проверил HLStoRGB и RGBtoHLS работают правильно.
Может еще какие-то действия с L (lightness) нужно делать?
REA (2004-07-07 10:07:00) [31]Локализуй неверный пиксел, просчитай значение вручную и по шагам....