5.5. Alueet ja maskit

Jokainen image-moduulin operaatio käsittelee oletuksena lähdekuvansa jokaista pikseliä. Se on yksinkertaisin käyttäytymismalli kuvata, ja oikea silloin kun algoritmin tehtävä todella kattaa koko kehyksen – tasainen värikorjaus, globaali histogrammi tai koodauskerros lähetystä varten. Mutta käytännössä useimmat algoritmit haluavat tarkastella vähempää. Värimerkkiä seuraava blob-seuranta välittää siitä osasta näkymää, jossa merkki voi esiintyä, eikä sen takana olevasta seinästä. Morfologinen siivousvaihe on turvallinen vain niiden pikselien yli, jotka aiempi vaihe merkitsi ehdokkaiksi. Kasvojentunnistin saattaa toimia vain sen rajauslaatikon sisällä, jonka karkeampi tunnistin on jo rajannut. image-moduuli tukee tätä työtä kahden mekanismin avulla, jotka rajaavat operaation pikselien osajoukkoon: suorakulmaiset kohdealueet ja binääriset maskit. Ne yhdistyvät vapaasti, ja lähes jokainen pikseleitä käsittelevä metodi hyväksyy jommankumman – tai molemmat – avainsana-argumenttina.

5.5.1. Kohdealueet

Kohdealue on suorakulmainen pikseliryhmä, joka nimetään koordinaattisivulla esitetyllä (x, y, w, h) -nelikolla. Noin kolmekymmentä pinnan metodia hyväksyy roi-avainsana-argumentin; kun se on annettu, operaatio suoritetaan vain kyseisen suorakulmion sisällä olevilla pikseleillä ja jättää muun kuvan koskemattomaksi. Kun roi on None tai jätetään pois, operaatio suoritetaan koko kuvalle – aivan kuin olisi annettu roi=(0, 0, width, height).

Koodissa avainsana sijaitsee niiden muiden argumenttien rinnalla, joita operaatio ottaa:

# Compute a histogram over a centred crop of the image.
h = img.get_histogram(roi=(64, 64, 128, 128))

Ensimmäinen asia, jonka ROI:t tuovat, on väärien positiivisten hallinta. Värinseurain, joka katsoo vain pöytää, ei koskaan laukea ohi kulkevasta paidasta; reunantunnistin, joka toimii vain määritellyn työalueen sisällä, ei koskaan raportoi itse kamerakiinnikkeen reunoja. Hakualueen pienentäminen siihen osaan näkymää, josta algoritmi todella välittää, on halvin parannus, jonka putki voi tehdä omaan luotettavuuteensa.

Toinen asia, jonka ne tuovat, on karkeasta hienoon -putki. Tunnistustulosobjektit – blob, rect, apriltag ja niin edelleen – paljastavat rajauslaatikkonsa samana (x, y, w, h) -nelikkona, jonka roi hyväksyy. Niinpä karkea ensimmäinen vaihe voi palauttaa rajauslaatikon, laatikko putoaa suoraan seuraavan vaiheen roi-arvoksi, ja toinen vaihe suoritetaan suppeammalla alueella. Jokainen asteittainen kaventaminen sekä nopeuttaa seuraavaa vaihetta että tekee sen tuloksista luotettavampia, koska hakuavaruus on jo suodatettu.

5.5.2. Binääriset maskit

Suorakulmio on oikea muoto, kun kohdealue on akselien suuntainen. Kun se ei ole – kaareva alue, ei-konveksi alue tai pikselit, jotka jokin aiempi vaihe luokitteli ”osumiksi” – operaatiolle on sen sijaan kerrottava, että sen tulee rajata itsensä mielivaltaiseen pikselikuvioon. Tämän mekanismi on binäärimaski: erillinen Image, samankokoinen kuin lähde, jota käytetään pikselikohtaisena päälle/pois-kytkimenä. Maskin nollasta poikkeava pikseli sanoo ”sisällytä vastaava lähdepikseli”; nollapikseli sanoo ”jätä lähdepikseli rauhaan.”

Maski on yleensä BINARY-kuva – yksi bitti per pikseli -muoto, joka on olemassa juuri tätä tarkoitusta varten – mutta mikä tahansa yksikanavainen kuva toimii, koska käyttäjä tulkitsee minkä tahansa nollasta poikkeavan arvon päälle-tilaksi.

Suodatus-, kynnystys- ja aritmetiikkametodit hyväksyvät mask-avainsana-argumentin. Muoto on jokaisessa sama: erikseen varattu binäärikuva, samankokoinen kuin lähde, joka annetaan eteenpäin.

ROI:t ja maskit yhdistyvät. Anna molemmat, ja operaatio suoritetaan vain niillä pikseleillä, jotka ovat ROI:n sisällä ja päällä maskissa. Nämä kaksi mekanismia antavat sovelluskoodille riippumattomat vivut – yksi suorakulmaiselle kohdealueelle, yksi sen sisällä olevalle mielivaltaiselle kuviolle – ilman että kumpikaan muoto perii rajoituksia toiselta.

Pieni ruudukko, joka esittää kuvaa. Ruudukon ylä-keskiosaan piirretty katkoviivasuorakulmio merkitsee ROI:n: vain tämän suorakulmion sisällä olevat pikselit huomioidaan. ROI:n sisällä likimain ympyrän muotoinen joukko täytettyjä soluja merkitsee maskin: vain nämä täytetyt solut tosiasiassa muokataan. Loput solut on varjostettu vaaleasti osoittamaan, että ne ovat koskemattomia.

ROI rajaa operaation akselien suuntaiseen suorakulmioon. Maski kaventaa sitä edelleen mielivaltaiseen pikselikuvioon. Nämä kaksi yhdistyvät: vain ROI:n sisällä ja maskissa päällä olevat pikselit muokataan.

5.5.3. Maskien rakentaminen

Kolme Image-metodia rakentaa yleisiä maskigeometrioita paikan päällä nollaamalla valitun alueen ulkopuolella olevat pikselit:

Kukin ottaa (x, y, w, h) (suorakulmiolle ja ellipsille) tai (x, y, radius) (ympyrälle). Minkä tahansa niistä kutsuminen ilman argumentteja keskittää geometrian ja mitoittaa sen täyttämään kuvan, mikä on se muoto, johon sovellus turvautuu, kun tavoitteena on yksinkertainen koko kuvan kokoinen soikio tai ympyrä, joka piilottaa vain kulmat.

mask = image.Image(img.width(), img.height(), image.BINARY)
mask.clear()              # start from all zeros
mask.mask_ellipse()       # centred, full-size oval

Mielenkiintoiset maskit syntyvät harvoin pelkistä mask_*-metodeista. Ne tulevat putken aiemmista vaiheista: kynnystysvaihe tuottaa binäärikuvan, jonka nollasta poikkeavat pikselit merkitsevät osumat, juuri oikea muoto syötettäväksi seuraavan vaiheen mask=-argumenttiin. Morfologinen siivousvaihe hioo maskia muuttamatta sen muotoa. Mikä tahansa, joka päätyy yksikanavaiseksi kuvaksi, on itsessään kelvollinen maski.

5.5.4. Kuinka operaatiot muokkaavat kuvaa

Viime sivujen jokaisessa koodinpätkässä näkyvä kaava – operaatio palauttaa saman img-kuvan ketjutusta varten – on syytä nostaa erikseen esiin, jotta sitä ei tarvitse toistaa joka kerta, kun uusi metodi esitellään. Kolme metodiperhettä esiintyy Image-pinnalla, ja kukin käsittelee lähdekuvaa eri tavalla:

  • Operoivat metodit muokkaavat lähteen pikseleitä paikan päällä ja palauttavat saman kuvan ketjutusta varten. Piirto-, aritmetiikka-, kynnystys- ja suodatinperheet käyttäytyvät kaikki tällä tavalla. img.gaussian(1) sumentaa img-kuvan ja palauttaa saman img-kuvan; uudelleensijoittaminen – img = img.gaussian(1) – on harmitonta mutta tarpeetonta.

  • Muunnosmetodit operoivat oletuksena paikan päällä samalla tavalla kuin operoivat metodit, mutta ne hyväksyvät copy=True ja copy_to_fb=True varatakseen erillisen tuloskuvan, kun lähde on säilytettävä. Muotomuunnokset ja geometriset kopiot ovat tämän perheen pääjäsenet.

  • Tarkastusmetodit lukevat pikselit ja palauttavat tulosobjektin – listan tunnistetuista piirteistä, histogrammin tai joukon tilastoja – muuttamatta lähdekuvaa lainkaan.

Tämä kolmijako on johdonmukainen koko pinnalla. Se, mihin perheeseen metodi kuuluu, kertoo sovellukselle mitä kutsulta odottaa: säilyvätkö lähteen pikselit ehjinä, varataanko erillinen tuloskuva, ja onko paluuarvo itse lähde vai jokin muu.