Ich habe ein 2D NumPy-Array und möchte alle Werte darin, die größer oder gleich einem Schwellenwert T sind, durch 255.0 ersetzen. Meines Wissens nach wäre der grundlegendste Weg:
shape = arr.shape
result = np.zeros(shape)
for x in range(0, shape[0]):
for y in range(0, shape[1]):
if arr[x, y] >= T:
result[x, y] = 255
Was ist der prägnanteste und pythonischste Weg, dies zu tun?
Gibt es einen schnelleren (möglicherweise weniger prägnanten und/oder weniger pythonischen) Weg, dies zu tun?
Dies wird Teil eines Unterprogramms zur Fenster-/Ebenenanpassung für MRI-Scans des menschlichen Kopfes sein. Das 2D Numpy-Array sind die Bildpixeldaten.
Ich denke, der schnellste und prägnanteste Weg, dies zu tun, ist die Verwendung von NumPy's eingebauter Fancy-Indizierung. Wenn Sie ein ndarray
mit dem Namen arr
haben, können Sie alle Elemente >255
durch einen Wert x
wie folgt ersetzen:
arr[arr > 255] = x
Ich habe dies auf meinem Rechner mit einer 500 x 500 Zufallsmatrix durchgeführt, wobei ich alle Werte >0,5 durch 5 ersetzt habe, und es dauerte durchschnittlich 7,59 ms.
In [1]: import numpy as np
In [2]: A = np.random.rand(500, 500)
In [3]: timeit A[A > 0.5] = 5
100 loops, best of 3: 7.59 ms per loop
Da Sie eigentlich ein anderes Array wollen, das arr
ist, wenn arr < 255
, und 255
sonst, kann dies einfach gemacht werden:
result = np.minimum(arr, 255)
Allgemeiner gesagt, für eine untere und/oder obere Grenze:
result = np.clip(arr, 0, 255)
Wenn Sie nur auf die Werte über 255 zugreifen wollen, oder etwas Komplizierteres, ist @mtitan8's Antwort allgemeiner, aber np.clip
und np.minimum
(oder np.maximum
) sind schöner und viel schneller für Ihren Fall:
In [292]: timeit np.minimum(a, 255)
100000 loops, best of 3: 19.6 µs per loop
In [293]: %%timeit
.....: c = np.copy(a)
.....: c[a>255] = 255
.....:
10000 loops, best of 3: 86.6 µs per loop
Wenn Sie es an Ort und Stelle machen wollen (d.h. arr
modifizieren, anstatt result
zu erzeugen), können Sie den out
Parameter von np.minimum
verwenden:
np.minimum(arr, 255, out=arr)
oder
np.clip(arr, 0, 255, arr)
(der Name "out=" ist optional, da die Argumente in der gleichen Reihenfolge wie in der Funktionsdefinition stehen).
Bei der In-Place-Änderung ist die boolesche Indizierung wesentlich schneller (ohne dass die Kopie separat erstellt und dann geändert werden muss), aber immer noch nicht so schnell wie minimum
:
In [328]: %%timeit
.....: a = np.random.randint(0, 300, (100,100))
.....: np.minimum(a, 255, a)
.....:
100000 loops, best of 3: 303 µs per loop
In [329]: %%timeit
.....: a = np.random.randint(0, 300, (100,100))
.....: a[a>255] = 255
.....:
100000 loops, best of 3: 356 µs per loop
Zum Vergleich: Wenn Sie Ihre Werte sowohl mit einem Minimum als auch mit einem Maximum einschränken wollten, müssten Sie dies ohne clip
zweimal tun, mit etwas wie
np.minimum(a, 255, a)
np.maximum(a, 0, a)
oder,
a[a>255] = 255
a[a<0] = 0
Sie können auch numpy.putmask verwenden:
np.putmask(arr, arr>=T, 255.0)
Hier ein Leistungsvergleich mit der eingebauten Indizierung von Numpy's:
In [1]: import numpy as np
In [2]: A = np.random.rand(500, 500)
In [3]: timeit np.putmask(A, A>0.5, 5)
1000 loops, best of 3: 1.34 ms per loop
In [4]: timeit A[A > 0.5] = 5
1000 loops, best of 3: 1.82 ms per loop