Egy 2D numpy tömb összes minimumának megkeresése.
A 2D-s tömböket pixelekből felépített digitális (szürkeárnyalatos) képként képzelhetjük el. Minden egyes pixelhez tartozik egy érték, amely a fényességet jelöli. Ezek az értékek egy mátrixban vannak ábrázolva, ahol a pixelek pozíciói a két tengelyre vannak leképezve. Ha meg akarjuk találni a legsötétebb pontokat, meg kell vizsgálnunk az egyes pontok szomszédait.
1. módszer:
Ezt úgy lehet elvégezni, hogy minden egyes cellára vonatkozóan minden egyes [i,j] cellán iterálva ellenőrizzük. Ha az összes szomszéd nagyobb, mint az aktuális cella, akkor az egy lokális minimum. Ez a megközelítés nem optimális, mivel a szomszédos cellákon redundáns számításokat kell elvégezni.
2. módszer: Az "és" operátor használata
Az első lépés a tömb globális maximumának hozzáadása a tömb környezetéhez, hogy amikor az elemenkénti vizsgálat eléri a tömb "szélét", az összehasonlítás működjön. Mivel az aktuális cellát az előző és a következő cellával hasonlítjuk össze, a tengelyek végén hibaüzenet keletkezne. A lokális minimum mindig kisebb lesz, mint a globális maximum, így az összehasonlításunk jól fog működni. Ezután végigmegyünk a tömb celláin, elvégezve az összehasonlítást. A redundáns számítások csökkentése érdekében logikai "és" műveletet használunk, így ha valamelyik feltétel nem teljesül, az algoritmus nem végzi el a további összehasonlítást.
A feltételeknek megfelelő elemek indexeit egy tuple listában gyűjtjük össze. Vegyük észre, hogy az eredeti tömb indexei különböznek a kibővített tömb indexeitől! Ezért az indexeket -1-gyel csökkentjük.
import numpy as np
data = np.array([[-210, 2, 0, -150],
[4, -1, -60, 10],
[0, 0, -110, 10],
[-50, -11, -2, 10]])
a = np.pad(data, (1, 1), mode='constant', constant_values=(np.amax(data), np.amax(data)))
loc_min = []
rows = a.shape[0]
cols = a.shape[1]
for ix in range(0, rows - 1):
for iy in range(0, cols - 1):
if a[ix, iy] < a[ix, iy + 1] and a[ix, iy] < a[ix, iy - 1] and \
a[ix, iy] < a[ix + 1, iy] and a[ix, iy] < a[ix + 1, iy - 1] and \
a[ix, iy] < a[ix + 1, iy + 1] and a[ix, iy] < a[ix - 1, iy] and \
a[ix, iy] < a[ix - 1, iy - 1] and a[ix, iy] < a[ix - 1, iy + 1]:
temp_pos = (ix-1, iy-1)
loc_min.append(temp_pos)
print(loc_min)
3. módszer: A scipy ndimage minimum szűrőjének használata
Szerencsére erre a feladatra is van egy scipy függvény:
A scipy.ndimage.minimum_filter(input, size=None, footprint=None, output=None, mode='reflect', cval=0.0, origin=0) egy boolean tömböt hoz létre, ahol a helyi minimumok 'True' értékűek. A 'size' paramétert használjuk, amely megadja a bemeneti tömbből minden egyes elem pozíciójában vett alakot, hogy meghatározzuk a szűrőfüggvény bemenetét. A footprint egy boolean tömb, amely (implicit módon) egy alakzatot határoz meg, de azt is, hogy az alakzaton belül mely elemek kerülnek átadásra a szűrőfüggvénynek. A mode paraméter határozza meg, hogy a bemeneti tömb hogyan bővüljön, amikor a szűrő átfed egy szegélyt. A bemeneti tömb dimenzióinak számával megegyező hosszúságú módok sorozatának átadásával minden tengely mentén különböző módok adhatók meg. Itt a 'konstans' paraméter van megadva, így a bemenet a határon túli összes értéket a 'cval' paraméter által megadott konstans értékkel tölti ki. A 'cval' értéke a globális maximumra van beállítva, így biztosítva, hogy a határon lévő lokális minimumok is megtalálhatók legyenek. A szűrők működésével kapcsolatos részletesebb információkért lásd a scipy dokumentációt. Ezután ellenőrizzük, hogy mely cellák "True" értékűek, így az összes helyi minimum indexe egy tömbben van.
import numpy as np
from scipy.ndimage.filters import minimum_filter
data = np.array([[2, 100, 1000, -5],
[-10, 9, 1800, 0],
[112, 10, 111, 100],
[50, 110, 50, 140]])
minima = (data == minimum_filter(data, 3, mode='constant', cval=0.0))
# print(data)
# print(minima)
res = np.where(1 == minima)
print(res)
Összefoglaló:
Mint fentebb láttuk, többféleképpen is megkereshetjük a helyi minimumokat egy numpy tömbben, de mint mindig, most is hasznos külső könyvtárakat használni ehhez a feladathoz.