-
问题:在二维空间中,假设你有一条线段,其一个端点固定在原点 (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 是旋转后的位置坐标。
pythonimport 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()
函数的基本语法如下:pythoncv2.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_REFLECT
、cv2.BORDER_WRAP
等。 -
borderValue
:当borderMode
为cv2.BORDER_CONSTANT
时使用的常数值。
-
-
下面是一些常见的仿射变换示例,包括平移、旋转和缩放。
pythonimport 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()
-
- 旋转
pythonimport 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()
-
- 缩放
pythonimport 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)是叉积。
-
-
下面是一个示例代码,展示了如何在四维空间中绕不同的平面旋转一个点,并计算旋转后的新位置。
pythonimport 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。
pythonimport 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 模式。
pythonimport 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 格式,可以按照以下步骤进行:
pythonimport 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
pythonimport 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)
-
构建旋转变换矩阵对二维到高维空间的线段点进行旋转
羞儿2024-11-04 19:01
相关推荐
sp_fyf_202429 分钟前
【大语言模型】ACL2024论文-35 WAV2GLOSS:从语音生成插值注解文本AITIME论道29 分钟前
论文解读 | EMNLP2024 一种用于大语言模型版本更新的学习率路径切换训练范式明明真系叻1 小时前
第二十六周机器学习笔记:PINN求正反解求PDE文献阅读——正问题88号技师3 小时前
2024年12月一区SCI-加权平均优化算法Weighted average algorithm-附Matlab免费代码IT猿手3 小时前
多目标应用(一):多目标麋鹿优化算法(MOEHO)求解10个工程应用,提供完整MATLAB代码88号技师3 小时前
几款性能优秀的差分进化算法DE(SaDE、JADE,SHADE,LSHADE、LSHADE_SPACMA、LSHADE_EpSin)-附Matlab免费代码2301_764441333 小时前
基于python语音启动电脑应用程序HyperAI超神经3 小时前
未来具身智能的触觉革命!TactEdge传感器让机器人具备精细触觉感知,实现织物缺陷检测、灵巧操作控制galileo20164 小时前
转化为MarkDown说私域4 小时前
私域电商逆袭密码:AI 智能名片小程序与商城系统如何梦幻联动