Additív zaj egycsatornás szürkeárnyalatos képhez adása OpenCV-ben
A zajt önálló képként állítjuk elő, képpontonként megfelelő eloszlású és paraméterű véletlelen számként.
Nagyon figyeljünk arra, hogy a zaj kép esetén pozitív és negatív értékek is előfordulhatnak! Ehhez megfelelő előjeles egész, vagy lebegőpontos típust kell választanunk! További probléma, hogy a véletlenszám-generáló függvények nem veszik figyelembe a csatornák számát, ha több is van, akkor is csak a legelsőt töltik ki! Emiatt eleve célszerű lehet a zajkép mátrix méretét egycsatornásként létrehozni. Például:
noise = np.zeros(img.shape[:2], np.int16)
Egyenletes eloszlású zaj képet a cv2.randu() függvénnyel készíthetünk, megadott minimum és maximum értékek között (a példában [-10, 10]). Első paraméterként át kell adni egy már létező képmátrixot.
cv2.randu(noise, -10.0, 10.0)
Normál eloszlású zajt pedig a cv2.randn() függvénnyel, várható érték és szórás megadásával. A várható érték rendszerint 0.0, a szórás értékkel tudjuk szabályozni a zajterhelés erősségét. Itt is szükséges a képmátrix előzetes létrehozása.
cv2.randn(noise, 0.0, 20.0)
Additív zajt a képhez a mátrixok összeadásával adhatunk. Itt is fontos az eredmény típusának pontos megválasztása!
imnoise1 = cv2.add(img, noise, dtype=cv2.CV_8UC1)
vagy
imnoise2 = cv2.add(img, noise, dtype=cv2.CV_16SC1)
Fontos!
Lényeges különbség van az imnoise1 és az imnoise2 képmátrixok között! Az első esetben az eredmény típusa eleve 8 bites, előjel nélküli egész, így a nullánál kisebb, és a 255-nél nagyobb intenzitásértékek csonkolódnak 0 és 255 értékekre. Az imnoise2 típusa 16 bites előjeles egész, vagyis egy [0, 255] intenzitástartományú kép esetén a zajterheléssel negatív, valamint 255-nél nagyobb intenzitásértékek is ki fognak alakulni.
Melyik megközelítést válasszuk?
Gondoljuk át, az adott probléma esetén melyik közelíti jobban a valós zajterhelést?
Egyszerűbb a munka, és a valóságot is jól közelíti az első megközelítés: a mért, folytonos szenzor értékek [0, 255] értékre kvantálódnak, a mérési tartományon kívül értéket nem is biztos, hogy a szenzor egyáltalán tudna adni. Eleve jogos elvárás lehet, hogy a tökéletesen mért, zajjal nem terhelt képpontok értéke ne változzon, ami így biztosított.
Ha valamiért mégis a 16 bites előjeles vagy lebegőpontos eredményt választjuk, akkor ezekből a reprezentációkból célszerű visszatérni a 8 bitesre. Ezt megtehetjük normalizálva és csonkolva.
A normalizálás esetén a képmátrix minimális eleme az általunk megadott minimális értékbe, a mátrix maximális eleme a megadott maximálisba képződik, közöttük pedig a beosztás lineáris. Ezzel találkoztunk már korábban is.
imnoise2 = cv2.add(img, noise, dtype=cv2.CV_16SC1)
imnoisenorm = cv2.normalize(imnoise2, None, 0, 255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)
Csonkolás esetén az ábrázolható tartományon kívüli értékek az ábrázolható minimális és maximális értékkel helyettesítődnek. Ez megoldható a típuskonverzió előtt végrehajtott vágás művelettel, ahogyan korábban láttuk. Így az első megközelítéssel egyező eredményt kapunk.