2D和3D图形变换与矩阵的关系

图形变换

举一个例子将第一象限的坐标 ( 1 , 4 ) 点顺时针旋转 π 2 后对应点的坐标 ? 首先告诉你一个矩阵( 2 D 图形顺时针旋转矩阵,不用管怎么来的) [ cos ⁡ ( θ ) sin ⁡ ( θ ) 0 − sin ⁡ ( θ ) cos ⁡ ( θ ) 0 0 0 1 ] 将坐标 ( 1 , 4 ) → [ 1 4 1 ] 计算变换后的坐标 [ cos ⁡ ( π 2 ) sin ⁡ ( π 2 ) 0 − sin ⁡ ( π 2 ) cos ⁡ ( π 2 ) 0 0 0 1 ] [ 1 4 1 ] = [ 0 1 0 − 1 0 0 0 0 1 ] [ 1 4 1 ] = [ 4 − 1 1 ]    ⟹    ( 4 , − 1 ) . 这就是矩阵的乘法在几何中妙用,接下来我们就看看有哪些类似 − 2 D 图形顺时针旋转矩阵 − 的矩阵。 举一个例子将第一象限的坐标(1,4)点顺时针旋转\frac{\pi}{2}后对应点的坐标?\\ 首先告诉你一个矩阵(2D图形顺时针旋转矩阵,不用管怎么来的)\\ \left[\begin{matrix}{\cos(\theta)}&{\sin(\theta)}&{0}\\{-\sin(\theta)}&{\cos(\theta)}&{0}\\{0}&{0}&{1}\\\end{matrix}\right]\\ 将坐标(1,4)\rightarrow\begin{bmatrix}1\\4\\1\end{bmatrix}\\ 计算变换后的坐标\begin{bmatrix}\cos(\frac\pi2)&\sin(\frac\pi2)&0\\-\sin(\frac\pi2)&\cos(\frac\pi2)&0\\0&0&1\end{bmatrix}\begin{bmatrix}1\\4\\1\end{bmatrix}=\begin{bmatrix}0&1&0\\-1&0&0\\0&0&1\end{bmatrix}\begin{bmatrix}1\\4\\1\end{bmatrix}=\begin{bmatrix}4\\-1\\1\end{bmatrix}\implies(4,-1).\\ 这就是矩阵的乘法在几何中妙用,接下来我们就看看有哪些类似-2D图形顺时针旋转矩阵-的矩阵。 举一个例子将第一象限的坐标(1,4)点顺时针旋转2π后对应点的坐标?首先告诉你一个矩阵(2D图形顺时针旋转矩阵,不用管怎么来的) cos(θ)sin(θ)0sin(θ)cos(θ)0001 将坐标(1,4) 141 计算变换后的坐标 cos(2π)sin(2π)0sin(2π)cos(2π)0001 141 = 010100001 141 = 411 (4,1).这就是矩阵的乘法在几何中妙用,接下来我们就看看有哪些类似2D图形顺时针旋转矩阵的矩阵。

2D图形各种变换矩阵

2D图形变换代码实现

平移

dx:左移距离
dy:右移距离
注:当俩个都存在的时候表名可以左移矩阵乘右移矩阵(可以试试),也可以理解左右移动复合(这里没有谁先谁后的概念)。

[ 1 0 d x 0 1 d y 0 0 1 ] \left[\begin{array}{ccc}1&0&dx\\0&1&dy\\0&0&1\end{array}\right] 100010dxdy1

顺时针旋转

为了方便这里角度为正

[ cos ⁡ ( θ ) sin ⁡ ( θ ) 0 − sin ⁡ ( θ ) cos ⁡ ( θ ) 0 0 0 1 ] \left[\begin{matrix}{\cos(\theta)}&{\sin(\theta)}&{0}\\{-\sin(\theta)}&{\cos(\theta)}&{0}\\{0}&{0}&{1}\\\end{matrix}\right] cos(θ)sin(θ)0sin(θ)cos(θ)0001

逆时针旋转

为了方便这里角度也为正

[ cos ⁡ ( θ ) − sin ⁡ ( θ ) 0 sin ⁡ ( θ ) cos ⁡ ( θ ) 0 0 0 1 ] \left[\begin{array}{ccc}{\cos(\theta)}&{-\sin(\theta)}&{0}\\{\sin(\theta)}&{\cos(\theta)}&{0}\\{0}&{0}&{1}\\\end{array}\right] cos(θ)sin(θ)0sin(θ)cos(θ)0001

放缩与镜像

Sx:Sx>1表示x方向放大,0<Sx<1表示x方向缩小。-1<Sx<0表示x方向缩小且镜像,Sx=-1在x方向仅仅镜像,Sx<-1在x方向放大且镜像
Sy:Sy>1表示x方向放大,0<Sy<1表示y方向缩小。-1<Sy<0表示y方向缩小且镜像,Sy=-1在x方向仅仅镜像,Sy<-1在y方向放大且镜像

[ S x 0 0 0 S y 0 0 0 1 ] \left.\left[\begin{matrix}{Sx}&{0}&{0}\\{0}&{Sy}&{0}\\{0}&{0}&{1}\\\end{matrix}\right.\right] Sx000Sy0001

裁剪

shx:y轴不变沿着x轴移动(虽然和平移差不多,但是不同y移动的幅度是不一样,这就导致整个图形是倾斜的。矩形会变成平行四边形)
shy:x轴不变沿着y轴移动(同理)

[ 1 s h x 0 s h y 1 0 0 0 1 ] \begin{bmatrix}1&shx&0\\shy&1&0\\0&0&1\end{bmatrix} 1shy0shx10001

3D图形各种变换矩阵

3D图形变换代码实现

平移

参考2D平移的参数

[ 1 0 0 d x 0 1 0 d y 0 0 1 d z 0 0 0 1 ] \left[\begin{array}{cccc}1&0&0&dx\\0&1&0&dy\\0&0&1&dz\\0&0&0&1\end{array}\right] 100001000010dxdydz1

在x轴顺、逆时针旋转

参考2D旋转的参数。这里的顺、逆时针,是让对应坐标轴的箭头插入眼睛。然后左顺,右逆。

顺 : [ 1 0 0 0 0 cos ⁡ ( θ ) sin ⁡ ( θ ) 0 0 − sin ⁡ ( θ ) cos ⁡ ( θ ) 0 0 0 0 1 ] 逆 : [ 1 0 0 0 0 cos ⁡ ( θ ) − sin ⁡ ( θ ) 0 0 sin ⁡ ( θ ) cos ⁡ ( θ ) 0 0 0 0 1 ] 顺:\left.\left[\begin{array}{cccc}1&0&0&0\\0&\cos(\theta)&\sin(\theta)&0\\0&-\sin(\theta)&\cos(\theta)&0\\0&0&0&1\end{array}\right.\right] 逆:\begin{bmatrix}1&0&0&0\\0&\cos(\theta)&-\sin(\theta)&0\\0&\sin(\theta)&\cos(\theta)&0\\0&0&0&1\end{bmatrix} : 10000cos(θ)sin(θ)00sin(θ)cos(θ)00001 : 10000cos(θ)sin(θ)00sin(θ)cos(θ)00001

在y轴顺、逆时针旋转

顺 : [ cos ⁡ ( θ ) 0 sin ⁡ ( θ ) 0 0 1 0 0 − sin ⁡ ( θ ) 0 cos ⁡ ( θ ) 0 0 0 0 1 ] 逆 : [ cos ⁡ ( θ ) 0 − sin ⁡ ( θ ) 0 0 1 0 0 sin ⁡ ( θ ) 0 cos ⁡ ( θ ) 0 0 0 0 1 ] 顺:\begin{bmatrix}\cos(\theta)&0&\sin(\theta)&0\\0&1&0&0\\-\sin(\theta)&0&\cos(\theta)&0\\0&0&0&1\end{bmatrix} 逆:\begin{bmatrix}\cos(\theta)&0&-\sin(\theta)&0\\0&1&0&0\\\sin(\theta)&0&\cos(\theta)&0\\0&0&0&1\end{bmatrix} : cos(θ)0sin(θ)00100sin(θ)0cos(θ)00001 : cos(θ)0sin(θ)00100sin(θ)0cos(θ)00001

在z轴顺、逆时针旋转

顺 : [ cos ⁡ ( θ ) sin ⁡ ( θ ) 0 0 − sin ⁡ ( θ ) cos ⁡ ( θ ) 0 0 0 0 1 0 0 0 0 1 ] 逆 : [ cos ⁡ ( θ ) − sin ⁡ ( θ ) 0 0 sin ⁡ ( θ ) cos ⁡ ( θ ) 0 0 0 0 1 0 0 0 0 1 ] 顺:\left[\begin{array}{cccc}\cos\left(\theta\right)&\sin\left(\theta\right)&0&0\\-\sin\left(\theta\right)&\cos\left(\theta\right)&0&0\\0&0&1&0\\0&0&0&1\end{array}\right] 逆:\begin{bmatrix}\cos\left(\theta\right)&-\sin\left(\theta\right)&0&0\\\sin\left(\theta\right)&\cos\left(\theta\right)&0&0\\0&0&1&0\\0&0&0&1\end{bmatrix} : cos(θ)sin(θ)00sin(θ)cos(θ)0000100001 : cos(θ)sin(θ)00sin(θ)cos(θ)0000100001

放缩和镜像

参考2D放缩和镜像

[ S x 0 0 0 0 S y 0 0 0 0 S z 0 0 0 0 1 ] \begin{bmatrix}Sx&0&0&0\\0&Sy&0&0\\0&0&Sz&0\\0&0&0&1\end{bmatrix} Sx0000Sy0000Sz00001

透视投影

模拟人眼或相机在观察三维场景时所看到的景象,考虑了物体距离观察者的远近关系。透视投影使离观察者更远的物体看起来较小,与现实中的效果相似。
fov: 视野角度(Field of View Angle)
aspect: 屏幕纵横比(Aspect Ratio)
near: 近剪裁面(Near Clipping Plane)
far: 远剪裁面(Far Clipping Plane)

[ 1 aspect ⋅ tan ⁡ ( fov 2 ) 0 0 0 0 1 tan ⁡ ( fov 2 ) 0 0 0 0 − far + near far − near − 2 ⋅ far ⋅ near far − near 0 0 − 1 0 ] \begin{bmatrix} \frac{1}{{\text{{aspect}} \cdot \tan(\frac{{\text{{fov}}}}{2})}} & 0 & 0 & 0 \\ 0 & \frac{1}{{\tan(\frac{{\text{{fov}}}}{2})}} & 0 & 0 \\ 0 & 0 & -\frac{{\text{{far}} + \text{{near}}}}{{\text{{far}} - \text{{near}}}} & -\frac{{2 \cdot \text{{far}} \cdot \text{{near}}}}{{\text{{far}} - \text{{near}}}} \\ 0 & 0 & -1 & 0 \\ \end{bmatrix} aspecttan(2fov)10000tan(2fov)10000farnearfar+near100farnear2farnear0

正交投影

将物体投影到一个平行的二维平面上(三视图的每一视都属于正交投影),不考虑物体的远近效果(投影面积与实际物理面积一致),因此在投影中不会发生透视效果。
left, right: 这些参数定义了平行投影平面的左右截断平面,决定了投影的宽度。
bottom, top: 这些参数定义了平行投影平面的底部和顶部截断平面,决定了投影的高度。
near, far: 近剪裁面和远剪裁面定义了可见空间的深度范围,物体在这个范围之外的部分将不可见。这些参数决定了投影的深度

[ 2 ( r i g h t − l e f t ) 0 0 − ( r i g h t + l e f t ) ( r i g h t − l e f t ) 0 2 ( t o p − b o t t o m ) 0 − ( t o p + b o t t o m ) ( t o p − b o t t o m ) 0 0 2 ( f a r − n e a r ) − ( f a r + n e a r ) ( f a r − n e a r ) 0 0 0 1 ] \begin{bmatrix}\frac2{(right-left)}&0&0&-\frac{(right+left)}{(right-left)}\\0&\frac2{(top-bottom)}&0&-\frac{(top+bottom)}{(top-bottom)}\\0&0&\frac2{(far-near)}&-\frac{(far+near)}{(far-near)}\\0&0&0&1\end{bmatrix} (rightleft)20000(topbottom)20000(farnear)20(rightleft)(right+left)(topbottom)(top+bottom)(farnear)(far+near)1

2D和3D变换的代码

2D变换

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

# 打开图片
image = Image.open("img.png")

# 将图像转换为NumPy数组
image_array = np.array(image)

# 获取图像的宽度和高度
width, height, channels = image_array.shape

# 创建一个空白的NumPy数组,用于保存转化后的图像数据
transformational_image_array = np.zeros_like(image_array, dtype=np.uint8)

# 定义新的change_array用于移动、旋转、放缩、镜像图片,这里的矩阵和图片中的每个像素实际位置进行乘法运算
change_array = np.array([
    [-1, 0, 300],
    [0, -1, 300],
    [0, 0, 1]
])

# 遍历图像的每个像素位置
for x in range(width):
    for y in range(height):
        # 获取当前像素的颜色值
        pixel_color = image_array[x, y]

        # 计算新位置的像素坐标
        final_x, final_y, _ = np.dot(change_array, [x - width / 2, y - height / 2, 1]).astype(int)
        final_x = int(final_x + width / 2)  # 转为整数
        final_y = int(final_y + height / 2)

        # 确保镜像后的坐标在合法范围内
        if 0 <= final_x < width and 0 <= final_y < height:
            transformational_image_array[x, y] = image_array[final_x, final_y]

# 创建一个包含两个子图的图像
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))

# 在第一个子图中显示原始图像
ax1.imshow(image_array)
ax1.set_title('Original Image')
ax1.axis('off')  # 不显示坐标轴

# 在第二个子图中显示变换后的图像
ax2.imshow(transformational_image_array)
ax2.set_title('Transformational Image')
ax2.axis('off')  # 不显示坐标轴

# 显示图像
plt.show()

# 关闭图片对象
image.close()

3D变换

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import numpy as np

# 创建一个Figure对象和3D坐标轴
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# 定义正方体的顶点坐标,恰好是xyz单位向量为边的正方体。
vertices = np.array([
    [0, 0, 0],
    [1, 0, 0],
    [1, 1, 0],
    [0, 1, 0],
    [0, 0, 1],
    [1, 0, 1],
    [1, 1, 1],
    [0, 1, 1]
])

# 创建复合变换矩阵
composite_matrix = np.array([
    [-1, 0, 0, -0.5],  # 镜像、不放缩和平移(X轴上向负方向移动0.5个距离)
    [0, -2, 0, 0],     # 镜像、放大(Y轴上负方向放大2倍)和没有在Y轴上平移
    [0, 0, -2, 0],     # 镜像、放大(Z轴上负方向放大2倍)和没有在Z轴上平移
    [0, 0, 0, 1]
])

# 给vertices(空间点坐标)增加最后全1列(为了和复合变换矩阵可以作乘法运算补充出来的)
num_rows, num_cols = vertices.shape
new_column = np.ones((num_rows, 1), dtype=int)
vertices_new = np.hstack((vertices, new_column))
# 应用复合变换到正方体的顶点,注意要转置矩阵
transformetional_vertices = np.dot(vertices_new, composite_matrix.T)
# 定义正方体的面
faces = [
    [vertices[0], vertices[1], vertices[2], vertices[3]],
    [vertices[4], vertices[5], vertices[6], vertices[7]],
    [vertices[0], vertices[1], vertices[5], vertices[4]],
    [vertices[2], vertices[3], vertices[7], vertices[6]],
    [vertices[1], vertices[2], vertices[6], vertices[5]],
    [vertices[0], vertices[3], vertices[7], vertices[4]]
]

# 绘制原始正方体的面
ax.add_collection3d(Poly3DCollection(faces, facecolors='cyan', linewidths=1, edgecolors='r', alpha=.25))

# 去掉最后一行
mirrored_vertices = transformetional_vertices[:, :-1]

# 绘制镜像后的正方体的面
mirrored_faces = [
    [mirrored_vertices[0], mirrored_vertices[1], mirrored_vertices[2], mirrored_vertices[3]],
    [mirrored_vertices[4], mirrored_vertices[5], mirrored_vertices[6], mirrored_vertices[7]],
    [mirrored_vertices[0], mirrored_vertices[1], mirrored_vertices[5], mirrored_vertices[4]],
    [mirrored_vertices[2], mirrored_vertices[3], mirrored_vertices[7], mirrored_vertices[6]],
    [mirrored_vertices[1], mirrored_vertices[2], mirrored_vertices[6], mirrored_vertices[5]],
    [mirrored_vertices[0], mirrored_vertices[3], mirrored_vertices[7], mirrored_vertices[4]]
]

# 绘制镜像后的正方体的面
ax.add_collection3d(Poly3DCollection(mirrored_faces, facecolors='magenta', linewidths=1, edgecolors='k', alpha=.25))

# 绘制X、Y、Z轴
ax.quiver(0, 0, 0, 1.2, 0, 0, color='red', label='X')
ax.quiver(0, 0, 0, 0, 1.2, 0, color='green', label='Y')
ax.quiver(0, 0, 0, 0, 0, 1.2, color='blue', label='Z')

# 设置X轴、Y轴和Z轴的刻度位置和标签
ax.set_xticks(np.arange(-2, 2, step=1))  # 设置X轴刻度
ax.set_yticks(np.arange(-2, 2, step=1))  # 设置Y轴刻度
ax.set_zticks(np.arange(-2, 2, step=1))  # 设置Z轴刻度

# 设置坐标轴标签
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')

# 显示图例
ax.legend()

# 显示图形
plt.show()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值