5.3. Pikseliformaatit¶
Reunoja tunnistava algoritmi olettaa, että jokainen pikseli sisältää kirkkausarvon. Värillistä kohdetta seuraava algoritmi olettaa, että jokainen pikseli kantaa väriä. Morfologista sulkemista suorittava algoritmi olettaa, että jokainen pikseli on joko päällä tai pois. Image-objektin kantama pikseliformaatti – yksi luetelluista Vision Sensors -formaateista – tekee näistä olettamuksista etukäteen tarkistettavia: formaatti kertoo ennalta, missä muodossa pikselit ovat ja mitkä algoritmit voivat siten ajaa niillä ilman muunnosvaihetta.
Tämä sivu käsittelee sitä, miten tuo rajoite ilmenee käytännössä. Oikea formaatti riippuu siitä, mitä putki aikoo tehdä, ja formaattien väliset muunnosmenetelmät ovat se, miten useampaa kuin yhtä formaattia tarvitseva putki ketjuttaa vaiheet yhteen.
Viisi pakkaamatonta pikseliformaattia ja se, miten niiden tavut pakkautuvat. JPEG ja PNG eivät ole tässä piirrettyinä, koska ne ovat vaihtuvanpituisia pakattuja virtoja eivätkä kiinteäkokoisia pikseliruudukkoja.¶
5.3.1. Harmaasävyn työjuhta¶
Suurin osa klassisesta konenäöstä tiivistyy kirkkausarvojen käsittelyyn. Reunantunnistus, mallin sovitus, AprilTag-dekoodaus, optisen virtauksen arviointi, morfologiset operaattorit, blob-analyysi – ne kaikki tarkastelevat sillä tasolla, jolla algoritmit toimivat, sitä kuinka kirkas kukin pikseli on ja miten kirkkaus vertautuu lähellä olevien pikselien kirkkauteen. Näkymän väri on usein hyödyllinen niitä kutsuvalle sovellukselle, mutta algoritmit itse eivät sitä tarvitse.
Harmaasävyformaatti antaa algoritmeille juuri sen ilman ylimääräistä kuormaa. Yksi tavu per pikseli sisältää kirkkausarvon väliltä 0 (musta) ja 255 (valkoinen). Formaatti on puolet RGB565:n ja YUV422:n koosta ja kolmasosa RGB888:n koosta, joten jokainen operaatio käy läpi vähemmän dataa – sekä nopeammin että pienemmällä puskurikuormalla. Pienemmillä kameroilla, joilla kehyspuskuri kilpailee muun skriptin kanssa RAM-muistista, tuo jalanjäljen ero voi ratkaista, mahtuuko putki ylipäätään. Jos väri ei ole vihje, jota algoritmi tarvitsee, harmaasävy on oikea vastaus.
5.3.2. Väri RGB565:n kautta¶
Kun väri on vihje – värillisen merkin seuraaminen, punaisten omenoiden erottaminen vihreistä, käyttöliittymäelementin poimiminen sen sävyn perusteella – kaksi tavua per pikseli ostaa riittävästi väriä algoritmien suorittamia luokitteluja varten. RGB565 on kameran oletusväriformaatti ja se, jota värin huomioon ottavat menetelmät rajapinnalla odottavat.
Selitetyn kehyksen renderöinti – tunnistuslaatikoiden piirtäminen, diagnostiikkatekstin kirjoittaminen, kehyksen saaminen näytölle tai etäkatselijalle – vaatii myös luonnostaan RGB565:tä. IDE:n esikatselu, kortin näytönohjaimet ja useimmat verkkokohteet joko käyttävät formaattia suoraan tai muuntavat siitä edullisesti.
5.3.3. Bayer tallennusformaattina¶
Bayer-kuva on sensorin raakatuloste ennen kuin ISP debayeroi sen valmiiksi väriesitykseksi. Jokainen pikseli on yksi tavu, joka sisältää yhden värikanavan – sen, jonka kyseisessä kohdassa mosaiikkia oleva värisuodin päästi läpi. Tämä tekee Bayer-kuvasta saman kokoisen kuin harmaasävykuva ja kolmasosan RGB888:n koosta, mikä sopii siihen, mihin Bayer todella on hyödyllinen: monen kehyksen tallentamiseen kerralla, kun RAM on rajoittava tekijä.
Mutta algoritmit image-moduulissa eivät toimi Bayer-kuvilla suoraan. Ilman debayerointia mikään pikseli ei kanna riittävästi tietoa tehdäkseen väripäätelmän yksinään, ja kuviot, joita algoritmit etsivät – reunat, kulmat, blobit – vääristyisivät mosaiikin vuoksi. Ainoat tavat lukea tai muokata Bayer-kuvaa ovat get_pixel() ja set_pixel(); kaikki muu odottaa valmista esitystä.
Tästä seuraava kaava on tallentaa kehykset Bayer-muodossa niin kauan kuin niiden täytyy odottaa jonossa ja muuntaa kukin joko harmaasävyksi tai RGB565:ksi sillä hetkellä, kun sen käsittely todella alkaa. Muunnos maksaa CPU-syklejä mutta säästää sen RAM-muistin, joka muuten varattaisiin valmiiden kehysten säilyttämiseen koko sovelluksen eliniäksi.
Muista
image-moduulin ainoat operaatiot Bayer-pikseleihin suoraan ovat get_pixel(), set_pixel() ja JPEG-koodauspolku, joka syöttää IDE:n esikatselun tai etäkatselijan. Piirtäminen, analyysi ja suodatus vaativat kaikki ensin muunnoksen harmaasävyksi, RGB565:ksi tai binääriksi.
5.3.4. YUV422 putkille, jotka haluavat molemmat¶
YUV422 erottaa kunkin pikselin tiedon luminanssikanavaksi (Y) ja kahdeksi krominanssikanavaksi (U ja V) ja näytteistää krominanssia harvemmin niin, että vierekkäiset pikseliparit jakavat yhden U:n ja yhden V:n. Tavut per pikseli ovat keskimäärin kaksi – sama kuin RGB565 – mutta ne on aseteltu niin, että Y-kanava on jo jatkuva 8-bittinen harmaasävykuva tunnetuissa kohdissa puskurissa.
Tuo asettelu on juuri sitä, mitä putki haluaa, kun osa sen vaiheista on harmaasävytyötä ja osa tarvitsee väriä. Y-arvojen lukeminen suoraan harmaasävyvaiheita varten ohittaa eksplisiittisen muunnoksen kustannuksen; U- ja V-kanavat ovat saatavilla, kun myöhempi vaihe todella tarvitsee väriä. Tuon tietyn kaavan ulkopuolella RGB565 on yleensä yksinkertaisempi valinta värille ja harmaasävy yksinkertaisempi valinta pelkkää kirkkautta koskevaan työhön – YUV422:n arvo tulee siitä, että se on hyvä molemmissa samaan aikaan.
Muista
image-moduuli toimii YUV422:lla rajatummin kuin harmaasävyllä, RGB565:llä tai binäärillä – suorat Y-kanavan luvut harmaasävytyötä varten ja JPEG-koodauspolku, joka syöttää IDE:n esikatselun tai etäkatselijan. Värin huomioon ottavat menetelmät odottavat RGB565:tä; YUV422-kehykset tarvitsevat eksplisiittisen muunnoksen ennen värianalyysiä tai piirtämistä.
5.3.5. Binääri, maskit ja kynnystetty tuloste¶
Binäärikuva on yksi bitti per pikseli: jokainen pikseli on joko 0 tai 1. Formaatti esiintyy harvoin sensorin sieppauksena; sen sijaan se ilmenee kynnystyksen luonnollisena tulosteena (jossa väri- tai kirkkaustesti luokittelee kunkin pikselin joko ”kyllä, vastaa” tai ”ei, ei vastaa”) sekä morfologisten operaatioiden ja monien menetelmien hyväksymän mask-argumentin luonnollisena syötteenä.
Formaatin käytännön etu on sen koko. Binäärikuva on kahdeksasosa harmaasävykuvan jalanjäljestä, joten suuren maskin kantaminen mukana – pikselikohtainen valinta siitä, mihin kohtiin jokin myöhempi operaatio koskee – on edullista. Se, että monet operaatiot hyväksyvät binäärikuvan mask=-avainsana-argumenttina, on saman asian toinen puoli: formaatti on pieni, ja yhden vaiheen binääritulosteen ketjuttaminen toisen maskisyötteeksi on yleinen putkikaava.
5.3.6. JPEG ja PNG rajalla¶
JPEG- ja PNG-tyyppiset Image-objektit eroavat muista valikoimassa. Ne eivät ole pikseliruudukoita; ne ovat pakattuja tavuvirtoja, jotka koodaavat pikselidataa muotoon, jota pikselitason operaatiot eivät voi lukea. get_pixel()-kutsu JPEG:lle ei palauta kohdassa olevaa pikseliä; pikseli ei ole purettuna missään puskurissa menetelmän haettavaksi.
JPEG ja PNG esiintyvät kuvankäsittelyn rajalla, jossa pikselidata poistuu kamerasta tai saapuu siihen pakatussa muodossa. Kehyksen tallentaminen levylle JPEG-muodossa pitää tiedoston pienenä; kehyksen lähettäminen verkon yli JPEG-muodossa pitää siirron edullisena; viitekehyksen lataaminen JPEG-tiedostosta antaa sen olla levyllä paljon pienemmässä muodossa kuin raakapikselit olisivat. Mihin tahansa näistä käyttötapauksista pakattu esitys on oikea vastaus. Mutta jotta JPEG:lle voi tehdä mitään varsinaista käsittelyä, sovellus muuntaa sen ensin käyttökelpoiseen muotoon – ja tuossa muunnoksessa pakatut tavut laajenevat pikseleiksi ja puskurin paisuminen (30 KB:n JPEG voi muuttua 600 KB:n RGB565:ksi) todella tapahtuu.
5.3.7. Muunto formaattien välillä¶
Muunnospolku on se, joka ompelee eri formaatit yhdeksi putkeksi. Viisi Image-luokan menetelmää ottaa olemassa olevan kuvan ja palauttaa uuden eri formaatissa:
to_grayscale()tuottaa yhden tavun per pikseli -kuvan, formaatin jota klassiset algoritmit haluavat.to_rgb565()tuottaa kahden tavun per pikseli -väriformaatin, jota sekä värin huomioon ottavat menetelmät että IDE:n esikatselu puhuvat.to_bitmap()tuottaa yhden bitin binäärikuvan, formaatin jonka morfologia jamask-argumentit hyväksyvät.to_jpeg()tuottaa JPEG-pakatun kuvan, joka soveltuu tallennukseen tai siirtoon.to_png()tuottaa PNG-pakatun kuvan, kun häviötön koodaus on parempi kuin JPEG:n pienemmät tiedostot.
Jokainen muunnos suoritetaan oletuksena paikallaan: lähdekuvan puskuri ylikirjoitetaan muunnetulla tuloksella, ja lähteen alkuperäiset pikselit ovat poissa kutsun palattua. Se on edullisin vaihtoehto sekä CPU:n että muistin kannalta, ja se on oikea vastaus, kun lähdekehystä ei tarvita mihinkään muuhun.
Kun lähdettä yhä tarvitaan – kun putken myöhemmän vaiheen täytyy nähdä alkuperäinen kehys – kaksi avainsana-argumenttia ohittaa paikallaan-oletuksen. copy=True varaa erillisen puskurin muunnetulle kuvalle Python-keosta ja jättää lähteen ennalleen. copy_to_fb=True tekee saman varauksen mutta sijoittaa sen kehyspuskuriin keon sijaan – mihin sovellus tarttuu, kun muunnetun kuvan täytyy päätyä IDE:n esikatseluun, koska IDE lukee kehyspuskurista.
Kaksi muuta menetelmää tuottaa RGB565-kuvia, jotka on väritetty paletin kautta suoran muunnoksen sijaan. to_rainbow() kuvaa kunkin yksikanavaisen syöttöarvon väriksi pitkin sileää gradienttia, joka kulkee näkyvän spektrin läpi. to_ironbow() kuvaa kunkin syöttöarvon epälineaariseksi lämpökuvaimen paletiksi, joka kulkee mustasta tummien punaisten ja oranssien kautta valkoiseen. Molemmat ovat visualisointityökaluja eivätkä mittaustyökaluja; tarkoitus on tehdä yksikanavaisesta kuvasta, jonka raaka-arvot olisivat muuten silmälle näkymättömiä, yhdellä silmäyksellä luettava.
5.3.8. Puskurin koko¶
Vielä yksi formaatteja koskeva yksityiskohta, joka on syytä sanoa ääneen. size() raportoi aina tavupuskurin koon, ei pikselien määrää. Pakkaamattomille formaateille se seuraa suoraan mitoista ja tavuista per pikseli: width * height * bytes_per_pixel. JPEG:lle ja PNG:lle se on pakatun virran koko, joka vaihtelee kehyksestä toiseen riippuen siitä, mitä näkymä sisältää. Koodi, joka varaa puskureita tavubudjeteista, käyttää size()-menetelmää ensimmäiseen tapaukseen; koodi, joka virtauttaa pakattuja kehyksiä kamerasta ulos, lukee sen jokaisen pakkauksen jälkeen tietääkseen, kuinka monta tavua virta todella sisältää.