Skip navigation

Aritmetikai és logikai műveletek

Numpy vs OpenCV aritmetika

Mind a Numpy, mind az OpenCV lehetőséget biztosít képek közötti aritmetikai és logikai műveletekre, mint például az összeadás, kivonás, szorzás. Ha az egyik kép helyett skalár értéket adunk meg, akkor minden képpontra egyenként fogja a skalárral való műveletet elvégezni.

Fontos! Nagy különbség van a Numpy és az OpenCV aritmetika között!

  • Numpy esetén alul- vagy túlcsorduláskor körkörös az értékváltás az értéktartományon belül. Például np.uint8 típus esetén 255 + 1 = 0.
  • Az OpenCV úgynevezett szaturált aritmetikát használ: túlcsorduláskor a maximális, alulcsorduláskor a minimális értéket adja! Az előző példa szerint itt 255 + 1 = 255.

Képmátrixok esetén ez utóbbi természetesebb látványt ad, emiatt célszerűbb az OpenCV függvények használata, még ha a Numpy szintaktikailag egyszerűbb is lenne.

Próbáljuk ki az alábbiakat:

nparr = np.array([0, 50, 100, 150, 200, 250], dtype=np.uint8)
print(nparr)

print(nparr + 100)
print(nparr - 100)

print(cv2.add(nparr, 100))
print(cv2.add(nparr, -100))

Az eredmények:

[ 0 50 100 150 200 250]
[100 150 200 250 44 94]
[156 206 0 50 100 150]
[[100]
[150]
[200]
[250]
[255]
[255]]
[[ 0]
[ 0]
[ 0]
[ 50]
[100]
[150]]

Megállapítások:

  • A Numpy a túlcsordulást és az alulcsordulást másként kezeli, mint az OpenCV!
  • Az OpenCV aritmetika Numpy-ban elérhető eredménye más felépítésű (shape), mint a Numpy összeadásé.

Megjegyzések:

  • A Numpy esetén is van lehetőség az alul- és túlcsordulások OpenCV-hez hasonló kezelésére az np.clip(arr, min, max) függvény használatával. Az arr tömb min értéknél kisebb elemei min-t, max-nál nagyobb értékű elemei pedig a max értékét kapják. Ez viszont csak akkor működik megfelelően, ha a képünk típusa tudja reprezentálni az alul- és túlcsorduló értékeket, vagyis leginkább egy kisebb értékkészletű típusba történő visszaalakítás előtt lehet érdemes használni.
  • Ehhez viszont olyan típus reprezentáció kell, amely képes a nagyobb értékkészlet tárolására, vagyis használata nehézkes, előzetes és utólagos típuskonverziókat igényel.

    Kép és skalár aritmetika többcsatornás képen

    többcsatornás képen a Numpy operátorokkal végzett skalár műveletek minden csatornára végrehajtódnak, az OpenCV esetén viszont csak a [0] indexű csatorna értékeire! OpenCV esetén így a következő lépések elvégzése javasolt:

    • cv2.split() függvénnyel csatornákra bontani,
    • csatornánként elvégezni a műveleteket,
    • majd a cv2.merge() segítségével összevonni az így módosított csatornákat.

    Az OpenCV dokumentáció szerint többcsatornás képen lehetne aritmetikai műveleteket végezni a csatornaszám dimenziójával megegyező tömbbel, ami teljesen logikusan is hangzik, de jelenleg a Python interfész esetén ez futási hibát okoz.

    OpenCV aritmetikai és bitenkénti logikai függvények

    Az OpenCV számos függvényt definiál képek közötti és skalár értékekkel való aritmetikára és logikai műveletekre. Néhány ezek közül:

    • cv2.absdiff(): abszolút különbség.
    • cv2.add(), cv2.subtract(): összeadás, kivonás.
    • cv2.addWeighted(): súlyozott összeadás.
    • cv2.scaleAdd(): skálázott összeadás.
    • cv2.bitwise_and(), cv2.bitwise_not(), cv2.bitwise_or(), cv2.bitwise_xor(): bitenként számolt logikai ÉS, NEM, VAGY, KIZÁRÓ VAGY.
    • cv2.divide(), cv2.multiply(): osztás, szorzás.
    • cv2.exp(): exponens.
    • cv2.log(): logaritmus.
    • cv2.pow(): hatványozás.
    • cv2.min(), cv2.max(): képpontonkénti minimum, maximum (az eredmény képmátrix lesz).
    • cv2.normalize(): értékkészlet normalizálás.

    Egy képmátrixra statisztika számítás, skalár eredménnyel:

    • cv2.mean(): átlag.
    • cv2.meanStdDev(): átlag és szórás.
    • cv2.minMaxIdx(): minimum és maximum értéke és indexe.
    • cv2.sum(): összeg.

    Függvények részletes szintaktikája:

    Dokumentáció (angol nyelven):

    Feladat

    Készítsünk programot, amely:

    • Betölt egy képet.
    • Szürkeárnyalatosra alakítja.
    • Megszorozza a képpontokat elemenként 2-vel, Numpy tömbként és OpenCV multiply() függvénnyel is.
    • Megjeleníti a képeket.

    Numpy eredmény:


    OpenCV multiply() eredmény:


    Az OpenCV esetén minden magas intenzitású képpont, amely 255 feletti értéket kap, 255, vagyis maximális fényességű fehér színértékre áll be. A Numpy esetén a magas intenzitású pontok túlcsorduláskor alacsony, vagyis sötét intenzitásértéket kapnak. Képek esetén az OpenCV aritmetikája ad használhatóbb eredményt.

    Ha el akarjuk kerülni az értékkészlet csonkolást, alakítsuk át a képet más, nagyobb bitszélességű adattípusra. Ezzel az előző témakörben ismerkedtünk meg.

    Változás detekció

    Két képmátrix abszolút különbségének számításával az intenzitásértékek változását kapjuk meg. Ha konstans hátteret feltételezünk, akkor a mozgó objektumok detektálására használhatjuk.

    Készítsünk programot, amely betölti az imageSequenceBackground.jpg (imseqbg), imageSequence00000005.jpg (imseq1), imageSequence00000006.jpg (imseq2) képeket, majd meghatározza az imseq1 és imseq2 változását a háttérhez (imseqbg), valamint egymáshoz képest is! (A képek a seq1 és a seq1/gray mappákban találhatók a példatárban.)

    A jobb láthatóságért invertáljuk a különbségképeket!

    Az abszolút különbség az absdiff() OpenCV függvénnyel számítható.

    A háttérkép (imageSequenceBackground.jpg) mesterségesen lett előállítva a 26 darab bemeneti kép alapján. Próbáljuk kitalálni, hogyan készülhetett!


    imageSequenceBackground.jpg


    imageSequence00000005.jpg


    imageSequence00000006.jpg


    Eredmények

    adiff1 = 255 - cv2.absdiff(imseqbg, imseq1)


    adiff2 = 255 - cv2.absdiff(imseqbg, imseq2)


    adiff3 = 255 - cv2.absdiff(imseq1, imseq2)