开发者

Reprojecting polar to cartesian grid

开发者 https://www.devze.com 2022-12-19 01:42 出处:网络
I have a polar (r,theta) grid (which means that each cell is an annulus section) containing values of some physical quantity (e.g. temperature), and I would like to re-grid (or re-project, or resample

I have a polar (r,theta) grid (which means that each cell is an annulus section) containing values of some physical quantity (e.g. temperature), and I would like to re-grid (or re-project, or resample) these values onto a cartesian grid. Are there any Python packages that can do this?

I am not interested in converting the coord开发者_JAVA百科inates of the centers of the cells from polar to cartesian - this is very easy. Instead, I'm looking for a package that can actually re-grid the data properly.

Thanks for any suggestions!


Thanks for your answers - after thinking a bit more about this I came up with the following code:

import numpy as np

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as mpl

from scipy.interpolate import interp1d
from scipy.ndimage import map_coordinates


def polar2cartesian(r, t, grid, x, y, order=3):

    X, Y = np.meshgrid(x, y)

    new_r = np.sqrt(X*X+Y*Y)
    new_t = np.arctan2(X, Y)

    ir = interp1d(r, np.arange(len(r)), bounds_error=False)
    it = interp1d(t, np.arange(len(t)))

    new_ir = ir(new_r.ravel())
    new_it = it(new_t.ravel())

    new_ir[new_r.ravel() > r.max()] = len(r)-1
    new_ir[new_r.ravel() < r.min()] = 0

    return map_coordinates(grid, np.array([new_ir, new_it]),
                            order=order).reshape(new_r.shape)

# Define original polar grid

nr = 10
nt = 10

r = np.linspace(1, 100, nr)
t = np.linspace(0., np.pi, nt)
z = np.random.random((nr, nt))

# Define new cartesian grid

nx = 100
ny = 200

x = np.linspace(0., 100., nx)
y = np.linspace(-100., 100., ny)

# Interpolate polar grid to cartesian grid (nearest neighbor)

fig = mpl.figure()
ax = fig.add_subplot(111)
ax.imshow(polar2cartesian(r, t, z, x, y, order=0), interpolation='nearest')
fig.savefig('test1.png')

# Interpolate polar grid to cartesian grid (cubic spline)

fig = mpl.figure()
ax = fig.add_subplot(111)
ax.imshow(polar2cartesian(r, t, z, x, y, order=3), interpolation='nearest')
fig.savefig('test2.png')

Which is not strictly re-gridding, but works fine for what I need. Just posting the code in case it is useful to anyone else. Feel free to suggest improvements!


I came to this post some time ago when trying to do something similar, this is, reprojecting polar data into a cartesian grid and vice-versa. The solution proposed here works fine. However, it takes some time to perform the coordinate transform. I just wanted to share another approach which can reduce the processing time up to 50 times or more.

The algorithm uses the scipy.ndimage.interpolation.map_coordinates function.

Let's see a little example:

import numpy as np

# Auxiliary function to map polar data to a cartesian plane
def polar_to_cart(polar_data, theta_step, range_step, x, y, order=3):

    from scipy.ndimage.interpolation import map_coordinates as mp

    # "x" and "y" are numpy arrays with the desired cartesian coordinates
    # we make a meshgrid with them
    X, Y = np.meshgrid(x, y)

    # Now that we have the X and Y coordinates of each point in the output plane
    # we can calculate their corresponding theta and range
    Tc = np.degrees(np.arctan2(Y, X)).ravel()
    Rc = (np.sqrt(X**2 + Y**2)).ravel()

    # Negative angles are corrected
    Tc[Tc < 0] = 360 + Tc[Tc < 0]

    # Using the known theta and range steps, the coordinates are mapped to
    # those of the data grid
    Tc = Tc / theta_step
    Rc = Rc / range_step

    # An array of polar coordinates is created stacking the previous arrays
    coords = np.vstack((Ac, Sc))

    # To avoid holes in the 360º - 0º boundary, the last column of the data
    # copied in the begining
    polar_data = np.vstack((polar_data, polar_data[-1,:]))

    # The data is mapped to the new coordinates
    # Values outside range are substituted with nans
    cart_data = mp(polar_data, coords, order=order, mode='constant', cval=np.nan)

    # The data is reshaped and returned
    return(cart_data.reshape(len(y), len(x)).T)

polar_data = ... # Here a 2D array of data is assumed, with shape thetas x ranges

# We create the x and y axes of the output cartesian data
x = y = np.arange(-100000, 100000, 1000)

# We call the mapping function assuming 1 degree of theta step and 500 meters of
# range step. The default order of 3 is used.
cart_data = polar_to_cart(polar_data, 1, 500, x, y)

I hope this helps someone in the same situation as me.


OpenCV 3.4 can do this now pretty easily with warpPolar()

Very simple to call:

import numpy as np
import cv2
from matplotlib import pyplot as plt

# Read in our image from disk
image = cv2.imread('washington_quarter.png',0)
plt.imshow(image),plt.show()

Reprojecting polar to cartesian grid

margin = 0.9 # Cut off the outer 10% of the image
# Do the polar rotation along 1024 angular steps with a radius of 256 pixels.
polar_img = cv2.warpPolar(image, (256, 1024), (image.shape[0]/2,image.shape[1]/2), image.shape[1]*margin*0.5, cv2.WARP_POLAR_LINEAR)
# Rotate it sideways to be more visually pleasing
polar_img = cv2.rotate(polar_img, cv2.ROTATE_90_COUNTERCLOCKWISE)
plt.imshow(polar_img),plt.show()

Reprojecting polar to cartesian grid


You can do this more compactly with scipy.ndimage.geometric_transform. Here is some sample code:

import numpy as N
import scipy as S
import scipy.ndimage

temperature = <whatever> 
# This is the data in your polar grid.
# The 0th and 1st axes correspond to r and θ, respectively.
# For the sake of simplicity, θ goes from 0 to 2π, 
# and r's units are just its indices.

def polar2cartesian(outcoords, inputshape, origin):
    """Coordinate transform for converting a polar array to Cartesian coordinates. 
    inputshape is a tuple containing the shape of the polar array. origin is a
    tuple containing the x and y indices of where the origin should be in the
    output array."""

    xindex, yindex = outcoords
    x0, y0 = origin
    x = xindex - x0
    y = yindex - y0

    r = N.sqrt(x**2 + y**2)
    theta = N.arctan2(y, x)
    theta_index = N.round((theta + N.pi) * inputshape[1] / (2 * N.pi))

    return (r,theta_index)

temperature_cartesian = S.ndimage.geometric_transform(temperature, polar2cartesian, 
    order=0,
    output_shape = (temperature.shape[0] * 2, temperature.shape[0] * 2),
    extra_keywords = {'inputshape':temperature.shape,
        'center':(temperature.shape[0], temperature.shape[0])})

You can change order=0 as desired for better interpolation. The output array temperature_cartesian is 2r by 2r here, but you can specify any size and origin you like.


Are there any Python packages that can do this?

Yes! There is now – at least one – Python package that has a function to re-map a matrix from cartesian to polar coordinates: abel.tools.polar.reproject_image_into_polar(), which is part of the PyAbel package.

(Iñigo Hernáez Corres is correct, scipy.ndimage.interpolation.map_coordinates is the fastest way that we have found so far to reproject from cartesian to polar coordinates.)

PyAbel can be installed from PyPi by entering the following on the command line:

pip install pyabel

Then, in python, you can use the following code to re-project an image into polar coordinates:

import abel
abel.tools.polar.reproject_image_into_polar(MyImage)

[Depending on the application, you might consider passing the jacobian=True argument, which re-scales the intensities of the matrix to take into the account the stretching of the grid (changing "bin sizes") that takes place when you transform from Cartesian to polar coodinates.]

Here is a complete example:

import numpy as np
import matplotlib.pyplot as plt
import abel

CartImage = abel.tools.analytical.sample_image(501)[201:-200, 201:-200]

PolarImage, r_grid, theta_grid = abel.tools.polar.reproject_image_into_polar(CartImage)

fig, axs = plt.subplots(1,2, figsize=(7,3.5))
axs[0].imshow(CartImage , aspect='auto', origin='lower')
axs[1].imshow(PolarImage, aspect='auto', origin='lower', 
              extent=(np.min(theta_grid), np.max(theta_grid), np.min(r_grid), np.max(r_grid)))

axs[0].set_title('Cartesian')
axs[0].set_xlabel('x')
axs[0].set_ylabel('y')

axs[1].set_title('Polar')
axs[1].set_xlabel('Theta')
axs[1].set_ylabel('r')

plt.tight_layout()
plt.show()

Reprojecting polar to cartesian grid

Note: there is another good discussion (about re-mapping color images to polar coordinates) on SO: image information along a polar coordinate system

0

精彩评论

暂无评论...
验证码 换一张
取 消