Reprojecting polar to cartesian grid

前端 未结 5 1053
不思量自难忘°
不思量自难忘° 2020-12-24 14:22

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

相关标签:
5条回答
  • 2020-12-24 14:48

    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()
    

    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()
    

    0 讨论(0)
  • 2020-12-24 14:50

    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.

    0 讨论(0)
  • 2020-12-24 14:50

    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()
    

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

    0 讨论(0)
  • 2020-12-24 14:53

    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!

    0 讨论(0)
  • 2020-12-24 15:07

    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.

    0 讨论(0)
提交回复
热议问题