jjzjj

Sophus库安装和使用

阿栋阿栋 2023-05-22 原文

1.前言

Sophus库是一个较好的李群和李代数的C++库,它很好的支持了SO(3),so(3),SE(3)和se(3)。Sophus库是基于Eigen基础上开发的,继承了Eigen库中的定义的各个类。因此在使用Eigen库中的类时,既可以使用Eigen命名空间,也可以使用Sophus命名空间。由于历史原因,早期的Sophus库是非模板类,只能提供双精度,后来又改写了一个模板类的,支持不同精度但也增加了使用难度。

总之,现在的Sophus库有两个版本:早期的非模板类和现在的模板类,本文会介绍如何安装这两个版本。github源码路径

2.非模板类Sophus安装

非模板类Sophus的依赖库是Eigen,版本为3.3.X,需提前安装好Eigen库,安装可参考
(1)下载源文件(需要先安装Eigen 3.3.X)

git clone https://github.com/strasdat/Sophus.git                  // 下载的最新版是模板类的
cd Sophus
git checkout a621ff    // 切换为非模板类的历史版本

(2)安装Sophus

cd Sophus
mkdir build
cd build
cmake ..  
make
sudo make install

头文件会安装到/usr/local/include/sophus

(3)非模板Sophus的使用
在非模板类中,库是利用.c.h的方式实现的
引入头文件:

//引用非模板类库
#include “sophus/so3.h”
#include “sophus/se3.h”

cmake编译时,CMakeLists.txt文件的编写

# 非模板类库
cmake_minimum_required( VERSION 2.8 )
project( useSophus )
set(CMAKE_CXX_STANDARD 11)

find_package( Sophus REQUIRED )
include_directories( ${Sophus_INCLUDE_DIRS} )
add_executable( useSophus useSophus.cpp )
# 由于非模板类版本是有库文件的,因此需要链接
target_link_libraries( useSophus ${Sophus_LIBRARIUES} )

3.模板类Sophus安装

模板类Sophus的依赖库是Eigen(版本为3.3.X)和fmt,需提前安装好Eigen库和fmt库,Eigen库的安装可参考这个

(1)安装fmt库

git clone https://github.com/fmtlib/fmt.git
cd fmt
# 默认安装是安装为静态库文件,以后有库文件依赖fmt库的话只能生成静态库,不能为共享库,因此推荐安装为共享库方式
# 如果要安装为共享库文件,就需要在CMakeLists.txt文件中添加:add_compile_options(-fPIC)
mkdir build
cd build
cmake ..
make
sudo make install

(2)下载Sophus源文件

git clone https://github.com/strasdat/Sophus.git

(3)安装Sophus

cd Sophus
mkdir build
cd build
cmake ..  
make
sudo make install

头文件会安装到/usr/local/include/sophus

(4)模板类Sophus的使用
模板类库中是集合在一个.hpp中实现的,因此不需要Sophus库文件的链接,但是Sophus中还依赖于fmt库,需要对fmt库文件链接
引入头文件:

//引用模板类库
#include “sophus/so3.hpp”
#include “sophus/se3.hpp”

cmake编译时,CMakeLists.txt文件的编写

# 模板类(依赖fmt库)
cmake_minimum_required(VERSION 3.0)
project(learn_Sophus)
set(CMAKE_CXX_STANDARD 11)

find_package(Sophus REQUIRED)
include_directories(${Sophus_INCLUDE_DIRS})
add_executable(learn_Sophus sophus_1.cpp)
# 需要链接fmt的动态库文件
target_link_libraries(learn_Sophus fmt::fmt)
# 或者也可以改为
# target_link_libraries(learn_Sophus Sophus::Sophus)

4.不依赖fmt库的模板类Sophus安装

正常情况下,模板类的Sophus会依赖fmt,fmt库是用于实现I/O文本格式化输出的功能,在Sophus中实现日志文件打印,因此去除掉fmt库也不影响我们正常使用Sophus库,且Sophus库本身和Eigen库一样纯用hpp文件构成,本身不需要库文件的链接,现在多了个fmt库的依赖感觉破坏了Sophus库的简化美感。
在github上,作者说在cmake编译源码时指定"-DUSE_BASIC_LOGGING=ON"可以安装不依赖于fmt库,即:

cd Sophus
mkdir build
cd build
cmake ../ -DUSE_BASIC_LOGGING=ON
make
sudo make install

但结果发现编译的hpp文件中还是存在个别文件(如commont.hpp)用到了fmt库,根据github上的提问,找到了一种解决方法:
在include前添加\#define SOPHUS_USE_BASIC_LOGGING,注意必需是include前,否则还是依赖于fmt库:

// C++自己的程序中:
// 需要在include sophus库头文件前添加该宏定义
#define SOPHUS_USE_BASIC_LOGGING
#include <iostream>
#include <sophus/so3.hpp>
#include <sophus/se3.hpp>

此时CMakeLists.txt文件为:

cmake_minimum_required(VERSION 3.0)
project(learn_Sophus)
set(CMAKE_CXX_STANDARD 11)

find_package(Sophus REQUIRED)
include_directories(${Sophus_INCLUDE_DIRS})
# 此时不需要库文件的链接了
add_executable(learn_Sophus sophus_1.cpp)

5.Sophus库的基本使用

下面的例子是模板类的Sophus库使用,非模板类基本类似,就是数据类型变了点。

/*
Eigen库是一个开源的C++线性代数库,它提供了快速的有关矩阵的线性代数运算,还包括解方程等功能。
但是Eigen库提供了集合模块,但没有提供李代数的支持。一个较好的李群和李代数的库是Sophus库,它很好的支持了
SO(3),so(3),SE(3)和se(3)。Sophus库是基于Eigen基础上开发的,继承了Eigen库中的定义的各个类。因此在
使用Eigen库中的类时,既可以使用Eigen命名空间,也可以使用Sophus命名空间:
    Eigen::Matrix3d和Sophus::Matrix3d
    Eigen::Vector3d和Sophus::Vector3d
此外,为了方便说明SE(4)和se(4),Sophus库还typedef了Vector4d、Matrix4d、Vector6d和Matrix6d等,即:
    Sophus::Vector4d
    Sophus::Matrix4d
    Sophus::Vector6d
    Sophus::Matrix6d
*/

// 添加该宏定义可以使sophus库不依赖fmt库,必需得在include<sophus>前添加
// #define SOPHUS_USE_BASIC_LOGGING
#include <iostream>
#include <sophus/so3.hpp>
#include <sophus/se3.hpp>
#include <cmath>
#include <Eigen/Dense>

void func_1();
void func_2();

int main()
{
    // func_1();
    func_2();
    return 0;
}

void func_1()
{
    // 李群SO3和旋转矩阵R和李代数so3

    // 1.旋转矩阵R <-> 李群SO3
    // 沿Z轴旋转90度的旋转矩阵
    Eigen::Matrix3d R = Eigen::AngleAxisd(M_PI/2,Eigen::Vector3d::UnitZ()).toRotationMatrix();
    // Sophus模板库和eigen一样选择精度,如SO3d、SO3f、SE3d、SE3f
    // 旋转矩阵R -> 李群SO3
    Sophus::SO3d SO3_R(R);  // 构造函数参数可以是旋转矩阵
    // 旋转矩阵R <- 李群SO3
    Eigen::Matrix3d R_SO3 = SO3_R.matrix();
    std::cout << SO3_R.matrix() <<std::endl; // 输出时需要将SO3转换为矩阵形式

    // 2.四元数q -> 李群SO3
    Eigen::Quaterniond q(R);
    Sophus::SO3d SO3_q(q);  // 构造函数参数可以是四元数
    std::cout << SO3_q.matrix() <<std::endl; 

    // 3. 李群SO3 <-> 李代数so3
    // 李群SO3 -> 李代数so3
    Eigen::Vector3d so3 =  SO3_R.log();
    std::cout << so3.transpose() <<std::endl;
    // 李群SO3 <- 李代数so3
    Sophus::SO3d SO3_so3 = Sophus::SO3d::exp(so3);
    std::cout << SO3_so3.matrix() <<std::endl; 

    // 4.李代数so3 <-> 三维反对称矩阵R_v
    // 李代数so3 -> 三维反对称矩阵R_v
    Eigen::Matrix3d R_v = Sophus::SO3d::hat(so3);
    std::cout << R_v <<std::endl; 
    // 李代数so3 <- 三维反对称矩阵R_v
    Eigen::Vector3d so3_Rv = Sophus::SO3d::vee(R_v);
    std::cout << so3_Rv.transpose() <<std::endl;

    // 5.增加扰动
    Eigen::Vector3d update_so3(1e-4,0,0);//增加扰动
    Sophus::SO3d SO3_updated=Sophus::SO3d::exp(update_so3)*SO3_R;
    std::cout<<SO3_updated.matrix()<<std::endl;


}

void func_2()
{
    // 李群SE3和变换矩阵T和李代数se3

    // 1.(旋转矩阵R,平移向量t) <-> 李群SE3
    Eigen::Vector3d t(1,0,0);
    Eigen::Matrix3d R = Eigen::AngleAxisd(M_PI/2,Eigen::Vector3d::UnitZ()).toRotationMatrix();
    // (旋转矩阵R,平移向量t) -> 李群SE3
    Sophus::SE3d SE3_Rt(R,t);
    std::cout<<SE3_Rt.matrix()<<std::endl;  // 矩阵的组成是[R,t;0,1]
    // (旋转矩阵R,平移向量t) <- 李群SE3
    Eigen::Matrix3d R_ = SE3_Rt.matrix().block<3,3>(0,0);
    Eigen::Vector3d t_ = SE3_Rt.matrix().block<3,1>(0,3);
    std::cout<<R_<<std::endl;
    std::cout<<t_<<std::endl;

    // 2.(四元数q,平移向量t) -> 李群SE3
    Eigen::Quaterniond q(R);
    Sophus::SE3d SE3_qt(q,t);
    std::cout<<SE3_qt.matrix()<<std::endl;

    // 3.李群SE3 <-> 李代数se3
    // 李群SE3 -> 李代数se3
    Sophus::Vector6d se3 = SE3_Rt.log(); //Eigen库中没有预先定义6维向量,可以使用Sophus库中定义的
    std::cout<<se3.transpose()<<std::endl;  //平移在前而旋转在后,这里的平移并不是真正空间上的平移
    // 李群SE3 <- 李代数se3
    Sophus::SE3d SE3_se3 = Sophus::SE3d::exp(se3);
    std::cout<<SE3_se3.matrix()<<std::endl;

    // 4.李代数se3 <-> 反对称矩阵R_v
    // 李代数se3 -> 反对称矩阵R_v
    Sophus::Matrix4d R_v = Sophus::SE3d::hat(se3);
    std::cout<<R_v<<std::endl;
    // 李代数se3 <- 反对称矩阵R_v
    Sophus::Vector6d se3_Rv = Sophus::SE3d::vee(R_v);
    std::cout<<se3_Rv.transpose()<<std::endl;

    // 5.增加扰动
    Sophus::Vector6d update_se3;
    update_se3.setZero();
    update_se3(1,0)=1e-4;
    Sophus::SE3d SE3_updated=Sophus::SE3d::exp(update_se3)*SE3_Rt;
    std::cout<<SE3_updated.matrix()<<std::endl;

}

使用总结如下:

有关Sophus库安装和使用的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐