Дополнен и отрефакторен метод реализации алгоритма Кабша, добавлен метод вычисления углов поворота
50 lines
2.9 KiB
Python
50 lines
2.9 KiB
Python
from typing import Tuple
|
||
|
||
import numpy
|
||
|
||
from numpy.linalg import svd
|
||
|
||
|
||
def centroid(points: numpy.ndarray) -> numpy.ndarray:
|
||
return points.mean(axis=0)
|
||
|
||
|
||
def calculate_rotation_matrix(actual_points: numpy.ndarray,
|
||
expected_points: numpy.ndarray) -> numpy.ndarray:
|
||
"""
|
||
Вычисление матрицы поворота, который необходим для приближения текущих точек к ожидаемым, на основе алгоритма Кабша
|
||
:param actual_points: массив текущих точек
|
||
:param expected_points: массив ожидаемых точек
|
||
:return: Матрица поворотов
|
||
"""
|
||
# Для применения алгоритма Кабша необходимо,
|
||
# чтобы центроиды обрабатываемых массивов точек совпадали с началом координат
|
||
centred_actual_points = actual_points - centroid(actual_points)
|
||
centred_expected_points = expected_points - centroid(expected_points)
|
||
|
||
# Вычисляем матрицу кросс-ковариаций
|
||
cross_covariance_matrix = numpy.dot(numpy.transpose(centred_actual_points), centred_expected_points)
|
||
|
||
# Применяем к полученной матрице кросс-вариаций сингулярное разложение
|
||
left_singular_vectors_matrix, singular_matrix, right_singular_vectors_matrix = svd(cross_covariance_matrix)
|
||
|
||
# Некая нормализация полученного разложения (сам не знаю что здесь происходит, поэтому не трогаю)
|
||
if (numpy.linalg.det(left_singular_vectors_matrix) * numpy.linalg.det(right_singular_vectors_matrix)) < 0.0:
|
||
singular_matrix[-1] = -singular_matrix[-1]
|
||
left_singular_vectors_matrix[:, -1] = -left_singular_vectors_matrix[:, -1]
|
||
|
||
return numpy.dot(left_singular_vectors_matrix, right_singular_vectors_matrix)
|
||
|
||
|
||
def convert_rotation_matrix_to_angles(rotation_matrix: numpy.ndarray) -> Tuple[float, float, float]:
|
||
"""
|
||
Вычисление углов поворота модели на основе применяемой к ней матрицы поворота
|
||
:param rotation_matrix: матрица поворота
|
||
:return: Кортеж из трёх углов - угол поворота вокруг оси X, угол поворота вокруг оси Y, угол поворота вокруг оси Z
|
||
"""
|
||
# TODO Требует доработки, так как иногда может всплывать деление на 0
|
||
alpha = numpy.arccos(rotation_matrix[2, 2] / (1 - rotation_matrix[0, 2] ** 2) ** 0.5)
|
||
beta = numpy.arcsin(rotation_matrix[0, 2])
|
||
gamma = numpy.arccos(rotation_matrix[0, 0] / (1 - rotation_matrix[0, 2] ** 2) ** 0.5)
|
||
return alpha, beta, gamma
|