5.9. Aritmetikai műveletek

Az előző szakaszban tárgyalt rajzolási család bele fest egy képbe. Az aritmetikai család két képet egy harmadikba egyesít – összeadja a képpontértékeiket, kivonja egyiket a másikból, minden pozíción a minimumot vagy a maximumot veszi. A képpontonkénti aritmetikai műveletek e kis halmazára épül a képkocka-különbségképzés, a háttérkivonás, az expozíció-rétegzés és néhány további klasszikus minta.

Az aritmetikai család az Image osztályon elég kicsi ahhoz, hogy egyszerre felsoroljuk:

  • add() – képpontonkénti self + other, a formátum maximumára csonkítva.

  • sub() – képpontonkénti self - other, alul 0 értékre csonkítva.

  • rsub() – képpontonkénti other - self, 0 értékre csonkítva (ugyanaz az aritmetika, mint a sub, csak az operandusok felcserélve).

  • min() – a két érték képpontonkénti minimuma.

  • max() – képpontonkénti maximum.

  • difference() – képpontonkénti |self - other|, az abszolút különbség.

Plusz két kapcsolódó egyképes művelet:

  • invert() – minden képpont lecserélése 255 - pixel értékre (vagy a formátumnak megfelelő maximumra).

  • negate() – az invert() álneve.

Felül két vízszintes gradienssáv, amelyek az A és B forrásképet képviselik -- az A balról jobbra sötéttől világosig, a B balról jobbra világostól sötétig halad. Alattuk öt gradienssáv, amelyek az A-ra és B-re alkalmazott egyes páronkénti műveletek eredményét képviselik: az A.add(B) egyenletesen fehérnek tűnik, mert minden pozíció 255 fölé összegződik és csonkolódik; az A.sub(B) a bal felén nulla, és jobb felé világosodik; az A.difference(B) V alakot mutat, mindkét végén világos, középen sötét; az A.min(B) a végeken sötét, középen világosabb; az A.max(B) a végeken világos, középen szürke.

Két forrásgradiens, A és B, valamint az egyes páronkénti műveletek rájuk alkalmazott eredménye. Minden művelet pozícióról pozícióra fut – ami az eredményben bármely helyen megjelenik, az kizárólag az adott helyen lévő két forrásképponttól függ.

5.9.1. Két operandusforma

A két képet kezelő metódusok mindegyike a második operandusához az alábbi formák bármelyikét elfogadja:

  • Egy másik, azonos méretű Image. Az aritmetika pozícióról pozícióra fut – az eredmény az (x, y) pozíción a mindkét kép (x, y) pozícióján lévő forrásképpontokra alkalmazott művelet.

  • Egy skaláris érték – egész szám szürkeárnyalatos esetén, (r, g, b) tuple RGB565 esetén. Ugyanaz a skalár alkalmazódik minden pozíción.

A skaláris forma akkor hasznos, ha az alkalmazás minden képpontot egy állandó értékkel akar eltolni. Az img.add(40) az egész képet 40-nel világosítja; az img.sub((20, 20, 20)) minden képpontot 20-szal sötétít csatornánként; az img.max(50) minden 50 alatti képpontot 50-re emel, a többit pedig békén hagyja – ez az a fajta művelet, amely a közel feketének mutatkozó érzékelőalapot lapos sötétszürkévé alakítja, hogy a következő szakaszok dolgozhassanak vele.

5.9.2. Csonkolás

A képpontértékek minden műveletben a formátum tartományán belül maradnak. Egy 8 bites csatornánál ez 0255 jelent: bármi, ami 255 fölé csordult volna túl, vissza lesz csonkítva 255 értékre, és bármi, ami 0 alá ment volna, fel lesz csonkítva 0 értékre. Nincs átfordulás.

Ez a választás a gyakorlatban számít. Az add által világosított képpontok soha nem hoznak létre hirtelen sötétedési műterméket a világos végen, ahol egyébként a matematika túlcsordulna; a sub által sötétített képpontok soha nem hoznak létre hirtelen világosodási műterméket a sötét végen, ahol egyébként alulcsordulna. Az eredmények vizuálisan értelmesek maradnak némi információveszteség árán a telített szélsőértékeknél.

A csonkolás miatt is adnak vissza a sub és az rsub egymástól eltérő eredményt. Az img_a.sub(img_b) az a azon részét adja, amely világosabb, mint a b, és nullát mindenhol máshol; az img_a.rsub(img_b) a b azon részét adja, amely világosabb, mint az a. Mindkettő hasznos egyoldalú változásészleléshez – ha az alkalmazás csak a világosodott képpontokkal törődik, vagy csak a sötétedett képpontokkal –, de egyik sem ragadja meg a két képkocka közötti összes változást.

5.9.3. A különbségművelet

A kétoldalú változásészleléshez a használandó művelet a difference(), amely minden pozíción a |self - other| értéket számítja – az abszolút, előjel nélküli különbséget. Minden olyan képpont, amely bármelyik irányban megváltozott, nem nulla értékként jelenik meg az eredményben, az adott pozíción a változás mértékével arányos nagysággal.

Ez a tulajdonság – pontosan ott nem nulla, ahol a két kép eltér – teszi a difference műveletet a képkockáról képkockára történő változásészlelés igavonójává. Egy indításkor eltárolt referencia-képkocka és egy friss felvétel, a difference műveleten átfuttatva, olyan képet eredményez, amelynek nem nulla képpontjai minden olyan pozíciót megjelölnek, ahol a jelenetben valami megmozdult vagy megváltozott a fényessége.

5.9.4. Hatókörözés maszkkal

Az összes aritmetikai metódus elfogadja a régiók és maszkok oldalon bevezetett mask kulcsszavas argumentumot. Ha maszkot adunk át, a művelet csak azokon a pozíciókon fut, ahol a maszk nem nulla; mindenhol máshol a célkép érintetlen marad.

Ez az összeállítás két mintában jelenik meg. Az első egy művelet korlátozása egy ismert területre: például két képkocka összeadása csak egy észlelt jelölő határoló dobozán belül. A második egy összetett képkocka darabonkénti felépítésemin egy képkockasorozat felett egy előtér-maszkon belül, max ugyanazon sorozat felett a kiegészítő maszkon belül – ez a fajta minta.

5.9.5. Helyben, a bemenetek megőrzésével

Az aritmetikai metódusok mindegyike a korábban kialakított működési konvenciót követi: mindegyik helyben módosítja a forrásképet, és ugyanazt a képet adja vissza a láncoláshoz. A forrás képpontjai eltűnnek a hívás után – lecserélődnek a műveletnek a második operandusként átadottal szembeni eredményével.

Amikor az alkalmazásnak mindkét bemenetet meg kell őriznie, a biztonságos minta az, hogy az egyiket előbb lemásolja:

diff = current.copy()       # leaves current intact
diff.difference(reference)  # diff now holds the absolute difference

Ez a minta – másolás, majd művelet – a gerince bármely képkocka-különbségképzési láncnak, ahol a referencia-képkockának túl kell élnie az összehasonlítást, hogy a következő rögzített képkockán újra felhasználható legyen.

Hat kombináló művelettel, két egyképes művelettel, egy abszolút-különbség igavonóval és a hatókörözéshez használt mask kulcsszóval a képpont-aritmetikai eszköztár lefedi a fényesség- és csatornakombinációkat, amelyekre a klasszikus gépi látásnak szüksége van. A felszínen maradó aritmetikaszerű eszközök bitenként, nem pedig értékenként működnek.