【李群李代数】Sophus库中SE3类测试(附manif 与sophus 对比)

测试演示

8a45c63194599adc54a193876f84b280.png

测试结果

对Sophus库中SE3类进行一系列的测试,包括李群性质、原始数据访问、变异访问器、构造函数以及拟合等方面。在每个测试中,都会使用一些预设的数据进行操作,并通过SOPHUS_TEST_APPROX和SOPHUS_TEST_EQUAL等宏来检查操作结果是否符合预期。如果所有测试都通过,则整个程序会返回0,表示测试成功。如果有任何一个测试未通过,则程序会输出相应的错误信息。这是一种常见的单元测试策略,可以帮助开发者确保代码的正确性和稳定性。

se3测试源码:

#include <iostream>// 包含标准输入输出流库#include <sophus/se3.hpp>// 包含Sophus库中的SE3类
#include "tests.hpp" // 包含测试头文件// Explicit instantiate all class templates so that all member methods
// get compiled and for code coverage analysis.
// 显式实例化所有类模板,以便所有成员方法都被编译并进行代码覆盖率分析。
namespace Eigen {
template class Map<Sophus::SE3<double>>;// 实例化Map类模板,用于映射Sophus::SE3<double>类型
template class Map<Sophus::SE3<double> const>;// 实例化Map类模板,用于映射Sophus::SE3<double> const类型
}  // namespace Eigennamespace Sophus {template class SE3<double, Eigen::AutoAlign>;// 实例化SE3类模板,使用double类型和Eigen::AutoAlign对齐选项
template class SE3<float, Eigen::DontAlign>;// 实例化SE3类模板,使用float类型和Eigen::DontAlign对齐选项
#if SOPHUS_CERES
template class SE3<ceres::Jet<double, 3>>;  // 如果定义了SOPHUS_CERES,则实例化SE3类模板,使用ceres::Jet<double,// 3>类型
#endiftemplate <class Scalar>
class Tests {// 定义Tests类模板,用于测试public:using SE3Type = SE3<Scalar>;// 定义SE3Type类型别名,等价于SE3<Scalar>using SO3Type = SO3<Scalar>;// 定义SO3Type类型别名,等价于SO3<Scalar>using Point = typename SE3<Scalar>::Point;// 定义Point类型别名,等价于SE3<Scalar>::Pointusing Tangent = typename SE3<Scalar>::Tangent;// 定义Tangent类型别名,等价于SE3<Scalar>::TangentScalar const kPi = Constants<Scalar>::pi();// 定义常量kPi,等于pi的值Tests() {// 构造函数se3_vec_ = getTestSE3s<Scalar>();// 获取测试用的SE3对象向量Tangent tmp;// 定义临时变量tmptmp << Scalar(0), Scalar(0), Scalar(0), Scalar(0), Scalar(0), Scalar(0);// 给tmp赋值tangent_vec_.push_back(tmp);// 将tmp添加到tangent_vec_向量中tmp << Scalar(1), Scalar(0), Scalar(0), Scalar(0), Scalar(0), Scalar(0);tangent_vec_.push_back(tmp);tmp << Scalar(0), Scalar(1), Scalar(0), Scalar(1), Scalar(0), Scalar(0);tangent_vec_.push_back(tmp);tmp << Scalar(0), Scalar(-5), Scalar(10), Scalar(0), Scalar(0), Scalar(0);tangent_vec_.push_back(tmp);tmp << Scalar(-1), Scalar(1), Scalar(0), Scalar(0), Scalar(0), Scalar(1);tangent_vec_.push_back(tmp);tmp << Scalar(20), Scalar(-1), Scalar(0), Scalar(-1), Scalar(1), Scalar(0);tangent_vec_.push_back(tmp);tmp << Scalar(30), Scalar(5), Scalar(-1), Scalar(20), Scalar(-1), Scalar(0);tangent_vec_.push_back(tmp);point_vec_.push_back(Point(Scalar(1), Scalar(2), Scalar(4))); // 添加一个点到point_vec_向量中point_vec_.push_back(Point(Scalar(1), Scalar(-3), Scalar(0.5)));// 添加一个点到point_vec_向量中point_vec_.push_back(Point(Scalar(-5), Scalar(-6), Scalar(7)));// 添加一个点到point_vec_向量中}void runAll() {// 定义runAll函数,用于运行所有测试bool passed = testLieProperties();// 运行testLieProperties函数,测试李群性质passed &= testRawDataAcces();// 运行testRawDataAcces函数,测试原始数据访问passed &= testMutatingAccessors();// 运行testMutatingAccessors函数,测试变异访问器passed &= testConstructors();// 运行testConstructors函数,测试构造函数passed &= testFit();           // 运行testFit函数,测试拟合processTestResult(passed);// 处理测试结果}private:bool testLieProperties() {// 定义testLieProperties函数,用于测试李群性质// 创建LieGroupTests对象,用于测试SE3Type类型的李群性质LieGroupTests<SE3Type> tests(se3_vec_, tangent_vec_, point_vec_);return tests.doAllTestsPass();// 返回所有测试是否通过}bool testRawDataAcces() {// 定义testRawDataAcces函数,用于测试原始数据访问bool passed = true;// 定义passed变量,表示所有测试是否通过Eigen::Matrix<Scalar, 7, 1> raw;// 定义raw矩阵,用于存储原始数据raw << Scalar(0), Scalar(1), Scalar(0), Scalar(0), Scalar(1), Scalar(3),// 给raw矩阵赋值Scalar(2);Eigen::Map<SE3Type const> map_of_const_se3(raw.data());  // 创建map_of_const_se3对象,用于映射SE3Type// const类型的数据// 测试map_of_const_se3对象的unit_quaternion()函数返回值的系数是否接近raw矩阵的前4个元素SOPHUS_TEST_APPROX(passed, map_of_const_se3.unit_quaternion().coeffs().eval(),raw.template head<4>().eval(), Constants<Scalar>::epsilon(), "");// 测试map_of_const_se3对象的translation()函数返回值是否接近raw矩阵的后3个元素SOPHUS_TEST_APPROX(passed, map_of_const_se3.translation().eval(),raw.template tail<3>().eval(),Constants<Scalar>::epsilon(), "");// 测试map_of_const_se3对象的unit_quaternion()函数返回值的系数的数据指针是否等于raw矩阵的数据指针SOPHUS_TEST_EQUAL(passed,map_of_const_se3.unit_quaternion().coeffs().data(),raw.data(), "");// 测试map_of_const_se3对象的translation()函数返回值的数据指针是否等于raw矩阵的数据指针加4SOPHUS_TEST_EQUAL(passed, map_of_const_se3.translation().data(),raw.data() + 4, "");Eigen::Map<SE3Type const> const_shallow_copy = map_of_const_se3;// 创建const_shallow_copy对象,浅拷贝map_of_const_se3对象// 测试const_shallow_copy对象的unit_quaternion()函数返回值的系数是否等于map_of_const_se3对象的unit_quaternion()函数返回值的系数SOPHUS_TEST_EQUAL(passed,const_shallow_copy.unit_quaternion().coeffs().eval(),map_of_const_se3.unit_quaternion().coeffs().eval(), "");// 测试const_shallow_copy对象的translation()函数返回值是否等于map_of_const_se3对象的translation()函数返回值SOPHUS_TEST_EQUAL(passed, const_shallow_copy.translation().eval(),map_of_const_se3.translation().eval(), "");Eigen::Matrix<Scalar, 7, 1> raw2;// 定义raw2矩阵,用于存储原始数据raw2 << Scalar(1), Scalar(0), Scalar(0), Scalar(0), Scalar(3), Scalar(2),Scalar(1);// 给raw2矩阵赋值Eigen::Map<SE3Type> map_of_se3(raw.data());// 创建map_of_se3对象,用于映射SE3Type类型的数据Eigen::Quaternion<Scalar> quat;// 创建quat四元数对象quat.coeffs() = raw2.template head<4>();// 给quat四元数对象的系数赋值map_of_se3.setQuaternion(quat);// 设置map_of_se3对象的四元数为quatmap_of_se3.translation() = raw2.template tail<3>();// 设置map_of_se3对象的平移向量为raw2矩阵的后3个元素测试map_of_se3对象的unit_quaternion()函数返回值的系数是否接近raw2矩阵的前4个元素SOPHUS_TEST_APPROX(passed, map_of_se3.unit_quaternion().coeffs().eval(),raw2.template head<4>().eval(),Constants<Scalar>::epsilon(), "");// 测试map_of_se3对象的translation()函数返回值是否接近raw2矩阵的后3个元素SOPHUS_TEST_APPROX(passed, map_of_se3.translation().eval(),raw2.template tail<3>().eval(),Constants<Scalar>::epsilon(), "");// 测试map_of_se3对象的unit_quaternion()函数返回值的系数的数据指针是否等于raw矩阵的数据指针SOPHUS_TEST_EQUAL(passed, map_of_se3.unit_quaternion().coeffs().data(),raw.data(), "");// 测试map_of_se3对象的translation()函数返回值的数据指针是否等于raw矩阵的数据指针加4SOPHUS_TEST_EQUAL(passed, map_of_se3.translation().data(), raw.data() + 4,"");// 测试map_of_se3对象的unit_quaternion()函数返回值的系数的数据指针是否不等于quat四元数对象的系数的数据指针SOPHUS_TEST_NEQ(passed, map_of_se3.unit_quaternion().coeffs().data(),quat.coeffs().data(), "");Eigen::Map<SE3Type> shallow_copy = map_of_se3;// 创建shallow_copy对象,浅拷贝map_of_se3对象// 测试shallow_copy对象的unit_quaternion()函数返回值的系数是否等于map_of_se3对象的unit_quaternion()函数返回值的系数SOPHUS_TEST_EQUAL(passed, shallow_copy.unit_quaternion().coeffs().eval(),map_of_se3.unit_quaternion().coeffs().eval(), "");// 测试shallow_copy对象的translation()函数返回值是否等于map_of_se3对象的translation()函数返回值SOPHUS_TEST_EQUAL(passed, shallow_copy.translation().eval(),map_of_se3.translation().eval(), "");Eigen::Map<SE3Type> const const_map_of_se3 = map_of_se3;// 创建const_map_of_se3对象,浅拷贝map_of_se3对象// 测试const_map_of_se3对象的unit_quaternion()函数返回值的系数是否等于map_of_se3对象的unit_quaternion()函数返回值的系数SOPHUS_TEST_EQUAL(passed,const_map_of_se3.unit_quaternion().coeffs().eval(),map_of_se3.unit_quaternion().coeffs().eval(), "");// 测试const_map_of_se3对象的translation()函数返回值是否等于map_of_se3对象的translation()函数返回值SOPHUS_TEST_EQUAL(passed, const_map_of_se3.translation().eval(),map_of_se3.translation().eval(), "");// 创建const_se3常量对象,使用quat四元数和raw2矩阵的后三个元素初始化SE3Type const const_se3(quat, raw2.template tail<3>().eval());for (int i = 0; i < 7; ++i) {  // 循环遍历0到6// 测试const_se3常量对象的data()函数返回值第i个元素是否等于raw2矩阵第i个元素SOPHUS_TEST_EQUAL(passed, const_se3.data()[i], raw2.data()[i], "");}// 创建se3变量,使用quat四元数和raw2矩阵的后三个元素初始化SE3Type se3(quat, raw2.template tail<3>().eval());for (int i = 0; i < 7; ++i) {// 循环遍历0到6//  测试se3变量的data()函数返回值第i个元素是否等于raw2矩阵第i个元素SOPHUS_TEST_EQUAL(passed, se3.data()[i], raw2.data()[i], "");}for (int i = 0; i < 7; ++i) {  // 循环遍历0到6// 测试se3变量的data()函数返回值第i个元素是否等于raw矩阵第i个元素SOPHUS_TEST_EQUAL(passed, se3.data()[i], raw.data()[i], "");}SE3Type trans = SE3Type::transX(Scalar(0.2));// 创建trans变量,使用SE3Type::transX函数初始化,沿x轴平移0.2SOPHUS_TEST_APPROX(passed, trans.translation().x(), Scalar(0.2),Constants<Scalar>::epsilon(), "");// 测试trans变量的translation()函数返回值的x分量是否接近0.2trans = SE3Type::transY(Scalar(0.7));// 使用SE3Type::transY函数初始化trans变量,沿y轴平移0.7SOPHUS_TEST_APPROX(passed, trans.translation().y(), Scalar(0.7),Constants<Scalar>::epsilon(), "");// 测试trans变量的translation()函数返回值的y分量是否接近0.7trans = SE3Type::transZ(Scalar(-0.2));// 使用SE3Type::transZ函数初始化trans变量,沿z轴平移-0.2SOPHUS_TEST_APPROX(passed, trans.translation().z(), Scalar(-0.2),Constants<Scalar>::epsilon(), "");// 测试trans变量的translation()函数返回值的z分量是否接近-0.2Tangent t;// 定义t变量,用于存储切向量t << Scalar(0), Scalar(0), Scalar(0), Scalar(0.2), Scalar(0), Scalar(0);// 给t变量赋值  运动螺旋[dx,dy,dz,wx,wy,wz]// 测试SE3Type::rotX函数返回值的矩阵是否等于SE3Type::exp函数返回值的矩阵SOPHUS_TEST_EQUAL(passed, SE3Type::rotX(Scalar(0.2)).matrix(),SE3Type::exp(t).matrix(), "");t << Scalar(0), Scalar(0), Scalar(0), Scalar(0), Scalar(-0.2), Scalar(0); // 给t变量赋值SOPHUS_TEST_EQUAL(passed, SE3Type::rotY(Scalar(-0.2)).matrix(),SE3Type::exp(t).matrix(), "");// 测试SE3Type::rotY函数返回值的矩阵是否等于SE3Type::exp函数返回值的矩阵t << Scalar(0), Scalar(0), Scalar(0), Scalar(0), Scalar(0), Scalar(1.1);SOPHUS_TEST_EQUAL(passed, SE3Type::rotZ(Scalar(1.1)).matrix(),SE3Type::exp(t).matrix(), "");// 测试SE3Type::rotZ函数返回值的矩阵是否等于SE3Type::exp函数返回值的矩阵Eigen::Matrix<Scalar, 7, 1> data1, data2;// 定义data1和data2矩阵,用于存储数据data1 << Scalar(0), Scalar(1), Scalar(0), Scalar(0), Scalar(1), Scalar(2),Scalar(3);// 给data1矩阵赋值data1 << Scalar(0), Scalar(0), Scalar(1), Scalar(0), Scalar(3), Scalar(2),Scalar(1);  // 给data1矩阵赋值Eigen::Map<SE3Type> map1(data1.data()), map2(data2.data());// 创建map1和map2对象,分别映射data1和data2矩阵的数据// map -> map assignmentmap2 = map1;// 将map1对象赋值给map2对象// 测试map1对象的matrix()函数返回值是否等于map2对象的matrix()函数返回值SOPHUS_TEST_EQUAL(passed, map1.matrix(), map2.matrix(), "");// map -> type assignmentSE3Type copy;// 创建copy变量copy = map1;// 将map1对象赋值给copy变量// 测试map1对象的matrix()函数返回值是否等于copy变量的matrix()函数返回值SOPHUS_TEST_EQUAL(passed, map1.matrix(), copy.matrix(), "");// type -> map assignment// 使用SE3Type::trans和SE3Type::rotZ函数初始化copy变量,沿x、y、z轴分别平移4、5、6,绕z轴旋转0.5copy = SE3Type::trans(Scalar(4), Scalar(5), Scalar(6)) *SE3Type::rotZ(Scalar(0.5));map1 = copy;// 将copy变量赋值给map1对象// 测试map1对象的matrix()函数返回值是否等于copy变量的matrix()函数返回值SOPHUS_TEST_EQUAL(passed, map1.matrix(), copy.matrix(), "");return passed;  // 返回所有测试是否通过}// 定义testMutatingAccessors函数,用于测试变异访问器bool testMutatingAccessors() {bool passed = true;// 定义passed变量,表示所有测试是否通过SE3Type se3;// 创建se3变量// 创建R变量,使用SO3Type::exp函数初始化,指数映射点 旋转矢量(0.2, 0.5, 0.0)SO3Type R(SO3Type::exp(Point(Scalar(0.2), Scalar(0.5), Scalar(0.0))));se3.setRotationMatrix(R.matrix());  // 设置se3变量的旋转矩阵为R变量的矩阵// 测试se3变量的rotationMatrix()函数返回值是否接近R变量的矩阵SOPHUS_TEST_APPROX(passed, se3.rotationMatrix(), R.matrix(),Constants<Scalar>::epsilon(), "");return passed;// 返回所有测试是否通过}// 定义testConstructors函数,用于测试构造函数bool testConstructors() {bool passed = true;// 定义passed变量,表示所有测试是否通过// 创建I矩阵,初始化为单位矩阵Eigen::Matrix<Scalar, 4, 4> I = Eigen::Matrix<Scalar, 4, 4>::Identity();// 测试SE3Type默认构造函数返回值的矩阵是否等于I矩阵SOPHUS_TEST_EQUAL(passed, SE3Type().matrix(), I, "");SE3Type se3 = se3_vec_.front();//  获取se3_vec_向量的第一个元素赋值给se3变量Point translation = se3.translation();// 获取se3变量的translation()函数返回值赋值给translation变量SO3Type so3 = se3.so3();// 获取se3变量的so3()函数返回值赋值给so3变量// 测试SE3Type构造函数返回值的矩阵是否接近se3变量的矩阵SOPHUS_TEST_APPROX(passed, SE3Type(so3, translation).matrix(), se3.matrix(),Constants<Scalar>::epsilon(), "");// 测试SE3Type构造函数返回值的矩阵是否接近se3变量的矩阵SOPHUS_TEST_APPROX(passed, SE3Type(so3.matrix(), translation).matrix(),se3.matrix(), Constants<Scalar>::epsilon(), "");// 测试SE3Type构造函数返回值的矩阵是否接近se3变量的矩阵SOPHUS_TEST_APPROX(passed,SE3Type(so3.unit_quaternion(), translation).matrix(),se3.matrix(), Constants<Scalar>::epsilon(), "");// 测试SE3Type构造函数返回值的矩阵是否接近se3变量的矩阵SOPHUS_TEST_APPROX(passed, SE3Type(se3.matrix()).matrix(), se3.matrix(),Constants<Scalar>::epsilon(), "");return passed;// 返回所有测试是否通过}template <class S = Scalar>enable_if_t<std::is_floating_point<S>::value, bool> testFit() {// 定义testFit函数模板,用于测试拟合,仅当S类型为浮点数类型时启用bool passed = true;// 定义passed变量,表示所有测试是否通过for (int i = 0; i < 100; ++i) {// 循环遍历0到99Matrix4<Scalar> T = Matrix4<Scalar>::Random();// 创建T矩阵,初始化为随机数//使用一些数值方法来计算一个最接近 T 的刚体变换矩阵。//这个刚体变换矩阵可以由一个旋转矩阵和一个平移向量构成,//这两个部分都可以从 T 矩阵中提取出来。然后,这个函数会使用这些信息来构造一个新的 SE3Type 对象并返回SE3Type se3 = SE3Type::fitToSE3(T);// 使用SE3Type::fitToSE3函数拟合T矩阵,赋值给se3变量SE3Type se3_2 = SE3Type::fitToSE3(se3.matrix());// 使用SE3Type::fitToSE3函数拟合se3变量的矩阵,赋值给se3_2变量// 测试se3和se2_2两个变量的矩阵是否接近SOPHUS_TEST_APPROX(passed, se3.matrix(), se3_2.matrix(),Constants<Scalar>::epsilon(), "");}for (Scalar const angle :{Scalar(0.0), Scalar(0.1), Scalar(0.3), Scalar(-0.7)}) {// 循环遍历角度数组中的每个元素// 测试SE3Type::rotX函数返回值的angleX()函数返回值是否接近angle  SOPHUS_TEST_APPROX(passed, SE3Type::rotX(angle).angleX(), angle,Constants<Scalar>::epsilon(), "");// 测试SE3Type::rotY函数返回值的angleY()函数返回值是否接近angleSOPHUS_TEST_APPROX(passed, SE3Type::rotY(angle).angleY(), angle,Constants<Scalar>::epsilon(), "");// 测试SE3Type::rotZ函数返回值的angleZ()函数返回值是否接近angleSOPHUS_TEST_APPROX(passed, SE3Type::rotZ(angle).angleZ(), angle,Constants<Scalar>::epsilon(), "");}return passed;// 返回所有测试是否通过}template <class S = Scalar>enable_if_t<!std::is_floating_point<S>::value, bool> testFit() {// 定义testFit函数模板,用于测试拟合,仅当S类型不为浮点数类型时启用return true;// 直接返回true}std::vector<SE3Type, Eigen::aligned_allocator<SE3Type>> se3_vec_;// 定义se3_vec_向量,用于存储SE3Type类型的对象std::vector<Tangent, Eigen::aligned_allocator<Tangent>> tangent_vec_;// 定义tangent_vec_向量,用于存储Tangent类型的对象std::vector<Point, Eigen::aligned_allocator<Point>> point_vec_;// 定义point_vec_向量,用于存储Point类型的对象
};int test_se3() {// 定义test_se3函数,用于测试SE3类using std::cerr;using std::endl;cerr << "Test SE3" << endl << endl;cerr << "Double tests: " << endl;Tests<double>().runAll();// 运行所有double类型的测试cerr << "Float tests: " << endl;Tests<float>().runAll();// 运行所有float类型的测试#if SOPHUS_CEREScerr << "ceres::Jet<double, 3> tests: " << endl;Tests<ceres::Jet<double, 3>>().runAll();// 运行所有ceres::Jet<double, 3>类型的测试
#endifreturn 0;
}
}  // namespace Sophusint main() { return Sophus::test_se3(); }// 主函数,运行Sophus命名空间下的test_se3函数,并返回其返回值

测试代码的目的:

  1. 测试代码主要是为了验证sophus库中的算法实现是否正确。开发者通过编写测试用例,来确保各种算法场景下的输出结果与预期一致。

  2. 测试代码也可以用于回归测试。当sophus库有更新时,可以运行测试代码,验证更新后算法的输出是否与之前一致,防止引入新的bug。

  3. 测试代码可以作为使用sophus库的示例代码。通过查看测试代码,用户可以更快地理解如何正确使用sophus库中的接口。

  4. 编写测试代码是良好的编码习惯。充分的测试可以提高代码质量,降低出错概率。维护测试代码也可以让开发者更好地理解自己编写的代码。

  5. 开源项目提供测试代码,可以让用户对代码质量更有信心,也方便其他开发者为项目编写新的测试用例。

  6. 自动化测试框架也可以通过运行测试代码,帮助开发者进行持续集成和部署。

sophus vs manif :

73587e3ccdf83d57ebbe6fa7e652be15.png

1d1c30e6c823c47ce56c1ee3a8082c2b.png

14fb10bec6c99d815b5cefe611833c12.png

9e8bd7716d6da0e7149be9bd50c1fd42.png

参考网址:
1. https://juejin.cn/post/7067858653339975688

Sophus源码逐行解读 ( 结合视觉SLAM十四讲的概念 )

2. https://juejin.cn/post/7075761513113321479 

Lie Group Foundations

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/64380.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV模块介绍

其中core、highgui、imgproc是最基础的模块&#xff0c;该课程主要是围绕这几个模块展开的&#xff0c;分别介绍如下: core模块实现了最核心的数据结构及其基本运算&#xff0c;如绘图函数、数组操作相关函数。 highgui模块实现了视频与图像的读取、显示、存储等接口。 imgp…

Unity中Transform移动相关

路程 方向 * 速度 * 时间 参数一&#xff1a;表示位移多少 路程 方向 * 速度 * 时间 参数二&#xff1a;表示 相对坐标系 默认 该参数 是相对于自己坐标系的 相对于世界坐标系的 Z轴 动 始终是朝 世界坐标系 的 Z轴正方向移动 this.transform.Translate(Vector3.forwar…

F5服务器负载均衡能力如何?一文了解

但凡知道服务器负载均衡这个名词的&#xff0c;基本都知道 F5&#xff0c;因为负载均衡是 F5 的代表作&#xff0c;换句话来说&#xff0c;负载均衡就是由 F5 发明的。提到F5服务器负载均衡能力如何&#xff1f;不得不关注F5提出的关于安全、网络全面优化的解决方案&#xff0c…

设计模式-中介者模式

文章目录 一、前言二、中介者模式1、定义2、未使用/使用中介者模式对比2.1、未使用中介者模式&#xff1a;2.2、使用中介者模式&#xff1a; 3、角色分析3.1、中介者&#xff08;Mediator&#xff09;&#xff1a;3.2、同事&#xff08;Colleague&#xff09;&#xff1a;3.3、…

Python爬虫乱码问题之encoding和apparent_encoding的区别

encoding是从http中的header中的charset字段中提取的编码方式&#xff0c;若header中没有charset字段则默认为ISO-8859-1编码模式&#xff0c;则无法解析中文&#xff0c;这是乱码的原因 apparent_encoding会从网页的内容中分析网页编码的方式&#xff0c;所以apparent_encodi…

android frida 逆向 自吐加密算法

前言&#xff1a; ♛ frida hook android Android 逆向神器 前几天在学习 Android 逆向的时候发现了一个神器&#xff1a;通过 frida hook 我们可以 “劫持” 一些函数 为我们所用&#xff0c; 今天就和大家上手一个 加密函数的劫持 让打印出&#xff1a; 加密秘钥 …

开箱报告,Simulink Toolbox库模块使用指南(五)——S-Fuction模块(C MEX S-Function)

文章目录 前言 C MEX S-Function 算法原理 原始信号创建 编写S函数 仿真验证 Tips 分析和应用 总结 前言 见《开箱报告&#xff0c;Simulink Toolbox库模块使用指南&#xff08;一&#xff09;——powergui模块》 见《开箱报告&#xff0c;Simulink Toolbox库模块使用…

PhpStorm安装篇

PhpStorm安装篇: 下载地址 : 进入官网下PhpStorm: PHP IDE and Code Editor from JetBrains 下载完之后&#xff0c;安装包 安装目录建议不要放C盘&#xff0c;放其他盘&#xff0c;其他直接一直点 next &#xff0c;到结束 安装完&#xff0c;打开编辑器 注册账号并登录后…

Android投屏总结

#android手机投屏 ####导语 至于手机投屏的实现方法可谓五花八门&#xff0c;今天小袁就说下以开发人员的角度来说下当今手机的主流投屏方法。目前这种将终端信号经由WiFi传输到电视、电视盒的技术有三种&#xff1a;DLNA、AirPlay、Miracast、Google Cast。 ##手机投屏智能电…

python 深度学习 解决遇到的报错问题3

目录 一、AttributeError: The vocab attribute was removed from KeyedVector in Gensim 4.0.0. 二、ImportError: cannot import name logsumexp 三、FutureWarning: Passing (type, 1) or 1type as a synonym of type is deprecated; in a future version of numpy, it w…

VBA:对Excel单元格进行合并操作

Sub hb()Dim nn 3For i 3 To 18If Range("b" & i) <> Range("b" & i 1) ThenRange("b" & n & ":b" & i).Mergen i 1End IfNextEnd Sub

记录--前端使用a链接下载内容增加loading效果

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 问题描述&#xff1a;最近工作中出现一个需求&#xff0c;纯前端下载 Excel 数据&#xff0c;并且有的下载内容很多&#xff0c;这时需要给下载增加一个 loading 效果。 代码如下&#xff1a; // util…

Maven入门教程(三):Maven语法

视频教程&#xff1a;Maven保姆级教程 Maven入门教程(一)&#xff1a;安装Maven环境 Maven入门教程(二)&#xff1a;idea/Eclipse使用Maven Maven入门教程(三)&#xff1a;Maven语法 Maven入门教程(四)&#xff1a;Nexus私服 Maven入门教程(五)&#xff1a;自定义脚手架 6.Mav…

Loki日志系统

1、Loki是什么&#xff1f; Loki是一个开源的日志聚合系统&#xff0c;由Grafana Labs开发和维护。它旨在帮助用户收集、存储和查询大规模的日志数据&#xff0c;帮助用户更好地理解和监控他们的应用程序和系统。 Loki的设计灵感来自于Prometheus&#xff0c;它采用了类似的标…

【小沐学Unity3d】3ds Max 骨骼动画制作(蒙皮修改器skin)

文章目录 1、简介2、蒙皮修改器3.1 骨骼对象测试3.2 Biped对象测试 3、动画制作4、FBX导出结语 1、简介 “蒙皮”修改器是一种骨骼变形工具&#xff0c;主要设计用于通过另一个对象对一个对象进行变形来创建角色动画。可使用骨骼、样条线和其他对象变形网格、面片和 NURBS 对象…

python3+requests:接口自动化测试(二)

前言&#xff1a;上篇文章python3requestsunittest&#xff1a;接口自动化测试&#xff08;一&#xff09;&#xff1a;已经介绍了基于unittest框架的实现接口自动化&#xff0c;但是也存在一些问题&#xff0c;比如最明显的测试数据和业务没有区分开&#xff0c;接口用例不便于…

【机器学习】线性回归

Model Representation 1、问题描述2、表示说明3、数据绘图4、模型函数5、预测总结附录 1、问题描述 一套 1000 平方英尺 (sqft) 的房屋售价为300,000美元&#xff0c;一套 2000 平方英尺的房屋售价为500,000美元。这两点将构成我们的数据或训练集。面积单位为 1000 平方英尺&a…

2010-2021年上市公司和讯网社会责任评级CSR数据/和讯网上市公司社会责任数据

2010-2021年上市公司和讯网社会责任评级CSR数据 1、时间&#xff1a;2010-2021年 2、指标&#xff1a;股票名称、股票代码、年份、总得分、等级、股东责任、员工责任、供应商、客户和消费者权益责任、环境责任、社会责任、所属年份 3、样本量&#xff1a;4万 4、来源&#…

数据结构与算法基础-学习-31-交换排序之冒泡排序、快速排序

排序的其他相关知识点和源码分享可以参考之前的博客&#xff1a; 《数据结构与算法基础-学习-30-插入排序之直接插入排序、二分插入排序、希尔排序》 一、交换排序基本思想 两两比较&#xff0c;如果发生逆序则交换位置&#xff0c;直到所有数据记录都排好序为止。 二、冒…

大模型理解之CLIP

前言 2021年2月份&#xff0c;CLIP模型被提出&#xff0c;想法很简单&#xff0c;性能高效&#xff0c;而且具备很好的泛化性。我在这里简单谈论下我对CLIP模型的理解&#xff0c;以及发现的一些问题。 我是在沐神的视频中了解的CLIP, 里面提到CLIP最大的贡献在于打破了固定类…