﻿<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xml" href="/cjs/examples.screen.xsl" media="screen"?>
<examples chapter="Základní grafické operace – Numpy a Pillow" directory="grafika.2">

  <use-math/>

  <!--note>
      NOTE
  </note-->

  <theory>
      <p>
          V těchto cvičeních budeme opět pracovat s obrázkem: <img src="_files/kvetina/kvetina.jpg" width="500" height="375" alt="květina" style="vertical-align: top;"/>
      </p>
      <p>
          Byl vyfocen digitálním fotoaparátem a uložen v barvovém prostoru sRGB ve formátu JPEG. (A samozřejmě také výrazně zmenšen.) Jelikož úkolem tohoto cvičení je naučit se používat <em>Numpy</em> a další dostupné nástroje, pro načítání a ukládání už budeme používat metody knihovny <em>Pillow</em>.
      </p>
      <!--note>
          PS: U většiny příkladů je pro zajímavost uvedeno řešení pomocí knihovny <em>Pillow</em>.
      </note-->
      <p>
          Jsou-li k práci potřeba nějaké rovnice, jsou uvedeny v nápovědě (a také odkázány na zdroj), proto se jí nevyhýbejte ^_~
      </p>
  </theory>


  <example>
    <text>
        Převeďte uvedený obrázek z pozitivu do negativu: <img src="grafika.2/negativ.Numpy.jpg" width="500" height="375" alt="květina negativně" style="vertical-align: top;"/>
    </text>
    <hint>
        Tohle je asi první cvičení na <a href="/materialy/python/numpy/broadcasting.xml"><em>broadcasting</em></a> – potřebujeme všechny barvové složky v každém pixelu odečíst od 255 a nemusíme kvůli tomu vyrábět matici 375×500×3.
    </hint>
    <!--solution src="grafika.2_Pillow/negativ_PIL.py" lang="python" /-->
  </example>

  <example>
    <text>
        S negativem úzce souvisí tzv. <em>solarizace</em> – převod do negativních barev pouze vybraných barevných odstínů. Toto je například výstup, v němž jsou převedeny pouze barvy o indexu větším než 77 (tedy vlastně ty světlejší): <img src="grafika.2/solarized_1.Numpy.jpg" width="500" height="375" alt="květina solarizovaně" style="vertical-align: top;"/>
    </text>
    <hint>
        Tohle je pravděpodobně první cvičení na <a href="/materialy/python/numpy/arrays.slicing.xml"><em>výřezy z polí</em></a> – ze všech pixelů potřebujeme zpracovat pouze ty, které mají určitou hodnotu.
    </hint>
    <!--solution src="grafika.2_Pillow/solarizace_PIL.py" lang="python" /-->
  </example>

  <example>
    <text>
        Převeďte uvedený obrázek do odstínů šedi: <img src="grafika.2/grayscale.Numpy-2.jpg" width="500" height="375" alt="květina v odstínech šedi" style="vertical-align: top;"/>
    </text>
    <hint>
        Protože se správným – a překvapivě náročným – postupem jsme se už seznámili v <a href="grafika.1.xml">předchozím cvičení</a>, použijeme nyní jednodušší konverzní výraz podle <em>ITU-R 601-2 luma transform</em> pro převod z nelineárních hodnot R, G a B na tzv. <em>lumu</em> (nikoli tedy <em>luminanci</em>!):
        $$Y^'_{601} = 0.299 * R^' + 0.587 * G^' + 0.114 * B^'$$
        PS: Pro podrobnosti viz <a href="http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC11" class="external">What is "luma"?</a>.
    </hint>
    <!--solution src="grafika.2_Pillow/grayscale_PIL.py" lang="python" /-->
  </example>

  <example>
    <text>
        Nyní v rámci procvičení výřezů numpyovských polí vyextrahujte z originálního obrázku jednotlivé barevné kanály:<br/>
        <center>
            <img src="grafika.2/R.jpg" width="250" _height="375" alt="květina – složka R"/>
            <img src="grafika.2/G.jpg" width="250" _height="375" alt="květina – složka G"/>
            <img src="grafika.2/B.jpg" width="250" _height="375" alt="květina – složka B"/>
        </center>
    </text>
    <hint>
        Jedna barvová složka představuje světlost v příslušném jednom barevném kanálu, proto se zobrazují v odstínech šedi. Čistě teoreticky si můžete dát tu práci a pokusit se je zobrazit v „přirozené“ barvě, ale jelikož to na webu umíme jenom přes plné RGB-spektrum, není to vůbec jednoduché.
    </hint>
    <!--solution src="grafika.2_Pillow/RGB_PIL.py" lang="python" /-->
  </example>
  
  <example>
    <text>
        Jelikož už z předchozího příkladu umíte vzít světlosti příslušné jednotlivým barvám, zkuste nyní popřehazovat barvové kanály mezi sebou a uložit výsledek:<br/>
        <center>
            <img src="grafika.2/swap-RGB.jpg" width="250" _height="375" alt="květina RGB" title="RGB"/>
            <img src="grafika.2/swap-RBG.jpg" width="250" _height="375" alt="květina RBG" title="RBG"/>
            <br/>
            <img src="grafika.2/swap-GRB.jpg" width="250" _height="375" alt="květina GRB" title="GRB"/>
            <img src="grafika.2/swap-GBR.jpg" width="250" _height="375" alt="květina GBR" title="GBR"/>
            <br/>
            <img src="grafika.2/swap-BRG.jpg" width="250" _height="375" alt="květina BRG" title="BRG"/>
            <img src="grafika.2/swap-BGR.jpg" width="250" _height="375" alt="květina BGR" title="BGR"/>
        </center>
    </text>
    <hint>
        Softwaru je samozřejmě šumák, co hodnoty v poli představují – RGB-matice rozměru <code>m×n×3</code> je vyhodnocena jako RGB pouze proto, že se k ní tak chováme.
    </hint>
    <!--solution src="grafika.2_Pillow/swap-all_PIL.py" lang="python" /-->
  </example>

  <example>
    <text>
        Jako další procvičení na výřezy numpyovských polí zmenšete vstupní obrázek třebas na polovinu:
        <img src="grafika.2/subsample.jpg" width="250" height="188" alt="květina poloviční (výřezem)" style="vertical-align: top;"/>
    </text>
    <hint>
        Při zmenšování jde o ztrátu informace a překvapivě se dá rozumných (tedy koukatelných) výsledků dosáhnout pouhým výběrem podmnožiny všech pixelů, což je smyslem této úlohy. Správně by se „zahazované“ pixely měly nějakým způsobem průměrovat, ale to je bonus.
    </hint>
    <!--solution src="grafika.2_Pillow/subsample_PIL.py" lang="python" /-->
  </example>

  <example>
    <text>
        Jako další operaci na <em>broadcasting</em> zkuste originální obrázek ztmavit:
        <img src="grafika.2/darker.jpg" width="500" height="375" alt="květina ztmavená" style="vertical-align: top;"/>
    </text>
    <hint>
        Ztmavit obrázek znamená zmenšit světlost v jeho jednotlivých barvových kanálech. V nejjednodušším případě ve všech stejně, jedná se tedy o <em>broadcasting</em> skaláru. Reálně by se spíše počítal každý kanál jiným koeficientem a šlo by tak o <em>broadcasting</em> vektorem, ale to si také necháme na jindy. (Natožpak pak ztmavování pomocí vhodné nelineární funkce.)
        <br/>
        Mimochodem – při ztmavování obrázku pochopitelně začneme přicházet o informace, především ve stínech. Za prvé menší rozdíly asi nerozeznáme tak dobře a za druhé zmenšováním čísel blízko nuly můžeme informaci prostě ztratit i díky konečné přesnosti výpočtu. V praxi se snadno a rychle stane, že se tmavé plochy začnou za chvíli všechny mapovat na jednolitou černou.
    </hint>
    <!--solution src="grafika.2_Pillow/darker_PIL.py" lang="python" /-->
  </example>

  <example>
    <text>
        Doplňkovou operací ke ztmavení je zesvětlání:
        <img src="grafika.2/lighter.jpg" width="500" height="375" alt="květina XXX" style="vertical-align: top;"/>
        <br/>
        Pozor – tato úloha už není tak přímočará jako předchozí na ztmavení!
    </text>
    <hint>
        Zcela naopak k předchozí úloze musíme nyní světlost v jednotlivých barvových kanálech zvětšit (a zase v zájmu zjednodušení použijeme pouze <em>broadcasting</em> skalárem místo vektorem nebo dokonce rovnou nějakou nelineární funkcí). Jenomže zatímco přibližovat se k nule jsme mohli bez nesnází, jen tak si zvětšovat čísla dost dobře nemůžeme – typický výstupní obrázek má na jeden barvový kanál vyhrazen pouze jeden bajt a do něj se vleze nejvyšší číslo 255.
        <br/>
        Je jasné, že vypočítané hodnoty musíme držet v rozmezí 0-255 a že tak při zesvětlování začneme ztrácet informace nejdříve z těch světlejších míst – prostě se dřív všechny namapují na čistou bílou. (A když to přeženete, tak tam kromě čisté černé namapujete úplně všechno ;-)
    </hint>
    <!--solution src="grafika.2_Pillow/lighter_PIL.py" lang="python" /-->
  </example>

  <example>
    <text>
        Ať si vyzkoušíme také něco složitějšího než jen násobení skalárem – „vypněte“ ve výstupních obrázcích vždy jeden kanál a druhé dva zachovejte:
        <center>
            <img src="grafika.2/GB.jpg" width="250" _height="375" alt="květina – složky GB"/>
            <img src="grafika.2/RB.jpg" width="250" _height="375" alt="květina – složky RB"/>
            <img src="grafika.2/RG.jpg" width="250" _height="375" alt="květina – složky RG"/>
        </center>
        Zdejší výsledky jsou tmavší, protože jsem „vypínaný“ kanál namapoval na 0. Můžete ale zkusit všelicos a všelijak, tohle samozřejmě není jediné možné řešení.
    </text>
  </example>

  <example>
    <text>
        Na závěr si zahrajeme na analogového fotografa vybaveného digitální technikou ^_~ Dostali jste <a href="_files/kvetina/kvetina.negativ.png">barevný negativ</a> a máte za úkol ho zkopírovat (tedy zachovat velikost) pomocí zvětšovacího přístroje se zeleným filtrem. Jelikož ale nemáte možnost změřit osvit pozitivu, musíte provést klasickou proužkovou zkoušku – rozdělit pozitiv na několik (obdélníkových) oblastí a postupným posouváním krycí masky po nich vyzkoušet, jak se délka osvitu projeví (samozřejmě pouze v dané části obrazu). Programově tedy:
        <ul>
            <li>
                Výstupem je pozitiv, musíte proto barvy převést z negativu.
            </li>
            <li>
                Zelený filtr je ideální, ze tří barvových složek originálu tak použijete pouze zelený kanál.
            </li>
            <li>
                „Osvit“ testujte v pěti oblastech následujícím způsobem – prostřední část prostě zkopírujte, dvě krajní na jedné straně „podsviťte“ (tedy ztmavte) a druhé dvě krajní naopak „přesviťte“ (tedy zesvětlete). V zájmu procvičení práce s numpy-poli spočítejte výstup pro horizontální i vertikální směr.
            </li>
        </ul>
        Při „osvitové řadě“ 0.25, 0.5, 1, 2, 4 byste mohli obdržet něco takovéhoto:
        <center>
            <img src="grafika.2/osvit.V.jpg" width="500" height="375" alt="zkouška osvitu vodorovně" />
            <img src="grafika.2/osvit.S.jpg" width="500" height="375" alt="zkouška osvitu svisle" />
        </center>
    </text>
    <hint>
        Možná trochu zamotané, ale relativně přímočaré cvičení. Jen si dejte pozor, abyste nepřišli o originální obrázek – potřebujete ho pro dva výpočty.
    </hint>
  </example>


</examples>
