wake-up-neo.net

Resampling eines Numpy-Arrays, das ein Bild darstellt

Ich bin auf der Suche nach einem Resample für ein Numpy-Array, das Bilddaten in einer neuen Größe darstellt, vorzugsweise mit der Wahl der Interpolationsmethode (am nächsten, bilinear usw.). Ich weiß, dass es gibt

scipy.misc.imresize

dies geschieht genau durch Umbrechen der PIL-Größenänderungsfunktion. Das einzige Problem ist, dass das Numpy-Array, da es PIL verwendet, den Bildformaten entsprechen muss, sodass ich maximal 4 "Farb" -Kanäle habe.

Ich möchte in der Lage sein, beliebige Bilder mit einer beliebigen Anzahl von "Farb" -Kanälen in der Größe anzupassen. Ich habe mich gefragt, ob es einen einfachen Weg gibt, dies in scipy/numpy zu tun, oder ob ich meinen eigenen rollen muss.

Ich habe zwei Ideen, wie ich mir eine zusammenstellen kann:

  • eine Funktion, die scipy.misc.imresize auf jedem Kanal separat
  • erstelle meine eigene mit scipy.ndimage.interpolation.affine_transform

Die erste Methode ist für große Datenmengen wahrscheinlich langsam, und die zweite Methode bietet keine andere Interpolationsmethode als Splines.

69
Gustav Larsson

Basierend auf Ihrer Beschreibung möchten Sie scipy.ndimage.zoom .

Bilineare Interpolation wäre order=1, am nächsten ist order=0 und kubisch ist die Standardeinstellung (order=3).

zoom ist speziell für Daten mit regelmäßigem Raster gedacht, für die Sie eine neue Auflösung festlegen möchten.

Ein kurzes Beispiel:

import numpy as np
import scipy.ndimage

x = np.arange(9).reshape(3,3)

print 'Original array:'
print x

print 'Resampled by a factor of 2 with nearest interpolation:'
print scipy.ndimage.zoom(x, 2, order=0)


print 'Resampled by a factor of 2 with bilinear interpolation:'
print scipy.ndimage.zoom(x, 2, order=1)


print 'Resampled by a factor of 2 with cubic interpolation:'
print scipy.ndimage.zoom(x, 2, order=3)

Und das Ergebnis:

Original array:
[[0 1 2]
 [3 4 5]
 [6 7 8]]
Resampled by a factor of 2 with nearest interpolation:
[[0 0 1 1 2 2]
 [0 0 1 1 2 2]
 [3 3 4 4 5 5]
 [3 3 4 4 5 5]
 [6 6 7 7 8 8]
 [6 6 7 7 8 8]]
Resampled by a factor of 2 with bilinear interpolation:
[[0 0 1 1 2 2]
 [1 2 2 2 3 3]
 [2 3 3 4 4 4]
 [4 4 4 5 5 6]
 [5 5 6 6 6 7]
 [6 6 7 7 8 8]]
Resampled by a factor of 2 with cubic interpolation:
[[0 0 1 1 2 2]
 [1 1 1 2 2 3]
 [2 2 3 3 4 4]
 [4 4 5 5 6 6]
 [5 6 6 7 7 7]
 [6 6 7 7 8 8]]

Edit: Wie Matt S. ausführte, gibt es einige Einschränkungen beim Zoomen von Multiband-Bildern. Ich kopiere den folgenden Teil fast wörtlich aus einem meiner frühere Antworten :

Das Zoomen funktioniert auch für 3D-Arrays (und nD-Arrays). Beachten Sie jedoch, dass Sie, wenn Sie beispielsweise um das Zweifache zoomen, entlang all Achsen zoomen.

data = np.arange(27).reshape(3,3,3)
print 'Original:\n', data
print 'Zoomed by 2x gives an array of shape:', ndimage.zoom(data, 2).shape

Dies ergibt:

Original:
[[[ 0  1  2]
  [ 3  4  5]
  [ 6  7  8]]

 [[ 9 10 11]
  [12 13 14]
  [15 16 17]]

 [[18 19 20]
  [21 22 23]
  [24 25 26]]]
Zoomed by 2x gives an array of shape: (6, 6, 6)

Bei Bildern mit mehreren Bändern möchten Sie normalerweise nicht entlang der "z" -Achse interpolieren, um neue Bänder zu erstellen.

Wenn Sie so etwas wie ein 3-Band-RGB-Bild haben, das Sie zoomen möchten, können Sie dies tun, indem Sie eine Folge von Tupeln als Zoomfaktor angeben:

print 'Zoomed by 2x along the last two axes:'
print ndimage.zoom(data, (1, 2, 2))

Dies ergibt:

Zoomed by 2x along the last two axes:
[[[ 0  0  1  1  2  2]
  [ 1  1  1  2  2  3]
  [ 2  2  3  3  4  4]
  [ 4  4  5  5  6  6]
  [ 5  6  6  7  7  7]
  [ 6  6  7  7  8  8]]

 [[ 9  9 10 10 11 11]
  [10 10 10 11 11 12]
  [11 11 12 12 13 13]
  [13 13 14 14 15 15]
  [14 15 15 16 16 16]
  [15 15 16 16 17 17]]

 [[18 18 19 19 20 20]
  [19 19 19 20 20 21]
  [20 20 21 21 22 22]
  [22 22 23 23 24 24]
  [23 24 24 25 25 25]
  [24 24 25 25 26 26]]]
100
Joe Kington

Wenn Sie ein Resample erstellen möchten, sollten Sie in Scipys Kochbuch nach Rebinning suchen. Insbesondere die am Ende definierte Funktion congrid unterstützt Rebinning oder Interpolation (entspricht der gleichnamigen Funktion in IDL). Dies sollte die schnellste Option sein, wenn Sie keine Interpolation wünschen.

Sie können auch direkt scipy.ndimage.map_coordinates verwenden, um eine Spline-Interpolation für jede Art von Resampling (einschließlich unstrukturierter Gitter) durchzuführen. Ich finde map_coordinates langsam für große Arrays (nx, ny> 200).

Für die Interpolation auf strukturierten Gittern verwende ich normalerweise scipy.interpolate.RectBivariateSpline . Sie können die Reihenfolge des Splines (linear, quadratisch, kubisch usw.) und sogar unabhängig für jede Achse auswählen. Ein Beispiel:

    import scipy.interpolate as interp
    f = interp.RectBivariateSpline(x, y, im, kx=1, ky=1)
    new_im = f(new_x, new_y)

In diesem Fall führen Sie eine bi-lineare Interpolation durch (kx = ky = 1). Die nächstgelegene Art der Interpolation wird nicht unterstützt, da dies nur eine Spline-Interpolation über ein Rechtecknetz ist. Es ist auch nicht die schnellste Methode.

Wenn Sie nach bi-linearer oder bikubischer Interpolation suchen, ist es im Allgemeinen viel schneller, zwei 1D-Interpolationen durchzuführen:

    f = interp.interp1d(y, im, kind='linear')
    temp = f(new_y)
    f = interp.interp1d(x, temp.T, kind='linear')
    new_im = f(new_x).T

Sie können auch kind='nearest' Verwenden, in diesem Fall jedoch die Quer-Arrays entfernen.

13
tiago

Hast du dir Scikit-Bild angesehen? Es ist transform.pyramid_* Funktionen könnten für Sie nützlich sein.

8
Peter Wang

Ich habe kürzlich ein Problem mit scipy.ndimage.interpolation.zoom gefunden, das ich als Fehlerbericht eingereicht habe: https://github.com/scipy/scipy/issues/32

Als Alternative (oder zumindest für mich) habe ich festgestellt, dass die Datei skimage.transform.resize von scikit-image korrekt funktioniert: http://scikit-image.org/docs/dev/api/skimage.transform) .html # skimage.transform.resize

Dies funktioniert jedoch anders als die interpolation.zoom von scipy - anstatt einen Multiplikator anzugeben, geben Sie die gewünschte Ausgabeform an. Dies funktioniert für 2D- und 3D-Bilder.

Für nur 2D-Bilder können Sie transform.rescale verwenden und einen Multiplikator oder eine Skala wie bei interpolation.zoom angeben.

6
Zehan

Diese Lösung skaliert X und Y des eingespeisten Bildes, ohne die RGB-Kanäle zu beeinflussen:

import numpy as np
import scipy.ndimage

matplotlib.pyplot.imshow(scipy.ndimage.zoom(image_np_array, zoom = (7,7,1), order = 1))

Hoffe das ist nützlich.

0
Martin Frasch