Barva

 

Každý pixel je v bitmapovém souboru reprezentován určitým počtem bitů. Tím je určen počet barev, které může daný pixel nabýt. Je-li  počet bitů na pixel, je možno zobrazit  barev. Dvouúrovňová (jednobitová) zařízení dovolují zobrazovat dvě úrovně (monochromatické monitory, jehličkové tiskárny). Lidské oko má konečný počet barevných receptorů, které obsáhnou rozsah světelných frekvencí 380-770 nm. Tvrdí se, že lidské oko dovede rozeznat až deset milionů barev (přesný počet se v individuálních případech samozřejmě liší). Zařízení, které je schopno zobrazit 224 = 16 777 216  barev, považujeme proto za true color (pravé barvy). True color zařízení tedy potřebuje 24 = 3*8 bitů = 3byty na pixel. V minulosti byla termínem true color označována i zařízení o 15 resp 16 bitech na pixel (32768 resp. 65536 barev).

 

Nejčastěji sestrojovanými útvary na výstupním zařízení jsou digitalizovaný bod – pixel, dále digitalizovaná úsečka a digitalizovaná kružnice, resp. její oblouk.

 

Na většině digitálních zařízení se na jednotlivé pixely odkazujeme pomocí světové souřadné soustavy. Oproti zvyklostem analytické geometrie bývá počátek umístěn vlevo nahoře, „osa y“ je tak orientována shora dolů. Bod, úsečka i kružnice přitom patří mezi tzv. primitiva, tj. útvary, které lze sestrojit pomocí procedur dodávaných přímo s jednotlivými grafickými systémy. Například v Delphi jsou objekty, v nichž je možno provádět grafické konstrukce, vybaveny objektem Canvas – což je model výše definované digitální roviny. Tento objekt obsahuje objekt Pixels – matici pixelů, kterým je možné přiřazovat hodnoty – barvy. Například příkaz Canvas. Pixels[100,150]:= clBlack {colorBlack} obarví černě bod o světových souřadnicích [100,150]. Konstanta clBlack je předdefinována, podobně jako konstanty představující další „běžné barvy“ – clWhite, clYellow, atd. Kreslicí plocha je inicializována jako bílá. Digitální úsečka je realizována dvojicí metod Canvas.MoveTo(x,y) a Canvas.LineTo(x,y). První z nich přesouvá „zvednuté kreslící pero“ (objekt Canvas.Pen) do bodu o specifikovaných světových souřadnicích, druhý činí totéž s „perem spuštěným“. Podobně je možno sestrojit např. elipsu metodou Ellipse(x1,y1,x2,y2). Parametry této metody definují úhlopříčku obdélníka s vodorovnými resp. svislými stranami, do kterých se má elipsa vepsat (je-li takto definován čtverec, výsledkem je samozřejmě kružnice).

 

 

Barvy v osmibitové hloubce

 

Pro „běžného uživatele“ těchto systémů, který je používá k nenáročným grafickým konstrukcím, tento přístup většinou postačuje. K náročným konstrukcím je však třeba přistupovat zcela jinak. Přinejmenším je potřeba jinak přistupovat k barvám. Předdefinovaných odstínů je k dispozici šestnáct a výše uvedený způsob naprosto neumožňuje např. generovat barevné odstíny potřebné pro obrazovou analýzu či stínování objektů. Také používání výše uvedených „předdefinovaných metod“ ke konstrukci primitiv digitální roviny je problematické. Je sice teoreticky možné, prakticky však mnohdy značně neúnosné. Při náročných konstrukcích není vyjímkou, že tato primitiva je třeba sestrojovat řádově stotisíckrát či milionkrát a v těchto případech se ukazuje, že tyto metody jsou značně pomalé. Algoritmus konstrukce těchto objektů implementovaný v grafickém systému není znám, neboť tyto konstrukce bývají předmětem firemních tajemství, jejich kvalitu tedy posuzovat nelze. Faktem však je že „přehlednost“, „intuitivní zřejmost“ a „programátorské pohodlí“ běžného uživatele je draze zaplaceno už jen komplikovaným a tím značně pomalým přístupem k objektu, do kterého se má vlastně kreslit. Například každá tečka odkazující na zděděný objekt, vlastnost či metodu znamená přesměrování ukazatele při jeho hledání v programu. Např. v  příkazu  Image1.Picture.Bitmap.Canvas.Pixels[i,j]:= to znamená, že k nalezení matice Pixels musí program vždy „projít“ čtyři adresy a až na páté se dopátrá objektu, do kterého přiřazuje. Čím je programátorovo pohodlí větší, tím jsou i objekty rozsáhlejší a komplikovanější a tím komplikovanější je i každé hledání, které se při konstrukci každého dalšího objektu (v tomto případě bodu) opakuje. Navíc (zřejmě z důvodů kompatibility) jsou tyto barvy deklarovány jako DWord, tedy jako dvaatřicetibitové objekty, přestože při tomto přístupu je k dispozici pouze šestnáct barev a stačily by pouze čtyři bity. Podstatně rychlejší (i když poněkud komplikovanější) konstrukce bodu spočívá v přímém přístupu do bitmapy. Zde si ukážeme přístup osmibitový, pixel výstupního zařízení budeme obarvovat barvou .

 

Nejdříve je třeba deklarovat jednotlivé barvy jako konstanty:


 

const

slBlack    =0;

slMaroon   =1;

slGreen    =2;

slOlive    =3;

slNavy     =4;

slPurple   =5;

slTeal     =6;

slGray    =12;

 

 

 

slSilver  =7;

slRed     =13;

slLime    =14;

slYellow  =15;

slBlue    =16;

slFuchsia =17;

slAqua    =18;

slWhite   =19;

 


 


 

Tyto barvy jsou osmibitové. Jejich názvy (např. scanlineAqua) jsem volil odlišně od standardních názvů označující čtyřiadvacetibitové barevné konstanty v Borland Delphi (colorAqua). Nedojde tak k předefinování a obojí sadu je možno používat současně - standardní barvy při práci s objektem Canvas, osmibitové pak při práci se ScanLine.

 

Barvy ve výše uvedené deklaraci uvádím v pořadí, které odpovídá implicitní paletě formátu *.bmp 256 color imolementované ve Windows95. Hodnoty musí odpovídat hodnotám, generujícím příslušnou barvu na osmibitovém řádku formátu Windows Bitmap. Barev je šestnáct, neboť tento systém musí fungovat i ve čtyřbitové hloubce (např. v nouzovém režimu Windows). Poslední hodnota je však devatenáct, posloupnost hodnot je zajímavá zvláště ve druhém a třetím sloupci. Chybějící hodnoty uvnitř této posloupnosti generují barvy, které mezi základními nejsou. Proč tomu tak je, vědí asi jen vývojoví pracovníci firmy Microsoft.

 

Dále využijeme pole typu PByteArray, což je pole ukazatelů na obrazový řádek - ScanLine. Chceme-li použít přímý přístup, musíme nejdříve vytvořit bitmapu s odpovídající barevnou hloubkou pixelu Protože typ PByteArray je pole proměnných typu byte, je třeba, aby barevná hloubka v bitech byla násobkem osmi - nejméně tedy 8 bitů (256 barev) tak, jako v našem případě:

 

Procedure InitImage(Image:TImage;Width,Height:Integer);

begin

  Image.Align:=alNone;

  Image.Picture.Bitmap.PixelFormat:=pf8bit;

  Image.Picture.Bitmap.Width:=Width;  ¨

  Image.Picture.Bitmap.Height:=Height;

  Image.Width:=Width;Image.Height:=Height;

end;

 

Velkou nepříjemností osmibitového přístupu ve Windows je skutečnost, že výše uvedené barevné konstanty odpovídají příslušným barvám pouze v implicitním nastavení palety v systému Windows 95. Vyšší verze mají implicitní paletu definovanou pokaždé jinak. Je ovšem možné vytvořit si vlastní paletu tak, aby byla nezávislá na použité verzi Windows. Výše uvedenou proceduru InitImage doplníme o definici příslušné palety:

 

Procedure InitColorImage(Image:TImage;Width,Height:Integer);

{pro předefinování nastavených barev}

var Table        :array[Byte] of TRGBQuad;

begin

  Image.Align:=alNone;

  Image.Picture.Bitmap.PixelFormat:=pf8bit;

  Image.Picture.Bitmap.Width:=Width;   

  Image.Picture.Bitmap.Height:=Height;

  Image.Width:=Width;Image.Height:=Height;

  With Image1.Picture.Bitmap do

    Begin  {předefinovávání jednotlivých barev}

     With Table[0] do                                      {černá – odstín slBlack }

       begin

         rgbRed:=0;rgbGreen:=0;rgbBlue:=0;rgbReserved:=0;

       end;

     With Table[1] do                                       {velmi tmavá červená}

       begin

         rgbRed:=51;rgbGreen:=0;rgbBlue:=0;rgbReserved:=0;

       end;

  With Table[14] do                                       {olivová – odstín slOlive}

       begin

        rgbRed:=128;rgbGreen:=128;rgbBlue:=0;rgbReserved:=0;

       end;

  With Table[180] do                                        {modrá – odstín slBlue}

       Begin

        rgbRed:=0;rgbGreen:=0;rgbBlue:=255;rgbReserved:=0;

       end;

  With Table[255] do                                         {bílá – odstín slWhite}

       begin   

        rgbRed:=255;rgbGreen:=255;rgbBlue:=255;rgbReserved:=0;

       end;

{ošetření chybného nastavení palety}

  if SetDIBColorTable(Canvas.Handle,0,255,table)=0

       then RaiseLastWin32Error;

  Canvas.Draw(0,0,Image1.Picture.Bitmap);                      {nastavení palety}

  end;

end;

 

Jednotlivé barvy se nastavují pomocí tabulky Table (Table[i] nastavuje i-tou barvu v paleté). K tomu, abychom mohli jednotlivé barvy správně nastavit, musímě vědět, jak je namíchat z červené, zelené a modré barvy (hodnoty rgbRed, rgbGreen a rgbBlue u jednotlivých položek). Barvy jsou totiž implementovány v tzv. barevném systému RGB, o kterém budeme mluvit v kpt. 4. V příští kapitole budeme používat jednotku Graph2D_256, která výše uvedeným způsobem nastavuje barvy nezávisle na verzi OS Windows. Konstanty základních barev mají následující hodnoty: const

 


slBlack    =0;

slMaroon   =3;

slGreen   =12;

slOlive   =14;

slNavy    =72;

slPurple  =38;

slTeal    =48;

slGray    =86;

slSilver  =172;

slRed     =5;

slLime    =30;

slYellow  =35;

slBlue    =180;

slFuchsia =185;

slAqua    =210;

slWhite   =255;

 


 

Často je potřeba v osmibitové hloubce deklarovat ne 256 barev, ale 256 odstínů šedé. Princio je stejný jako v proceduře InitColorImage, šedé odstíny však mají složky R,G,B stejné velikosti – od nuly (černá) do 255 (bílá). Procedura, která takovou paletu nastavuje, pak vypadá následovně:

 

Procedure InitGrayScaleImage(Image:TImage;Width,Height:Integer);

{pro předefinování nastavených barev}

var Table        :array[Byte] of TRGBQuad;

    I            :byte;

begin

  Image.Align:=alNone;

  Image.Picture.Bitmap.PixelFormat:=pf8bit;

  Image.Picture.Bitmap.Width:=Width;   

  Image.Picture.Bitmap.Height:=Height;

  Image.Width:=Width; Image.Height:=Height;

  With Image1.Picture.Bitmap do

    for i:=0 to 255 do     {předefinovávání jednotlivých barev}

       With Table[i] do                                    {černá – odstín slBlack }

         begin

          rgbRed:=i;rgbGreen:=i;rgbBlue:=i;rgbReserved:=0;

         end;

            {ošetření chybného nastavení palety}

         if SetDIBColorTable(Canvas.Handle,0,255,table)=0

                then RaiseLastWin32Error;

         Canvas.Draw(0,0,Image1.Picture.Bitmap);               {nastavení palety}

      end;

end;

 

Definice barevné palety je součástí bitmapy. Jestliže tedy do obrázku Image1 nahrajeme 256 barevný bitmapový obrázek, paleta je tímto obrázkem opět předefinována. Naopak předefinujeme-li paletu již nahranému obrázku, docílíme velmi rychlých barevných efektů.

 

1. Příklad – demonstrace rychlosti obarvení pixelu: vyplňme původně bílou kreslicí plochu bod po bodu jinou barvou:

 

Klasické „pohodlné“ řešení:

 

Procedure PointFillingOfCanvas(Image:TImage;Color:DWord);

   begin

     for j:=0 to Image.Height-1 do    for i:=0 to Image.Width-1 do     Image.Canvas.Pixels[i,j]:=Color;

   end;

 

Při tomto řešení je implicitně využito toho, že objekt typu TImage v Delphi obsahuje bitmapu s hloubkou pixelů odpovídající režimu grafické karty, který lze ve Windows nastavit z nabídky Start/Nastavení/Ovládací panely/Obrazovka/ Nastavení/Barevná paleta.

 

Řešení s přímým přístupem: Nejdříve je třeba vytvořit bitmapu s osmibitovou barevnou hloubkou, a to buď barevnou (procedurou InitColorImage), anebo šedotónovou (procedura InitGrayscaleImage). Dále využijeme pole typu PByteArray, což je pole ukazatelů na obrazový řádek - ScanLine.

Nyní k vlastní proceduře na obarvení pixelu. Chceme-li ji vytvořit přehledně, budeme pracovat s jednotlivými pixely jako s uspořádanými dvojicemi celočíselných souřadnic. Globálně je tedy třeba deklarovat typ Pixel:

 

            Type TPixel =array [1..2] of integer;

 

který budeme dále používat. Proměnné tohoto typu - pixely pak budeme obarvovat následující procedurou:

 

            Procedure PutPixel(Image:TImage;P:TPixel;Color:Byte);

     var  SL:PByteArray;

     begin

       SL:=Image.Picture.Bitmap.ScanLine[P[2]];

       SL[P[1]]:=Color;

     end;

 

konečně následuje vyplnění obrazu:

 

Procedure PointFillingOfScanLine(Image:TImage;Color:Byte);

var P:TPixel;

    i,j:Integer;

begin

  for j:=0 to Image.Height-1 do

    for i:=0 to Image.Width-1 do

     begin

     P[1]:=i;P[2]:=j;      

     PutPixel(Image.Canvas.Pixels[i,j]:=Color;

     end;

end;

 

Tato procedura je 20 – 30 krát rychlejší než dříve uvedená procedura PointFillingOfImage-Canvas (konkrétní hodnota závisí na právě probíhajících dalších událostech v operačním systému). Je přehledné, původní přiřazení do matice pixels je pouze nahrazeno rychlejší procedurou PutPixel. Nevyužívá nicméně beze zbytku předností tohoto přístupu, jehož cílem je maximální urychlení celého procesu. Dalšího zlepšení je možné dosáhnout použitím příkazů procedury PutPixel přímo v  těle cyklu a na tuto proceduru vůbec neodkazovat. Programu tak v každém pixelu digitální roviny odpadne povinnost proceduru PutPixel hledat. Po této úpravě dojde k dalšímu průměrně dvojnásobnému urychlení a oproti klasickému řešení je tato procedura rychlejší 50 – 60 krát. Stále však v cyklu zůstávají dva víceméně zbytečná přiřazení (nastavení bodu -  P[1]:=i;P[2]:=j;) hlavní dosud nevyužitou výhodou  je však to, že si procedura PutPixel „nepamatuje“ řádek. Přestože konkrétně tato konstrukce sestrojuje vodorovné řádky, je v každém sousedním pixelu řádek zbytečně znovu nastavován. Všechny tyto nevýhody lze odstranit následující konstrukcí:

 

Maximálně rychlé řešení:

 

Procedure FillingOfScanLines(Image:TImage;Color:Byte);

var     i,j           :Integer;

        SL:PByteArray;

begin

  for j:=0 to Image.Height-1 do

    begin

     SL:=Image.Picture.Bitmap.ScanLine[j];

     for i:=0 to Image1.Width-1 do SL[i]:=Color;

    end;

end;

 

Poměr zrychlení  u tohoto řešení ve srovnání s řešením klasickým se již pohybuje ve stovkách  (většinou mezi 300 – 400), podařilo se mi však naměřit již i přes 700. V případě, že celou digitální rovinu neohodnocujeme konstantní hodnotou, ale tuto hodnotu nějakým způsobem počítáme, tento poměr pochopitelně klesá. Část potřebného času totiž zabírají operace s hodnotami, které jsou ve všech případech stejné. Zrychlení nicméně zůstává velmi významné (např. při sestrojení negativu obrazu se pohybuje kolem 200).

 

Procedura PutPixel provádí ohodnocení pixelu digitální roviny barvou . Chceme-li naopak zjistit aktuální ohodnocení, použijeme "inverzní" proceduru GetPixel:

 

Procedure GetPixel(Image:TImage;P:TPixel;var Color:Byte);

var   SL:PByteArray;

begin

  SL:=Image.Picture.Bitmap.ScanLine[P[2]];

  Color:=SL[P[1]];

end;

 

Testový příklad: zde je porovnána rychlost procedur PointFillingOfCanvas a FillingOfScanLines. V obou příkladech se celý obraz bod po bodu vyplní pořadě červenou, zelenou a modrou barvou (v příkladu jsou obě procedury uvedeny bez parametrů).

 

zdrojový kód   a zde můžete program  spustit

 

V dalších řešených příkladech je tento přístup využit ke konstrukci úsečky. Algoritmus bude podrobně popsán v další kapitole. Výsledkem je konstrukce podstatně rychlejší, než standardní Canvas.MoveTo - Canvas.LineTo:

 

zdrojový kód   a zde můžete program  spustit

 

Tato „rychlá úsečka“ je použita k hranovým konstrukcím ploch, jejichž rychlost můžeme opět porovnat s „tradičním“ přístupem.

 

Zde najdeme    zdrojový kód   a zde můžete program  spustit

 

Později tento přístup využijeme také k rychlým operacím s obrazy tak jak je ukázáno v tomto příkladě, k němuž

 

zde najdeme     zdrojový kód   a zde můžete program  spustit

 

 

Vznik barevného vjemu – omezení oka         - velikost vnímaných objektů

                                                                       - počet barev

 

Velikost fyzického pixelu na obrazovce - řádově desetiny milimetru. Několik takových pixelů o různých barvách není oko schopno rozlišit. Zraková informace je v mozku integrována a my vnímáme třeba i barvu, která na výstupním zařízení vůbec není zobrazena.

 

 

Barevné systémy – barvy jsou realizovány mícháním základních barev.

 

Aditivní systém "nepopsaný" podklad černý, barvy vznikají přidáváním základních barev.

R(ed)G(reen)B(lue) – monitory

Barevný prostor RGB (RGB krychle)

 

 

Zde si můžeme ukázat, jak zobrazovat řezy RGB krychle rovnoběžně s některou souřadnou rovinou:

To samozřejmě zatím nebudeme dělat v rovnoběžném či středovém promítání, řez zobrazíme jako čtverec ve skutečné velikosti:

 

                       

Příklad 1: Sestrojme řez RGB krychlí rovnoběžný s některou z jejích stěn. Zvolme např. řez rovnoběžný s rovinou Green-Blue, procházející na ose Red hodnotou 128 (viz připojený obrázek). Prozatím ho samozřejmě nebudeme sestrojovat v axonometrii, spokojíme se se skutečnou velikostí. S použitím objektu Canvas by tato procedura mohla vypadat např takto:

 

procedure TForm1.Cut_Of_RGB (Sender: TObject);

const Red=128;

var   Green,Blue:Byte;

begin

  for Green:=0 to 255 do  for Blue:=0 to 255 do

     Canvas.Pixels[Green,Blue]:=Red+256*Green+256*256*Blue;

end;

 

 

Proměnné Green a  Blue nám kromě definice intenzity barevných složek poslouží jako proměnné v cyklech: vnější přidává zelenou v řádku, vnitřní modrou po sloupcích. Původně šedý povrch našeho okna (proměnná jménem Canvas - plátno) je objekt typu TCanvas (typ plátno). Toto  „plátno“ má řadu vlastností, které nám umožní na něj malovat.  Obsahuje např matici Pixels (body). Každý bod je uložen na třech bytech (R,G,B). K vlastnostem objektových proměnných se dostáváme  „přes tečku“. Zadáme-li tedy např. Canvas. Pixels[50,50]:= 9856050, je na bod o světových souřadnicích [50,50] uložena barva definovaná trojicí (R,G,B)=(50,100,150) (šedomodrá), neboť  9856050=50 + 100*256 + 150*256*256.

 

V řešení, jehož                  zdrojový kód najdete zde              a                    spustitelný kód zde,

 

je použita procedura PutPixel přistupující do bitmapy pomocí matice Scanline.

 

Při použití pokročilejších programátorských technik může řešení vypadat např. takto:

           

Ovladatelná RGB krychle

 

Příklad 2: stínování barev: Barevný odstín je v systému RGB dán poměrem barevných složek Red, Green, Blue, jas jejich absolutní velikostí. Chceme-li měnit jas barvy při zachování odstínu, musíme zachovat poměr složek a plynule měnit jejich velikost. To lze provést např. takto:

 

procedure TForm1.AreaShading(Sender: TObject);

const                                                                                                                                                                                                                                              {definice barevného odstínu - poměru barevných složek}

        Red_Portion=255;Green_Portion=127;Blue_Portion=127;

var     Red,Green,Blue,                                                                    {barevné složky}

        Value :Byte;                 {pro změnu jasu barevných složkek}

begin

  for Value:=255 downto 0 do          {od nejvyššího do nejnižšího jasu}

  begin                                  {nastavení barevných složek}

  Red:=Trunc(Value*Red_Portion/255); Green:=Trunc(Value*Green_Portion/255);

  Blue :=Trunc(Value*Blue_Portion/255);

  With Draw2D.Image1.Canvas do

    begin

      Pen.Color:=Red+256*Green+256*256*Blue;                   {barva pera}

                                                                                         {vodorovná úsečka přes šířku plochy}

      MoveTo(0,255-Value);LineTo(256,255-Value);           

  end;

  end;

end;

 

 

Barevný odstín nemusíme samozřejmě zadávat natvrdo tak, jako v předchozí ukázce. Lze ho vybrat pomocí Objektu typu TPictureDialog z lišty Dialogs, který vyvolá standardní editor barev, o kterém už byla řeč. Hodnotu barvy - Color - lze přímo použít ve standardních kreslících metodách a objektech (Pixels, Pen, Brush atd.), pro naše účely je však třeba z této barvy vyoperovat barevné složky Red, Green, Blue, např:

 

procedure TForm1.ColorChange(Sender: TObject);

begin

  if ColorDialog1.Execute then

  begin

    Blue_Portion:=ColorDialog1.Color div (256*256);

    Green_Portion:=(ColorDialog1.Color - 256*256*Blue_Portion) div 256;

    Red_Portion:=ColorDialog1.Color - 256*256*Blue_Portion - 256*Green_Portion;

  end;

end;

 

V programu je samozřejmě potřeba zařídit, aby takto nastavené hodnoty Red_Portion Green_Portion, Blue_Portion mohla převzít výše uvedená procedura AreaShading (např. jejich globální deklarací).

 

Zde najdete kompletní  zdrojový kód   a zde    spustitelný kód.

 

Příklad 3: Sestavme program, který sestrojí drsný podklad osvětlený z pravého dolního rohu.

Barevný odstín je volen pomocí Color Dialogu, jako v předchozím příkladě. „Úhlopříčného“ stínu dosáhneme funkcí, která má v levém horním rohu (x=0, y=0)  hodnotu 0 (roh je tmavý), v pravém dolním rohu (x=255, y=255) pak hodnotu 255 (roh je světlý) a po druhé úhlopříčce je konstantní. Tyto podmínky splňuje např. funkce z =(x+y)/2 Výsledek však není příliš hezký (stín je příliš velký a celý obrázek je velmi tmavý). V našem příkladu proto byla tato funkce umístěna do argumentu funkce arctan. Obraz je nyní celý černý. Funkci musíme vynásobit vhodnou konstantou, abychom posunuli supremum množiny funkčních hodnot z p/2 na 255. Stín zde nyní naopak není téměř vůbec. Vydělením argumentu vhodným číslem však docílíme potřebné velikosti. „Zdrsnění“ plochy docílíme funkcí Random, jejíž hodnoty jsou náhodná čísla z intervalu á0;1). Tento interval je roztažen konstantou Roughness. Čím je tato konstanta vyšší, povrch se jeví drsnější. Po této úpravě však hodnota z může „vypadnout“ z intervalu á0;255ñ, což je třeba ošetřit (viz následující řádek programu). Hodnoty Red, Green, Blue nastavíme podobně, jako v předchozím příkladu. Plochu však nemůžeme vyplňovat úsečkami, neboť se zde barva mění po jednotlivých pixelech:

 

procedure TForm1.AreaShading(Sender: TObject);

const Roughness=20;

var   Red,Green,Blue,x,y:Byte;

      z                 :Double;

begin

   for y:=0 to 255 do

   begin

    for x:=0 to 255 do

    begin

     z:=2*255/pi*arctan((x+y)/160);     {funkce určující tvar stínu}

     z:=z+2*Roughness*Random-Roughness;   {"zdrsnění" plochy randomem}

     if z<0                      {ošetření přetečení intervalu <0,255>}

         then z:=0 else if z>255 then z:=255;

     Red  :=Trunc(z*Red_Portion/255);    {nastavení hodnot složek}

     Green:=Trunc(z*Green_Portion/255);

     Blue :=Trunc(z*Blue_Portion/255);

                                                                                   {vykreslení bodu}

     Image1.Canvas.Pixels[x,y]:=Red +256*Green+256*256*Blue;

   end;

 end;

end;

 

V řešeném příkladu je opět využit rychlejší přístup do bitmapy procedurou PutPixel.

 

Zde najdete kompletní  zdrojový kód   a zde    spustitelný kód.

 

Subtraktivní systém: "nepopsaný" podklad černý, barvy vznikají přidáváním základních barev

C(yan)M(agenta)Y(ellow) – tiskárny, z praktických důvodů se přidává černá C(yan)M(agenta)Y(ellow)(blac)K (kvalitnější černá, šetří inkoust)

 

 

Barevný prostor CMY (CMY krychle)

Řezy v prostoru RGB:  Řez  prostoru  rovinou konstantního jasu

 

 

Řezy rovinami konstantního jasu v prostoru  mají zásadní význam při konstrukci dalších barevných prostorů.

 

Prostor CIE

 

 

 

 

 

 

Konkrétní realizaci uživatelského výběru barev známe ze standardního color dialogu systému Windows:

 

 

 

Barevné palety: velmi často se stává, že potřebujeme využít jen některé z barev, které nabízí daný barevný prostor a které navíc potřebujeme mít seřazeny podle jistého kriteria (např. první barva černá, druhá žlutá, třetí modrá atd.). Budeme-li chtít např. sestrojit mapu jistého území, použijeme jisté odstíny modré podle hloubky vodních nádrží, jisté odstíny zelené pro nížiny a hnědé pro hory. Přitom např. fialové, růžové a jiné odstíny nebudeme vůbec potřebovat. Barvy budou číslovány podle nadmořské výšky. Chceme-li modelovat rozklad světla hranolem, budeme potřebovat pouze složky spektra, jejichž pořadí bude určeno vlnovou délkou světla. Je samozřejmě otázkou, jakým mechanismem tento výběr provést a očíslovat. Jednou z možností je v příslušném barevném prostoru zadat křivku, procházející požadovanými barvami, přičemž pořadí barev je určeno parametrizací křivky. (tak např. vznikla třetí paleta v ukázce). V případě, že je paleta nespojitá (viz přechod mezi vodou a nížinou), musí být nespojitá i příslušná křivka v barevném prostoru. Ve složitějších případech, kdy paletu není jednoduché určit rovnicí, můžeme paletu definovat např. tabulkou hodnot (viz druhá ukázky, která je interpretací tabulky citlivosti lidského oka na jednotlivé vlnové délky viditelného světla), popř. může být paleta definována přímo obrazem (v našem případě např. příslušným barevným proužkem).

 

 

    

 

Zde najdete kompletní                  zdrojový kód      a zde      spustitelný kód.