pythonmatplotlibimage-processingimage-rotationcontourf

How can I plot a specific profile from rotated data on contourf or pcolormesh graph


I have an image stored in a numpy array. I have created a function to rotate that data by an angle theta. To perform the rotation the function converts the index coordinates of the image (i,j) to (x,y) and applies a rotation matrix. Then the function returns a meshgrid for the rotated (X, Y) coordinates.

I would like to overlay the non-rotated image and the rotated image on the same coordinate system and extract specific vertical & horizontal profiles. I cannot navigate the rotated image properly because it can only be navigated with 'ij' using the map_coordinates function(as far as I know).

Setup and function definitions:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import pyplot as plt
def rotate_image(arr, dpi, theta_degrees = 0.0, pivot_point = [0,0]):

  theta_radians = (np.pi/180.0)* theta_degrees
  c = round(np.cos(theta_radians), 3)
  s = round(np.sin(theta_radians), 3)

  rotation_matrix = np.array([[c, -s, 0],
                              [s, c, 0],
                              [0, 0,  1]])
  #print(rotation_matrix)

  width, height = arr.shape
  pivot_point_xy = np.array([(25.4 / dpi[0])* pivot_point[0], (25.4/dpi[1])*pivot_point[1]])
  pivot_shift_vector = np.array([[pivot_point_xy[0]],
                                 [pivot_point_xy[1]],
                                 [0]])
  
  x = (25.4 / dpi[0]) * np.array(range(width)) #convert pixels to mm units
  y = (25.4 / dpi[1]) * np.array(range(height))#convert pixels to mm units
  
  XX , YY = np.meshgrid(x,y)
  ZZ = arr
  coordinates = np.stack([XX,YY,ZZ])
  #shift to rotation point, apply rotation, shift back to original coordinates
  coordinates_reshape = np.reshape(coordinates, (3,-1))
  translated_coordinates = coordinates_reshape - pivot_shift_vector
  rotated_coordinates = np.matmul(rotation_matrix, translated_coordinates)
  final_coordinates = rotated_coordinates + pivot_shift_vector
  final_coordinates_reshaped = np.reshape(final_coordinates, (3, width, height))
  
  return final_coordinates_reshaped

Example plots:

img = np.arange(1,26).reshape((5,5))

rotated_img_0 = rotate_image(img, theta_degrees= 0, dpi =[1,1], pivot_point = [2.5,2.5])
rotated_img_1 = rotate_image(img, theta_degrees= 45, dpi =[1,1], pivot_point = [2.5,2.5])

# plot
fig, ax = plt.subplots(2, 1, figsize = (10,20))

ax[0].pcolormesh(*rotated_img_0, vmin=0, vmax=rotated_img_0[2].max())
ax[0].pcolormesh(*rotated_img_1, vmin=0, vmax=rotated_img_1[2].max(), alpha = 0.7)
ax[0].hlines(60, rotated_img_1[0].min(), rotated_img_1[0].max() , color = 'black')

ax[1].contourf(*rotated_img_0, vmin=0, vmax=rotated_img_0[2].max())
ax[1].contourf(*rotated_img_1, vmin=0, vmax=rotated_img_1[2].max(), alpha = 0.7)
ax[1].hlines(60, rotated_img_1[0].min(), rotated_img_1[0].max() , color = 'black')

plt.show()

I tried to adapt from scipy the interpolate2d methods outlined here but it doesn't work on rotated data: https://docs.scipy.org/doc//scipy-0.17.0/reference/generated/scipy.interpolate.interp2d.html

Map_coordinates also works on the non-rotated data using 'ij' coordinates. Simple slicing of i,j would also be ok for my purposes.

I would like to be able to extract the same profile from each chart at the same xy coordinates. Example of the output of the included code.  Extract profiles shown by horizontal line


Solution

  • Although this isn't a direct answer I decided that it was best to go around the problem. I rewrote the rotate_image function so that simple array slicing can be used to extract the profiles using map_coordinates function.

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy import ndimage
    
    def rotate_image(img, theta_degrees = 0.0, pivot_point = np.array([[0], 
    [0]])):
    
        width , height = img.shape
    
        #compute the 2D rotation matrix
        theta_radians = (np.pi/180.0)* theta_degrees
        c = round(np.cos(theta_radians), 3)
        s = round(np.sin(theta_radians), 3)
    
        rotation_matrix = np.array([[c, -s],
                              [s, c]])
    
        #create a sampling point cloud using meshgrid
        X, Y = range(width), range(height)
        XX , YY = np.meshgrid(X, Y)
        coordinates = np.stack([XX, YY])
        coordinates_reshape = np.reshape(coordinates, (2,-1))
    
        #rotate the image around the chosen pivot point
        translated_coordinates = coordinates_reshape - pivot_point
        rotated_coordinates = np.matmul(rotation_matrix, 
          translated_coordinates)
        final_coordinates = rotated_coordinates + pivot_point
        final_coordinates_reshaped = np.reshape(final_coordinates, (2, width, 
                  height))
    
        #use scipy map_coordinates function to resample the image at the new 
        #coordinates
        rotated_image = ndimage.map_coordinates(img, 
                         final_coordinates_reshaped, mode = 'constant')
    
        return rotated_image
    
    img = np.random.rand(100, 100)*100
    
    rotated_img = rotate_image(img, 20, np.array([[50],[50]]))
    
    #graph Results
    fig, ax = plt.subplots(2,1)
    ax[0].imshow(rotated_img)
    ax[0].hlines(50, 0, 99)
    ax[1].plot(rotated_img[50])
    

    enter image description here