1. はじめに
PIL と Numpy プログラミングを使用して、画像の自由な回転を実現します。
2. 技術的なポイント
(1) Python PIL ライブラリを使用して、画像を NumPy 配列として読み取ります。
(2)回転後の画像サイズを拡大する画像回転変換方式を採用し、回転角度と元の画像サイズに応じて画像画素の回転変換行列を計算する。
(3) 回転変換行列を使用して、回転後の元の画像の 4 つの頂点のピクセル座標を計算し、最大座標から最小座標を減算して回転後の画像の新しいサイズを計算し、そのサイズを格納する NumPy 配列を作成します。新しいイメージ。(4)逆マッピング
の方法に従って、新しい画像のピクセルをスキャンし、逆変換によって対応する元の画像のピクセルを決定し、その RGB 値を新しい画像のピクセルに割り当てます。(5) NumPy 配列を画像出力として保存します。
3. コードの実装
def rotateImageWithZoom(image_path: str, rotate_angle: float):
"""
放大图幅的图片旋转
:param image_path: 图片路径
:param rotate_angle: 旋转角度,单位:degree,顺时针为正
:return: 新的图片numpy数组
"""
img = Image.open(image_path)
img_mat = np.asarray(img)
beta = deg2rad(rotate_angle)
h = img_mat.shape[0]
w = img_mat.shape[1]
K1 = np.array([[0, -1, 0.5 * h], [1, 0, 0.5 * w], [0, 0, 1]])
K2 = np.array([[cos(beta), sin(beta), 0], [-sin(beta), cos(beta), 0], [0, 0, 1]])
# 坐标变换矩阵
K = np.matmul(K1, K2)
# 旋转后左上角像素点位置
left_up = np.matmul(K, np.array([[0], [0], [1]]))
# 旋转后左下角像素点位置
left_down = np.matmul(K, np.array([[h - 1], [0], [1]]))
# 旋转后右上角像素点位置
right_up = np.matmul(K, np.array([[0], [w - 1], [1]]))
# 旋转后右下角像素点位置
right_down = np.matmul(K, np.array([[h - 1], [w - 1], [1]]))
# 确定外接矩形尺寸
x1 = np.array([left_up.reshape((left_up.shape[0],)),
left_down.reshape((left_up.shape[0],)),
right_up.reshape((left_up.shape[0],)),
right_down.reshape((left_up.shape[0],))]).astype(int)
# 旋转后图像尺寸
new_h = np.max(x1[:, 0]) - np.min(x1[:, 0])
new_w = np.max(x1[:, 1]) - np.min(x1[:, 1])
x_min = np.min(x1[:, 0])
y_min = np.min(x1[:, 1])
# 新图像
new_img_mat = np.ones((new_h, new_w, 3)) * 255
# 反向映射
K_inv = np.linalg.inv(K)
for x in range(new_img_mat.shape[0]):
for y in range(new_img_mat.shape[1]):
old_pos = np.matmul(K_inv, np.array([[x + x_min + 1], [y + y_min + 1], [1]])).astype(int)
if 0 <= old_pos[0] < h and 0 <= old_pos[1] < w:
new_img_mat[x, y] = img_mat[old_pos[0], old_pos[1]]
# numpy数组转图片
new_img_mat = new_img_mat.astype(int)
new_img = Image.fromarray(new_img_mat.astype(np.uint8))
new_img.save('photos/rotated_photo_{}.png'.format(rotate_angle))
plt.imshow(new_img_mat)
plt.xlabel("${} ^0$".format(rotate_angle))
plt.show()
return new_img_mat.astype(int)
4.効果を実感する
使用方法は次のとおりです。
if __name__ == '__main__':
rotateImageWithZoom('photos/takagi.jpeg', -60.3)
元の画像:
回転 -60.3°:
注: matplotlib が画像を描画する場合、x 軸は画像の高さ、y 軸は画像の幅ですが、一般的な画像ビューアの x 軸は幅、y 軸は画像の幅です。高さ。
5. 結果の分析
回転後の画像のサイズが大きく変化しています。拡大すると-61.3°回転した画像がぼやけていることもわかります。これは、回転変換の際に各ピクセルをサイズのない理想的な点としてみなしたためです。回転後の座標は 10 進数 (つまり、サブピクセル座標) が表示され、逆マッピング中に座標が丸められるため、丸め誤差が生じ、一部のピクセルが失われます。0°、90°、180°、-90°の角度では丸め誤差が 0 であるため、フレームの変更を除いて回転後の鮮明さの変化はありません。
結論:画像を回転および変形するときは、ピクセルの損失による画質の低下を避けるために、特別な角度を選択するようにしてください。-10°、-61.3° などの特殊な角度ではない場合は、透明度が基本的に変わらないことを保証するために、回転後にブレを除去します。