- vừa được xem lúc

Các phương pháp xoay vector trong không gian 2D và 3D

0 0 133

Người đăng: Pham Minh Hoang

Theo Viblo Asia

Lời mở đầu

Chào các bạn, mọi người có khỏe không, hôm nay tôi muốn bàn một chút về việc xoay vector trong không gian 2 chiều và 3 chiều. Do không phải dân chuyên Toán nên các thuật ngữ như Euler, Quaternions, ... tôi cũng chả có cách nào giải thích cho các bạn, nhưng đưa ra vài ví dụ trong lập trình chắc vẫn được nên hôm nay tôi viết bài này cũng muốn tham khảo ý kiến một chút.

Xoay vector trong không gian 2D

Như các bạn đã biết, không gian 2D chỉ chứa trục x và trục y nên ta nhìn qua là một mặt phẳng không có chiều sâu. Để rõ ràng, tôi sẽ minh họa một vector tạo thành từ 2 điểm bất kỳ bằng thư viện matplotlib.

from matplotlib import pyplot as plt
import math
import numpy as np
p1 = [0, 0]
p2 = [40, 40] plt.axis([-50, 50, -50, 50])
plt.plot([p1[0], p2[0]], [p1[1], p2[1]], label = "line 1")

Tôi đã có 1 vector trong không gian 2 chiều, giờ tôi sẽ xoay vector theo một góc chỉ định, ở đây tôi lấy góc 90 độ. Dựa trên công thức dưới đây sẽ sinh ra x y của vector mới

Nếu code theo python thì ta có

newX = v[0] * math.cos(angle) - v[1] * math.sin(angle)
newY = v[0] * math.sin(angle) + v[1] * math.cos(angle)

Nhưng như thế vector sẽ bị xoay ngược chiều kim đồng hồ nên tôi phải thay đổi một chút

newX = v[0] * math.cos(angle) + v[1] * math.sin(angle)
newY = -v[0] * math.sin(angle) + v[1] * math.cos(angle)

Minh họa dựa theo matplotlib

p1 = [0, 0]
p2 = [40, 40] plt.axis([-50, 50, -50, 50])
plt.plot([p1[0], p2[0]], [p1[1], p2[1]], label = "line 1") v = [p2[0] - p1[0], p2[1] - p1[1]] angle = np.deg2rad(90) newX = v[0] * math.cos(angle) + v[1] * math.sin(angle)
newY = -v[0] * math.sin(angle) + v[1] * math.cos(angle) p3 = [p1[0] + newX, p1[1] + newY] plt.axis([-50, 50, -50, 50])
plt.plot([p1[0], p3[0]], [p1[1], p3[1]], label = "line 2") plt.xlabel('x')
plt.ylabel('y')
plt.show()

Xoay vector bởi 180 độ

Xoay vector trong không gian 3D

Không gian bao gồm chiều rộng x, chiều cao y và chiều sâu z. Một điểm nằm trong không gian này có giá trị (x, y, z). Cũng như việc xoay vector trong không gian 2 chiều, tôi cần tìm ma trận rotation R rồi nhân với tọa độ của vector sẽ sinh ra một vector mới.

Xoay vector theo trục

Cho một góc 90 độ, chuyển từ độ (degree) thành radian, chọn trục z làm trục quay, tìm rotation vector của trục quay bằng thư viện scipy. Tôi giải thích sơ qua module Rotation của thư viện này chút.

  • Đầu tiên tìm unit vector của trục (axis)
  • Sau đó cross product của unit vector với ma trận I (Identify matrix).
  • Cuối cùng dùng hàm exponential với param là góc và A sẽ trả về ma trận xoay (rotation matrix)
a = axis/norm(axis) #1
A = I x a
exp(theta,A) 

Sau khi có ma trận xoay chỉ cần nhân với vector cần xoay sẽ sinh ra một vector mới quay theo trục một góc 90 độ.

from scipy.spatial.transform import Rotation as R vec = [1,1,1] rotation_degrees = 90
rotation_radians = np.radians(rotation_degrees)
rotation_axis = np.array([0, 0, 1]) rotation_vector = rotation_radians * rotation_axis
rotation = R.from_rotvec(rotation_vector)
rotated_vec = rotation.apply(vec) print(rotated_vec)

Euler angle

Định nghĩa: miêu tả hướng của một vật thể trong không gian 3 chiều

Ví dụ: Giả sử tôi có một video quay một máy bay, khi xử lý video cung cấp các frame và tọa độ x y z. Ở frame đầu tiên, máy bay được coi là không dịch chuyển. Từ frame thứ 10 máy bay dịch chuyển và thay đổi vị trí một góc 30 độ. Quá trình biến đổi hướng có thể chia thành 3 giai đoạn:

  • Yaw Rotation: chuyển động quay quanh trục z của vector một góc ψ, tạo nên tọa độ mới mà trục z không thay đổi nhưng trục x, y quay theo góc ψ.

  • Pitch Rotation

  • Roll Rotation

  • Ma trận xoay theo góc và trục chỉ định (ux, uy, uz). Với u là unit vector
from math import pi ,sin, cos def R(theta, u): return [[cos(theta) + u[0]**2 * (1-cos(theta)), u[0] * u[1] * (1-cos(theta)) - u[2] * sin(theta), u[0] * u[2] * (1 - cos(theta)) + u[1] * sin(theta)], [u[0] * u[1] * (1-cos(theta)) + u[2] * sin(theta), cos(theta) + u[1]**2 * (1-cos(theta)), u[1] * u[2] * (1 - cos(theta)) - u[0] * sin(theta)], [u[0] * u[2] * (1-cos(theta)) - u[1] * sin(theta), u[1] * u[2] * (1-cos(theta)) + u[0] * sin(theta), cos(theta) + u[2]**2 * (1-cos(theta))]] def Rotate(pointToRotate, point1, point2, theta): u= [] squaredSum = 0 for i,f in zip(point1, point2): u.append(f-i) squaredSum += (f-i) **2 u = [i/squaredSum for i in u] r = R(theta, u) rotated = [] for i in range(3): rotated.append(round(sum([r[j][i] * pointToRotate[j] for j in range(3)]))) return rotated point = [1,0,0]
p1 = [0,0,0]
p2 = [0,1,0] print Rotate(point, p1, p2, pi)

Công thức Euler–Rodrigues

Định nghĩa: một phương pháp tính vị trí của rotated point.

Một phép xoay quanh trục tọa độ gốc được biểu diễn bởi 4 param a, b, c, d

Khi áp dụng công thức này, một điểm có tọa độ x sẽ xoay về một vị trí mới có tọa độ x'

Code python: hàm rotation_matrix() trả về một ma trận xoay ngược chiều kim đồng hồ theo trục và góc.

import numpy as np
import math def rotation_matrix(axis, theta): """ Return the rotation matrix associated with counterclockwise rotation about the given axis by theta radians. """ axis = np.asarray(axis) axis = axis / math.sqrt(np.dot(axis, axis)) a = math.cos(theta / 2.0) b, c, d = -axis * math.sin(theta / 2.0) # bỏ dấu trừ nếu muốn thuận chiều kim đồng hồ aa, bb, cc, dd = a * a, b * b, c * c, d * d bc, ad, ac, ab, bd, cd = b * c, a * d, a * c, a * b, b * d, c * d return np.array([[aa + bb - cc - dd, 2 * (bc + ad), 2 * (bd - ac)], [2 * (bc - ad), aa + cc - bb - dd, 2 * (cd + ab)], [2 * (bd + ac), 2 * (cd - ab), aa + dd - bb - cc]]) v = [3, 5, 0]
axis = [4, 4, 1]
theta = 1.2 print(np.dot(rotation_matrix(axis, theta), v)) # [ 2.74911638 4.77180932 1.91629719]

Quaternions

Cũng như Euler-Rodrigues, quaternion là một vector có 4 phần tử dùng để tính vị trí của rotated point. Ta cũng có thể biến đổi Euler parameters a, b, c, d trên thành các hệ số của quaternion

Một quaternion có thể tính như sau

def angle_axis_quat(theta, axis): """ Given an angle and an axis, it returns a quaternion. """ axis = np.array(axis) / np.linalg.norm(axis) return np.append([np.cos(theta/2)],np.sin(theta/2) * axis)

Xoay vector bởi quaternions bằng công thức

Một vector xoay là tích của một quaternion với nghịch đảo của nó. Quaternion này lại là tích của unit vector với liên hợp của nó.

q1:

q2:

Tích của 2 quaternions

def mult_quat(q1, q2): """ Quaternion multiplication. """ q3 = np.copy(q1) q3[0] = q1[0]*q2[0] - q1[1]*q2[1] - q1[2]*q2[2] - q1[3]*q2[3] q3[1] = q1[0]*q2[1] + q1[1]*q2[0] + q1[2]*q2[3] - q1[3]*q2[2] q3[2] = q1[0]*q2[2] - q1[1]*q2[3] + q1[2]*q2[0] + q1[3]*q2[1] q3[3] = q1[0]*q2[3] + q1[1]*q2[2] - q1[2]*q2[1] + q1[3]*q2[0] return q3

Sau khi có được rotated quaternions, áp dụng vào vector cần xoay sẽ sinh ra một vector mới.

def rotate_quat(quat, vect): """ Rotate a vector with the rotation defined by a quaternion. """ # Transfrom vect into an quaternion  vect = np.append([0],vect) # Normalize it norm_vect = np.linalg.norm(vect) vect = vect/norm_vect # Computes the conjugate of quat quat_ = np.append(quat[0],-quat[1:]) # The result is given by: quat * vect * quat_ res = mult_quat(quat, mult_quat(vect,quat_)) * norm_vect return res[1:] v = [3, 5, 0]
axis = [4, 4, 1]
theta = 1.2 print(rotate_quat(angle_axis_quat(theta, axis), v))
# [2.74911638 4.77180932 1.91629719]

Lời kết

Như các bạn thấy thì cả bài này hầu như là một bài tổng hợp các cách xoay vector trong không gian hai chiều và ba chiều, do đó còn nhiều thiếu sót và không đầy đủ, mong các cao nhân có thể giúp đỡ thêm thắt lý thuyết công thức cho tác giả và người đọc hiểu thêm.

References

http://www.chrobotics.com/library/understanding-quaternions#:~:text=A quaternion is a four,for much more than rotations.

https://www.kite.com/python/answers/how-to-rotate-a-3d-vector-about-an-axis-in-python#:~:text=Rotate a vector v about,with an identity matrix I .

https://gist.github.com/LyleScott/e36e08bfb23b1f87af68c9051f985302

https://stackoverflow.com/questions/6802577/rotation-of-3d-vector

https://stackoverflow.com/questions/17763655/rotation-of-a-point-in-3d-about-an-arbitrary-axis-using-python

https://en.wikipedia.org/wiki/Rotation_matrix#Examples

https://en.wikipedia.org/wiki/Euler–Rodrigues_formula

Bình luận

Bài viết tương tự

- vừa được xem lúc

Lập Trình Hướng Đối Tượng trong Python

Chào các bạn Trong bài này, bạn sẽ tìm hiểu về Lập trình hướng đối tượng (OOP) bằng Python và khái niệm cơ bản của nó và một số các ví dụ. Các bạn cùng tìm hiểu trong bài viết của mình nhé.

0 0 35

- vừa được xem lúc

Lớp trong Python

. Hôm ni, mình học tiếp về bạn “Lớp(class) trong python”, bài blog tiếp theo nằm trong series “Khám phá Đại Bản Doanh Python”(nội dung trong bài series này từ chủ yếu mình lấy từ python.org rồi viết lại hoặc dịch lại theo ngôn ngữ của mình).

0 0 17

- vừa được xem lúc

Tìm hiểu về thư viện Numpy trong Python(Phần 3)

Trong bài viết trước tôi đã giới thiệu cho bạn về NumPy, tìm hiểu về Mảng trong NumPy. Trong bài viết này chúng ta sẽ tiếp tục tìm hiểu về các kiểu dữ liệu khác trong NumPy.

0 0 128

- vừa được xem lúc

Hướng dẫn cài đặt Anaconda trên Ubuntu

Anaconda là một nền tảng mã nguồn mở về Data Science và Machine Learning trên Python thông dụng nhất hiện nay, Anaconda có vai trò đơn giản hóa việc triển khai và quản lí các gói cài đặt khi làm việc với Python. Anaconda được cài đặt dễ dàng trên 3 nền tảng hệ điều hành thông dụng hiện nay là Ubuntu

0 0 31

- vừa được xem lúc

Tùy chỉnh Exceptions trong Python

Chào các bạn trong bài viết này, mình sẽ giới thiệu với các bạn về cách tùy chỉnh các Exceptions trong Python.Mình sẽ giải thích cho các bạn hiểu và cách xử dụng chúng.

0 0 24

- vừa được xem lúc

Không gian tên(namspace) và phạm vi(scope) trong Python

. Khi mình ngồi học và dịch bài "Class trong Python" cho sê-ri "Khám Phá Đại Bản Doanh Python", mình đã đụng hai bạn này, và các bạn thật là trừu tượng và khó gặm. Thế là mình tìm kiếm và viết bài này để hiểu rõ hơn về hai bạn ấy, hi vọng bạn đọc thêm để hiểu về Python nhé.

0 0 34