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.
 

163 lines
4.7 KiB

import cv2
import numpy as np
from math import cos, sin, radians
def get_rotation_matrix(angle_x, angle_y, angle_z):
"""生成3D旋转矩阵"""
# 转换为弧度
rx = radians(angle_x)
ry = radians(angle_y)
rz = radians(angle_z)
# X轴旋转矩阵
mat_x = np.array([
[1, 0, 0],
[0, cos(rx), -sin(rx)],
[0, sin(rx), cos(rx)]
])
# Y轴旋转矩阵
mat_y = np.array([
[cos(ry), 0, sin(ry)],
[0, 1, 0],
[-sin(ry), 0, cos(ry)]
])
# Z轴旋转矩阵
mat_z = np.array([
[cos(rz), -sin(rz), 0],
[sin(rz), cos(rz), 0],
[0, 0, 1]
])
# 组合旋转矩阵
rotation_matrix = np.dot(np.dot(mat_x, mat_y), mat_z)
return rotation_matrix
def perspective_transform(image, angle_x=0, angle_y=0, angle_z=0, scale=1.0):
"""应用透视变换"""
h, w = image.shape[:2]
# 获取旋转矩阵
rotation_matrix = get_rotation_matrix(angle_x, angle_y, angle_z)
# 创建3D点到2D点的映射
# 将2D图像视为3D空间中Z=0平面上的物体
points_3d = np.array([
[0, 0, 0], # 左上
[w, 0, 0], # 右上
[w, h, 0], # 右下
[0, h, 0] # 左下
], dtype=np.float32)
# 应用旋转
points_3d_rotated = np.dot(points_3d, rotation_matrix.T)
# 添加透视效果 - 这里简单地将Z坐标作为深度
# 可以调整这个值来改变透视强度
points_2d_homo = points_3d_rotated[:, :2] / (scale - points_3d_rotated[:, 2:3] * 0.001)
# 计算变换矩阵
src_points = np.array([[0, 0], [w, 0], [w, h], [0, h]], dtype=np.float32)
dst_points = points_2d_homo.astype(np.float32)
# 计算中心偏移
min_xy = dst_points.min(axis=0)
max_xy = dst_points.max(axis=0)
dst_points -= min_xy
# 计算新图像大小
new_w = int(max_xy[0] - min_xy[0])
new_h = int(max_xy[1] - min_xy[1])
# 获取透视变换矩阵
M = cv2.getPerspectiveTransform(src_points, dst_points)
# 应用变换
transformed = cv2.warpPerspective(image, M, (new_w, new_h))
return transformed
def combined_perspective_transform(image, angle_x1, angle_y1, angle_z1, angle_y2, scale1=1.0, scale2=1.0):
"""合并两次变换:第一次任意旋转,第二次Y轴旋转"""
h, w = image.shape[:2]
# 第一次旋转矩阵
rot1 = get_rotation_matrix(angle_x1, angle_y1, angle_z1)
# 第二次旋转矩阵 (Y轴旋转)
rot2 = get_rotation_matrix(0, angle_y2, 0)
# 合并旋转矩阵
combined_rot = np.dot(rot2, rot1)
# 创建3D点到2D点的映射
points_3d = np.array([
[0, 0, 0], # 左上
[w, 0, 0], # 右上
[w, h, 0], # 右下
[0, h, 0] # 左下
], dtype=np.float32)
# 应用合并后的旋转
points_3d_rotated = np.dot(points_3d, combined_rot.T)
# 添加透视效果
points_2d_homo = points_3d_rotated[:, :2] / ((scale1 * scale2) - points_3d_rotated[:, 2:3] * 0.001)
# 计算变换矩阵
src_points = np.array([[0, 0], [w, 0], [w, h], [0, h]], dtype=np.float32)
dst_points = points_2d_homo.astype(np.float32)
# 计算中心偏移
min_xy = dst_points.min(axis=0)
max_xy = dst_points.max(axis=0)
dst_points -= min_xy
# 计算新图像大小
new_w = int(max_xy[0] - min_xy[0])
new_h = int(max_xy[1] - min_xy[1])
# 获取透视变换矩阵
M = cv2.getPerspectiveTransform(src_points, dst_points)
# 应用变换
transformed = cv2.warpPerspective(image, M, (new_w, new_h))
return transformed
def show_transformed():
image = cv2.imread('images/trans/transformed_image.jpg')
# 应用透视变换
# 参数说明:angle_x, angle_y, angle_z 分别为绕X,Y,Z轴的旋转角度
# scale 控制透视效果的强度
transformed = perspective_transform(image, angle_x=34, angle_y=43, angle_z=-35, scale=1)
# 显示结果
cv2.imshow('Original', image)
cv2.imshow('Transformed', transformed)
cv2.waitKey(0)
cv2.destroyAllWindows()
def show_transformed_combined():
image = cv2.imread('images/trans/transformed_image.jpg')
if image is None:
print("请替换为您的图片路径")
else:
# 第一次变换:任意角度
# 第二次变换:Y轴旋转90度
final_result = combined_perspective_transform(
image,
angle_x1=34, angle_y1=0, angle_z1=-35, # 第一次旋转参数
angle_y2=43, # 第二次Y轴旋转90度
scale1=1.2, scale2=1.0 # 透视参数
)
cv2.imshow('Original', image)
cv2.imshow('Final Result', final_result)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
show_transformed_combined()