从上一讲的内容中可以知道一次完整的欧式变换(旋转+平移)可以用式子:来表示。
假设我们现在对做了两次欧式变换:和,得到的向量分别为、,用上式来表示就是:
,,
于是从到的变换就可以写成。
这不是一个线性关系,可以想象到,如果经过多次的欧式变换,那么这个式子就会变的异常的复杂。
引入变换矩阵和齐次坐标就是为了解决这个问题。
变换矩阵和齐次坐标
我们可以将上面从到变换的式子改写成用矩阵表示的形式:
在上面的式子中,我们在一个三维向量的末尾添加了数字1,使得左边变成了四维向量,称为齐次坐标。
将上面的矩阵打开就是下面的式子:
对于这个四维向量,我们可以把旋转和平移写在一个矩阵里面,通过引入矩阵使得整个关系变成线性关系。矩阵T称为变换矩阵。
关于齐次坐标,还有下面这些需要知道。
通过添加最后一维,我们用四个实数来描述了一个三维向量,这显然多了一个自由度,但是这样允许我们把变换写成线性的形式。在齐次坐标中,某个点的每个分量同时乘以一个非零常数后,仍然表示同一个点。因此一个点的具体坐标值不是唯一的。如和表示的是同一个点。
但是,当最后一项不为0时,我们总是可以把所有坐标分量除以最后一项,强制最后一项为1,从而得到一个点唯一的坐标表示。(也就是将非齐次坐标转换为齐次坐标)。如:
通过齐次坐标和变换矩阵,两次变换(多次变换也是如此)的累加就可以有很好的形式:
,
实践部分:Eigen库使用
Eigen是一个c++开源线性代数库。它提供了快速的有关矩阵的线性代数运算,包括解方程等功能。关于Eigen的更多资料可以在这里找到。
1、Eigen库的安装
如果在ubuntu上还没有安装Eigen库的话,可以先使用apt-get命令安装Eigen:
sudo apt-get install libeigen3-dev
我已经安装过了,执行之后提示如下:
Eigen头文件的默认位置在 /usr/include/eigen3/ 中。
与其他库相比,Eigen的特殊之处在于:它是一个纯用头文件搭建起来的库。这意味着你只能找到它的头文件,而没有.so或者.a那样的二进制文件。在使用的时候,也只需要引入Eigen的头文件即可,不需要链接库文件(因为根本就没有库文件)。
2、调用Eigen库进行矩阵运算
首先,简单的介绍介绍一下Matrix class:Eigen库以矩阵为基本数据单元,它是一个模板类,定义如下:
Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
三个参数的含义分别为:数据类型、行数、列数。
例如,下面语句定义了一个4*4的float类型的矩阵:
Eigen::Matrix<float, 4, 4> matrix4f;
使用Eigen库的时候,由于Eigen库没有库文件,因此不需要使用target_link_directories语句,只需要使用一个链接头文件目录的语句include_directories,如下:
include_directories("/usr/include/eigen3")
源文件内容:
#include <iostream>
#include "Eigen/Dense"
using namespace std;
int main() {
//定义一个2*3的int矩阵和一个3*2的int矩阵
Eigen::Matrix<int, 2, 3> matrix3i_a;
Eigen::Matrix<int, 3, 2> matrix3i_b;
//输入矩阵matrix3i_a数据
cout<<"matrix3i_a的内容为:"<<endl;
matrix3i_a<<1, 2, 3, 4, 5, 6;
cout<<matrix3i_a<<endl;
//输入矩阵matrix3i_b数据
for(int i=0; i<3; i++){
for(int j=0; j<2; j++){
matrix3i_b(i, j)=2*i;
}
}
cout<<"matrix3i_b的内容为:"<<endl;
cout<<matrix3i_b<<endl;
//matrix3i_a和matrix3i_b进行四则运算
cout<<"matrix3i_a*matrix3i_b的结果为:"<<endl;
cout<<matrix3i_a*matrix3i_b<<endl;
cout<<"matrix3i_a的转置为:"<<endl;
cout<<matrix3i_a.transpose()<<endl;
cout<<"matrix3i_a的各个元素的和为:"<<endl;
cout<<matrix3i_a.sum()<<endl;
return 0;
}
CMakeLists.txt的内容:
cmake_minimum_required(VERSION 3.12)
project(use_eigen)
set(CMAKE_CXX_STANDARD 14)
#添加头文件
include_directories("/usr/include/eigen3")
add_executable(use_eigen main.cpp)
上面的程序中需要注意的就是:输入矩阵数据的时候,使用的是输出运算符而不是输入运算符。(这里的运算符都是重载之后的运算符)。
这一篇暂时就先学到这里了,明天开始学习旋转向量、欧拉角、四元数。