Tulvan täyttö - Flood fill
Tulvan täyttö , jota kutsutaan myös siementäytteeksi , on algoritmi, joka määrittää ja muuttaa tiettyyn solmuun yhdistettyä aluetta moniulotteisessa taulukossa, jolla on jokin vastaava attribuutti. Sitä käytetään "ämpäri" Täyttötyökalu of maali ohjelmia täyttää kytketty, samoin värinen alueilla eri väriä, ja peleissä kuten Go ja Miinaharava määrittämiseksi, mitkä osat poistetaan. Muunnos nimeltään rajan fill käyttää samoja algoritmeja vaan määritellään alue liitetään tiettyyn solmuun, jolla ei ole erityistä määrite.
Huomaa, että tulvitäyttö ei sovellu täytettyjen monikulmioiden piirtämiseen, koska se jättää väliin pikselit terävämmissä kulmissa. Katso sen sijaan parilliset ja parittomat säännöt .
Algoritmin parametrit
Perinteinen tulvan täyttöalgoritmi sisältää kolme parametria: aloitussolmu, kohdeväri ja korvaava väri. Algoritmi etsii kaikki taulukon solmut, jotka on yhdistetty aloitussolmuun kohdevärin polulla, ja muuttaa ne korvaavaksi väreksi. Rajatäyttöä varten kohdevärin tilalle toimitetaan reunuksen väri.
Jotta algoritmia voidaan yleistää yleisellä tavalla, seuraavissa kuvauksissa on sen sijaan käytettävissä kaksi rutiinia. Yksi nimeltään Inside
joka palauttaa totta täyttämättömille pisteille, jotka värinsä mukaan olisivat täytetyn alueen sisällä, ja toinen kutsutaan Set
joka täyttää pikselin/solmun. Mikään sitä Set
kutsunut solmu ei saa enää olla Inside
.
Riippuen siitä, katsommeko solmujen koskettavan toisiinsa liitettyjä kulmia vai ei, meillä on kaksi muunnosta: kahdeksan- ja nelisuuntainen.
Pinoon perustuva rekursiivinen toteutus (nelisuuntainen)
Varhaisin tunnettu, epäsuorasti pinopohjainen, rekursiivinen , nelisuuntainen tulvantäyttö toteutetaan seuraavasti:
Flood-fill (node): 1. If node is not Inside return. 2. Set the node 3. Perform Flood-fill one step to the south of node. 4. Perform Flood-fill one step to the north of node 5. Perform Flood-fill one step to the west of node 6. Perform Flood-fill one step to the east of node 7. Return.
Vaikka ylläoleva algoritmi on helppo ymmärtää, sen käyttäminen on epäkäytännöllistä kielillä ja ympäristöissä, joissa pinotilaa on vakavasti rajoitettu (esim. Mikro -ohjaimet ).
Rekursion siirtäminen tietorakenteeseen
Rekursion siirtäminen tietorakenteeseen (joko pinoon tai jonoon ) estää pinon ylivuodon. Se on samanlainen kuin yksinkertainen rekursiivinen ratkaisu, paitsi että rekursiivisten puheluiden soittamisen sijaan se työntää solmut pinoon tai jonoon kulutusta varten, ja tietorakenteen valinta vaikuttaa leviämismalliin:
Flood-fill (node): 1. Set Q to the empty queue or stack. 2. Add node to the end of Q. 3. While Q is not empty: 4. Set n equal to the first element of Q. 5. Remove first element from Q. 6. If n is Inside: Set the n Add the node to the west of n to the end of Q. Add the node to the east of n to the end of Q. Add the node to the north of n to the end of Q. Add the node to the south of n to the end of Q. 7. Continue looping until Q is exhausted. 8. Return.
Lisää mahdollisia optimointeja
- Tarkista ja aseta kunkin solmun pikseliväri ennen sen lisäämistä pinoon/jonoon, mikä pienentää pinon/jonon kokoa.
- Käytä silmukkaa itä/länsi -suuntiin ja jonota pikselit ylä-/alapuolelle. (Tehdään se samanlaiseksi span -täyttöalgoritmien kanssa, alla.)
- Lomaile kaksi tai useampia kopioita koodista ylimääräisillä pinoilla/jonoilla, jotta OoO -prosessorit saavat enemmän mahdollisuuksia rinnastaa
- Käytä useita säikeitä (mieluiten hieman eri vierailutilauksilla, jotta ne eivät pysy samalla alueella)
Edut
- Erittäin yksinkertainen algoritmi - helppo tehdä virheetön.
Haitat
- Kuluttaa paljon muistia, etenkin pinon käytön aikana.
- Testaa useimmat täytetyt pikselit yhteensä neljä kertaa.
- Ei sovellu kuvion täyttämiseen, koska se vaatii pikselitestitulosten muuttamista.
- Pääsykuvio ei ole välimuistiystävällinen jonotusvaihtoehdolle.
- Ei voi helposti optimoida usean pikselin sanoja tai bittitasoja varten.
Span täyttö
On mahdollista optimoida asioita edelleen työskentelemällä ensisijaisesti jännevälien kanssa. Ensimmäinen julkaistu täydellinen esimerkki toimii seuraavan perusperiaatteen mukaisesti. Aloita siemenpisteestä täyttämällä vasemmalle ja oikealle ja seuraamalla reunoja. Sitten skannaat saman osan ylä- ja alapuolella olevasta viivasta etsimällä uusia siemenpisteitä jatkaaksesi. Tämä algoritmi on suosituin sekä lainauksissa että toteutuksissa, vaikka useimmat täytetyt pikselit testataan yhteensä kolme kertaa. Pseudokoodimuodossa:
fn fill(x, y): if not Inside(x, y) then return let s = new empty stack or queue add (x, y) to s while s is not empty: Remove an (x, y) from s let lx = x while Inside(lx - 1, y): Set(lx - 1, y) lx = lx - 1 while Inside(x, y): Set(x, y) x = x + 1 scan(lx, x - 1, y + 1, s) scan(lx, x - 1, y - 1, s) fn scan(lx, rx, y, s): let added = false for x in lx .. rx: if not Inside(x, y): added = false else if not added: Add (x, y) to s added = true
Ajan myötä seuraavat optimoinnit toteutettiin:
- Kun uusi skannaus olisi kokonaan isovanhemman alueella, se löytäisi varmasti vain täytetyt pikselit, joten se ei tarvitse jonottaa.
- Lisäksi kun uusi skannaus on isovanhemman alueen päällekkäin, vain ylitykset (U-käännökset ja W-käännökset) on skannattava.
- On mahdollista täyttää siemeniä etsiessään
Lopullinen, yhdistetty skannaus ja täyttöalue-täyteaine julkaistiin sitten vuonna 1990 ja etenee seuraavasti (vaikka tässä oleva versio korjaa joitain alkuperäisen virheitä):
fn fill(x, y): if not Inside(x, y) then return let s = new empty queue or stack Add (x, x, y, 1) to s Add (x, x, y - 1, -1) to s while s is not empty: Remove an (x1, x2, y, dy) from s let x = x1 if Inside(x, y): while Inside(x - 1, y): Set(x - 1, y) x = x - 1 if x < x1: Add (x, x1-1, y-dy, -dy) to s while x1 < x2: while Inside(x1, y): Set(x1, y) x1 = x1 + 1 Add (x, x1 - 1, y+dy, dy) to s if x1 - 1 > x2: Add (x2 + 1, x1 - 1, y-dy, -dy) while x1 < x2 and not Inside(x1, y): x1 = x1 + 1 x = x1
Edut
- 2x-8x nopeampi kuin pikselirekursiivinen algoritmi.
- Pääsykuvio on välimuisti- ja bittitasoystävällinen.
- Voi piirtää vaakasuoran viivan yksittäisten pikseleiden asettamisen sijaan.
Haitat
- Vierailee edelleen pikseleissä, jotka se on jo täyttänyt. (Suositulla algoritmilla kolme skannausta useimmista pikseleistä. Viimeisessä tapauksessa vain lisätarkistuksia pikseleistä, joissa on reikiä täytetyllä alueella.)
- Ei sovellu kuvion täyttämiseen, koska se vaatii pikselitestitulosten muuttamista.
Kuvion täyttötuen lisääminen
Kaksi yleistä tapaa saada mittausalue- ja pikselipohjaiset algoritmit tukemaan kuvion täyttämistä ovat joko käyttää ainutlaatuista väriä tavallisena täyttönä ja korvata se sitten kuviolla tai seurata (2d: n boolean-taulukossa tai alueina), mistä pikselistä on käytetty osoittamaan, että pikselit eivät ole enää täytettävissä. Inside on palautettava epätosi tällaisille vierailluille kuvapisteille.
Kaavioteoreettinen täyttö
Jotkut teoreetikot käyttivät ongelmaan nimenomaista kuvaajateoriaa, pitäen pikselien alueita tai niiden aggregaatteja solmuina ja tutkimalla niiden yhteyksiä. Ensimmäinen julkaistu kuvaajateorialgoritmi toimi samalla tavalla kuin yllä oleva täyttöalue, mutta sillä oli tapa havaita, milloin se kaksinkertaistaa jännevälien täytön. Valitettavasti siinä oli virheitä, joiden vuoksi se ei täyttänyt joitain täyttöjä. Korjattu algoritmi julkaistiin myöhemmin samalla periaatteella graafiteoriassa; se kuitenkin muuttaa kuvaa sen edetessä estämään väliaikaisesti mahdolliset silmukat, mikä vaikeuttaa ohjelmallista käyttöliittymää. Myöhemmin julkaistu algoritmi riippui siitä, että raja on erilainen kuin kaikki muu kuvassa, joten se ei sovellu useimpiin käyttötarkoituksiin; se vaatii myös ylimääräisen bitin pikseliä kohti kirjanpidossa.
Edut
- Sopii kuvion täyttöön suoraan, koska se ei koskaan testaa uudelleen täytettyjä pikseleitä.
- Kaksinkertainen alkuperäisen mittausalgoritmin nopeus yksinkertaisten täyttöjen saamiseksi.
- Pääsykuvio on välimuisti- ja bittitasoystävällinen.
Haitat
- Väliä on säännöllisesti verrattava jokaiseen jonon "etuosaan", mikä hidastaa merkittävästi monimutkaisia täyttöjä.
- Siirtyminen edestakaisin kuvaajan teoreettisen ja pikselialueen välillä vaikeuttaa ymmärtämistä.
- Koodi on melko monimutkainen, mikä lisää virheiden mahdollisuutta.
Kävelypohjainen täyttö (kiinteän muistin menetelmä)
On olemassa menetelmä, joka käytännössä ei käytä muistia neljään kytkettyyn alueeseen teeskennellen olevansa maalari, joka yrittää maalata alueen maalaamatta itseään nurkkaan. Tämä on myös menetelmä sokkelojen ratkaisemiseksi. Neljä pikseliä, jotka muodostavat ensisijaisen rajan, tutkitaan, jotta voidaan selvittää, mitä on tehtävä. Taidemaalari voi joutua johonkin useista olosuhteista:
- Kaikki neljä rajapikseliä täytetään.
- Kolme rajapikseliä on täytetty.
- Kaksi rajapikseliä on täytetty.
- Yksi rajapikseli on täynnä.
- Nollarajapikselit täytetään.
Jos polkua tai rajaa on noudatettava, käytetään oikean käden sääntöä. Taidemaalari seuraa aluetta asettamalla oikean kätensä seinälle (alueen raja) ja etenemällä alueen reunan ympäri poistamatta kättään.
Tapauksessa #1 maalari maalaa (täyttää) pikselin, jonka päällä maalari seisoo, ja pysäyttää algoritmin.
Tapauksessa #2 on olemassa alueelta johtava polku. Maalaa pikseli, jolla maalari seisoo, ja siirry avoimen polun suuntaan.
Tapauksessa #3 kaksi rajapikseliä määrittävät polun, joka, jos maalaamme nykyisen pikselin, voi estää meitä pääsemästä takaisin polun toiselle puolelle. Tarvitsemme "merkin" määritelläksemme, missä olemme ja mihin suuntaan olemme menossa nähdäksemme, palaammeko koskaan täsmälleen samaan pikseliin. Jos olemme jo luoneet tällaisen "merkin", säilytämme edellisen merkin ja siirrymme seuraavaan pikseliin oikean käden säännön mukaisesti.
Merkkiä käytetään ensimmäiseen 2 pikselin rajaan, joka havaitaan muistamaan, mistä kulku alkoi ja mihin suuntaan maalari liikkui. Jos merkki kohdataan uudelleen ja maalari kulkee samaan suuntaan, maalari tietää, että on turvallista maalata neliö merkillä ja jatkaa samaan suuntaan. Tämä johtuu siitä, että (jonkin tuntemattoman polun kautta) merkin toisella puolella olevat pikselit voidaan saavuttaa ja maalata tulevaisuudessa. Merkki poistetaan tulevaa käyttöä varten.
Jos maalari kohtaa merkin, mutta on menossa toiseen suuntaan, on tapahtunut jonkinlainen silmukka, joka sai maalarin palaamaan merkkiin. Tämä silmukka on poistettava. Merkki nostetaan, ja maalari etenee sitten merkin aiemmin osoittamaan suuntaan käyttämällä vasemmanpuoleista sääntöä rajalle (samanlainen kuin oikean käden sääntö, mutta käyttämällä maalarin vasenta kättä). Tämä jatkuu, kunnes risteys löytyy (vähintään kolme avointa rajapikseliä). Edelleen käyttämällä vasemmanpuoleista sääntöä maalari etsii nyt yksinkertaista kohtaa (kaksi rajapikseliä). Kun tämä kahden pikselin rajapolku on löydetty, pikseli maalataan. Tämä katkaisee silmukan ja sallii algoritmin jatkaa.
Tapauksessa #4 meidän on tarkistettava vastakkaiset 8-kulmaiset kulmat nähdäksemme, ovatko ne täytettyjä vai eivät. Jos jompikumpi tai molemmat täytetään, tämä luo monen polun risteyksen, eikä sitä voida täyttää. Jos molemmat ovat tyhjiä, nykyinen pikseli voidaan maalata ja maalari voi liikkua oikean käden säännön mukaisesti.
Algoritmi vaihtaa aikaa muistiin. Yksinkertaisille muodoille se on erittäin tehokas. Jos muoto on kuitenkin monimutkainen ja siinä on monia ominaisuuksia, algoritmi käyttää paljon aikaa alueen reunojen jäljittämiseen yrittäen varmistaa, että kaikki voidaan maalata.
Tämä algoritmi oli ensimmäisen kerran kaupallisesti saatavilla vuonna 1981 Vicom -kuvankäsittelyjärjestelmässä, jonka valmistaja oli Vicom Systems, Inc. Kävelyalgoritmi julkaistiin vuonna 1994. Klassinen rekursiivinen tulvan täyttöalgoritmi oli saatavilla myös Vicom -järjestelmässä.
Pseudokoodi
Tämä on optimaalisen kiinteän muistin tulvan täyttöalgoritmin pseudokooditoteutus, joka on kirjoitettu jäsennellyllä englannilla:
- Muuttujat
-
cur
,mark
Jamark2
kumpikin joko pikselikoordinaateille tai nolla- HUOMAUTUS: kun
mark
asetuksena on nolla, älä poista sen aiempaa koordinaattiarvoa. Pidä nämä koordinaatit saatavilla, jotta ne voidaan tarvittaessa palauttaa muistiin.
- HUOMAUTUS: kun
-
cur-dir
,mark-dir
Jamark2-dir
kukin pitää suunnassa (vasemmalle, oikealle, ylös tai alas) -
backtrack
jafindloop
jokaisella on boolean arvot -
count
on kokonaisluku
- Algoritmi
- HUOMAUTUS: Kaikki suunnat (edessä, takana, vasemmalla, oikealla) ovat suhteessa
cur-dir
set cur to starting pixel set cur-dir to default direction clear mark and mark2 (set values to null) set backtrack and findloop to false while front-pixel is empty do move forward end while jump to START MAIN LOOP: move forward if right-pixel is inside then if backtrack is true and findloop is false and either front-pixel or left-pixel is inside then set findloop to true end if turn right PAINT: move forward end if START: set count to number of non-diagonally adjacent pixels filled (front/back/left/right ONLY) if count is not 4 then do turn right while front-pixel is inside do turn left while front-pixel is not inside end if switch count case 1 if backtrack is true then set findloop to true else if findloop is true then if mark is null then restore mark end if else if front-left-pixel and back-left-pixel are both inside then clear mark set cur jump to PAINT end if end case case 2 if back-pixel is not inside then if front-left-pixel is inside then clear mark set cur jump to PAINT end if else if mark is not set then set mark to cur set mark-dir to cur-dir clear mark2 set findloop and backtrack to false else if mark2 is not set then if cur is at mark then if cur-dir is the same as mark-dir then clear mark turn around set cur jump to PAINT else set backtrack to true set findloop to false set cur-dir to mark-dir end if else if findloop is true then set mark2 to cur set mark2-dir to cur-dir end if else if cur is at mark then set cur to mark2 set cur-dir to mark2-dir clear mark and mark2 set backtrack to false turn around set cur jump to PAINT else if cur at mark2 then set mark to cur set cur-dir and mark-dir to mark2-dir clear mark2 end if end if end if end case case 3 clear mark set cur jump to PAINT end case case 4 set cur done end case end switch end MAIN LOOP
Edut
- Jatkuva muistin käyttö.
Haitat
- Pääsykuvio ei ole välimuisti- tai bittitasoystävällinen.
- Voi viettää paljon aikaa kävellen silmukoiden ympäri ennen niiden sulkemista.
Vektorin toteutukset
Inkscapen versio 0.46 sisältää kauhan täyttötyökalun, joka antaa samanlaisen tuloksen kuin tavalliset bittikarttaoperaatiot ja käyttää sitäkin: kangas renderöidään, tulvan täyttö suoritetaan valitulle alueelle ja tulos jäljitetään sitten polulle. Se käyttää rajaehdon käsitettä .
Katso myös
- Leveys ensimmäinen haku
- Syvyyshaku
- Kaavion läpikäynti
- Liitetyn komponentin merkinnät
- Dijkstran algoritmi
Ulkoiset linkit
- Esimerkki toteutuksista rekursiiviseen ja ei-rekursiiviseen, klassiseen ja skannauslinjan tulvaan , Lode Vandevenne.
- Esimerkki Java-toteutuksesta käyttäen Q ei-rekursiivista.
Viitteet
- ^ a b c Smith, Alvy Ray (1979). Sävy Täytä . SIGGRAPH '79: Tietokonegrafiikkaa ja vuorovaikutteisia tekniikoita käsittelevän kuudennen vuosikonferenssin artikkelit. s. 276–283. doi : 10.1145/800249.807456 .
- ^ a b Ackland, Bryan D; Weste, Neil H (1981). Reunalipun algoritmi - Täyttömenetelmä rasteriskannausnäyttöihin . IEEE-tapahtumat tietokoneissa (Volume: C-30, Issue: 1). s. 41–48. doi : 10.1109/TC.1981.6312155 .
- ^ a b c d e f g h i j Fishkin, Kenneth P; Barsky, Brian A (1985). Analyysi ja algoritmi täyttämisen lisäämiseksi . Tietokoneella tuotetut kuvat: Graphics Interface'n uusin prosessi '85. s. 56–76. doi : 10.1007/978-4-431-68033-8_6 .
- ^ Newman, William M; Sproull, Robert Fletcher (1979). Interaktiivisen tietokonegrafiikan periaatteet (2. painos). McGraw-Hill. s. 253. ISBN 978-0-07-046338-7.
- ^ Pavlidis, Theo (1982). Grafiikan ja kuvankäsittelyn algoritmit . Springer-Verlag. s. 181. ISBN 978-3-642-93210-6.
- ^ a b c d e f g h i Levoy, Marc (1982). Alueen tulvan algoritmit . KUVA 1981 Kaksiulotteinen tietokoneanimaatio kurssin toteaa.
- ^ Foley, JD; van Dam, A; Feiner, SK; Hughes, SK (1990). Tietokonegrafiikka: periaatteet ja käytäntö (2. painos). Addison – Wesley. s. 979–982. ISBN 978-0-201-84840-3.
- ^ Heckbert, Paul S (1990). "IV.10: Siemenen täyttöalgoritmi". Julkaisussa Glassner, Andrew S (toim.). Grafiikka Jalokivet . Academic Press. s. 275–277. ISBN 0122861663.
- ^ a b Lieberman, Henry (1978). Kuinka värittää värityskirjaan . SIGGRAPH '78: Tietokonegrafiikkaa ja vuorovaikutteisia tekniikoita käsittelevän viidennen vuosikonferenssin artikkelit. s. 111–116. doi : 10.1145/800248.807380 .
- ^ a b c Shani, Uri (1980). Alueiden täyttäminen binäärirasterikuvissa: Kaavioteoreettinen lähestymistapa . SIGGRAPH '80: Tietokonegrafiikkaa ja vuorovaikutteisia tekniikoita käsittelevän seitsemännen vuosikonferenssin artikkelit. s. 321–327. doi : 10.1145/800250.807511 .
- ^ a b Pavlidis, Theo (1981). Muotojen täyttö rasterigrafiikassa . SIGGRAPH '81: Tietokonegrafiikkaa ja vuorovaikutteisia tekniikoita käsittelevän kahdeksannen vuosikonferenssin artikkelit. s. 29–36. doi : 10.1145/800224.806786 .
- ^ Henrich, Dominik (1994). Avaruustehokas alue, joka täyttää rasterigrafiikkaa . Visuaalinen tietokone. s. 205–215. doi : 10.1007/BF01901287 .