vectorized_filter#
- scipy.ndimage.vectorized_filter(input, function, *, size=None, footprint=None, output=None, mode='reflect', cval=None, origin=None, axes=None, batch_memory=1073741824)[Quelle]#
Ein Array mit einer vektorisierten Python-Aufrufbaren als Kernel filtern
- Parameter:
- inputarray_like
Das Eingabearray.
- functioncallable
Kernel, der über ein Fenster zentriert um jedes Element von input angewendet wird. Die Aufrufbare muss die Signatur haben
function(window: ndarray, *, axis: int | tuple) -> scalar
wobei
axisdie Achse (oder Achsen) vonwindowangibt, entlang derer die Filterfunktion ausgewertet wird.- sizeSkalar oder Tupel, optional
Siehe footprint unten. Wird ignoriert, wenn footprint angegeben ist.
- footprintArray, optional
Entweder size oder footprint muss definiert sein. size gibt die Form an, die aus dem Eingabearray entnommen wird, an jeder Elementposition, um die Eingabe für die Filterfunktion zu definieren. footprint ist ein boolesches Array, das (implizit) eine Form angibt, aber auch, welche der Elemente innerhalb dieser Form an die Filterfunktion übergeben werden. Somit ist
size=(n, m)äquivalent zufootprint=np.ones((n, m)). Wir passen size an die Anzahl der durch axes angegebenen Dimensionen an. Zum Beispiel, wenn axes(0, 2, 1)ist undnfürsizeübergeben wird, dann ist die effektive size(n, n, n).- outputarray oder dtype, optional
Das Array, in das die Ausgabe platziert werden soll, oder der Datentyp des zurückgegebenen Arrays. Standardmäßig wird ein Array mit demselben Datentyp wie input erstellt.
- mode{‘reflect’, ‘constant’, ‘nearest’, ‘mirror’, ‘wrap’}, optional
Der Parameter mode bestimmt, wie das Eingabearray über seine Grenzen hinaus erweitert wird. Standard ist ‘reflect’. Das Verhalten für jeden gültigen Wert ist wie folgt:
- ‘reflect’ (d c b a | a b c d | d c b a)
Die Eingabe wird erweitert, indem über den Rand des letzten Pixels gespiegelt wird. Dieser Modus wird auch manchmal als halb-Sample-symmetrisch bezeichnet.
- ‘constant’ (k k k k | a b c d | k k k k)
Die Eingabe wird erweitert, indem alle Werte außerhalb des Rands mit demselben konstanten Wert gefüllt werden, der durch den Parameter cval definiert ist.
- ‘nearest’ (a a a a | a b c d | d d d d)
Die Eingabe wird erweitert, indem das letzte Pixel wiederholt wird.
- ‘mirror’ (d c b | a b c d | c b a)
Die Eingabe wird erweitert, indem über die Mitte des letzten Pixels gespiegelt wird. Dieser Modus wird auch manchmal als ganz-Sample-symmetrisch bezeichnet.
- ‘wrap’ (a b c d | a b c d | a b c d)
Die Eingabe wird erweitert, indem zum gegenüberliegenden Rand umgebrochen wird.
- ‘valid’ (| a b c d |)
Die Eingabe wird nicht erweitert; vielmehr wird die Ausgabegröße je nach Fenstergröße gemäß der folgenden Berechnung reduziert
window_size = np.asarray(size if size is not None else footprint.shape) output_shape = np.asarray(input.shape) output_shape[np.asarray(axes)] -= (window_size - 1)
- cvalskalar, optional
Wert, mit dem die Ränder der Eingabe gefüllt werden, wenn mode ‘constant’ ist. Standard ist 0.0.
- originint oder Sequenz, optional
Steuert die Platzierung des Filters auf den Pixeln des Eingangsarrays. Ein Wert von 0 (Standard) zentriert den Filter über dem Pixel, wobei positive Werte den Filter nach links und negative Werte nach rechts verschieben. Durch Übergabe einer Sequenz von Ursprüngen mit der Länge, die der Anzahl der Dimensionen des Eingangsarrays entspricht, können entlang jeder Achse unterschiedliche Verschiebungen angegeben werden.
- axestuple of int, optional
Wenn None, wird input entlang aller Achsen gefiltert. Andernfalls wird input entlang der angegebenen Achsen gefiltert. Wenn axes angegeben ist, muss die Dimensionalität von footprint und die Länge von Tupeln, die für size oder origin verwendet werden, mit der Länge von axes übereinstimmen. Die i-te Achse von footprint und das i-te Element in diesen Tupeln entspricht dem i-ten Element von axes.
- batch_memoryint, default: 2**30
Die maximale Anzahl von Bytes, die von Daten im
window-Array belegt werden, das anfunctionübergeben wird.
- Rückgabe:
- outputndarray
Gefiltertes Array. Der dtype ist der Ausgabedtype von function. Wenn function skalarwertig ist, wenn sie auf ein einzelnes Fenster angewendet wird, ist die Form der Ausgabe die von input (es sei denn,
mode=='valid'; siehe mode-Dokumentation). Wenn function mehrwertig ist, wenn sie auf ein einzelnes Fenster angewendet wird, hängt die Platzierung der entsprechenden Dimensionen innerhalb der Ausgabegröße vollständig vom Verhalten von function ab; siehe Beispiele.
Siehe auch
Hinweise
Diese Funktion arbeitet, indem sie input gemäß mode auffüllt und dann die bereitgestellte function auf Chunks einer gleitenden Fensteransicht über dem aufgefüllten Array aufruft. Dieser Ansatz ist sehr einfach und flexibel, und daher hat die Funktion viele Funktionen, die von einigen anderen Filterfunktionen nicht angeboten werden (z. B. Speichersteuerung, Unterstützung für
float16und komplexe Datentypen sowie alle NaN-Behandlungsfunktionen, die von der function-Argument bereitgestellt werden).Dieser Brute-Force-Ansatz kann jedoch erhebliche redundante Arbeit leisten. Verwenden Sie einen spezialisierten Filter (z. B.
minimum_filteranstelle dieser Funktion mitnumpy.minals Aufrufbare;uniform_filteranstelle dieser Funktion mitnumpy.meanals Aufrufbare), wenn möglich, da sie möglicherweise einen effizienteren Algorithmus verwendet.Wenn kein spezialisierter Filter verfügbar ist, ist diese Funktion ideal, wenn function eine vektorisierte, reine Python-Aufrufbare ist. Noch bessere Leistung kann durch Übergeben einer
scipy.LowLevelCallableangeneric_filtererzielt werden.generic_filterkann auch für teure Aufrufbare mit großen Filter-Footprints und Aufrufbare, die nicht vektorisiert sind (d. h. solche ohneaxis-Unterstützung), bevorzugt werden.Diese Funktion bietet nicht die Argumente
extra_argumentsoderextra_keywords, die von einigen ndimage-Funktionen bereitgestellt werden. Dafür gibt es zwei Gründe:Die Weiterleitungsfunktionalität kann vom Benutzer erreicht werden: Wickeln Sie einfach die ursprüngliche Aufrufbare in eine andere Funktion, die die erforderlichen Argumente bereitstellt; z. B.
function=lambda input, axis: function(input, *extra_arguments, axis=axis, **extra_keywords).Es gibt Anwendungsfälle, bei denen function zusätzliche *gleitende Fensterdaten* zusätzlich zu input an function übergeben werden sollen. Dies ist noch nicht implementiert, aber wir reservieren diese Argumentnamen für eine solche Funktion, die die Fähigkeit hinzufügt und keine doppelte Schnittstelle zur vorhandenen Fähigkeit bietet.
Beispiele
Angenommen, wir möchten einen Medianfilter mit gerader Fenstergröße auf einem
float16-Bild durchführen. Darüber hinaus hat das Bild NaNs, die ignoriert werden sollen (und effektiv vom Filter entfernt werden).median_filterunterstützt keinefloat16-Daten, sein Verhalten bei Vorhandensein von NaNs ist nicht definiert, und für gerade Fenstergrößen gibt es nicht den üblichen Stichprobenmedian zurück – den Durchschnitt der beiden mittleren Elemente. Dies wäre ein hervorragender Anwendungsfall fürvectorized_filtermitfunction=np.nanmedian, das die erforderliche Schnittstelle unterstützt: es akzeptiert ein Datenarray beliebiger Form als erstes Positionsargument und ein Achsentupel als Schlüsselwortargumentaxis.>>> import numpy as np >>> from scipy import datasets, ndimage >>> from scipy.ndimage import vectorized_filter >>> import matplotlib.pyplot as plt >>> ascent = ndimage.zoom(datasets.ascent(), 0.5).astype(np.float16) >>> ascent[::16, ::16] = np.nan >>> result = vectorized_filter(ascent, function=np.nanmedian, size=4)
Die ursprünglichen und gefilterten Bilder plotten.
>>> fig = plt.figure() >>> plt.gray() # show the filtered result in grayscale >>> ax1 = fig.add_subplot(121) # left side >>> ax2 = fig.add_subplot(122) # right side >>> ax1.imshow(ascent) >>> ax2.imshow(result) >>> fig.tight_layout() >>> plt.show()
Ein weiterer Bedarf, der von
vectorized_filtererfüllt wird, ist die Durchführung von Multi-Output-Filtern. Angenommen, wir möchten ein Bild zusätzlich zum Median nach dem 25. und 75. Perzentil filtern. Wir könnten die drei Filter separat durchführen.>>> ascent = ndimage.zoom(datasets.ascent(), 0.5) >>> def get_quantile_fun(p): ... return lambda x, axis: np.quantile(x, p, axis=axis) >>> ref1 = vectorized_filter(ascent, get_quantile_fun(0.25), size=4) >>> ref2 = vectorized_filter(ascent, get_quantile_fun(0.50), size=4) >>> ref3 = vectorized_filter(ascent, get_quantile_fun(0.75), size=4) >>> ref = np.stack([ref1, ref2, ref3])
Allerdings unterstützt
vectorized_filterauch Filter, die mehrere Ausgaben zurückgeben, solange output nicht spezifiziert ist und batch_memory ausreichend hoch ist, um die Berechnung in einem einzigen Chunk durchzuführen.>>> def quartiles(x, axis): ... return np.quantile(x, [0.25, 0.50, 0.75], axis=axis) >>> res = vectorized_filter(ascent, quartiles, size=4, batch_memory=np.inf) >>> np.all(np.isclose(res, ref)) np.True_
Die Platzierung der zusätzlichen Dimension(en), die mit mehreren Ausgaben korrespondieren, liegt im Ermessen von function. quartiles stellt einfach eine Dimension voran, die den drei Ausgaben entspricht, weil dies das Verhalten von np.quantile ist
>>> res.shape == (3,) + ascent.shape True
Wenn wir wollten, dass diese Dimension angehängt wird
>>> def quartiles(x, axis): ... return np.moveaxis(np.quantile(x, [0.25, 0.50, 0.75], axis=axis), 0, -1) >>> res = vectorized_filter(ascent, quartiles, size=4, batch_memory=np.inf) >>> res.shape == ascent.shape + (3,) True
Angenommen, wir möchten einen "Modus"-Filter implementieren – einen Filter, der den am häufigsten vorkommenden Wert innerhalb des Fensters auswählt. Ein einfacher (aber ziemlich langsamer) Ansatz ist die Verwendung von
generic_filtermitscipy.stats.mode.>>> from scipy import stats >>> rng = np.random.default_rng() >>> input = rng.integers(255, size=(50, 50)).astype(np.uint8) >>> def simple_mode(input): ... return stats.mode(input, axis=None).mode >>> ref = ndimage.generic_filter(input, simple_mode, size=5)
Wenn Geschwindigkeit wichtig ist, kann
vectorized_filterden Leistungsvorteil einer vektorisierten Aufrufbaren nutzen.>>> def vectorized_mode(x, axis=(-1,)): ... n_axes = 1 if np.isscalar(axis) else len(axis) ... x = np.moveaxis(x, axis, tuple(range(-n_axes, 0))) ... x = np.reshape(x, x.shape[:-n_axes] + (-1,)) ... y = np.sort(x, axis=-1) ... i = np.concatenate([np.ones(y.shape[:-1] + (1,), dtype=bool), ... y[..., :-1] != y[..., 1:]], axis=-1) ... indices = np.arange(y.size)[i.ravel()] ... counts = np.diff(indices, append=y.size) ... counts = np.reshape(np.repeat(counts, counts), y.shape) ... k = np.argmax(counts, axis=-1, keepdims=True) ... return np.take_along_axis(y, k, axis=-1)[..., 0] >>> res = vectorized_filter(input, vectorized_mode, size=5) >>> np.all(res == ref) np.True_
Abhängig von der Maschine kann die Version
vectorized_filterbis zu 100x schneller sein.