Funktionaalista grafiikkaa

Samankaltaiset tiedostot
ELM GROUP 04. Teemu Laakso Henrik Talarmo

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Matematiikan tukikurssi

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Matematiikan tukikurssi

TIE Principles of Programming Languages CEYLON

Konformigeometriaa. 5. maaliskuuta 2006

Värijärjestelmät. Väritulostuksen esittely. Tulostaminen. Värien käyttäminen. Paperinkäsittely. Huolto. Vianmääritys. Ylläpito.

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Luku 3. Listankäsittelyä. 3.1 Listat

Gimp JA MUUT KUVANKÄSITTELYOHJELMAT

Injektio (1/3) Funktio f on injektio, joss. f (x 1 ) = f (x 2 ) x 1 = x 2 x 1, x 2 D(f )

Tyyppejä ja vähän muutakin. TIEA341 Funktio ohjelmointi 1 Syksy 2005

KUVANKÄSITTELY THE GIMP FOR WINDOWS OHJELMASSA

Tietotekniikan valintakoe

Koka. Ryhmä 11. Juuso Tapaninen, Akseli Karvinen. 1. Taustoja 2. Kielen filosofia ja paradigmat 3. Kielen syntaksia ja vertailua JavaScriptiin Lähteet

TIE Principles of Programming Languages. Seminaariesityksen essee. Ryhmä 18: Heidi Vulli, Joni Heikkilä

Tyyppiluokat II konstruktoriluokat, funktionaaliset riippuvuudet. TIES341 Funktio-ohjelmointi 2 Kevät 2006

KUVANKÄSITTELYN TEORIAA

Ohjelmoinnin perusteet Y Python

Kuvankäsi*ely 1. Digitaaliset kuvat ja niiden peruskäsi3eet. Kimmo Koskinen

Racket ohjelmointia osa 1. Tiina Partanen Lielahden koulu 2014

tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Matematiikan tukikurssi

n! k!(n k)! n = Binomikerroin voidaan laskea pelkästään yhteenlaskun avulla käyttäen allaolevia ns. palautuskaavoja.

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Malliratkaisut Demot

Laajennetaan vielä Ydin-Haskellia ymmärtämään vakiomäärittelyt. Määrittely on muotoa

Kuvat. 1. Selaimien tunnistamat kuvatyypit

Ohjelmoinnin perusteet Y Python

Valokuvien matematiikkaa

811120P Diskreetit rakenteet

Matematiikan johdantokurssi, syksy 2016 Harjoitus 11, ratkaisuista

Tekijä Pitkä matematiikka Suoran pisteitä ovat esimerkiksi ( 5, 2), ( 2,1), (1, 0), (4, 1) ja ( 11, 4).

Tietorakenteet ja algoritmit

Laiska laskenta, korekursio ja äärettömyys. TIEA341 Funktio ohjelmointi Syksy 2005

Ohjelmoinnin perusteet Y Python

Se mistä tilasta aloitetaan, merkitään tyhjästä tulevalla nuolella. Yllä olevassa esimerkissä aloitustila on A.

KYMENLAAKSON AMMATTIKORKEAKOULU Tietotekniikka TI10 / Tietoverkot. Jaska Kauppila. GIMP ja muut kuvankäsittelyohjelmat. Linux 2012 Seminaarityö

Alkuraportti. LAPPEENRANNAN TEKNILLINEN YLIOPISTO TIETOJENKÄSITTELYN LAITOS CT10A Kandidaatintyö ja seminaari

Ohjelmoinnin perusteet Y Python

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

Kys /Kaarisairaala, Evoluutio julkisivuteos, 2015 Partanen & Lamusuo Oy DIGI PRINT. Aineistovaatimukset ja aineiston siirto

Nopea kertolasku, Karatsuban algoritmi

Yhtälöryhmä matriisimuodossa. MS-A0004/A0006 Matriisilaskenta. Tarkastellaan esimerkkinä lineaarista yhtälöparia. 2x1 x 2 = 1 x 1 + x 2 = 5.

Toinen harjoitustyö. ASCII-grafiikkaa

Ohjelmoinnin peruskurssien laaja oppimäärä

Python-ohjelmointi Harjoitus 2

Kuvankäsittely. DigiReWork Annamari Mäenhovi Kati Nieminen

TEEMA 2 TAULUKKODATAN KÄSITTELY JA TIEDON VISUALISOINTI LUENTO 4

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Geneeriset tyypit. TIES542 Ohjelmointikielten periaatteet, kevät Antti-Juhani Kaijanaho. Jyväskylän yliopisto Tietotekniikan laitos

y=-3x+2 y=2x-3 y=3x+2 x = = 6

1.4 Funktion jatkuvuus

DIGI PRINT. Aineistovaatimukset ja aineiston siirto

Ohjelmoinnin perusteet Y Python

Alkuraportti. LAPPEENRANNAN TEKNILLINEN YLIOPISTO TIETOJENKÄSITTELYN LAITOS Ti Kandidaatintyö ja seminaari

PRINCIPLES OF PROGRAMMING LANGUAGES - DEBUGGER

Lineaarinen yhtälöryhmä

815338A Ohjelmointikielten periaatteet Harjoitus 4 vastaukset

Luento 6: Piilopinnat ja Näkyvyys

LUENTO 6 KUVANKÄSITTELY

58131 Tietorakenteet ja algoritmit (kevät 2016) Ensimmäinen välikoe, malliratkaisut

Uolevin reitti. Kuvaus. Syöte (stdin) Tuloste (stdout) Esimerkki 1. Esimerkki 2

Ohjelmointi 1 Taulukot ja merkkijonot

Ohjelmoinnin peruskurssi Y1

CSS-kielen avulla määritellään HTML-dokumentin tyyli. CSS avulla voidaan tarkemmin määritellä eri elementtien ominaisuuksia.

JOKKY OSK. Logo ja graafinen ohjeistus. Jaana Salo. JEDU / Piippola, Media 15A

PERL. TIE Principles of Programming Languages. Ryhmä 4: Joonas Lång & Jasmin Laitamäki

Mapu I Laskuharjoitus 2, tehtävä 1. Derivoidaan molemmat puolet, aloitetaan vasemmasta puolesta. Muistetaan että:

Reaalilukuvälit, leikkaus ja unioni (1/2)

Ohjelmoinnin peruskurssien laaja oppimäärä

BM20A5840 Usean muuttujan funktiot ja sarjat Harjoitus 1, Kevät 2018

Luento 3: 3D katselu. Sisältö

811312A Tietorakenteet ja algoritmit Kertausta jälkiosasta

Kertausta 1. kurssikokeeseen

13. Loogiset operaatiot 13.1

1. Lineaarialgebraa A := Matriisin osia voidaan muutella päivittämällä riviä, saraketta tai osamatriisia (Matlabmaisesti): B :=

7. PINTA-ALAFUNKTIO. A(x) a x b

S Laskennallinen Neurotiede

= 2 L L. f (x)dx. coshx dx = 1 L. sinhx nπ. sin. sin L + 2 L. a n. L 2 + n 2 cos. tehdään approksimoinnissa virhe, jota voidaan arvioida integraalin

Määrittelydokumentti

MS-A0202 Differentiaali- ja integraalilaskenta 2 (SCI) Luento 4: Ketjusäännöt ja lineaarinen approksimointi

Tarvikkeet: A5-kokoisia papereita, valmiiksi piirrettyjä yksinkertaisia kuvioita, kyniä

8. Kieliopit ja kielet

plot(f(x), x=-5..5, y= )

Chapel. TIE Ryhmä 91. Joonas Eloranta Lari Valtonen

811312A Tietorakenteet ja algoritmit, , Harjoitus 6, Ratkaisu

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

10.2. Säteenjäljitys ja radiositeettialgoritmi. Säteenjäljitys

JOHDATUS TEKOÄLYYN TEEMU ROOS

Ohjelmoinnin peruskurssien laaja oppimäärä

H5 Malliratkaisut - Tehtävä 1

Ohjelmoinnin perusteet Y Python

Luku 8. Aluekyselyt. 8.1 Summataulukko

Concurrency - Rinnakkaisuus. Group: 9 Joni Laine Juho Vähätalo

Transkriptio:

Funktionaalista grafiikkaa Tommi Teistelä totateis@jyu.fi 22.4.2008 Tiivistelmä Haskellin kaltaisten funktionaalisten ohjelmointikielten ilmaisukyky mahdollistaa grafiikan koostamisen perinteistä korkeammalla tasolla. Tässä paperissa pyritään esittelemään legacy-free tapoja rakentaa Haskell-kielellä tietokonegrafiikkaa alunperin kirjassa The Fun of Programming ja Haskell-grafiikkakirjastossa Pan [1] esitettyjen ideoiden pohjalta. 1 Johdanto Grafiikkaoperaatioiden toteuttaminen perinteisellä ohjelmointikielellä (lue: C) johtaa usein lähdekoodiin, jonka uudelleenkäytettävyys on heikkoa. Sopivien korkeamman tason ilmaisujen puutteessa samat operaatiot voi joutua pienien erojen takia toteuttamaan useita kertoja, ellei koodin selkeydestä, yksinkertaisuudesta ja/tai tehokkuudesta olla valmiita tinkimään. Avoimen lähdekoodin grafiikkaeditori GIMP on kärsinyt tästä jo pitkään: alkuperäinen GIMP tuki kunnolla ainoastaan 32-bittisiä RGBA-bittikarttoja, ja projektin koodin määrän kasvaessa pitkään kaivattu tuki 48-bittisille RGBAbittikartoille on yhä vaikeampi toteuttaa, puhumattakaan painotuotannossa käytettävistä CMYK-väreistä (Cyan, Magenta, Yellow, Key joka tässä tarkoittaa mustaa) ja vielä harvinaisemmista värien esitystavoista. Grafiikkakoodin korvaajaksi on kehitetty yleisempää, graafipohjaista kirjastoa jo vuodesta 2000, joskin tätä kirjoittaessa kirjaston liittäminen GIMP:iin on vasta alullaan. Kehittäjien haluttomuus sotkea vielä kehitteillä olevaa ohjelmaa tuella muille formaateille johti lopulta mm. CinePaint-projektin forkkaamiseen GIMP:n koodista [3]. Haskell-kieli tarjoaa joitakin ominaisuuksia, joiden avulla voidaan kirjoittaa huomattavasti selkeämpää ja uudelleenkäytettävämpää grafiikkakoodia. Näistä tärkeimpiä ovat korkeamman kertaluokan funktiot ja tyyppiluokat. 1

2 Kuvatiedon esittäminen Kuva täytyy pystyä esittämään jotenkin ohjelmassa. Ensimmäisenä kuvan esitysmuotona saattaa mieleen tulla mieleen lista kuvan muodostavien pikselien väriarvoista: type Color = (Float, Float, Float, Float) type Image = [[Color]] Värin esitys on yksinkertainen ja todettu toimivaksi: Color:in komponentit ovat punainen, vihreä, sininen ja alpha, joka määrittää värin läpikuultavuuden (0 = läpinäkyvä,.., 1 = ei läpinäkyvä). Toisaalta kuvan esitys näin vastaa melko hyvin sitä, miten kuva oikeasti säilytetään bittikarttamuodossa ja miten sitä on yleensä käsiteltykin ohjelmointikielissä. Tällaisen kuvatiedon käsittely on kuitenkin osa edellä mainittua ongelmaa, sillä se ei abstrahoi hyvin kuvan rakennetta ja tuottaa hankaluuksia useampien kuvien koostamisessa; listarakenne on otettava huomioon monessa vaiheessa. Kokeillaan jotakin funktionaalisempaa: type Point = (Float, Float) type Image = Point -> Color Kuva on nyt funktio, joka kuvaa tietyn kuvapisteen sen väriksi. Tämä poistaa pikseli -käsitteen kokonaan tästä vaiheesta. Piste-tyypin käyttöä voidaan vielä helpottaa toteuttamalla sille joitakin alkeellisia vektorioperaatioita. Muutetaan vielä Image tyyppikonstruktoriksi niin, että voimme käyttää erilaisia värityyppejä: type Image t = Point -> t type ImageC = Image Color Nyt kuva voi koostua mistä tahansa tyypistä t, kunhan se toteuttaa kuvaoperaatioiden tarpeisiin riittävästi perusoperaatioita, kuten esim. Haskellin Fractional-luokkaan kuuluvat tyypit, ja ImageC on nyt yllä esiteltyä Colortyyppiä käyttävä kuva. Erilaisten värityyppien lisäksi ainakin Boolean voi olla hyödyllinen kuvamaskien muodostamisessa (True = osa kuvaa, False = ei osa kuvaa) [2, s. 132]. 3 Kuvien koostaminen Yksi funktionaalisen kielen etu on kyky käyttää funktioita kunnollisina objekteina. Tässä esitettävä tapa koostaa kuvia perustuukin funktioiden yhdistämiseen korkeamman tason funktioilla, jotka ottavat parametriksi toisia funktioita (ja tässä tapauksessa myös palauttavat niitä). 2

3.1 Esimerkki koostamisesta: Alpha blending Alpha blending kuvaa kaksi väriarvoa ja nk. alpha-arvon [0..1] yhdeksi väriarvoksi seuraavasti: tulos = arvo1 (1 alpha) + arvo2 alpha (1) Usein alpha:n arvo saadaan toisesta väriarvosta. Tämä voidaan yllä määritellyn kuvatyypin rajoissa ilmaista korkeamman tason funktiona, joka ottaa parametreikseen kaksi kuvaa (funktiota) sekä alpha-arvon ja palauttaa alpha blendingin toteuttavan funktion: simplealphacompose :: Float -> ImageC -> ImageC -> ImageC simplealphacompose alpha image1 image2 p = ((image1 p) mulc (1-alpha)) addc ((image2 p) mulc alpha) where addc :: Color -> Color -> Color addc (r,g,b,a) (r2,g2,b2,a2) = (r+r2,g+g2,b+b2,a+a2) mulc :: Color -> Float -> Color mulc (r,g,b,a) x = (r*x, g*x, b*x, a*x) Kaksi kuvaa voidaan nyt yhdistää simplealphacompose:lla: imagered :: ImageC imagered _ = (1,0,0,1) imageblue :: ImageC imageblue _ = (0,1,0,1) imageyellow = simplealphacompose 0.5 imagered imageblue Alpha:n arvolla 0.5 syntyvän kuvan väri on lähdekuvien värien keskiarvo, joten imageyellow on keltainen (0.5, 0.5, 0.0, 1.0) kuva. 4 Vektorigrafiikkaa Yksi ylläolevan hienous on sen riippumattomuus perinteisestä kuvan pikseliesityksestä ; kuvaan voidaan sisällyttää helposti myös vektorigrafiikkaa. Vektorigrafiikkakuva voi yksinkertaisesti koostua funktiosta (kuvasta), joka tuottaa läpinäkyvän (alpha = 0) väriarvon pisteelle, joka ei ole osa vektorikappaletta. Monipuolisempia kappaleita voidaan toteuttaa esim. tekemällä kuvafunktio, joka käy läpi listan vektorikuvan alkeisosia ja palauttaa oikean väriarvon näiden pohjalta. Tämä lähestymistapa muistuttaa 3d-grafiikassa käytettyä säteen jäljitystä (raytracing). Esimerkiksi punainen 1-säteinen kiekko voidaan määritellä näin: 3

imagered :: ImageC imagered (x,y) sqrt(x+y) <= 1 = (1,0,0,1) imagered _ = (0,0,0,0) Tällaisista yksinkertaisista kappaleista voidaan muodostaa monimutkaisempia kuvioita koostamalla ja transformaatioilla. 4.1 Transformaatiot Erilaiset transformaatiot, kuten kuvan skaalaus, rotaatio ja erikoisemmat venytykset eivät tarvitse erikseen toteutusta joka kuvafunktiossa; koska kuvaa luetaan vain yksi piste kerrallaan, transformaatiot voidaan toteuttaa yksinkertaisesti toteuttamalla funktioita, jotka siirtävät kuvafunktiolle annettavia pisteitä [2, s. 139], esim. kuvan siirto (translaatio): imagetranslate :: Point -> Image a -> Image a imagetranslate translation image p = image (p - translation) Kuvan skaalaus: imagescale :: Point -> Image a -> Image a imagescale 0 = const (0,0,0,0) imagescale scale image p = image (p / scale) Skaalatessa jaetaan annettu piste skaalausarvolla, koska tarkoitus on edelleenkin siirtää kohtaa, josta kuvaa luetaan. Yrittäessä skaalata nollalla palautetaan const-funktionaalilla muodostettu funktio, joka palauttaa millä tahansa syötteellä täysin läpinäkyvän pikselin äärettömän pientä kuvaa ei tarvitse näyttää. Rotaatiot ja erikoisemmat transformaatiot voidaan toteuttaa samalla tavalla. 5 Bittikartat 5.1 Kuvan muuttaminen bittikartaksi Jos kuvaa on tarkoitus käyttää myös ohjelman ulkopuolella, se täytyy pystyä muuttamaan bittikartaksi. Triviaalisti bittikartan pikseleille saadaan laskettua väriarvot laskemalla kuvafunktiollamme leveys * korkeus kappaletta väriarvoja sopivista kuvan pisteistä ja muuntamalla ne bittikartassa käytettävään muotoon (tässä voidaan toteuttaa muunnokset eri väriprofiilien välillä). 4

Tämä voi kuitenkin tuottaa melko karkean lopputuloksen aliasoinnin takia, joten parempi tapa on soveltaa supersämpläystä: jokaista tuotettavaa pikseliä kohden lasketaan useampia näytteitä ja lasketaan niistä painotettu keskiarvo niin, että pikselin oikeasta paikasta saatu väri saa korkeimman painoarvon, ja muutama sen läheltä laskettu väriarvo pienempiä painoarvoja. Painotetun keskiarvon laskeminen voidaan toteuttaa esim. seuraavasti: supersample :: (Fractional a) => Float -> Image a -> Image a supersample offset image (x,y) = image (x,y) * 0.4 + image(x + offset, y + offset) * 0.15 + image(x + offset, y - offset) * 0.15 + image(x - offset, y + offset) * 0.15 + image(x - offset, y - offset) * 0.15 Esimerkkikoodissa lasketaan lopullinen väriarvo pisteen oikean sijainnin (painoarvo 0.4) lisäksi neljästä muusta sijainnista (painoarvo 0.15). Näytteiden sijaintia voidaan skaalata sopivalle etäisyydelle pisteestä offset:illä. Paras tulos syntynee pitämällä offset pienempänä kuin kuvapisteiden etäisyys toisistaan. Funktio(naali) supersample on myös kuva-tyyppiä, joten sitä voidaan tarvittaessa soveltaa vain osaan kuvarakenteesta. Näytteidenottokohtien sijoittelu voi vaikuttaa paljon algoritmin tehokkuuteen, ja esimerkissä olevat eivät välttämättä ole optimaalisia. 5.2 Bittikarttojen tuonti Bittikarttoja voidaan tuoda kuvarakenteeseen toteuttamalla funktio, joka lukee bittikarttakuvasta pikselien väriarvoja. Koska bittikartan koko tuskin on ääretön, eikä sen pikselitarkkuus ole todennäköisesti aivan sama kuin Pointtyypin (Float), pisteiden värien laskemisessa tarvitaan jonkinlainen interpolaatioalgoritmi, kun kuvasta luettava piste ei vastaa täysin minkään bittikarttakuvan pikselin sijaintia. Functional Images -tekstissä käytetty yksinkertainen box-filter -algoritmi [2, s. 149], joka tunnetaan myös nimellä bilinear filtering, antaa siedettäviä tuloksia kun kuvalle ei tehdä merkittäviä transformaatioita. Erikoisemmissa tilanteissa triviaali algoritmi voi johtaa näkyviin moiré-kuvioihin ja muihin epäkohtiin. 5

6 Yhteenveto Haskell-kielen korkeamman tason funktioiden päälle voidaan rakentaa helposti ilman muuta pohjakoodia yksinkertainen grafiikkakirjasto, joka vielä säilyttää perinteisiä imperatiivisiä ratkaisuja paremmin eron kuvan rakenteen ja sen esityksen välillä. Funktionaalisella kielellä voidaan myös pysyä hyvin lähellä erilaisten grafiikkaoperaatioiden matemaattisia määritelmiä. Ratkaisu ei sellaisenaan edellytä Haskellin laiskaa evaluaatiota [2, s. 132], joten se on mahdollinen toteuttaa monilla ei-laiskoilla funktionaalisilla kielillä. Laiskasta evaluaatiosta voi kuitenkin olla apua monimutkaisempien kuvien generoinnissa ohjelmallisesti, tai käsitellessä isoa kuvaa, josta tuotetusta bittikartasta tarvitsee näyttää kerrallaan vain pieni alue; ei-laiskalla kielellä tilanteen optimointi edellyttäisi ylimääräistä koodia. Lähteet [1] Conal Elliott, The Pan Home Page <URL: http://conal.net/pan/>, viitattu 21.4.2008. [2] Conal Elliott, Functional images, kirjassa The Fun of Programming (ISBN 0333992857). Functional Images-osa saatavilla WWW:stä: <URL: http://conal.net/papers/functional-images [3] The CinePaint Project, CinePaint FAQ, <URL: http://www.cinepaint.org/faq.html>, viitattu 22.4.2008. 6