【深度好文】2D坐标系下的点的转换矩阵(平移、缩放、旋转、错切)

本文主要用于回顾二维平面上点的转换矩阵相关概念和应用。

1. 平移 (Translation)

在2D空间中,我们经常需要将一个点平移到另一个位置。假设空间中的一点P,其用坐标表示为(x,y);将其向 x方向平移 tx,向y方向平移ty, 假设平移后点的坐标为(x’,y’),则上述点的平移操作可以归纳为如下公式:
在这里插入图片描述
使用齐次矩阵表示如下:
在这里插入图片描述
将上述过程用代码实现如下:

import matplotlib
import matplotlib.pyplot as plt
import numpy as np

X, Y = np.mgrid[0:1:5j, 0:1:5j]
x, y = X.ravel(), Y.ravel()

def trans_translate(x, y, tx, ty):
    T = [[1, 0, tx],
         [0, 1, ty],
         [0, 0, 1]]
    T = np.array(T)
    P = np.array([x, y, [1] * x.size])
    return np.dot(T, P)

fig, ax = plt.subplots(1, 4)
T_ = [[0, 0], [2.3, 0], [0, 1.7], [2, 2]]
for i in range(4):
    tx, ty = T_[i]
    x_, y_, _ = trans_translate(x, y, tx, ty)
    ax[i].scatter(x_, y_)
    ax[i].set_title(r'$t_x={0:.2f}$ , $t_y={1:.2f}$'.format(tx, ty))

    ax[i].set_xlim([-0.5, 4])
    ax[i].set_ylim([-0.5, 4])
    ax[i].grid(alpha=0.5)
    ax[i].axhline(y=0, color='k')
    ax[i].axvline(x=0, color='k')
plt.show()

效果图如下:
在这里插入图片描述

动态效果如下:
在这里插入图片描述

2. 缩放 (Scaling)

在2D空间中,对点(x,y)常用的另一种操作为相对于另一点(px,py)进行缩放操作,我们不妨x方向的缩放因子为sx,y方向的缩放因子为sy, 则上述点(x,y)相对于点(px,py)的缩放操作可以归纳为如下公式:
在这里插入图片描述
使用齐次矩阵表示如下:
在这里插入图片描述

将上述过程用代码实现如下:

def trans_scale(x, y, px, py, sx, sy):
    T = [[sx, 0 , px*(1 - sx)],
         [0 , sy, py*(1 - sy)],
         [0 , 0 , 1          ]]
    T = np.array(T)
    P = np.array([x, y, [1]*x.size])
    return np.dot(T, P)

fig, ax = plt.subplots(1, 4)
S_ = [[1, 1], [1.8, 1], [1, 1.7], [2, 2]]
P_ = [[0, 0], [0, 0], [0.45, 0.45], [1.1, 1.1]]
for i in range(4):
    sx, sy = S_[i]; px, py = P_[i]
    x_, y_, _ = trans_scale(x, y, px, py, sx, sy)
    ax[i].scatter(x_, y_)
    ax[i].scatter(px, py)
    ax[i].set_title(r'$p_x={0:.2f}$ , $p_y={1:.2f}$'.format(px, py) + '\n'
                    r'$s_x={0:.2f}$ , $s_y={1:.2f}$'.format(sx, sy))
    
    ax[i].set_xlim([-2, 2])
    ax[i].set_ylim([-2, 2])
    ax[i].grid(alpha=0.5)
    ax[i].axhline(y=0, color='k')
    ax[i].axvline(x=0, color='k')

plt.show()

效果图如下:
在这里插入图片描述

动态效果如下:
在这里插入图片描述

3. 旋转 (Rotation)

在2D空间中,对点(x,y)常用的另一种操作为相对于另一点(px,py)进行旋转操作,一般来说逆时针为正,顺时针为负,假设旋转角度为beta, 则上述点(x,y)相对于点(px,py)的旋转角度beta的操作可以归纳为如下公式:
在这里插入图片描述

使用齐次矩阵表示如下:
在这里插入图片描述

将上述过程用代码实现如下:

def trans_rotate(x, y, px, py, beta):
    beta = np.deg2rad(beta)
    T = [[np.cos(beta), -np.sin(beta), px*(1 - np.cos(beta)) + py*np.sin(beta)],
         [np.sin(beta),  np.cos(beta), py*(1 - np.cos(beta)) - px*np.sin(beta)],
         [0           ,  0           , 1                                      ]]
    T = np.array(T)
    P = np.array([x, y, [1]*x.size])
    return np.dot(T, P)

fig, ax = plt.subplots(1, 4)

R_ = [0, 225, 40, -10]
P_ = [[0, 0], [0, 0], [0.5, -0.5], [1.1, 1.1]]

for i in range(4):
    beta = R_[i]; px, py = P_[i]
    x_, y_, _ = trans_rotate(x, y, px, py, beta)
    ax[i].scatter(x_, y_)
    ax[i].scatter(px, py)
    ax[i].set_title(r'$\beta={0}°$ , $p_x={1:.2f}$ , $p_y={2:.2f}$'.format(beta, px, py))
    
    ax[i].set_xlim([-2, 2])
    ax[i].set_ylim([-2, 2])
    ax[i].grid(alpha=0.5)
    ax[i].axhline(y=0, color='k')
    ax[i].axvline(x=0, color='k')

plt.show

效果图如下:
在这里插入图片描述

动态效果如下:
在这里插入图片描述

4. 错切 (Shearing)

在2D空间中,对点(x,y)常用的另一种操作为相对于另一点(px,py)进行错切操作,错切一般用于弹性物体的变形处理。 不妨假设沿x方向错切参数为lambdax,沿y方向的错切参数为lambday, 则上述点(x,y)相对于点(px,py)的错切操作可以归纳为如下公式:
在这里插入图片描述

使用齐次矩阵表示如下:
在这里插入图片描述

将上述过程用代码实现如下:

def trans_shear(x, y, px, py, lambdax, lambday):
    T = [[1      , lambdax, -lambdax*px],
         [lambday, 1      , -lambday*py],
         [0      , 0      ,  1         ]]
    T = np.array(T)
    P = np.array([x, y, [1]*x.size])
    return np.dot(T, P)

fig, ax = plt.subplots(1, 4)

L_ = [[0, 0], [2, 0], [0, -2], [-2, -2]]
P_ = [[0, 0], [0, 0], [0, 1.5], [1.1, 1.1]]

for i in range(4):
    lambdax, lambday = L_[i]; px, py = P_[i]
    x_, y_, _ = trans_shear(x, y, px, py, lambdax, lambday)
    ax[i].scatter(x_, y_)
    ax[i].scatter(px, py)
    ax[i].set_title(r'$p_x={0:.2f}$ , $p_y={1:.2f}$'.format(px, py) + '\n'
                    r'$\lambda_x={0:.2f}$ , $\lambda_y={1:.2f}$'.format(lambdax, lambday))

    ax[i].set_xlim([-3, 3])
    ax[i].set_ylim([-3, 3])
    ax[i].grid(alpha=0.5)
    ax[i].axhline(y=0, color='k')
    ax[i].axvline(x=0, color='k')

plt.show()

效果图如下:
在这里插入图片描述

动态效果如下:
在这里插入图片描述

5. 总结

有了以上平移、旋转、缩放和错切矩阵后,我们就可以通过矩阵乘法求得点P任意变化后坐标。

关注公众号《AI算法之道》,获取更多AI算法资讯.
在这里插入图片描述

  • 14
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
这是一个比较复杂的问题,需要用到一些数学知识和算法。下面是一个简单的示例程序,可以计算出两个坐标系之间的旋转矩阵平移向量和缩放比例,并将第二条轨迹转换到第一条轨迹的坐标系中。 ```c++ #include <iostream> #include <vector> #include <Eigen/Dense> using namespace Eigen; int main() { // 定义两条轨迹的坐标 std::vector<Vector3d> trajectory1 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; std::vector<Vector3d> trajectory2 = {{2, 3, 4}, {5, 6, 7}, {8, 9, 10}}; // 计算每条轨迹的质心 Vector3d centroid1 = Vector3d::Zero(); Vector3d centroid2 = Vector3d::Zero(); for (auto& p : trajectory1) centroid1 += p; centroid1 /= trajectory1.size(); for (auto& p : trajectory2) centroid2 += p; centroid2 /= trajectory2.size(); // 计算每条轨迹的协方差矩阵 Matrix3d cov1 = Matrix3d::Zero(); Matrix3d cov2 = Matrix3d::Zero(); for (auto& p : trajectory1) cov1 += (p - centroid1) * (p - centroid1).transpose(); cov1 /= trajectory1.size(); for (auto& p : trajectory2) cov2 += (p - centroid2) * (p - centroid2).transpose(); cov2 /= trajectory2.size(); // 计算旋转矩阵缩放比例 JacobiSVD<Matrix3d> svd(cov1.inverse() * cov2, ComputeFullU | ComputeFullV); Matrix3d R = svd.matrixV() * svd.matrixU().transpose(); double scale = (cov1.inverse() * cov2).trace() / 3.0; // 计算平移向量 Vector3d t = centroid1 - scale * R * centroid2; // 输出结果 std::cout << "Rotation matrix:\n" << R << std::endl; std::cout << "Scale factor: " << scale << std::endl; std::cout << "Translation vector:\n" << t << std::endl; // 将第二条轨迹转换到第一条轨迹的坐标系中 for (auto& p : trajectory2) p = scale * R * p + t; return 0; } ``` 需要注意的是,这个程序假设两条轨迹的数相同,并且的顺序相同。如果实际情况不符合这些假设,就需要进行额外的处理。另外,这个程序还假设两个坐标系之间只存在旋转平移缩放,如果存在其他变换,例如错切变换,就需要使用更复杂的算法。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵卓不凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值