5.5. Területek és maszkok

Az image modul minden művelete alapértelmezés szerint a forráskép minden képpontját érinti. Ez a legegyszerűbben leírható viselkedés, és akkor a megfelelő, amikor az algoritmus feladata valóban a teljes képkockára terjed ki – egyenletes színkorrekció, globális hisztogram vagy egy átvitelre szánt kódolási menet. A gyakorlatban azonban a legtöbb algoritmus ennél kevesebbet szeretne megvizsgálni. Egy színes jelölőt figyelő foltkövető a jelenetnek azt a részét tekinti fontosnak, ahol a jelölő megjelenhet, nem pedig a mögötte lévő falat. Egy morfológiai tisztító menet csak azokon a képpontokon biztonságos, amelyeket egy korábbi szakasz jelöltként jelölt meg. Egy arcdetektor csak azon a határoló dobozon belül futhat, amelyet egy durvább detektor már leszűkített. Az image modul két mechanizmussal támogatja ezt a munkát, amelyek egy műveletet a képpontok egy részhalmazára szűkítenek: téglalap alakú érdeklődési területekkel és bináris maszkokkal. Ezek szabadon kombinálhatók, és szinte minden képpontokat érintő metódus elfogadja az egyiket vagy a másikat – vagy mindkettőt – kulcsszó argumentumként.

5.5.1. Érdeklődési területek

Az érdeklődési terület képpontok téglalapja, amelyet a koordináták oldalon bemutatott (x, y, w, h) négyes nevez meg. A felületen körülbelül harminc metódus fogad el egy roi kulcsszó argumentumot; ha jelen van, a művelet csak az adott téglalapon belüli képpontokon fut le, a kép többi részét érintetlenül hagyja. Ha a roi értéke None vagy hiányzik, a művelet a teljes képen fut le – ugyanúgy, mintha roi=(0, 0, width, height) lett volna átadva.

A kódban a kulcsszó a művelet bármely más argumentuma mellett szerepel:

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

Az ROI-k első előnye a téves találatok elleni védelem. Egy színkövető, amely csak az asztalt figyeli, soha nem fog kioldani az elsétáló ingre; egy éldetektor, amely csak a meghatározott munkaterületen belül fut, soha nem fogja jelenteni magának a kameratartónak az éleit. A keresési terület leszűkítése a jelenetnek arra a részére, amely az algoritmust valóban érdekli, a legolcsóbb fejlesztés, amelyet egy feldolgozási lánc a saját megbízhatóságán végezhet.

A második előny a durvától finomig haladó feldolgozási lánc. Az észlelési eredményobjektumok – egy blob, egy rect, egy apriltag és így tovább – ugyanazzal a (x, y, w, h) négyessel teszik elérhetővé a határoló dobozaikat, amelyet a roi is elfogad. Így egy durva első szakasz visszaadhat egy határoló dobozt, a doboz közvetlenül a következő szakasz roi paraméterébe kerül, és a második szakasz a szűkebb területen fut le. Minden fokozatos szűkítés egyszerre gyorsítja fel a következő szakaszt, és teszi megbízhatóbbá az eredményeit, mert a keresési teret már megszűrte.

5.5.2. Bináris maszkok

A téglalap a megfelelő forma, amikor az érdeklődési terület a tengelyekhez igazodik. Amikor nem – egy görbe vonalú terület, egy nem konvex alakzat, vagy azok a képpontok, amelyeket egy korábbi szakasz „találatként” osztályozott –, akkor a műveletnek meg kell mondani, hogy egy tetszőleges képpontmintázatra szűkítse magát. Ennek mechanizmusa a bináris maszk: egy külön Image, amely a forrással azonos méretű, és képpontonkénti be/ki kapcsolóként használatos. A maszk nem nulla képpontja azt jelenti, hogy „vedd figyelembe a megfelelő forrásképpontot”; a nulla képpont azt jelenti, hogy „hagyd békén a forrásképpontot”.

A maszk általában egy BINARY kép – a képpontonként egy bites formátum, amely pontosan erre a célra létezik –, de bármely egycsatornás kép működni fog, mert a felhasználó minden nem nulla értéket bekapcsoltként kezel.

A szűrő, küszöbölő és aritmetikai metódusok elfogadnak egy mask kulcsszó argumentumot. A forma mindegyiknél azonos: egy külön lefoglalt, a forrással azonos méretű bináris kép, amelyet átadunk.

Az ROI-k és a maszkok kombinálódnak. Add át mindkettőt, és a művelet csak azokon a képpontokon fut le, amelyek az ROI-n belül vannak és be vannak kapcsolva a maszkban. A két mechanizmus független vezérlőkart ad az alkalmazás kódjának – egyet a téglalap alakú érdeklődési területhez, egyet a benne lévő tetszőleges mintázathoz –, anélkül, hogy bármelyik forma örökölné a másik megkötéseit.

Egy képet ábrázoló kis rács. Egy szaggatott vonalú téglalap, amely a rács felső-középső részén húzódik, jelöli az ROI-t: csak az ezen a téglalapon belüli képpontok jönnek számításba. Az ROI-n belül egy nagyjából kör alakú kitöltött cellahalmaz jelöli a maszkot: csak ezek a kitöltött cellák módosulnak ténylegesen. A többi cella halványan árnyékolt, jelezve, hogy érintetlenek.

Egy ROI egy tengelyekhez igazodó téglalapra korlátozza a műveletet. Egy maszk tovább szűkíti azt egy tetszőleges képpontmintázatra. A kettő kombinálódik: csak az ROI-n belüli és a maszkban bekapcsolt képpontok módosulnak.

5.5.3. Maszkok építése

Három Image metódus épít fel gyakori maszkgeometriákat helyben azáltal, hogy a kiválasztott területen kívüli képpontokat nullázza:

Mindegyik egy (x, y, w, h) (a téglalaphoz és az ellipszishez) vagy egy (x, y, radius) (a körhöz) értéket vesz át. Bármelyikük argumentumok nélküli meghívása középre helyezi a geometriát, és úgy méretezi, hogy kitöltse a képet; ezt a formát akkor használja egy alkalmazás, amikor a cél egy egyszerű, teljes képet kitöltő ovális vagy kör, amely csak a sarkokat takarja el.

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

Az érdekes maszkok ritkán származnak önmagukban a mask_* metódusokból. A feldolgozási lánc korábbi szakaszaiból jönnek: egy küszöbölő menet egy olyan bináris képet állít elő, amelynek nem nulla képpontjai jelölik a találatokat, pontosan a megfelelő formát ahhoz, hogy a következő szakasz mask= argumentumába kerüljön. Egy morfológiai tisztító menet finomítja ezt a maszkot a formájának megváltoztatása nélkül. Bármi, ami egycsatornás képként végzi, önmagában érvényes maszk.

5.5.4. Hogyan módosítják a műveletek a képet

Az utóbbi néhány oldal minden kódrészletében látható mintázat – a művelet ugyanazt az img objektumot adja vissza a láncoláshoz – érdemes kifejezetten kiemelni, hogy ne kelljen újra meg újra megismételni, valahányszor egy új metódus kerül bemutatásra. Három metóduscsalád jelenik meg az Image felületén, amelyek mindegyike másképp kezeli a forrásképet:

  • A műveleti metódusok helyben módosítják a forrás képpontjait, és ugyanazt a képet adják vissza a láncoláshoz. A rajzolási, aritmetikai, küszöbölő és szűrő családok mind így viselkednek. Az img.gaussian(1) elmosja az img képet, és ugyanazt az img objektumot adja vissza; az újraértékadás – img = img.gaussian(1) – ártalmatlan, de szükségtelen.

  • A konverziós metódusok alapértelmezés szerint ugyanúgy helyben működnek, mint a műveleti metódusok, de elfogadják a copy=True és copy_to_fb=True paramétereket, hogy külön eredményképet foglaljanak le, amikor a forrást meg kell őrizni. A formátumkonverziók és a geometriai másolatok ennek a családnak a fő tagjai.

  • A vizsgálati metódusok beolvassák a képpontokat, és egy eredményobjektumot adnak vissza – egy észlelt jellemzők listáját, egy hisztogramot, egy statisztikahalmazt – anélkül, hogy egyáltalán módosítanák a forrásképet.

Ez a hármas felosztás az egész felületen következetes. Annak ismerete, hogy egy metódus melyik családhoz tartozik, megmondja az alkalmazásnak, mire számíthat egy hívástól: vajon a forrás képpontjai épségben maradnak-e, vajon külön eredménykép kerül-e lefoglalásra, és vajon a visszatérési érték maga a forrás vagy valami más.