You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

126 lines
4.6 KiB

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import 透视变换
import cv2
def build_3d_rotation_matrix(elev, azim, roll):
"""生成基于elev/azim/roll的完整旋转矩阵"""
elev_rad = np.radians(elev)
azim_rad = np.radians(azim)
roll_rad = np.radians(roll)
# 绕x轴旋转(elevation)
Rx = np.array([
[1, 0, 0],
[0, np.cos(elev_rad), -np.sin(elev_rad)],
[0, np.sin(elev_rad), np.cos(elev_rad)]
])
# 绕y轴旋转(azimuth)
Ry = np.array([
[np.cos(azim_rad), 0, np.sin(azim_rad)],
[0, 1, 0],
[-np.sin(azim_rad), 0, np.cos(azim_rad)]
])
# 绕z轴旋转(roll)
Rz = np.array([
[np.cos(roll_rad), -np.sin(roll_rad), 0],
[np.sin(roll_rad), np.cos(roll_rad), 0],
[0, 0, 1]
])
return Rz @ Ry @ Rx # 组合旋转顺序
if __name__ == '__main__':
# 参数设置
elev, azim, roll = 34, 0,-35
rotation_3d = build_3d_rotation_matrix(elev, azim, roll)
# 创建单位圆
theta = np.linspace(0, 2 * np.pi, 100)
x = np.cos(theta)
y = np.sin(theta)
z = np.zeros_like(x)
circle = np.vstack((x, y, z)) # 3xN
circle_transformed = rotation_3d @ circle
# 逆矩阵
inverse_matrix = np.linalg.inv(rotation_3d)
# 画图
fig = plt.figure(figsize=(12, 6))
# 设置窗口透明度
fig.canvas.manager.window.attributes('-alpha', 0.6) # 设置窗口透明度为 0.6
ax1 = fig.add_subplot(121, projection='3d')
ax2 = fig.add_subplot(122, projection='3d')
# 标识圆心
ax1.scatter(0, 0, 0, color='red', s=20, label='Center')
# 原始单位圆
ax1.plot(circle[0], circle[1], circle[2], label='Original Circle')
# 原始单位圆 横轴和纵轴
ax1.plot(circle[0], np.zeros_like(theta), circle[2], label='z View', color='r')
ax1.plot(np.zeros_like(theta), circle[1], circle[2], label='h View', color='b')
ax1.set_title('Original Circle (elev=90°, roll=0°)')
ax1.set_xlim([-1, 1])
ax1.set_ylim([-1, 1])
ax1.set_zlim([-1, 1])
ax1.set_box_aspect([1, 1, 1])
ax1.set_xlabel('X')
ax1.set_ylabel('Y')
ax1.set_zlabel('Z')
ax1.view_init(elev=90, azim=90) # 从Z轴方向观察 保持opencv方向一致 x->左 y->下
# 变换后的单位圆
# 标识圆心
ax2.scatter(0, 0, 0, color='red', s=20, label='Center')
ax2.plot(circle_transformed[0], circle_transformed[1], circle_transformed[2], color='r', label='Transformed Circle')
ax2.set_title('Transformed (elev=52°, roll=-35°)')
ax2.set_xlim([-1, 1])
ax2.set_ylim([-1, 1])
ax2.set_zlim([-1, 1])
ax2.set_xlabel('X')
ax2.set_ylabel('Y')
ax2.set_zlabel('Z')
ax2.set_box_aspect([1, 1, 1])
ax2.view_init(elev=90, azim=90) # 从Z轴方向观察
plt.show()
image_zhen= cv2.imread("images/trans/transformed_image.jpg")
image_xie = cv2.imread("images/trans/subRawImg.jpg")
# transformed_image_hy = cv2.warpPerspective(transformed_image, inverse_matrix, dsize=(image.shape[1], image.shape[0]))
# # 执行变换(自动计算输出图像尺寸)
# 裁剪像素值到 [0, 255] 范围
# 获取图像的大小
height, width = image_zhen.shape[:2]
# 计算中心点坐标
center_x = width // 2
center_y = height // 2
# 构造一个平移矩阵,将原点移到中心
M_translate = np.float32([
[1, 0, -1*center_x],
[0, 1, -1*center_y],
[0, 0, 1]
])
image_xie_padding = cv2.warpPerspective(image_xie, M_translate,
dsize=(image_xie.shape[1], image_xie.shape[0]))
cv2.imshow("image_xie_padding", image_xie_padding)
# 将平移矩阵与目标变换矩阵结合起来
# inverse_M_combined = np.dot(M_translate, inverse_matrix)
inverse_matrix[2][2]=1.0
inverse_M_combined = np.dot(M_translate, inverse_matrix)
print(f"斜矩阵={rotation_3d}")
rotation_3d_int = np.clip(rotation_3d, 0, 255)
print(f"斜矩阵_int={rotation_3d}")
print(f"逆矩阵={inverse_M_combined}")
inverse_M_combined_int = np.clip(inverse_M_combined, 0, 255)
# print(f"逆矩阵_int={inverse_M_combined_int}")
transformed_image_hy = cv2.warpPerspective(image_xie, inverse_M_combined_int,
dsize=(image_xie.shape[1]*2, image_xie.shape[0]*2))
cv2.imshow("transformed_image_hy", transformed_image_hy)
# transformed_image = cv2.warpPerspective(image_zhen, rotation_3d_int,dsize=(image_zhen.shape[1], image_zhen.shape[0]))
# cv2.imshow("rotated_img", transformed_image)
plt.show()
cv2.waitKey(0)
# cv2.destroyAllWindows()