构建旋转变换矩阵对二维到高维空间的线段点进行旋转

  • 问题:在二维空间中,假设你有一条线段,其一个端点固定在原点 (0, 0),另一个端点的初始位置为 (x1,y1) 。现在这条线段绕原点旋转了 θ 度(以弧度为单位),需要计算旋转后另一个端点的新位置 (x2,y2) 。

  • 旋转后的坐标可以通过以下公式计算:

    • x 2 = x 1 c o s ( θ ) − y 1 s i n ( θ ) y 2 = x 1 s i n ( θ ) + y 1 c o n ( θ ) x_2=x_1cos(θ)−y_1sin(θ)\\ y_2=x_1sin(θ)+y_1con(θ) x2=x1cos(θ)−y1sin(θ)y2=x1sin(θ)+y1con(θ)

    • x1,y1 是初始位置的坐标。θ 是旋转的角度(以弧度为单位)。x2,y2 是旋转后的位置坐标。

    python 复制代码
    import numpy as np
    from matplotlib import pyplot as plt
    import cv2
    def rotate_point(x1, y1, theta):
        """
        旋转一个点 (x1, y1) 绕原点 (0, 0) 旋转 theta 弧度。
        参数: x1, y1: 初始点的坐标。theta: 旋转角度(以弧度为单位)。
        返回: x2, y2: 旋转后点的坐标。
        """
        # 将角度转换为弧度
        theta_rad = np.radians(theta)
        x2 = x1 * np.cos(theta_rad) - y1 * np.sin(theta_rad)
        y2 = x1 * np.sin(theta_rad) + y1 * np.cos(theta_rad)
        # print("np.cos(theta_rad) , np.sin(theta_rad)",np.cos(theta_rad),np.sin(theta_rad))
        # print("np.sin(theta_rad) , np.cos(theta_rad)",np.sin(theta_rad),np.cos(theta_rad))
        return x2, y2
    def rotate_points(points, theta):
        """
        批量旋转多个点,参数 points 是二维数组,每一行表示一个点的坐标。
        参数 theta 是旋转角度(以弧度为单位)。
        返回值是旋转后的坐标。
        """
        x1, y1 = points.T
        x2, y2 = rotate_point(x1, y1, theta)
        return np.vstack((x2, y2)).T
    def rotate_point_by_warpAffine(x1, y1, theta):
        """
        利用 OpenCV 的 warpAffine 函数实现旋转一个点。
        参数: x1, y1: 初始点的坐标。theta: 旋转角度(以弧度为单位)。
        返回: x2, y2: 旋转后点的坐标。
        """
        bg_width = 400
        bg_height = 600
        background = np.zeros((bg_height, bg_width, 3), dtype=np.uint8)
        background.fill(255)  # 填充为白色
        cv2.circle(background, (int(bg_width / 2), int(bg_height / 2)), 5, (0, 0, 0), -1)  # 黑色圆点
        cv2.putText(background, f'center: (0, 0)', (int(bg_width / 2), int(bg_height / 2)),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)  # 黑色坐标
        normalize_factor = np.sqrt(x1*x1 + y1*y1)
        x1 = np.intp((x1/normalize_factor)* 200)+bg_width/2
        y1 = np.intp((y1/normalize_factor)* 200)+bg_height/2
        print("x1,y1",x1,y1)
        # 在背景上绘制初始点
        cv2.circle(background, (int(x1), int(y1)), 5, (0, 0, 255), -1)  # 红色点
        cv2.putText(background, f'rotated', (int(x1), int(y1)), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 255), 1)  # 红色坐标
        cv2.line(background, (0, int(bg_height/2)), (bg_width, int(bg_height/2)), (0, 0, 0), 1)
        cv2.line(background, (int(bg_width/2), 0), (int(bg_width/2), bg_height), (0, 0, 0), 1)
        M = cv2.getRotationMatrix2D((bg_width / 2, bg_height / 2), theta, 1)  # 旋转中心, 旋转角度, 缩放比例
        # 应用旋转矩阵
        rotated_image = cv2.warpAffine(background, M, (bg_width, bg_height))   # opencv 与 numpy 坐标系不同,需要调整
        # 在旋转后的图像上绘制旋转后的点
        cv2.circle(rotated_image, (int(x1), int(y1)), 5, (0, 255, 0), -1)  # 绿色点
        cv2.putText(rotated_image, f'original: ({x1-bg_width/2}, {y1-bg_height/2})', (int(x1), int(y1)), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1)  # 绿色坐标
        # 显示图像
        cv2.imshow('Rotated Point', rotated_image)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    def plot_rotation(x1, y1, x2, y2, theta_degrees):
        """
        绘制初始点和旋转后的点,并显示旋转角度。
        参数:x1, y1: 初始点的坐标。x2, y2: 旋转后点的坐标。 theta_degrees: 旋转角度(以度为单位)。
        """
        fig, ax = plt.subplots()
        # 绘制初始点
        ax.plot(x1, y1, 'ro', label='Initial Point')
        ax.text(x1, y1, f'({x1}, {y1})', fontsize=12, ha='right')
        # 绘制旋转后的点
        ax.plot(x2, y2, 'bo', label='Rotated Point')
        ax.text(x2, y2, f'({x2:.2f}, {y2:.2f})', fontsize=12, ha='left')
        # 绘制连接线
        ax.plot([0, x1], [0, y1], 'r--', label='Initial Line')
        ax.plot([0, x2], [0, y2], 'b--', label='Rotated Line')
        # 设置标题和标签
        ax.set_title(f'Rotation by {theta_degrees} degrees')
        ax.set_xlabel('X-axis')
        ax.set_ylabel('Y-axis')
        # 添加图例
        ax.legend()
        # 设置轴比例一致
        ax.set_aspect('equal', adjustable='box')
        # 显示图形
        plt.grid(True)
        plt.axhline(0, color='black', linewidth=0.5)
        plt.axvline(0, color='black', linewidth=0.5)
        plt.show()
    if __name__ == '__main__':
        # 示例
        x1, y1 = 3, 4  # 初始点的坐标
        theta_degrees = 45  # 旋转角度(以度为单位)
    
        # 计算旋转后的坐标
        x2, y2 = rotate_point(x1, y1, theta_degrees)
        # 绘制图形
        plot_rotation(x1, y1, x2, y2, theta_degrees)
    
        # 利用 OpenCV 的 warpAffine 函数实现旋转,通过旋转坐标系实现旋转
        rotate_point_by_warpAffine(x1, y1, theta_degrees)
    • 如果需要处理多个点的旋转,可以使用向量化操作来提高效率。例如,如果你有多个点,可以将它们存储在一个数组中,并一次性进行旋转计算。
  • cv2.warpAffine() 是 OpenCV 库中的一个函数,用于执行二维仿射变换。仿射变换是一种线性变换,可以包括平移、旋转、缩放和剪切操作。这个函数在图像处理中非常有用,可以用来对图像进行几何变换。仿射变换的原理仿射变换可以用以下公式表示:

    • ( x ′ y ′ ) = A ( x y ) + b \begin{pmatrix} x' \\ y' \end{pmatrix} = A \begin{pmatrix} x \\ y \end{pmatrix} + b (x′y′)=A(xy)+b

    • 其中:( (x, y) ) 是原图像中的点。( (x', y') ) 是变换后图像中的点。( A ) 是一个 2x2 的矩阵,表示线性变换(旋转、缩放、剪切)。( b ) 是一个 2x1 的向量,表示平移。

  • 具体来说,仿射变换可以写成:

    • ( x ′ y ′ ) = ( a 11 a 12 a 21 a 22 ) ( x y ) + ( b 1 b 2 ) \begin{pmatrix} x' \\ y' \end{pmatrix} = \begin{pmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \end{pmatrix} \begin{pmatrix} x \\ y \end{pmatrix} + \begin{pmatrix} b_1 \\ b_2 \end{pmatrix} (x′y′)=(a11a21a12a22)(xy)+(b1b2)

    • 在 OpenCV 中,仿射变换矩阵通常表示为一个 2x3 的矩阵:

    • M = ( a 11 a 12 b 1 a 21 a 22 b 2 ) M = \begin{pmatrix} a_{11} & a_{12} & b_1 \\ a_{21} & a_{22} & b_2 \end{pmatrix} M=(a11a21a12a22b1b2)

  • cv2.warpAffine() 函数解析,cv2.warpAffine() 函数的基本语法如下:

    python 复制代码
    cv2.warpAffine(src, M, dsize, dst=None, flags=cv2.INTER_LINEAR, borderMode=None, borderValue=None)
    • 参数说明:

    • src:输入图像。

    • M:2x3 的仿射变换矩阵。

    • dsize:输出图像的大小 (width, height)。

    • dst:可选参数,输出图像。

    • flags:插值方法,默认为 cv2.INTER_LINEAR(双线性插值)。其他选项包括 cv2.INTER_NEAREST(最近邻插值)、cv2.INTER_CUBIC(三次样条插值)等。

    • borderMode:边界填充模式,默认为 cv2.BORDER_CONSTANT。其他选项包括 cv2.BORDER_REFLECTcv2.BORDER_WRAP 等。

    • borderValue:当 borderModecv2.BORDER_CONSTANT 时使用的常数值。

  • 下面是一些常见的仿射变换示例,包括平移、旋转和缩放。

    python 复制代码
    import cv2
    import numpy as np
    # 读取图像
    image = cv2.imread("./image.jpg")
    # 定义平移矩阵
    tx, ty = 50, 30  # 水平和垂直方向的平移量
    M = np.float32([[1, 0, tx], [0, 1, ty]])
    # 执行仿射变换
    translated_image = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
    # 显示结果
    cv2.imshow("Translated Image", translated_image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
      1. 旋转
    python 复制代码
    import cv2
    import numpy as np
    # 读取图像
    image = cv2.imread("./image.jpg")
    # 定义旋转角度
    angle = 45  # 旋转角度
    center = (image.shape[1] // 2, image.shape[0] // 2)  # 旋转中心
    scale = 1.0  # 缩放比例
    # 计算旋转矩阵
    M = cv2.getRotationMatrix2D(center, angle, scale)
    # 执行仿射变换
    rotated_image = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
    # 显示结果
    cv2.imshow("Rotated Image", rotated_image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
      1. 缩放
    python 复制代码
    import cv2
    import numpy as np
    # 读取图像
    image = cv2.imread("./image.jpg")
    # 定义缩放因子
    scale_x, scale_y = 1.5, 1.5  # 水平和垂直方向的缩放因子
    M = np.float32([[scale_x, 0, 0], [0, scale_y, 0]])
    # 计算输出图像的大小
    new_width = int(image.shape[1] * scale_x)
    new_height = int(image.shape[0] * scale_y)
    # 执行仿射变换
    scaled_image = cv2.warpAffine(image, M, (new_width, new_height))
    # 显示结果
    cv2.imshow("Scaled Image", scaled_image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
  • 仿射变换 包括平移、旋转、缩放和剪切操作。可以通过定义不同的变换矩阵来实现平移、旋转和缩放等操作。

  • 仿射变换矩阵 是一个 2x3 的矩阵,表示线性变换和平移。

  • cv2.warpAffine() 函数用于执行仿射变换,需要输入图像、变换矩阵和输出图像的大小。

  • 在更高维度的空间中进行旋转操作,可以使用旋转矩阵或四元数等方法。对于三维以上的空间,旋转通常涉及多个轴的组合。这里我们将介绍如何在高维空间中进行旋转,并提供相应的 Python 代码示例。高维空间中的旋转

    • 在高维空间中,旋转可以通过多个低维旋转的组合来实现。具体来说,你可以通过将旋转分解为多个二维平面上的旋转来处理。例如,在四维空间中,你可以在 xy 平面、xz 平面、xw 平面等上分别进行旋转

    • 计算公式:假设我们有一个 n 维空间中的点 $ (\mathbf{p} = (p_1, p_2, \ldots, p_n))$,并且我们希望绕某个平面(例如 xy 平面)旋转角度 ( θ ) (\theta) (θ)。我们可以使用以下公式:

    • [ R i j ( θ ) = I + ( cos ⁡ ( θ ) − 1 ) ( e i e i T + e j e j T ) + sin ⁡ ( θ ) ( e i e j T − e j e i T ) ] [ R_{ij}(\theta) = I + (\cos(\theta) - 1)(\mathbf{e}_i \mathbf{e}_i^T + \mathbf{e}_j \mathbf{e}_j^T) + \sin(\theta)(\mathbf{e}_i \mathbf{e}_j^T - \mathbf{e}_j \mathbf{e}_i^T) ] [Rij(θ)=I+(cos(θ)−1)(eieiT+ejejT)+sin(θ)(eiejT−ejeiT)]

    • 其中:(I) 是单位矩阵。

    • $(\mathbf{e}_i) 和 (\mathbf{e}_j) $是标准基向量。

    • $(\mathbf{e}_i \mathbf{e}_i^T) 和 (\mathbf{e}_j \mathbf{e}_j^T) $是外积。

    • ( e i e j T − e j e i T ) (\mathbf{e}_i \mathbf{e}_j^T - \mathbf{e}_j \mathbf{e}_i^T) (eiejT−ejeiT)是叉积。

  • 下面是一个示例代码,展示了如何在四维空间中绕不同的平面旋转一个点,并计算旋转后的新位置。

    python 复制代码
    import numpy as np
    def rotation_matrix(n, i, j, theta):
        """生成绕指定平面旋转的旋转矩阵。
        参数:
        n: 空间的维度。
        i, j: 旋转平面的两个轴索引(0-based)。
        theta: 旋转角度(以弧度为单位)。
        返回:
        旋转矩阵。
        """
        # 创建单位矩阵
        R = np.eye(n)
        # 计算旋转矩阵
        R[i, i] = np.cos(theta)
        R[j, j] = np.cos(theta)
        R[i, j] = -np.sin(theta)
        R[j, i] = np.sin(theta)
        return R
    def rotate_point(point, i, j, theta):
        """ 旋转一个点绕指定平面旋转。
        参数:
        point: 初始点的坐标 (p1, p2, ..., pn)。
        i, j: 旋转平面的两个轴索引(0-based)。
        theta: 旋转角度(以弧度为单位)。
        返回: 旋转后点的坐标 (p1', p2', ..., pn')。
        """
        # 将点转换为列向量
        point_vector = np.array(point).reshape(-1, 1)
        # 生成旋转矩阵
        R = rotation_matrix(len(point), i, j, theta)
        # 应用旋转矩阵
        rotated_point_vector = np.dot(R, point_vector)
        # 将结果转换回行向量
        rotated_point = rotated_point_vector.flatten()
        return rotated_point
    # 示例
    point = (1, 2, 3, 4)  # 初始点的坐标
    i, j = 0, 1  # 旋转平面:xy 平面
    theta_degrees = 45  # 旋转角度(以度为单位)
    # 将角度转换为弧度
    theta_rad = np.radians(theta_degrees)
    # 计算旋转后的新位置
    rotated_point = rotate_point(point, i, j, theta_rad)
    print(f"初始坐标: {point}")
    print(f"旋转平面: ({i}, {j})")
    print(f"旋转角度: {theta_degrees} 度")
    print(f"旋转后坐标: {rotated_point}")
    • rotation_matrix 函数根据指定的平面生成旋转矩阵。

    • rotate_point 函数使用旋转矩阵将点旋转到新的位置。

    • 在示例中,我们定义了一个四维点 (1, 2, 3, 4),绕 xy 平面旋转 45 度,并计算旋转后的新位置。

  • 复合旋转

    • 如果你需要在多个平面上进行复合旋转,可以依次应用多个旋转矩阵。例如,在四维空间中,你可以先绕 xy 平面旋转,再绕 xz 平面旋转。

    python 复制代码
    # 示例
    point = (1, 2, 3, 4)  # 初始点的坐标
    theta_degrees = 45  # 旋转角度(以度为单位)
    theta_rad = np.radians(theta_degrees)
    # 绕 xy 平面旋转
    rotated_point_xy = rotate_point(point, 0, 1, theta_rad)
    # 绕 xz 平面旋转
    rotated_point_xz = rotate_point(rotated_point_xy, 0, 2, theta_rad)
    print(f"初始坐标: {point}")
    print(f"旋转角度: {theta_degrees} 度")
    print(f"绕 xy 平面旋转后的坐标: {rotated_point_xy}")
    print(f"再绕 xz 平面旋转后的坐标: {rotated_point_xz}")
  • 旋转矩阵 :在高维空间中,旋转可以通过多个低维旋转的组合来实现。每个旋转矩阵对应于一个二维平面的旋转。

  • Python 实现:通过定义旋转矩阵并应用这些矩阵,可以实现高维空间中的旋转操作。

  • 复合旋转:如果需要在多个平面上进行旋转,可以依次应用多个旋转矩阵。这种方法可以扩展到任意维度的空间,并且可以灵活地处理复杂的旋转操作。

  • 旋转注意点

    • 都是逆时针,角度为正时。
    • 角度单位 :cv2.getRotationMatrix2D 角度为度,三角函数计算偏移矩阵为弧度制
    • 注意通道维度变换 PIL CV2 torch tensorflow
  • 在使用如PIL (Pillow), OpenCV (cv2), PyTorch, 和 TensorFlow 这样的库处理图像时,理解通道维度的定义是非常重要的。这些库对于图像通道的默认处理方式有所不同,可以对各个工具如何处理图像通道的一般性说明:

    • PIL (Pillow),读取图像:PIL 默认以 RGB 模式读取图像,除非特别指定了其他模式(例如灰度模式)。因此,图像的数据形状通常是 (height, width, 3) 对于彩色图像。通道顺序:R, G, B。

    • OpenCV (cv2),读取图像:OpenCV 默认以 BGR 模式读取图像。这意味着图像数据形状同样是 (height, width, 3),但是颜色通道的顺序与 PIL 不同。通道顺序:B, G, R。如果需要将图像转换为RGB模式,可以使用 cv2.cvtColor(image, cv2.COLOR_BGR2RGB)。

    • PyTorch,处理图像:PyTorch 中通常期望图像数据格式为 [batch, channels, height, width]。因此,在使用 PyTorch 处理图像之前,可能需要调整图像的维度顺序。示例:如果原始图像是 (height, width, 3) 形状的 numpy 数组,则可以通过 image.transpose((2, 0, 1)) 转换为 (3, height, width) 的形式,然后作为张量输入到模型中。通道顺序:当从numpy数组创建张量时,应确保通道顺序符合预期,通常为 R, G, B。

      python 复制代码
      import torch
      import numpy as np
      from PIL import Image
      # 读取图像
      image = Image.open("image.jpg")
      image_np = np.array(image)
      # 转换为 PyTorch 张量,并调整维度顺序
      image_tensor = torch.from_numpy(image_np).permute(2, 0, 1).float() / 255.0
      print("Image shape (PyTorch):", image_tensor.shape)  # 输出: (3, height, width)
      # 如果需要批量处理
      batch_image_tensor = image_tensor.unsqueeze(0)  # 增加 batch 维度
      print("Batch image shape (PyTorch):", batch_image_tensor.shape)  # 输出: (1, 3, height, width)
    • TensorFlow / Keras,处理图像:TensorFlow 或 Keras 一般采用 [batch, height, width, channels] 的格式。这与 PyTorch 的默认格式相反。示例:直接加载的图像已经是 (height, width, 3) 形状,可以直接使用。通道顺序:R, G, B。如果是通过 OpenCV 加载的图像,则需要先转换为 RGB 模式

      python 复制代码
      import tensorflow as tf
      import numpy as np
      from PIL import Image
      # 读取图像
      image = Image.open("image.jpg")
      image_np = np.array(image)
      # 转换为 TensorFlow 张量
      image_tensor = tf.convert_to_tensor(image_np, dtype=tf.float32) / 255.0
      print("Image shape (TensorFlow):", image_tensor.shape)  # 输出: (height, width, 3)
      # 如果需要批量处理
      batch_image_tensor = tf.expand_dims(image_tensor, axis=0)  # 增加 batch 维度
      print("Batch image shape (TensorFlow):", batch_image_tensor.shape)  # 输出: (1, height, width, 3)
    • Scikit-image: 使用类似于 PIL 的 RGB 顺序,并且图像通常表示为 (height, width, 3)。

    • ImageMagick: 可以灵活地处理多种颜色空间,但默认情况下也倾向于使用 RGB 顺序。

    • Dlib: 主要用于人脸检测等任务,对图像的颜色空间支持较为灵活,但同样最常见的是 RGB 顺序。

  • 如果想从 OpenCV 读取图像并希望将其转换为 PyTorch 或 TensorFlow 格式,可以按照以下步骤进行:

    python 复制代码
    import cv2
    import torch
    import numpy as np
    # 读取图像
    image = cv2.imread("image.png")
    print("Image shape (OpenCV):", image.shape)  # 输出: (height, width, 3)
    # 将 BGR 转换为 RGB
    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    # 转换为 PyTorch 张量,并调整维度顺序
    image_tensor = torch.from_numpy(image_rgb).permute(2, 0, 1).float() / 255.0
    print("Image shape (OpenCV to PyTorch):", image_tensor.shape)  # 输出: (3, height, width)
    # 如果需要批量处理
    batch_image_tensor = image_tensor.unsqueeze(0)  # 增加 batch 维度
    print("Batch image shape (OpenCV to PyTorch):", batch_image_tensor.shape)  # 输出: (1, 3, height, width)
    • 从 OpenCV 到 TensorFlow

    python 复制代码
    import cv2
    import tensorflow as tf
    import numpy as np
    # 读取图像
    image = cv2.imread("image.jpg")
    # 将 BGR 转换为 RGB
    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    # 转换为 TensorFlow 张量
    image_tensor = tf.convert_to_tensor(image_rgb, dtype=tf.float32) / 255.0
    print("Image shape (OpenCV to TensorFlow):", image_tensor.shape)  # 输出: (height, width, 3)
    # 如果需要批量处理
    batch_image_tensor = tf.expand_dims(image_tensor, axis=0)  # 增加 batch 维度
    print("Batch image shape (OpenCV to TensorFlow):", batch_image_tensor.shape)  # 输出: (1, height, width, 3)
相关推荐
The Open Group40 分钟前
企业如何通过架构蓝图实现数字化转型
大数据·人工智能·分布式·微服务·云原生·架构·数字化转型
红米煮粥44 分钟前
BERT框架
人工智能·深度学习·bert
sz66cm1 小时前
数学基础 -- 线性代数之线性无关
人工智能·线性代数·机器学习
玩AI的小胡子1 小时前
目前主流的人工智能学习框架有哪些?
人工智能·aigc
qzhqbb1 小时前
语言模型的评测
人工智能·语言模型·自然语言处理
xw5556661 小时前
Audio-Language Models
人工智能·语言模型·自然语言处理
算家云1 小时前
MinerU容器构建教程
人工智能·ai·图像识别·数据提取·布局分析·网页信息处理·阅读编辑
全域观察1 小时前
两台手机如何提词呢,一台手机后置高清摄像一台手机前置提词+实时监测状态的解决方案来喽
大数据·人工智能·chatgpt·新媒体运营·程序员创富
广州视觉芯软件有限公司2 小时前
MFC,DLL界面库设计注意
c++·人工智能·计算机视觉·mfc
lqqjuly3 小时前
影响神经网络速度的因素- FLOPs、MAC、并行度以及计算平台
人工智能·深度学习·神经网络