Skip navigation

Numpy képreprezentáció

Képmátrix

A digitális képeket képmátrixban tároljuk. A mátrix elemei a képpontok, vagy az angol terminológiából átvéve a pixelek. A reprezentáció fontosabb tulajdonságai az alábbiak.

  • A képpontokat sor (y) és oszlop (x) indexeikkel címezhetjük.
  • Az indexelés általában a bal felső sarokból indul. Jellemzően ez a [0, 0] indexű elem. Egyes rendszerek, például a Matlab esetén ez az [1, 1].
  • Az indexelés során a koordináták megadási sorrendje rendszerenként eltérő! Például a Numpy először a sor (y) és utána az oszlop (x) koordinátát kéri. Az OpenCV függvényhívások esetén (x, y) sorrendet kell használni! Mindig figyeljünk arra, melyik függvénykönyvtár függvényét használjuk! Jegyezzük meg az alábbiakat: Numpy[y, x], OpenCV(x, y).
  • Fotók esetén a mátrix elemek vagy skalár számértékek (szürkeárnyalatos intenzitásképek, szín információ nélkül), vagy többelemű vektorok (például RGB színreprezentáció értékei).

Numpy tömbelem elérés

A Numpy Python csomag hatékony többdimenziós mátrix reprezentációt biztosít. Az OpenCV Python felülete is ezt használja a képmátrixok tárolására. A Numpy tömbök objektumok, amelyek függvényekkel és attribútumokkal is rendelkeznek. Természetesen lehetőség van a mátrix elemeinek elérésére is.

Egy Numpy képmátrix elemének elérési módja:

pixel = image[y, x]

Vagyis [sor, oszlop] sorrendben kell megadni a koordinátákat. Az eredmény skalár érték (1 csatornás kép esetén) vagy 3 elemű tömb (BGR színes kép) lesz. A 3 elemű tömböt tovább lehet indexelni [sor, oszlop, csatorna] formában. Például a vörös színkomponens elérése:

R = image[y, x, 2]

A Numpy tömb attribútumai információval szolgálnak többek között a mátrix indexelhető dimenzióinak számáról (ndim), az indexelhető dimenziók szerinti méretéről (shape), és az elemtípusáról (dtype).

Megjegyezzük, hogy ez a fajta Numpy képpont elérés rendkívül lassú, nagy mennyiségű adatelérést nem így érdemes csinálni. Használhatjuk a fejlettebb Numpy manipulációkat, vagy megírhatjuk a szükséges függvényeket C++-ban. Ezekkel itt most nem foglalkozunk.

Értékadás képmátrixok között

A Numpy képmátrix reprezentációban az értékadás (az = operátorral) referencia szerint történik! Ez azt jelenti, hogy onnantól kezdve mindkét változó ugyanarra a képmátrixra hivatkozik, az egyiken keresztüli változás a másikra is hatással van! Ha valódi másolatot szeretnénk készíteni egy képmátrixról, akkor hívjuk meg a mátrix objektum copy() függvényét! A referencia takarékosabb a memóriával, de például változás követés esetén muszáj lehet másolatot készíteni.

image = cv2.imread('OpenCV-logo.png')

image_ref = image

image_copy = image.copy()

A példánkban az image és az image_ref ugyanarra a képmátrixra fog hivatkozni.

Az image_copy egy új képmátrixot kap, az eredetivel megegyező tartalommal.

Ablakhoz rendelt egéresemény kezelése (OpenCV)

A következő példaprogramunk a képpontok elérését mutatja be. Betöltünk egy képet, megjelenítjük ablakban, valamint az ablakhoz egy OpenCV egéresemény-kezelőt kapcsolunk az alábbi módon:

cv2.setMouseCallback('image', mouse_click)

Ha az image nevű képmegjelenítő ablakban kattintunk vagy mozgunk az egérrel, akkor a rendszer meghívja a mouse_click() függvényünket, megfelelő paraméterezéssel.

Az egéresemények kezeléséről további részletek a függelékben találhatók.

02_01_mouseclick_pixels.py

Függvényt definiálni a def kulcsszóval tudunk. Meg kell adnunk a függvény nevét, zárójelek között pedig a paraméterlistát. A definíciót a kettőspont karakterrel kell lezárni.

Az egérkattintás kezelő függvényben számunkra az első három paraméter érdekes. Az event az egéresemény azonosítóját jelenti, az x és y pedig az ablakban megjelenő képen történt kattintás koordinátáját. Figyeljünk arra, hogy mivel ez OpenCV függvény, itt az első érték az x, vagyis az oszlop koordináta!

A függvény törzsét kötelező egy behúzásnyira (TAB, 4 szóköz, ...) illeszteni, egyébként szintaktikai hibát kapunk!

Ha függvényben használunk globális változókat, akkor fel kell őket sorolnunk a függvény elején a global kulcsszó után.

A bal egérgomb lenyomásakor a függvényben kiírjuk a képmátrix adott sorában és oszlopában szereplő értéket, ami skalár számérték (szürkeárnyalatos), vagy három elemű tömb (BGR képmátrix) is lehet.

Ezután megvizsgáljuk, hogy a dimenziók száma 3 értékű-e? Ha igen, ez azt jelenti, hogy egy kétdimenziós, de többcsatornás képünk van. Egycsatornás kép esetén ez az érték 2 a sor és oszlop dimenzióknak megfelelően. Ha többcsatornás a kép, akkor 2-es indexű csatorna értékét (a vöröset) is kiírjuk a konzolra.

A program jelenlegi változatában nem lenne szükséges az imshow újbóli hívása, de mivel gyakran az interaktív esemény hatására változik a képi tartalom is, és az csak akkor jelenik meg az ablakban, ha explicit frissítjük annak tartalmát, nem árt, ha megszokjuk, hogy szükség lehet rá.

A főprogramunk a kép betöltése után kiírja annak fontosabb attribútum értékeit, és elindítja az egérkezelést.

import cv2


def mouse_click(event, x, y, flags, param):
# Globalis valtozo atvetele
global image


if event == cv2.EVENT_LBUTTONDOWN:
# (x, y) színérték kiírása
print('Pixel = ', image[y, x])

# Ha 3 csatornás a kép
if image.ndim == 3:

print('R = ', image[y, x, 2])
cv2.imshow('image', image)


image = cv2.imread('OpenCV-logo.png', cv2.IMREAD_COLOR)
# image = cv2.imread('OpenCV-logo.png', cv2.IMREAD_GRAYSCALE)
print('Kép indexelhető dimenziói: ', image.ndim)

print('Kép mérete:', image.shape)
print('Kép pixeltípusa: ', image.dtype)


cv2.imshow('image', image)
# Egerkezelo callback fuggveny beallitasa az ablakhoz
cv2.setMouseCallback('image', mouse_click)
# Kilepes billentyunyomasra

cv2.waitKey(0)

cv2.destroyAllWindows()

Feladatok

Próbáljuk ki a programot úgy, hogy szürkeárnyalatos képpel dolgozunk!

Például beolvasáskor szürkeárnyalatosra konvertáljuk, ahogyan a kikommentározott sorban látható. Mit látunk a program futásakor egérkattintás kattintás után?

Bővítsük úgy a programot, hogy a kattintás helyén megváltozzon a képpont értéke!

Színes kép esetén vörös szín kerüljön beírásra, szürkeárnyalatos esetben pedig invertáljuk az értéket (vagyis vonjuk ki 255-ből)!

A vörös színt a [0, 0, 255] tömbbel definiálhatjuk (BGR a sorrend).

Próbáljunk más egér eseményre reagálni!

Nézzük meg mi történik, ha a bal egérgomb lenyomása helyett az egér mozgás (cv2.EVENT_MOUSEMOVE) okoz változást!

A bal egérgomb kattintási helyének sorában az összes képpont értékét módosítsuk!

Kérjük le a képmátrix oszlopainak számát a shape attribútummal. Az attribútum értékét tömbként indexelhetjük. Ennek második értéke (1-es index!) adja az oszlopok számát. Használjunk for ciklust az értékek módosításához!

Példa for ciklus készítésére Python-ban:

for i in range(0, 20):
print('i:', i)

Figyeljünk arra, hogy a range() kezdőértéket (opcionális, alapértéke 0), záróértéket, illetve lépésközt (opcionális, alapértéke 1) ad meg, viszont a záróértéket már nem veszi bele! A példánkban így 0 és 19 közötti i értékeket kapunk! A range(6, 21, 5) pedig a 6, 11, és 16 értékeket adja, a 21-et már nem!

Egészítsük ki a programot billentyűzet kezeléssel!

Az r billentyű lenyomására állítsuk vissza az eredeti képet! A q billentyű lenyomására lépjünk ki a programból. Minden más billentyű lenyomására ne történjen semmi érdemleges, folytatódjon a billentyűkezelő ciklus.

Tippek: A billentyűzetkezelési részletes leírás a függelékben található. Az eredeti képi tartalom megőrzésére készítsünk másolatot (copy) a beolvasás után.