5.3. Képpontformátumok

Egy éldetektáló algoritmus azt várja, hogy minden képpont egy fényességi értéket tároljon. Egy színes objektumot követő algoritmus azt várja, hogy minden képpont színt hordozzon. Egy morfológiai zárást végző algoritmus azt várja, hogy minden képpont vagy bekapcsolt, vagy kikapcsolt legyen. A képpontformátum, amelyet egy Image hordoz – a katalógusban felsorolt Vision Sensors egyike –, az, ami ezeket az elvárásokat előre ellenőrizhetővé teszi: a formátum már előre megmondja, hogy milyen formában vannak a képpontok, és ennélfogva mely algoritmusok futtathatók rajtuk konverziós lépés nélkül.

Ez az oldal arról szól, hogy ez a megkötés hogyan érvényesül a gyakorlatban. Hogy melyik formátum a helyes választás, az attól függ, hogy mit fog csinálni a feldolgozási lánc, a formátumok közötti konverziós módszerek pedig azt teszik lehetővé, hogy egy egynél több formátumot igénylő lánc egymáshoz fűzze a szakaszokat.

Öt feliratozott bájtelrendezési sáv függőleges egymásra rakása. A BINARY egy bájtot mutat nyolc egybites cellára osztva, "8 képpont bájtonként" felirattal. A GRAYSCALE három feliratozott egybájtos cellát mutat, mindegyik "1 képpont" felirattal. Az RGB565 két egymás melletti bájtot mutat RRRRR GGGGGG BBBBB bitmezőkkel, "1 képpont" felirattal. A YUV422 négy feliratozott bájtcellát mutat: Y0, U, Y1, V, "2 képpont" felirattal. A BAYER két, négy-négy feliratozott bájtcellából álló sort mutat: R G R G a felső sorban, G B G B az alsó sorban.

Az öt tömörítetlen képpontformátum, és az, ahogyan a bájtjaik pakolódnak. A JPEG és a PNG itt nem szerepel, mert ezek változó hosszúságú tömörített adatfolyamok, nem pedig fix méretű képpontrácsok.

5.3.1. A szürkeárnyalatos igásló

A klasszikus gépi látás nagy része a fényességi értékekkel való munkára vezethető vissza. Az éldetektálás, a sablonillesztés, az AprilTag-dekódolás, az optikai áramlás becslése, a morfológiai operátorok, a foltelemzés – mindegyik azon a szinten, ahol az algoritmusok működnek, azt vizsgálja, hogy mennyire fényes az egyes képpontok, és hogyan viszonyul ez a fényesség a közeli képpontok fényességéhez. A jelenet színe gyakran hasznos a hívó alkalmazás számára, de maguknak az algoritmusoknak nincs rá szükségük.

A szürkeárnyalatos formátum pontosan ezt adja át az algoritmusoknak, mindenféle többletköltség nélkül. Egy bájt képpontonként egy 0 (fekete) és 255 (fehér) közötti fényességi értéket tárol. A formátum fele akkora, mint az RGB565 és a YUV422, és harmada az RGB888 méretének, így minden művelet kevesebb adaton fut keresztül – gyorsabban és kisebb pufferterheléssel. A kisebb kamerákon, ahol a képkocka-puffer a szkript többi részével versenyez a RAM-ért, ez a helyigénybeli különbség akár azt is eldöntheti, hogy egy feldolgozási lánc egyáltalán elfér-e. Ha a szín nem az a támpont, amelyre az algoritmusnak szüksége van, akkor a szürkeárnyalatos a helyes válasz.

5.3.2. Szín az RGB565-ön keresztül

Amikor a szín az a támpont – színes jelölő követése, piros almák megkülönböztetése a zöldektől, egy felhasználói felületi elem kiválasztása a színárnyalata alapján –, akkor a képpontonkénti két bájt elegendő színt vásárol az algoritmusok által végzett osztályozásokhoz. Az RGB565 az alapértelmezett színformátum a kamerán, és ezt várják a felületen lévő, színekkel dolgozó módszerek is.

Egy annotált képkocka megjelenítése – észlelési dobozok rajzolása, diagnosztikai szöveg írása, a képkocka képernyőre vagy távoli megjelenítőhöz juttatása – szintén természetes módon RGB565-öt igényel. Az IDE előnézet, a fedélzeti kijelzővezérlők és a legtöbb hálózati célállomás vagy közvetlenül fogyasztja ezt a formátumot, vagy olcsón konvertál belőle.

5.3.3. A Bayer mint tárolási formátum

Egy Bayer kép a nyers érzékelőkimenet, mielőtt az ISP debayerelte volna egy kész színábrázolássá. Minden képpont egy bájt, amely egyetlen színcsatornát tárol – azt, amelyet a mozaik adott pozíciójában lévő színszűrő átengedett. Ez egy Bayer képet ugyanakkorává tesz, mint egy szürkeárnyalatos kép, és harmadakkorává, mint az RGB888, ami megfelel annak, amire a Bayer valójában hasznos: sok képkocka egyidejű tárolására, amikor a RAM a szűk keresztmetszet.

A bökkenő az, hogy az image modul algoritmusai nem közvetlenül a Bayer képeken dolgoznak. Debayerelés nélkül egyetlen képpont sem hordoz elegendő információt ahhoz, hogy önmagában színt ítéljen meg, és azokat a mintázatokat, amelyeket az algoritmusok keresnek – élek, sarkok, foltok –, eltorzítaná a mozaik. Egy Bayer kép olvasásának vagy módosításának egyetlen módja a get_pixel() és a set_pixel(); minden más kész ábrázolást vár.

Az ebből adódó mintázat az, hogy a képkockákat Bayer formátumban tároljuk addig, amíg várakozniuk kell egy sorban, és mindegyiket akkor konvertáljuk szürkeárnyalatossá vagy RGB565-té, amikor a feldolgozása ténylegesen elkezdődik. A konverzió CPU-ciklusokba kerül, de megtakarítja azt a RAM-ot, amelyet egyébként a kész képkockák tárolása kötne le az alkalmazás teljes élettartamára.

Megjegyzés

Az image modul egyetlen közvetlen művelete Bayer képpontokon a get_pixel(), a set_pixel(), valamint a JPEG-kódolási útvonal, amely az IDE előnézetet vagy egy távoli megjelenítőt táplálja. A rajzolás, az elemzés és a szűrés mind előbb szürkeárnyalatossá, RGB565-té vagy binárissá konvertálást igényel.

5.3.4. YUV422 a mindkettőt igénylő feldolgozási láncokhoz

A YUV422 az egyes képpontok információját egy luminanciacsatornára (Y) és két krominanciacsatornára (U és V) bontja szét, és úgy alulmintázza a krominanciát, hogy a szomszédos képpontpárok közösen használnak egyetlen U-t és egyetlen V-t. A képpontonkénti bájtok átlaga kettő – ugyanannyi, mint az RGB565 esetében –, de úgy vannak elrendezve, hogy az Y csatorna már eleve egy folytonos 8 bites szürkeárnyalatos kép, amely a pufferben ismert eltolásoknál helyezkedik el.

Ez az elrendezés pontosan az, amit egy feldolgozási lánc szeretne, amikor egyes szakaszai szürkeárnyalatos munkát végeznek, mások pedig színt igényelnek. Az Y értékek közvetlen olvasása a szürkeárnyalatos szakaszokhoz elkerüli egy explicit konverzió költségét; az U és V csatornák ott vannak, amikor egy későbbi szakasznak ténylegesen színre van szüksége. Ezen a konkrét mintázaton kívül az RGB565 általában az egyszerűbb választás a színhez, a szürkeárnyalatos pedig az egyszerűbb választás a csak fényességgel foglalkozó munkához – a YUV422 értéke abból fakad, hogy egyszerre jó mindkettőben.

Megjegyzés

Az image modul korlátozottabb módon dolgozik a YUV422-n, mint a szürkeárnyalatoson, az RGB565-ön vagy a bináris formátumon – közvetlen Y-csatorna-olvasások a szürkeárnyalatos munkához, valamint a JPEG-kódolási útvonal, amely az IDE előnézetet vagy egy távoli megjelenítőt táplál. A színekkel dolgozó módszerek RGB565-öt várnak; a YUV422 képkockák explicit konverziót igényelnek a színelemzés vagy a rajzolás előtt.

5.3.5. Bináris, maszkok és küszöbözött kimenet

Egy bináris kép képpontonként egy bit: minden képpont vagy 0, vagy 1. A formátum ritkán jelenik meg érzékelőfelvételként; ehelyett a küszöbözés természetes kimeneteként jelenik meg (ahol egy szín- vagy fényességteszt minden képpontot „igen, illeszkedik” vagy „nem, nem illeszkedik” besorolásba sorol), valamint a morfológiai műveletek és a sok módszer által elfogadott mask argumentum természetes bemeneteként.

A formátum gyakorlati előnye a mérete. Egy bináris kép egy szürkeárnyalatos kép helyigényének nyolcada, így egy nagy maszk magunkkal hordozása – annak képpontonkénti megválasztása, hogy egy későbbi művelet mely pozíciókat érintse – olcsó. Az, hogy sok művelet elfogad egy bináris képet mask= kulcsszó-argumentumként, ugyanennek a másik oldala: a formátum kicsi, és az egyik szakasz bináris kimenetének egy másik maszkbemenetébe láncolása gyakori feldolgozási mintázat.

5.3.6. JPEG és PNG a határon

A JPEG és PNG Image objektumok különböznek a katalógus többi elemétől. Ezek nem képpontrácsok; ezek tömörített bájtfolyamok, amelyek olyan formában kódolják a képpontadatokat, amelyet a képpontszintű műveletek nem tudnak olvasni. A get_pixel() hívása egy JPEG-en nem adja vissza az adott pozíción lévő képpontot; a képpont sehol nincs kicsomagolva a pufferben, ahonnan a módszer lehívhatná.

A JPEG és a PNG a képfeldolgozás határán jelenik meg, ahol a képpontadatok tömörített formában hagyják el vagy lépnek be a kamerába. Egy képkocka JPEG-ként lemezre mentése kicsiben tartja a fájlt; egy képkocka JPEG-ként hálózaton való elküldése olcsón tartja az átvitelt; egy referencia-képkocka JPEG-fájlból való betöltése lehetővé teszi, hogy az sokkal kisebb formában maradjon a lemezen, mint a nyers képpontok. Bármelyik ilyen felhasználási esetben a tömörített ábrázolás a helyes válasz. Ahhoz azonban, hogy bármilyen tényleges feldolgozást végezzünk egy JPEG-en, az alkalmazás előbb egy munkára alkalmas formátummá konvertálja – és ez a konverzió az, ahol a tömörített bájtok képpontokká bomlanak ki, és ahol a pufferfelfúvódás (egy 30 KB-os JPEG-ből 600 KB RGB565 lehet) ténylegesen bekövetkezik.

5.3.7. Konverzió formátumok között

A konverziós útvonal az, ami a különböző formátumokat egyetlen feldolgozási lánccá fűzi össze. Az Image osztály öt módszere fog egy meglévő képet, és egy újat ad vissza egy másik formátumban:

  • A to_grayscale() egy képpontonként egy bájtos képet állít elő, azt a formátumot, amelyet a klasszikus algoritmusok igényelnek.

  • A to_rgb565() a képpontonként két bájtos színformátumot állítja elő, amelyet mind a színekkel dolgozó módszerek, mind az IDE előnézet beszél.

  • A to_bitmap() egy egy bites bináris képet állít elő, azt a formátumot, amelyet a morfológia és a mask argumentumok elfogadnak.

  • A to_jpeg() egy JPEG-tömörített képet állít elő, amely mentésre vagy átvitelre alkalmas.

  • A to_png() egy PNG-tömörített képet állít elő, amikor a veszteségmentes kódolás előnyben részesül a JPEG kisebb fájljaival szemben.

Minden konverzió alapértelmezés szerint helyben fut: a forráskép pufferje felülíródik a konvertált eredménnyel, és a forrás eredeti képpontjai eltűnnek, miután a hívás visszatér. Ez a legolcsóbb lehetőség mind a CPU, mind a memória szempontjából, és ez a helyes válasz, amikor a forrás-képkockára nem lesz másra szükség.

Amikor a forrásra még mindig szükség van – amikor a feldolgozási lánc egy későbbi szakaszának látnia kell az eredeti képkockát –, két kulcsszó-argumentum felülbírálja a helyben végzett alapértelmezést. A copy=True egy külön puffert foglal a konvertált képnek a Python heap-en, és érintetlenül hagyja a forrást. A copy_to_fb=True ugyanazt a foglalást végzi, de a heap helyett a képkocka-pufferbe teszi – amihez egy alkalmazás akkor nyúl, amikor a konvertált képnek az IDE előnézetbe kell kerülnie, mivel az IDE a képkocka-pufferből olvas.

Két további módszer RGB565 képeket állít elő, amelyek egy paletta segítségével vannak színezve, nem pedig egyenes konverzióval. A to_rainbow() minden egycsatornás bemeneti értéket egy színhez rendel egy sima színátmenet mentén, amely végighalad a látható spektrumon. A to_ironbow() minden bemeneti értéket a nemlineáris hőkamera-palettához rendel, amely a feketétől a sötétvörösökön és narancsokon át a fehérig fut. Mindkettő inkább vizualizációs eszköz, mint mérési; a lényeg az, hogy egy egycsatornás képet, amelynek nyers értékei egyébként láthatatlanok lennének a szem számára, egy pillantással olvashatóvá tegyen.

5.3.8. Pufferméret

Egy utolsó, a formátumokkal kapcsolatos részlet, amelyet érdemes egyértelműsíteni. A size() mindig a bájtpuffer méretét jelenti, nem a képpontok számát. A tömörítetlen formátumoknál ez közvetlenül következik a méretekből és a képpontonkénti bájtokból: width * height * bytes_per_pixel. A JPEG és a PNG esetében ez a tömörített adatfolyam mérete, amely képkockáról képkockára változik attól függően, hogy mit tartalmaz a jelenet. Az a kód, amely bájtkeretekből foglal puffereket, az előbbi esetben a size() hívást használja; az a kód, amely tömörített képkockákat továbbít a kamerából, minden tömörítés után beolvassa, hogy megtudja, hány bájtot tartalmaz ténylegesen az adatfolyam.