Да, как вы подозреваете, вращение происходит относительно верхнего левого угла, который имеет координаты (0, 0). (Также: тригонометрические функции NumPy используют радианы , а не градусы, поэтому вам нужно преобразовать угол.) Чтобы вычислить вращение относительно центра, вы делаете небольшой хак: вы вычисляете преобразование для перемещенияизображение так, чтобы оно было отцентрировано (0, 0), затем вы поворачиваете его, а затем перемещаете результат назад. Вам нужно объединить эти преобразования в последовательности, потому что если вы сделаете это одно за другим, вы потеряете все в отрицательных координатах.
Это сделать намного проще, используя Однородные координаты , которые добавляют дополнительное "фиктивное" измерение к вашему изображению. Вот как ваш код будет выглядеть в однородных координатах:
import numpy as np
from matplotlib import pyplot as plt
from skimage import io
image = io.imread('sample_image')
img_transformed = np.zeros((image.shape), dtype=np.uint8)
c, s = np.cos(np.radians(45)), np.sin(np.radians(45))
rot_matrix = np.array([[c, s, 0], [-s, c, 0], [0, 0, 1]])
x, y = np.array(image.shape) // 2
# move center to (0, 0)
translate1 = np.array([[1, 0, -x], [0, 1, -y], [0, 0, 1]])
# move center back to (x, y)
translate2 = np.array([[1, 0, x], [0, 1, y], [0, 0, 1]])
# compose all three transformations together
trans_matrix = translate2 @ rot_matrix @ translate1
for i, row in enumerate(image):
for j,col in enumerate(row):
pixel_data = image[i,j] #get the value of pixel at corresponding location
input_coord = np.array([i, j, 1]) #this will be my [x,y] matrix
result = trans_matrix @ input_coord
i_out, j_out, _ = result #store the resulting coordinate location
#make sure the the i and j values remain within the index range
if (0 < int(i_out) < image.shape[0]) and (0 < int(j_out) < image.shape[1]):
img_transformed[int(i_out)][int(j_out)] = pixel_data
plt.imshow(img_transformed, cmap='gray')
Вышеприведенное должно работать нормально, но вы, вероятно, получите некоторые черные пятна из-за алиасинга . Может случиться так, что нет координат i, j от входной земли точно на выходном пикселе, так что пиксель никогда не обновляется. Вместо этого вам нужно выполнить итерацию по пикселям выходного изображения, а затем использовать обратное преобразование, чтобы найти, какой пиксель во входном изображении отображается ближе всего к этому выходному пикселю. Что-то вроде:
inverse_tform = np.linalg.inv(trans_matrix)
for i, j in np.ndindex(img_transformed.shape):
i_orig, j_orig, _ = np.round(inverse_tform @ [i, j, 1]).astype(int)
if i_orig in range(image.shape[0]) and j_orig in range(image.shape[1]):
img_transformed[i, j] = image[i_orig, j_orig]
Надеюсь, это поможет!