机器人位姿与齐次矩阵之间的相互转换(基于Eigen/OpenCV实现)

源码

网上查找了挺久机器人位姿与齐次矩阵之间的变换算法,但一直没找到理想的,这里自己做了实现,做过简单验证,但还可能存在问题,欢迎大家评论区指正讨论~

跳过理论,直接放代码了:

 common.h

#ifndef COMMON_H
#define COMMON_H

#include <math.h>

#ifndef M_PI
#define M_PI std::acos(-1)
#endif // !M_PI

/// <summary>
/// 旋转角顺序
/// </summary>
enum class E_ROTATION_SEQUENCE
{
	E_SEQ_XYZ = 0,
	E_SEQ_ZYX = 1
};

/// <summary>
/// 旋转角角度单位类型(degree/radian)
/// </summary>
enum class E_ANGLE_TYPE
{
	E_TYPE_DEGREE = 0,
	E_TYPE_RADIAN = 1
};

/// <summary>
/// 位姿结构体
/// </summary>
struct S_POSE
{
public:
	explicit S_POSE(double x, double y, double z, double rx, double ry, double rz)
		:X(x), Y(y), Z(z), Rx(rx), Ry(ry), Rz(rz) {};
public:
	double X;	double Y;	double Z;
	double Rx;	double Ry;	double Rz;
};

#endif // !COMMON_H

transformation_eg.h

/*****************************************************************************
*  @file     transformation_eg.h                                             *
*  @brief    用Eigen实现三维空间中位姿与矩阵之间的变换                          *
*  Details.  具体包括旋转角、旋转矩阵、齐次矩阵之间的变换						 *
*			 在固定角坐标系下描述旋转角顺序									 *
*                                                                            *
*  @author   Chan_XM                                                         *
*  @email    chan_xm14@163.com			                                     *
*  @version  V1.0														     *
*  @date     2024/11/16													     *
*  @license  NON															 *
*****************************************************************************/

#ifndef TRANSFORMATION_EG_H
#define TRANSFORMATION_EG_H

#include <Eigen/Dense>
#include <Eigen/Geometry>
#include "common.h"

class CTransformation_EG
{
public:
	/// <summary>
	/// 角度转弧度
	/// </summary>
	/// <param name="degree">角度(-180 180)</param>
	/// <returns>弧度(-3.14 3.14)</returns>
	static double degree2Radian(const double& degree);

	/// <summary>
	/// 弧度转角度
	/// </summary>
	/// <param name="radian">弧度(-3.14 3.14)</param>
	/// <returns>角度(-180 180)</returns>
	static double radian2Degree(const double& radian);

	/// <summary>
	/// 旋转角(degree)-> 旋转矩阵 默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价)转换
	/// </summary>
	/// <param name="rx">绕X轴旋转角</param>
	/// <param name="ry">绕Y轴旋转角</param>
	/// <param name="rz">绕Z轴旋转角</param>
	/// <param name="rotSeq">固定角坐标系描述下的旋转顺序(与欧拉角坐标系反向)</param>
	/// <returns>旋转矩阵(3x3)</returns>
	static Eigen::Matrix3d rotDegree2Matrix(double rx, double ry, double rz, const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ);

	/// <summary>
	/// 旋转角(radian)-> 旋转矩阵 默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价)转换
	/// </summary>
	/// <param name="rx">绕X轴旋转角</param>
	/// <param name="ry">绕Y轴旋转角</param>
	/// <param name="rz">绕Z轴旋转角</param>
	/// <param name="rotSeq">固定角坐标系描述下的旋转顺序(与欧拉角坐标系反向)</param>
	/// <returns>旋转矩阵(3x3)</returns>
	static Eigen::Matrix3d rotRadian2Matrix(double rx, double ry, double rz, const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ);

	/// <summary>
	/// 旋转矩阵 -> 旋转角(degree)默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价)转换
	/// </summary>
	/// <param name="matrix">旋转矩阵</param>
	/// <param name="rotSeq">固定角坐标系描述下的旋转顺序(与欧拉角坐标系反向)</param>
	/// <returns>旋转角(degree)</returns>
	static Eigen::Vector3d rotMatrix2RotDegree(const Eigen::Matrix3d& matrix, const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ);

	/// <summary>
	/// 旋转矩阵 -> 旋转角(Radian)默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价)转换
	/// </summary>
	/// <param name="matrix">旋转矩阵</param>
	/// <param name="rotSeq">固定角坐标系描述下的旋转顺序(与欧拉角坐标系反向)</param>
	/// <returns>旋转角(Radian)</returns>
	static Eigen::Vector3d rotMatrix2RotRadian(const Eigen::Matrix3d& matrix, const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ);

	/// <summary>
	/// 位姿 -> 齐次矩阵
	/// </summary>
	/// <param name="x">X</param>
	/// <param name="y">Y</param>
	/// <param name="z">Z</param>
	/// <param name="rx">Rx</param>
	/// <param name="ry">Ry</param>
	/// <param name="rz">Rz</param>
	/// <param name="rotSeq">旋转角顺序 默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价) </param>
	/// <param name="angleType">角度单位 默认为degree</param>
	/// <returns>齐次矩阵(4x4)</returns>
	static Eigen::Matrix4d pose2HmMatrix(double x, double y, double z, double rx, double ry, double rz,
		const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ,
		const E_ANGLE_TYPE& angleType = E_ANGLE_TYPE::E_TYPE_DEGREE);
	
	/// <summary>
	/// 位姿转齐次矩阵
	/// </summary>
	/// <param name="pose">位姿(包含X Y Z Rx Ry Rz)</param>
	/// <param name="rotSeq">旋转角顺序 默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价)</param>
	/// <param name="angleType">角度单位 默认为degree</param>
	/// <returns>齐次矩阵(4x4)</returns>
	static Eigen::Matrix4d pose2HmMatrix(const S_POSE& pose,
		const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ,
		const E_ANGLE_TYPE& angleType = E_ANGLE_TYPE::E_TYPE_DEGREE);

	/// <summary>
	/// 齐次矩阵转为位姿
	/// </summary>
	/// <param name="hmMatrix">齐次矩阵(4x4)</param>
	/// <param name="rotSeq">旋转角顺序 默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价)</param>
	/// <param name="angleType">角度单位 默认为degree</param>
	/// <returns>位姿(包含X Y Z Rx Ry Rz)</returns>
	static S_POSE hmMatrix2Pose(const Eigen::Matrix4d& hmMatrix, 
		const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ,
		const E_ANGLE_TYPE& angleType = E_ANGLE_TYPE::E_TYPE_DEGREE);

};

#endif // !TRANSFORMATION_EG_H

transformation_eg.cpp

/*****************************************************************************
*  @file     transformation_eg.cpp                                           *
*  @brief    用Eigen实现三维空间中位姿与矩阵之间的变换                          *
*                                                                            *
*  @author   Chan_XM                                                         *
*  @email    chan_xm14@163.com			                                     *
*  @version  V1.0														     *
*  @date     2024/11/16													     *
*  @license  NON															 *
*****************************************************************************/

#include "transformation_eg.h"
#include <iostream>

double CTransformation_EG::degree2Radian(const double& degree)
{
	return degree * M_PI / 180;
}

double CTransformation_EG::radian2Degree(const double& radian)
{
	return radian * 180 / M_PI;
}

Eigen::Matrix3d CTransformation_EG::rotDegree2Matrix(double rx, double ry, double rz, const E_ROTATION_SEQUENCE& rotSeq)
{
	rx = degree2Radian(rx);
	ry = degree2Radian(ry);
	rz = degree2Radian(rz);

	return CTransformation_EG::rotRadian2Matrix(rx, ry, rz, rotSeq);
}

Eigen::Matrix3d CTransformation_EG::rotRadian2Matrix(double rx, double ry, double rz, const E_ROTATION_SEQUENCE& rotSeq)
{
	Eigen::Matrix3d rotationMatrix;

	Eigen::AngleAxisd rotX(Eigen::AngleAxisd(rx, Eigen::Vector3d::UnitX()));
	Eigen::AngleAxisd rotY(Eigen::AngleAxisd(ry, Eigen::Vector3d::UnitY()));
	Eigen::AngleAxisd rotZ(Eigen::AngleAxisd(rz, Eigen::Vector3d::UnitZ()));

	if (rotSeq == E_ROTATION_SEQUENCE::E_SEQ_XYZ)
	{
		rotationMatrix = rotZ * rotY * rotX;
	}
	else
	{
		rotationMatrix = rotX * rotY * rotZ;
	}

	return rotationMatrix;
}

Eigen::Vector3d CTransformation_EG::rotMatrix2RotDegree(const Eigen::Matrix3d& matrix, const E_ROTATION_SEQUENCE& rotSeq)
{
	return rotMatrix2RotRadian(matrix, rotSeq) * 180 / M_PI;
}

Eigen::Vector3d CTransformation_EG::rotMatrix2RotRadian(const Eigen::Matrix3d& matrix, const E_ROTATION_SEQUENCE& rotSeq)
{
	double R11, R12, R13, R21, R22, R23, R31, R32, R33;
	R11 = matrix(0, 0);		R12 = matrix(0, 1);		R13 = matrix(0, 2);
	R21 = matrix(1, 0);		R22 = matrix(1, 1);		R23 = matrix(1, 2);
	R31 = matrix(2, 0);		R32 = matrix(2, 1);		R33 = matrix(2, 2);

	double alfa = 0.0, beta = 0.0, gama = 0.0;

	if (rotSeq == E_ROTATION_SEQUENCE::E_SEQ_XYZ)
	{
		beta = std::atan2(-R31, std::sqrt(R11 * R11 + R21 * R21));

		if (std::abs(beta - M_PI / 2) < 1e-6)
		{
			beta = M_PI / 2;
			alfa = 0.0;
			gama = std::atan2(R12, R22);
		}
		else if (std::abs(beta + M_PI / 2) < 1e-6)
		{
			beta = -M_PI / 2;
			alfa = 0.0;
			gama = -std::atan2(R12, R22);
		}
		else
		{
			alfa = std::atan2(R21 / std::cos(beta), R11 / std::cos(beta));
			gama = std::atan2(R32 / std::cos(beta), R33 / std::cos(beta));
		}

		Eigen::Vector3d rotDegree = { gama, beta,alfa };
		return rotDegree;
	}
	else if (rotSeq == E_ROTATION_SEQUENCE::E_SEQ_ZYX)	// 未考虑到R11、R13为0时,解存在退化的问题
	{
		beta = std::atan2(R13, std::sqrt(R11 * R11 + R12 * R12));

		if (std::abs(beta - M_PI / 2) < 1e-6)
		{
			beta = M_PI / 2;
			alfa = 0.0;
			gama = std::atan2(R32, R22);
		}
		else if (std::abs(beta + M_PI / 2) < 1e-6)
		{
			beta = -M_PI / 2;
			alfa = 0.0;
			gama = -std::atan2(R32, R22);
		}
		else
		{
			alfa = std::atan2(-R23 / std::cos(beta), R33 / std::cos(beta));
			gama = std::atan2(-R12 / std::cos(beta), R11 / std::cos(beta));
		}

		Eigen::Vector3d rotDegree = { alfa, beta, gama };
		return rotDegree;
	}
	else
	{
		return Eigen::Vector3d();
	}
}

Eigen::Matrix4d CTransformation_EG::pose2HmMatrix(double x, double y, double z, double rx, double ry, double rz, const E_ROTATION_SEQUENCE& rotSeq, const E_ANGLE_TYPE& angleType)
{
	Eigen::Matrix4d hmMatrix = Eigen::Matrix4d::Identity();

	Eigen::Matrix3d rotMatrix;

	if (angleType == E_ANGLE_TYPE::E_TYPE_DEGREE)
	{
		rotMatrix = rotDegree2Matrix(rx, ry, rz, rotSeq);
	}
	else
	{
		rotMatrix = rotRadian2Matrix(rx, ry, rz, rotSeq);
	}

	hmMatrix.block<3, 3>(0, 0) = rotMatrix;

	hmMatrix(0, 3) = x;
	hmMatrix(1, 3) = y;
	hmMatrix(2, 3) = z;

	return hmMatrix;
}

Eigen::Matrix4d CTransformation_EG::pose2HmMatrix(const S_POSE& pose, const E_ROTATION_SEQUENCE& rotSeq, const E_ANGLE_TYPE& angleType)
{
	return pose2HmMatrix(pose.X, pose.Y, pose.Z, pose.Rx, pose.Ry, pose.Rz, rotSeq, angleType);
}

S_POSE CTransformation_EG::hmMatrix2Pose(const Eigen::Matrix4d& hmMatrix, const E_ROTATION_SEQUENCE& rotSeq, const E_ANGLE_TYPE& angleType)
{
	Eigen::Matrix3d rotMatrix = hmMatrix.block<3, 3>(0, 0);

	Eigen::Vector3d rotAnagles;

	if (angleType == E_ANGLE_TYPE::E_TYPE_DEGREE)
	{
		rotAnagles = rotMatrix2RotDegree(rotMatrix, rotSeq);
	}
	else
	{
		rotAnagles = rotMatrix2RotRadian(rotMatrix, rotSeq);
	}

	double x = hmMatrix(0, 3);
	double y = hmMatrix(1, 3);
	double z = hmMatrix(2, 3);
	double rx = rotAnagles[0];
	double ry = rotAnagles[1];
	double rz = rotAnagles[2];

	return S_POSE(x, y, z, rx, ry, rz);
}

也可以访问GitHub仓库内容:https://github.com/Chan-XM/Transformation.git

transformation_cv.h

更新OpenCV版本实现位姿转换内容:

/*****************************************************************************
*  @file     transformation_cv.h                                             *
*  @brief    用OpenCV实现三维空间中位姿与矩阵之间的变换                         *
*  Details.  具体包括旋转角、旋转矩阵、齐次矩阵之间的变换						 *
*			 在固定角坐标系下描述旋转角顺序									 *
*                                                                            *
*  @author   Chan_XM                                                         *
*  @email    chan_xm14@163.com			                                     *
*  @version  V1.0														     *
*  @date     2024/11/20													     *
*  @license  NON															 *
*****************************************************************************/

#ifndef TRANSFORMATION_CV_H
#define TRANSFORMATION_CV_H

#include "common.h"

#include <opencv2/opencv.hpp>

class CTransformation_CV
{
public:
	/// <summary>
	/// 角度转弧度
	/// </summary>
	/// <param name="degree">角度(-180 180)</param>
	/// <returns>弧度(-3.14 3.14)</returns>
	static double degree2Radian(const double& degree);

	/// <summary>
	/// 弧度转角度
	/// </summary>
	/// <param name="radian">弧度(-3.14 3.14)</param>
	/// <returns>角度(-180 180)</returns>
	static double radian2Degree(const double& radian);

	/// <summary>
	/// 旋转角(degree)-> 旋转矩阵 默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价)转换
	/// </summary>
	/// <param name="rx">绕X轴旋转角</param>
	/// <param name="ry">绕Y轴旋转角</param>
	/// <param name="rz">绕Z轴旋转角</param>
	/// <param name="rotSeq">固定角坐标系描述下的旋转顺序(与欧拉角坐标系反向)</param>
	/// <returns>旋转矩阵(3x3)</returns>
	static cv::Mat rotDegree2Matrix(double rx, double ry, double rz, const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ);

	/// <summary>
	/// 旋转角(radian)-> 旋转矩阵 默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价)转换
	/// </summary>
	/// <param name="rx">绕X轴旋转角</param>
	/// <param name="ry">绕Y轴旋转角</param>
	/// <param name="rz">绕Z轴旋转角</param>
	/// <param name="rotSeq">固定角坐标系描述下的旋转顺序(与欧拉角坐标系反向)</param>
	/// <returns>旋转矩阵(3x3)</returns>
	static cv::Mat rotRadian2Matrix(double rx, double ry, double rz, const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ);

	/// <summary>
	/// 旋转矩阵 -> 旋转角(degree)默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价)转换
	/// </summary>
	/// <param name="matrix">旋转矩阵</param>
	/// <param name="rotSeq">固定角坐标系描述下的旋转顺序(与欧拉角坐标系反向)</param>
	/// <returns>旋转角(degree)</returns>
	static cv::Vec3d rotMatrix2RotDegree(const cv::Mat& matrix, const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ);

	/// <summary>
	/// 旋转矩阵 -> 旋转角(Radian)默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价)转换
	/// </summary>
	/// <param name="matrix">旋转矩阵</param>
	/// <param name="rotSeq">固定角坐标系描述下的旋转顺序(与欧拉角坐标系反向)</param>
	/// <returns>旋转角(Radian)</returns>
	static cv::Vec3d rotMatrix2RotRadian(const cv::Mat& matrix, const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ);

	/// <summary>
	/// 位姿 -> 齐次矩阵
	/// </summary>
	/// <param name="x">X</param>
	/// <param name="y">Y</param>
	/// <param name="z">Z</param>
	/// <param name="rx">Rx</param>
	/// <param name="ry">Ry</param>
	/// <param name="rz">Rz</param>
	/// <param name="rotSeq">旋转角顺序 默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价) </param>
	/// <param name="angleType">角度单位 默认为degree</param>
	/// <returns>齐次矩阵(4x4)</returns>
	static cv::Mat pose2HmMatrix(double x, double y, double z, double rx, double ry, double rz,
		const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ,
		const E_ANGLE_TYPE& angleType = E_ANGLE_TYPE::E_TYPE_DEGREE);

	/// <summary>
	/// 位姿转齐次矩阵
	/// </summary>
	/// <param name="pose">位姿(包含X Y Z Rx Ry Rz)</param>
	/// <param name="rotSeq">旋转角顺序 默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价)</param>
	/// <param name="angleType">角度单位 默认为degree</param>
	/// <returns>齐次矩阵(4x4)</returns>
	static cv::Mat pose2HmMatrix(const S_POSE& pose,
		const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ,
		const E_ANGLE_TYPE& angleType = E_ANGLE_TYPE::E_TYPE_DEGREE);

	/// <summary>
	/// 齐次矩阵转为位姿
	/// </summary>
	/// <param name="hmMatrix">齐次矩阵(4x4)</param>
	/// <param name="rotSeq">旋转角顺序 默认按照X-Y-Z固定角坐标系(或Z-Y-X欧拉角坐标系 二者等价)</param>
	/// <param name="angleType">角度单位 默认为degree</param>
	/// <returns>位姿(包含X Y Z Rx Ry Rz)</returns>
	static S_POSE hmMatrix2Pose(const cv::Mat& hmMatrix,
		const E_ROTATION_SEQUENCE& rotSeq = E_ROTATION_SEQUENCE::E_SEQ_XYZ,
		const E_ANGLE_TYPE& angleType = E_ANGLE_TYPE::E_TYPE_DEGREE);
};

#endif // !TRANSFORMATION_CV_H

transformation_cv.cpp

/*****************************************************************************
*  @file     transformation_cv.cpp                                           *
*  @brief    用OpenCV实现三维空间中位姿与矩阵之间的变换                          *
*                                                                            *
*  @author   Chan_XM                                                         *
*  @email    chan_xm14@163.com			                                     *
*  @version  V1.0														     *
*  @date     2024/11/16													     *
*  @license  NON															 *
*****************************************************************************/
#include "transformation_cv.h"

double CTransformation_CV::degree2Radian(const double& degree)
{
	return degree * M_PI / 180.0;
}

double CTransformation_CV::radian2Degree(const double& radian)
{
	return radian * 180.0 / M_PI;
}

cv::Mat CTransformation_CV::rotDegree2Matrix(double rx, double ry, double rz, const E_ROTATION_SEQUENCE& rotSeq)
{
    rx = degree2Radian(rx);
    ry = degree2Radian(ry);
    rz = degree2Radian(rz);

    return rotRadian2Matrix(rx, ry, rz, rotSeq);
}

cv::Mat CTransformation_CV::rotRadian2Matrix(double rx, double ry, double rz, const E_ROTATION_SEQUENCE& rotSeq)
{
    cv::Mat rotX = (cv::Mat_<double>(3, 3) <<
        1, 0, 0,
        0, cos(rx), -sin(rx),
        0, sin(rx), cos(rx));

    cv::Mat rotY = (cv::Mat_<double>(3, 3) <<
        cos(ry), 0, sin(ry),
        0, 1, 0,
        -sin(ry), 0, cos(ry));

    cv::Mat rotZ = (cv::Mat_<double>(3, 3) <<
        cos(rz), -sin(rz), 0,
        sin(rz), cos(rz), 0,
        0, 0, 1);

    cv::Mat rotationMatrix;
    if (rotSeq == E_ROTATION_SEQUENCE::E_SEQ_XYZ) {
        rotationMatrix = rotZ * rotY * rotX;
    }
    else {
        rotationMatrix = rotX * rotY * rotZ;
    }

    return rotationMatrix;
}

cv::Vec3d CTransformation_CV::rotMatrix2RotDegree(const cv::Mat& matrix, const E_ROTATION_SEQUENCE& rotSeq)
{
    return rotMatrix2RotRadian(matrix, rotSeq) * 180 / M_PI;
}

cv::Vec3d CTransformation_CV::rotMatrix2RotRadian(const cv::Mat& matrix, const E_ROTATION_SEQUENCE& rotSeq)
{
    if (matrix.cols != 3 || matrix.rows != 3)
    {
        std::cerr << "rotMatrix2RotRadian() matrix != 3x3" << std::endl;
        return cv::Vec3d();
    }

    if (matrix.channels() != 1)
    {
        std::cerr << "rotMatrix2RotDegree() matrix channels != 1" << std::endl;
        return cv::Vec3d();
    }

    double R11, R12, R13, R21, R22, R23, R31, R32, R33;

    switch (CV_MAT_DEPTH(matrix.type()))
    {
    case CV_32F:
    {
        R11 = matrix.at<float>(0, 0);		R12 = matrix.at<float>(0, 1);		R13 = matrix.at<float>(0, 2);
        R21 = matrix.at<float>(1, 0);		R22 = matrix.at<float>(1, 1);		R23 = matrix.at<float>(1, 2);
        R31 = matrix.at<float>(2, 0);		R32 = matrix.at<float>(2, 1);		R33 = matrix.at<float>(2, 2);
        break;
    }
    case CV_64F:
    {
        R11 = matrix.at<double>(0, 0);		R12 = matrix.at<double>(0, 1);		R13 = matrix.at<double>(0, 2);
        R21 = matrix.at<double>(1, 0);		R22 = matrix.at<double>(1, 1);		R23 = matrix.at<double>(1, 2);
        R31 = matrix.at<double>(2, 0);		R32 = matrix.at<double>(2, 1);		R33 = matrix.at<double>(2, 2);
        break;
    }

    default:
    {
        std::cerr << "rotMatrix2RotDegree() matrix type != float/double" << std::endl;
        return cv::Vec3d();
    }
    }

    double alfa = 0.0, beta = 0.0, gama = 0.0;

    if (rotSeq == E_ROTATION_SEQUENCE::E_SEQ_XYZ)
    {
        beta = std::atan2(-R31, std::sqrt(R11 * R11 + R21 * R21));

        if (std::abs(beta - M_PI / 2) < 1e-6)
        {
            beta = M_PI / 2;
            alfa = 0.0;
            gama = std::atan2(R12, R22);
        }
        else if (std::abs(beta + M_PI / 2) < 1e-6)
        {
            beta = -M_PI / 2;
            alfa = 0.0;
            gama = -std::atan2(R12, R22);
        }
        else
        {
            alfa = std::atan2(R21 / std::cos(beta), R11 / std::cos(beta));
            gama = std::atan2(R32 / std::cos(beta), R33 / std::cos(beta));
        }

        cv::Vec3d rotRadian = { gama, beta,alfa };
        return rotRadian;
    }
    else if (rotSeq == E_ROTATION_SEQUENCE::E_SEQ_ZYX)
    {
        beta = std::atan2(R13, std::sqrt(R11 * R11 + R12 * R12));

        if (std::abs(beta - M_PI / 2) < 1e-6)
        {
            beta = M_PI / 2;
            alfa = 0.0;
            gama = std::atan2(R32, R22);
        }
        else if (std::abs(beta + M_PI / 2) < 1e-6)
        {
            beta = -M_PI / 2;
            alfa = 0.0;
            gama = -std::atan2(R32, R22);
        }
        else
        {
            alfa = std::atan2(-R23 / std::cos(beta), R33 / std::cos(beta));
            gama = std::atan2(-R12 / std::cos(beta), R11 / std::cos(beta));
        }

        cv::Vec3d rotRadian = { alfa, beta, gama };
        return rotRadian;
    }
    else
    {
        return cv::Vec3d();
    }
}

cv::Mat CTransformation_CV::pose2HmMatrix(double x, double y, double z, double rx, double ry, double rz, const E_ROTATION_SEQUENCE& rotSeq, const E_ANGLE_TYPE& angleType)
{
    cv::Mat hmMatrix = cv::Mat::eye(4, 4, CV_64F);

    cv::Mat rotMatrix;

    if (angleType == E_ANGLE_TYPE::E_TYPE_DEGREE)
    {
        rotMatrix = rotDegree2Matrix(rx, ry, rz, rotSeq);
    }
    else
    {
        rotMatrix = rotRadian2Matrix(rx, ry, rz, rotSeq);
    }

    rotMatrix.copyTo(hmMatrix(cv::Rect(0, 0, 3, 3)));

    hmMatrix.at<double>(0, 3) = x;
    hmMatrix.at<double>(1, 3) = y;
    hmMatrix.at<double>(2, 3) = z;

    return hmMatrix;
}

cv::Mat CTransformation_CV::pose2HmMatrix(const S_POSE& pose, const E_ROTATION_SEQUENCE& rotSeq, const E_ANGLE_TYPE& angleType)
{
    return pose2HmMatrix(pose.X, pose.Y, pose.Z, pose.Rx, pose.Ry, pose.Rz, rotSeq, angleType);
}

S_POSE CTransformation_CV::hmMatrix2Pose(const cv::Mat& hmMatrix, const E_ROTATION_SEQUENCE& rotSeq, const E_ANGLE_TYPE& angleType)
{
    double x = 0.0, y = 0.0, z = 0.0, rx = 0.0, ry = 0.0, rz = 0.0;

    if (hmMatrix.cols != 4 || hmMatrix.rows != 4)
    {
        std::cerr << "hmMatrix2Pose() hmMatrix != 4x4" << std::endl;
        return S_POSE(x, y, z, rx, ry, rz);
    }

    if (hmMatrix.channels() != 1)
    {
        std::cerr << "hmMatrix2Pose() hmMatrix channels != 1" << std::endl;
        return S_POSE(x, y, z, rx, ry, rz);
    }

    cv::Mat rotMatrix = hmMatrix(cv::Range(0, 3), cv::Range(0, 3));

    std::cout << "rotMatrix = " << rotMatrix << std::endl << std::endl;

    cv::Vec3d angles;

    if (angleType == E_ANGLE_TYPE::E_TYPE_DEGREE)
    {
        angles = rotMatrix2RotDegree(rotMatrix, rotSeq);
    }
    else
    {
        angles = rotMatrix2RotRadian(rotMatrix, rotSeq);
    }

    rx = angles[0];     ry = angles[1];     rz = angles[2];

    switch (CV_MAT_DEPTH(hmMatrix.type()))
    {
    case CV_32F:
    {
        x = hmMatrix.at<float>(0, 3);
        y = hmMatrix.at<float>(1, 3);
        z = hmMatrix.at<float>(2, 3);
        break;
    }
    case CV_64F:
    {
        x = hmMatrix.at<double>(0, 3);
        y = hmMatrix.at<double>(1, 3);
        z = hmMatrix.at<double>(2, 3);
        break;
    }
    default:
    {
        std::cerr << "hmMatrix2Pose() matrix type != float/double" << std::endl;
        return S_POSE(x, y, z, rx, ry, rz);
    }
    }

    return S_POSE(x, y, z, rx, ry, rz);
}

参考

放几个关于欧拉角/旋转矩阵的参考链接,有兴趣的可以移步学习:

  1. 欧拉角:https://en.wikipedia.org/wiki/Euler_angles
  2. 旋转矩阵:https://en.wikipedia.org/wiki/Rotation_matrix
  3. 演算工具(3D Rotation Converter): 3D Rotation Converter
  4. 《机器人学导论》自行查找

后续

当前通过Eigen实现了在固定角坐标系下按照XYZ/ZYX两种方式,旋转角与旋转矩阵之间的互逆变换,后续有时间将会追加一下内容的实现:

  1. 用OpenCV的cv::Mat实现上述内容 - 已完成
  2. 补充其它旋转顺序(如ZYZ/XZX等);
  3. 补充Eigen/OpenCV两个框架下Rodrigues变换操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值