Skip navigation

Képmátrix típus konverziók

Képmátrix-képpont típusok

Numpy típusok

  • Memóriatakarékossági okokból szürkeárnyalatos képek esetén a [0, 255] egész típusú értékkészlet reprezentációját jellemzően 8 bites, előjel nélküli egész számként valósítják meg. Ez az uint8 (unsigned int 8 bits) Numpy típusnak felel meg.
  • Színes képeknél az egyes csatorna értékek kerülnek uint8 értékekként tárolásra. Többcsatornás (például színes) kép esetén a csatornák számát a Numpy tömb dimenzió megadásakor definiálhatjuk.
  • Fontos! Előfordulhat, hogy egyes műveletek kivezetnek a [0, 255] értékkészletből, ekkor az eredmény csonkolása következik be. Ha ez nem elfogadható, akkor célszerű eleve olyan adattípust használni, ami nagyobb értékkészletet biztosít, például 16 bites előjeles (int16) vagy előjel nélküli (uint16) egészet, vagy lebegőpontos (float32) számot, és előzetesen ebbe alakítani át a képet.
  • Használhatunk logikai típust (bool) is képmátrix elemtípusként.

OpenCV típusok

  • Amennyiben OpenCV függvény vár típus megnevezést paraméterként, akkor az OpenCV által definiált típus elnevezésket kell használnunk. Az OpenCV típusok megnevezésében a 8, 16 és 32 számértékek a bitszélességet, az U az előjel nélküli, az S az előjeles, az F pedig a lebegőpontos típust jelenti.
  • Többcsatornás képnél OpenCV esetén a típus megnevezéséhez kell a C betűt (Channel rövidítése) és a csatornák számát számként hozzáírni. Például a CV_8UC3 a 3 csatornás, előjel nélküli 8 bites egész reprezentációjú képtípus lesz. Ha a csatornaszámot nem adjuk meg, akkor 1 az alapértelmezés.

Összefoglaló

Az alábbi táblázatban foglaljuk össze a leggyakoribb típus megnevezéseket és értékkészleteket:

Numpy OpenCV Leírás
np.uint8 cv2.CV_8U Előjel nélküli, 8 bites egész szám: [0, 255]
np.uint16 cv2.CV_16U Előjel nélküli, 16 bites egész szám: [0, 65535]
np.int8 cv2.CV_8S Előjeles, 8 bites egész szám: [-128, 127]
np.int16 cv2.CV_16S Előjeles, 16 bites egész szám: [-32768, 32767]
np.float32 cv2.CV_32F 32 bites, IEEE 754 formátumú lebegőpontos szám
bool

Logikai igaz-hamis (False, True) érték.
A Numpy 1.20 verziójától az np.bool típus elavult, helyette használjuk az egyszerű Python bool-t.
OpenCV esetén a 0, nem 0 egész reprezentálja, külön típus nincs hozzá.

Típus konverziók

A képmátrix típusok között legegyszerűbben a Numpy segítségével válthatunk.

Használatához be kell importálnunk a numpy csomagot a szokásos módon.

import numpy as np

Beolvasunk egy képet, amely a példánkban uint8 típusú, 3 csatornás kép lesz.

img = cv2.imread('OpenCV-logo.png', cv2.IMREAD_COLOR)

Átalakítjuk float32 típusúvá.

img32f = np.float32(img)

Az átalakítás tetszőleges típusba hasonlóan megtehető.

Figyeljünk arra, hogy szűkebb értékkészletű típusra történő átalakítás esetén adatvesztés következhet be, a cél típus ábrázolási tartományán kívül eső értékek csonkolásra kerülnek! Ha szükséges, előzetesen alakítsuk át az értékkészletet!

Például ha np.float32 típusú képmátrixunk van, ahol az értékek [-500, 2000] közöttiek, akkor közvetlenül np.uint8 típusra alakítva a képmátrixot a [0, 255] értékkészleten kívül eső és a tört értékek csonkolódnak!

import numpy as np
nparr = np.array([-500.0, -100.4, -50.2, 0, 50.2, 100.8, 200, 2000.0], dtype=np.float32)
print(nparr)
nparr_uint8 = np.uint8(nparr)
print(nparr_uint8)

A futtatás eredménye:

[-500. -100.4 -50.2 0. 50.2 100.8 200 2000. ]
[ 12 156 206 0 50 100 200 208]

Figyeljük meg, hogy a [0, 255] közötti tört értékek csonkolódtak az egész értékekükre, vagyis nem kerekítés történik (a 100.8 értékből 100 lesz). Az értéktartományon kívüliek pedig nagyon fura új értéket kapnak (a -500.0 értékből 12, a 2000.0 értékből 208 lesz). Ennek okával és a megoldási lehetőségekkel foglalkozunk a következő részekben.

Képmátrix típusok megjelenítése és normalizálása

Fontos!

A képmátrixok megjelenítése szürkeárnyalatos esetben úgy alakul, hogy egész típus esetén az értékkészlet minimális értéke lesz a fekete, a maximális a fehér szín! Vagyis, ha 8 bitesről áttérünk 16 bites reprezentációra, a megjelenő kép gyakorlatilag teljesen sötét lesz, mert a [0, 255] csak egy szűk alsó részét tölti ki a 16 bites [0, 65535] értékkészletnek! Lebegőpontos képponttípus esetén a [0.0, 1.0] tartomány képződik le a fekete-fehér színekre. Fontos lehet ezekben az esetekben az értékkészletek átalakítása is!

Az értékkészlet átalakítást végezhetjük aritmetikai műveletekkel vagy normalizálással is.

Aritmetikai átalakítással

Egy 8 bitesről 16 bites reprezentációra áttérésnél a típuskonverzió után szorozzuk meg például a képmátrixot (ezzel minden elemét) 256 értékkel. Visszafelé irányban először osszuk el 256-tal és utána jöjjön a típuskonverzió. Vagyis az aritmetikai átalakítást mindig a nagyobb értékkészletet biztosító típussal végezzük! Az aritmetikai műveletekről részletesebben a következő részben olvashatunk.

Normalizálással

A normalizálás segítségével a képen előforduló min-max értéktartományt egy általunk megadott értéktartományba alakíthatjuk lineárisan. Erre az OpenCV normalize() függvénye használható. Az alpha és beta paraméterek adják az új értékkészlet minimális és maximális elemét. Példaként minimum és maximum képpontértékek szerinti átalakítást végzünk 32 bites lebegőpontos típusba, [0.0, 1.0] tartományba. Megjegyezzük, hogy a normalizáló függvény ennél összetetebb átalakításokra is képes, de itt nem részletezzük.

norm_image = cv2.normalize(image, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)

Figyeljünk arra viszont, hogy a normalizálás megváltoztathatja a kép megjelenését! Amennyiben az értékek nem töltik ki teljesen az adott típus értéktartományát, a normalizálás után ki fogják, ami szürke és a színcsatorna megjelenést befolyásolják.

Feladat

Készítsünk programot, amely betölt egy képet szürkeárnyalatosként, és ezt alakítsuk át többféle típusra! Jelenítsük meg a képeket, és írjunk ki egy képpont értéket a konzolra, hogy ellenőrizzük az átalakítást! A képmátrixokat írjuk ki képfájlba.

A feladat megoldását a 03_01_image_type_convert.py példaprogram mutatja.

Képmegjelenítési eredmények:

img_uint8 img_uint16 img_uint16_mult256
img_uint8[100, 100] = 255 img_uint16[100, 100] = 255 img_uint16[100, 100] = 65280

img_int16 img_float32 img_float32_norm
img_int16[100, 100] = 255 img_float32[100, 100] = 255.0 img_float32_norm[100, 100] = 1.0

Fájlba írási eredmények:

A képmegjelenítés megfelel a fentebb leírtaknak. A képmátrix fájlba mentésénél az alábbiakat figyelhetjük meg:

  • Az np.uint16 típus mentése esetén a függvény automatikusan elvégzi a 256 értékkel való osztást (az np.uint8 típusra való visszaskálázást).
  • A több típus esetén egy egyszerű típuskonverzió történik np.uint8 típusra csonkolással.

Konklúzió: fájlba írás előtt mindig alakítsuk vissza a menteni kívánt képmátrixot np.uint8 típusra!