Ordnen Sie die Daten in einem zweidimensionalen Array entsprechend der Transformation von polaren zu kartesischen Koordinaten neu an

8

Ich habe ein zweidimensionales Array, das Funktionswerte an Positionen in einem Polarkoordinatensystem darstellt. Zum Beispiel:

import numpy as np

radius = np.linspace(0, 1, 50)
angle = np.linspace(0, 2*np.pi, radius.size)
r_grid, a_grid = np.meshgrid(radius, angle)
data = np.sqrt((r_grid/radius.max())**2
               + (a_grid/angle.max())**2)

Hier dataist das in einem rechteckigen Gitter angeordnet, das den Polarkoordinaten entspricht. Ich möchte die Daten im Array so neu anordnen, dass die Achsen das entsprechende kartesische Koordinatensystem darstellen. Das alte und das neue Layout können wie folgt dargestellt werden:

import matplotlib.pyplot as plt

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=plt.figaspect(0.5))
ax1.set(title='Polar coordinates', xlabel='Radius', ylabel='Angle')
ax1.pcolormesh(r_grid, a_grid, data)
ax2.set(title='Cartesian coordinates', xlabel='X', ylabel='Y')
x_grid = r_grid * np.cos(a_grid)
y_grid = r_grid * np.sin(a_grid)
ax2.pcolormesh(x_grid, y_grid, data)

Beispiel

Hier werden die Koordinaten explizit angegeben und das Diagramm entsprechend angepasst. Ich möchte, dass die Daten stattdessen im Datenarray selbst neu angeordnet werden. Es sollte alle Werte enthalten und optional mit Nullen gefüllt sein, um der Form zu entsprechen (ähnlich wie scipy.ndimage.rotate(..., reshape=True)).

Wenn ich die polaren Arrays manuell durchlaufe, um die kartesischen Koordinaten zu berechnen, enthält das Ergebnis leere Bereiche, die idealerweise auch gefüllt werden sollten:

new = np.zeros_like(data)
visits = np.zeros_like(new)
for r, a, d in np.nditer((r_grid, a_grid, data)):
    i = 0.5 * (1 + r * np.sin(a)) * new.shape[0]
    j = 0.5 * (1 + r * np.cos(a)) * new.shape[1]
    i = min(int(i), new.shape[0] - 1)
    j = min(int(j), new.shape[1] - 1)
    new[i, j] += d
    visits[i, j] += 1
new /= np.maximum(visits, 1)
ax2.imshow(new, origin='lower')

Beispielversuch

Gibt es eine Möglichkeit, die Transformation zu erreichen und gleichzeitig leere Bereiche im resultierenden Datenarray zu vermeiden?

ein Gast
quelle

Antworten:

2

tl; dr: Nein, nicht ohne einige Bedingungen Ihres Problems zu ändern.

Das Artefakt, das Sie sehen, ist eine Eigenschaft der Transformation. Dies liegt nicht an der festen Winkelauflösung für alle Radien. Daher liegt es nicht an einer falschen oder schlechten Implementierung der Transformation. Das kartesische Gitter impliziert einfach eine höhere spezielle Auflösung in diesen Bereichen, da es aufgelöste Punkte von der Polarkarte gibt.

  • Die einzige "saubere" Möglichkeit (die mir derzeit einfällt), dies zu handhaben, besteht darin, eine einstellbare Auflösung in den Polarkoordinaten zu haben, um die 1 / r-Skalierung zu berücksichtigen. (Wenn Sie Daten eingeben, ist dies zulässig.)

  • Eine etwas betrügerische Art, dies ohne die Lücken zu visualisieren, würde darin bestehen, sie zufällig über die Lücken zu verteilen. Das Argument hier ist, dass Sie nicht die Auflösung haben, um zu entscheiden, in welchem ​​Bin sie anfangen sollten. Sie könnten sie also zufällig in eine werfen, die ein möglicher Ursprung gewesen sein könnte, und sie nicht alle in dieselbe werfen (wie Sie es gerade tun). Ich möchte diese Stärke jedoch entmutigen. Es gibt Ihnen nur eine schönere Handlung. Beachten Sie, dass dies in etwa dem Verhalten des oberen rechten Diagramms in Ihrer Frage entspricht.

465b
quelle
In der Tat besteht das Problem darin, die räumliche Auflösung mit zunehmendem Radius zu verringern, da die Winkelauflösung fest ist. Ich habe gerade einen Ansatz versucht, bei dem die Winkeldaten für jeden Radius mit einer Dichte interpoliert werden, die proportional zu ist, 1/rbevor die Transformation in kartesische Koordinaten berechnet wird. Die Ergebnisse sehen vielversprechend aus, es sind nur noch wenige Artefakte y = 0übrig, also beschäftige ich mich noch damit.
a_guest
1

Dies liefert nicht wirklich das erwartete Ergebnis, hilft Ihnen aber möglicherweise dabei, nach einigen erforderlichen Korrekturen eine Lösung zu finden ...


import numpy as np

radius = np.linspace(0, 1, 50)
angle = np.linspace(0, 2*np.pi, radius.size)
r_grid, a_grid = np.meshgrid(radius, angle)
data = np.sqrt((r_grid/radius.max())**2
               + (a_grid/angle.max())**2)


def polar_to_cartesian(data):
    new = np.zeros_like(data) * np.nan
    x = np.linspace(-1, 1, new.shape[1])
    y = np.linspace(-1, 1, new.shape[0])
    for i in range(new.shape[0]):
        for j in range(new.shape[1]):
            x0, y0 = x[j], y[i]
            r, a = np.sqrt(x0**2 + y0**2), np.arctan2(y0, x0)
            data_i = np.argmin(np.abs(a_grid[:, 0] - a))
            data_j = np.argmin(np.abs(r_grid[0, :] - r))
            val = data[data_i, data_j]

            if r <= 1:
                new[i, j] = val

    return new

new = polar_to_cartesian(data)
fig, ax = plt.subplots()
ax.imshow(new, origin='lower')

Geben Sie hier die Bildbeschreibung ein

EDIT: Geändert mit np.arctan2gemäß den Vorschlägen von OP.

dzang
quelle
Um die richtige Winkelabhängigkeit zu erhalten, np.arctan2sollte verwendet werden, dies führt jedoch in jedem Fall zu großen Abweichungen zu den Rändern des kartesischen Koordinatensystems. In der Realität gibt es keine Datenpunkte, aber da dieser Ansatz nur den nächsten verfügbaren Datenpunkt berücksichtigt, wird er gefüllt, während dies nicht der Fall sein sollte.
a_guest
@a_guest in der Tat berücksichtigt es nur den nächsten Wert. Es wird im Grunde eine Interpolation des nächsten Nachbarn durchgeführt. Wenn Sie eine fortgeschrittenere Interpolation benötigen, wird dies wahrscheinlich viel komplizierter, da die Interpolation im radialen Raum erfolgen sollte. Vielleicht wäre es eine Möglichkeit, skimage.transform.resizedas polare Bild um einen bestimmten Faktor aufzurüsten und eine bilineare bikubische Interpolation zu verwenden und dann diesen Ansatz zu verwenden, um die Transformation durchzuführen. Sie würden mit einer genaueren Transformation enden.
10.
@a_guest Begrenzung des Radius auf 1 könnte die Randprobleme lösen?
10.
0

Sie können das kartesische Array durchlaufen, jeden Gitterpunkt in Polarkoordinaten umwandeln und den Funktionswert durch Interpolation aus Ihren polaren Gitterdaten approximieren. Möglicherweise möchten Sie die Eckbereiche dennoch leer lassen, da nicht genügend Daten vorhanden sind.

Ich denke nicht, dass es einen besseren Weg gibt, es sei denn, Sie haben natürlich Zugriff auf die ursprüngliche Funktion.

Arne
quelle
Wenn ich Sie richtig verstehe, werden diese interpolierten Gitterpunkte "zwischen" den aktuellen Gitterpunkten positioniert. Daher ist es unentscheidbar, von welchem ​​Gitterpunkt sie kamen. Oder habe ich dich falsch verstanden?
465b
Ja, wenn Sie einen der kartesischen Gitterpunkte in Polarkoordinaten umwandeln, liegt dieser im Allgemeinen irgendwo zwischen vier der polaren Gitterpunkte. Sie weisen ihm also einen Funktionswert zu, indem Sie einen Durchschnitt der Funktionswerte dieser vier Gitterpunkte nehmen, gewichtet nach der Entfernung. Das habe ich mit Interpolation gemeint.
Arne
Ah, in Ordnung. Dies macht die einzelnen Punkte jedoch nur "größer", da sie auf vier Punkte verteilt werden, was nur für niedrige Werte von r hilfreich ist. Dies führt immer noch zu einem sternförmigen Muster für größere Werte von r
465b
Nein, das würde ich nicht sagen. Mit der oben beschriebenen Methode können Sie für jeden einzelnen kartesischen Gitterpunkt eine eindeutige Schätzung des Funktionswerts berechnen.
Arne