当前位置: 首页 > news >正文

PCL点云库入门——PCL库中Eigen数学工具库的基本使用(持续更新)

0、前言

        PCL点云库中的算法都基于Eigen数学工具库来实现的,因此,掌握Eigen库对于深入理解和应用PCL点云库至关重要。Eigen库不仅提供了高效的矩阵和向量运算,还支持复杂的线性代数、几何变换等操作,为PCL点云处理提供了强大的数学支持。PCL库中已经包含了Eigen库不需要单独的安装,直接包含头文件就可以使用,因此安装不在讲述。

1、Eigen库的简介

        Eigen库是一个高性能的C++模板库,专注于线性代数、矩阵和向量运算,以及相关的数值分析和算法。

1.1、Eigen库的特性

        Eigen库有如下一些特点:

        1)、易用性

        Eigen库是一个头文件库,这意味着它不需要编译成库文件,也不需要动态链接。开发者只需将Eigen的头文件包含在项目中即可使用,这极大地简化了集成过程。同时,Eigen支持多种数据类型,包括整数、浮点数和复数等,通过模板编程,Eigen能够为这些数据类型提供高效的矩阵和向量运算。

        2)、高性能与优化

        Eigen经过高度优化,能够充分利用现代CPU的性能。它支持SIMD(单指令多数据)指令集,如SSE和AVX,以及多线程计算,从而实现了高效的并行运算。此外,Eigen对稀疏矩阵和密集矩阵都提供了良好的支持,并且针对各种矩阵运算进行了优化,如矩阵乘法、矩阵分解(如Cholesky分解、QR分解、SVD分解)等。

        3)、灵活性与可扩展性

        Eigen库提供了多种矩阵大小选项,包括动态大小和固定大小,以满足不同的应用需求。用户还可以自定义扩展Eigen以适应特殊的数据结构或运算。这种灵活性和可扩展性使得Eigen能够广泛应用于各种领域。    

        4)、应用领域广

        Eigen库被广泛应用于科学计算、机器学习、计算机图形学、计算机视觉、信号处理、金融等领域。在科学计算中,Eigen可以用于求解线性方程组、矩阵分解和特征值问题等。在机器学习和计算机视觉中,Eigen常用于数据降维、模型参数估计、图像特征提取等任务。此外,Eigen还支持常用的几何运算,如旋转矩阵、四元数、矩阵变换等,这使得它在3D计算和机器人学中也具有广泛的应用。

1.2、Eigen库中的主要模块

        Eigen库中的主要模块如下表所示:

功能模块

简要功能描述

Core

包含Matrix和Array类,支持基础的线性代数运算和数组操作。

Geometry

提供旋转、平移、缩放以及2维和3维的各种变换功能。

LU

用于求逆、行列式以及LU分解。

Cholesky

支持LLT和LDLT Cholesky分解。

Householder

提供Householder变换。

SVD

实现奇异值分解(SVD),并配备最小二乘解算器。

QR

实现QR分解,并提供HouseholderQR、ColPivHouseholderQR、FullPivHouseholderQR三种方法。

Eigenvalues

用于特征值和特征向量的分解,提供EigenSolver、SelfAdjointEigenSolver、ComplexEigenSolver等方法

Sparse

支持稀疏矩阵的存储和运算。

Dense

包含Core、Geometry、LU、Cholesky、SVD、QR、Eigenvalues等模块,是Eigen库的核心部????

 2、Eigen库中向量和矩阵的定义

        在Eigen库中,所有的矩阵和向量均被视为矩阵模板类的实例。向量可以被看作是特殊形式的矩阵,具体表现为只包含1行或1列。

2.1、 Eigen库中的矩阵类

        Eigen库中Matrix类包含六个模板参数,目前仅需掌握其前三个参数。余下的三个参数均设有默认值,目前我们不予以深入探讨,后续章节将对此进行详细讨论。

        Matrix的三个必要模板参数为:

Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>

        其中三个参数的含义如下: 

        Scalar:代表标量类型,即数据类型。换言之,若您需要一个浮点数矩阵,请在此选择float。

常用的还有double和int类型。

        RowsAtCompileTimeColsAtCompileTime:指的是在编译阶段已确定的矩阵行数和列数(若编译时无法确定,可以动态的指定后面进行讨论)。

        Eigen库中提供了许多常用的矩阵类型的定义。Eigen常用的矩阵定义有如下:

    //2维方矩阵Eigen::Matrix2i;Eigen::Matrix2f;Eigen::Matrix2d;Eigen::Matrix2cf;Eigen::Matrix2cd;//3维方矩阵Eigen::Matrix3i;Eigen::Matrix3f;Eigen::Matrix3d;Eigen::Matrix3cf;Eigen::Matrix3cd;//4维方矩阵Eigen::Matrix4i;Eigen::Matrix4f;Eigen::Matrix4d;Eigen::Matrix4cf;Eigen::Matrix4cd; 

        Eigen库定义的都是比较常用的定义,矩阵维度小于4的,但维度超过4时,我们可以根据自己的数据进行定义,方式如下:

typedef Eigen::Matrix<float, 10, 10> Matrix10f;//10维的方正,其他类型的可以参照此定义方式进行。typedef Eigen::Matrix<double, 10, 10> Matrix10d;//10维的方正,其他类型的可以参照此定义方式进typedef Eigen::Matrix<double, 10, 10> Matrix10d;typedef Eigen::Matrix<float, 10, 15> Matrix10_15f;

2.2 、Eigen库中的向量

        正如先前所述,在Eigen库中,向量实际上是矩阵的一个特例,它们要么仅包含1行,要么仅包含1列。最常见的情形是仅含1列的向量,这种向量被称为列向量,通常简称为向量。相对地,仅含1行的向量则被称为行向量。

Eigen库中也提供了常用的向量类型的定义。Eigen定义的向量有如下:
 //2维向量Eigen::Vector2i;Eigen::Vector2f;Eigen::Vector2d;Eigen::Vector2cf;Eigen::Vector2cd;//3维向量Eigen::Vector3i;Eigen::Vector3f;Eigen::Vector3d;Eigen::Vector3cf;Eigen::Vector3cd;//4维向量Eigen::Vector4i;Eigen::Vector4f;Eigen::Vector4d;Eigen::Vector4cf;Eigen::Vector4cd;

        注意:Eigen库中上述常用定义的向量是列向量,定义方式是:

typedef Matrix<float, 3, 1> Vector3f;

        另外,行向量的定义为:

typedef Matrix<int, 1, 2> RowVector2i;

        按照自己的数据大小定义为:

typedef Eigen::Matrix<float, 10, 1> Vector10f;//10维的向量,其他类型的可以参照此定义方式进行。

2.3 、Eigen库中矩阵的动态维度(行、列)

        Eigen库的功能不仅限于处理编译时已知维度的矩阵。通过使用模板参数RowsAtCompileTimeColsAtCompileTime,我们可以指定一个特殊值Dynamic,这表明矩阵的维度在编译时是未知的,因此必须在运行时作为变量处理。在Eigen库中,这样的维度被称为动态大小;相对地,编译时已知的维度则被称为固定大小。例如,定义的 typedef MatrixXd 类型,它表示一个具有动态大小的双精度矩阵,其定义如下:

typedef Matrix<double, Dynamic, Dynamic> MatrixXd;

        同理,可以定义了动态的向量类型VectorXi,定义如下:

typedef Matrix<int, Dynamic, 1> VectorXi;

3、Eigen库中矩阵和向量的初始化

        下面对常用矩阵和向量的初始化进行应用实例说明。

3.1、矩阵的初始化

        方式1 :‘<<’法:

Eigen:: Matrix3f m;m << 1, 2, 3,4, 5, 6,7, 8, 9;

        方式2:‘(i,j)’法:

Eigen::Matrix3f m2;m2(0, 0) = 1, m2(0, 1) = 2, m2(0, 2) = 3;m2(1, 0) = 3, m2(1, 1) = 5, m2(1, 2) = 6;m2(2, 0) = 7, m2(2, 1) = 8, m2(2, 2) = 8;

        方式3 :常数矩阵法:

   //零矩阵Eigen::Matrix4f rt1 = Eigen::Matrix4f::Zero();//单位矩阵Eigen::Matrix4f rt2 = Eigen::Matrix4f::Identity();//随机矩阵Eigen::Matrix4f rt3 = Eigen::Matrix4f::Random();

3.2、向量的初始化

        方式1: ‘<<’法:

Eigen::Vector3f v1;v1 << 1, 2, 3;

        方式2:‘(i)’法:

Eigen::Vector3f v1;v1(0) = 1;v1(1) = 2;v1(2) = 3;

        方式3: 常数矩阵法:

    //全部值是0的向量Eigen::Vector3f v2 = Eigen::Vector3f::Zero();//全部值是1的向量Eigen::Vector3f v3 = Eigen::Vector3f::Identity();//随机向量Eigen::Vector3f v4 = Eigen::Vector3f::Random();

        方式4 :构造法:

Eigen::Vector3f v5(1, 2, 3);

4、Eigen库中矩阵和向量的算术操作

        Eigen库重载了常见的C++算术运算符(例如 +、-、*),以支持矩阵和向量的算术运算,如 dot() 和 cross() 等函数。对于Matrix类(包括矩阵和向量),运算符重载仅限于支持线性代数操作。例如,Matrix1 * Matrix2 表示两个矩阵的乘积,而向量与标量的加法是不被允许的。若需执行非线性代数的各种数组运算,则必须依赖于数组运算,这部分内容将在后续讨论。

4.1 、矩阵/向量加减

示例代码:
void MatrixVector_AddAndSubtraction()
{Eigen::Matrix2d a;a << 1, 2,3, 4;Eigen::MatrixXd b(2, 2);b << 2, 3,1, 4;std::cout << "a + b =\n" << a + b << std::endl;std::cout << "a - b =\n" << a - b << std::endl;a += b;std::cout << "Now a =\n" << a << std::endl;Eigen::RowVector3d v(1, 2, 3);Eigen::RowVector3d w(1, 0, 0);std::cout << "-v + w - v =\n" << -v + w - v << std::endl;
}

        结果:

4.2、标量与矩阵/向量的乘除

        示例代码:

void MatrixVectore_ScalarMD()
{Eigen::Matrix2d a;a << 1, 1,1, 1;Eigen::Vector3d v(1, 2, 3);std::cout << "a * 3 =\n" << a * 3 << std::endl;std::cout << "3 * v =\n" << 3 * v << std::endl;v *= 2;std::cout << "Now v =\n" << v << std::endl;Eigen::Matrix2d b;b << 9, 9,9, 9;Eigen::Vector3d v2(2, 4, 6);std::cout << "a / 3 =\n" << (b / 3 )<< std::endl;std::cout << " v/2 =\n" << (v2/2) << std::endl;
}

        结果:

4.3、矩阵与矩阵、矩阵与向量的相乘

        代码示例:

void MatrixVectoreMulti()
{Eigen::Matrix2d a;a << 1, 1,1, 1;Eigen::Matrix2d b;b << 9, 9,9, 9;std::cout << "a *b =\n" << a*b << std::endl;Eigen::Vector3d v(2, 4, 6);Eigen::Matrix3d m = Eigen::Matrix3d::Random();std::cout << "m =\n" <<m << std::endl;std::cout << "v*m=\n" <<m*v << std::endl;}

        结果:

4.4、向量的点乘和叉乘

         代码示例:

void VectorDotAndCross()
{Eigen::Vector3d v(1, 2, 3);Eigen::Vector3d w(1, 1, 1);cout << "Dot product: " << v.dot(w) << endl;double dp = v.adjoint() * w; cout << "Dot product via a matrix product: " << dp << endl;cout << "Cross product:\n" << v.cross(w) << endl;
}

        结果:

4.5、Eigen库中归约操作 

        Eigen还提供了一系列归约操作,用于将给定的矩阵或向量简化为单一数值。这些操作包括计算总和(通过sum()函数)、乘积(通过prod()函数)、以及所有系数的最大值(通过maxCoeff()函数)和最小值(通过minCoeff()函数)。

        代码示例:

void ReductionOperations()
{Eigen::Matrix2d mat;mat << 4, 5,6, 7;cout << "Matrix is mat.sum():       " << mat.sum() << endl;        cout << "Matrix is mat.prod():      " << mat.prod() << endl;          cout << "Matrix is mat.mean():      " << mat.mean() << endl;       cout << "Matrix is mat.minCoeff():  " << mat.minCoeff() << endl;   cout << "Matrix is mat.maxCoeff():  " << mat.maxCoeff() << endl;   cout << "Matrix is mat.trace():     " << mat.trace() << endl;     
}

        结果:

5、矩阵的块操作

        本小节主要进行矩阵中块操作的要点说明。块是矩阵或数组的矩形部分。块表达式既可以用作右值,也可以用作左值。与通常的Eigen表达式一样,只要让编译器进行优化,块操作的运行时成本为零。Eigen中有两个版本的块操作,语法如下:

块操作

动态尺寸块

固定尺寸块

Block of size (p,q), starting at (i,j)

matrix.block(i,j,p,q);

matrix.block<p,q>(i,j);

        在Eigen库中,索引从0开始的。这两个版本均适用于处理固定尺寸和动态尺寸的矩阵与数组。从语义上讲,这两种表达方式是等效的。唯一的差异在于,当处理的块维度较小时,固定稳定版本往往能够生成更快速的代码,前提是编译时已知该尺寸。

5.1、块的基本操作 

        代码示例:

void BasicOperationBlock()
{Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;cout << m.block<3, 3>(1, 1) << endl << endl;for (int i = 1; i <= 3; ++i){cout << "Block of size " << i << "x" << i << endl;cout << m.block(0, 0, i, i) << endl << endl;}
}

        结果:

5.2、块左值操作

        代码示例:

void OperationBlockLetfValue()
{Eigen::Array22f m;m << 1, 2,3, 4;Eigen::Array44f a = Eigen::Array44f::Constant(0.6);cout << "Array a:" << endl << a << endl << endl;a.block<2, 2>(1, 1) = m;cout << "Here is now a with m copied into its central 2x2 block:" << endl << a << endl << endl;a.block(0, 0, 2, 3) = a.block(2, 1, 2, 3);cout << "Here is now a with bottom-right 2x3 block copied into top-left 2x3 block:" << endl << a << endl << endl;
}

        结果:

5.3、块的行和列操作

        代码示例:

void OperationBlockRowAndCol()
{Eigen::MatrixXf m(3, 3);m << 1, 2, 3,4, 5, 6,7, 8, 9;cout << "M:" << endl << m << endl;cout << "2nd Row: " << m.row(1) << endl;m.col(2) += 3 * m.col(0);cout << "After adding 3 times the first column into the third column, the matrix m is:\n";cout << m << endl;
}

        结果: 

5.4、块的角点操作 

        Eigen库提供了专门的方法来处理矩阵或数组角部或边缘的块操作。例如,.topleftcorner()方法可用于引用矩阵左上角的特定块。下表总结了不同的角点操作:

块操作

动态尺寸块

固定尺寸块

Top-left p by q block *

matrix.topLeftCorner(p,q);

matrix.topLeftCorner<p,q>();

Bottom-left p by q block *

matrix.bottomLeftCorner(p,q);

matrix.bottomLeftCorner<p,q>();

Top-right p by q block *

matrix.topRightCorner(p,q);

matrix.topRightCorner<p,q>();

Bottom-right p by q block *

matrix.bottomRightCorner(p,q);

matrix.bottomRightCorner<p,q>();

Block containing the first q rows *

matrix.topRows(q);

matrix.topRows<q>();

Block containing the last q rows *

matrix.bottomRows(q);

matrix.bottomRows<q>();

Block containing the first p columns *

matrix.leftCols(p);

matrix.leftCols<p>();

Block containing the last q columns *

matrix.rightCols(q);

matrix.rightCols<q>();

Block containing the q columns starting from i *

matrix.middleCols(i,q);

matrix.middleCols<q>(i);

Block containing the q rows starting from i *

matrix.middleRows(i,q);

matrix.middleRows<q>(i);

        示例代码: 

void CornerOperationBlock()
{Eigen::Matrix4f m=Eigen::Matrix4f::Random();cout << "m = " << endl << m << endl;cout << "m.leftCols(2) =" << endl << m.leftCols(2) << endl << endl;cout << "m.bottomRows<2>() =" << endl << m.bottomRows<2>() << endl << endl;m.topLeftCorner(1, 3) = m.bottomRightCorner(3, 1).transpose();cout << "After assignment, m = " << endl << m << endl;
}

        结果:

6、向量的块操作 

        同样Eigen库也为向量和数组提供了块操作,格式如下表。

块操作

动态尺寸块

固定尺寸块

Block containing the first n elements *

vector.head(n);

vector.head<n>();

Block containing the last n elements *

vector.tail(n);

vector.tail<n>();

Block containing n elements, starting at position i *

vector.segment(i,n);

vector.segment<n>(i);

        代码示例: 

void VectroeOperationBlock()
{Eigen::ArrayXf a(6);a << 1, 2, 3, 4, 5, 6;cout << "a.head(3) =" << endl << a.head(3).transpose() << endl << endl;cout << "a.tail<3>() = " << endl << a.tail<3>().transpose() << endl << endl;a.segment(1, 4) *= 2;cout << "after 'a.segment(1,4) *= 2', a =" << endl << a.transpose() << endl;Eigen::VectorXf v(6);v << 11, 22, 33, 44, 55, 66;cout << "v.head(2) =" << endl << v.head(2).transpose() << endl << endl;cout << "v.tail<2>() = " << endl << v.tail<3>().transpose() << endl << endl;v.segment(1, 4) *= 2;cout << "after 'v.segment(1,4) *= 2', v =" << endl << v.transpose() << endl;}

        结果:

7、所有示例代码

        新建文件名PCLEigenmain.cpp,内容如下:

/*****************************************************************//**
* \file   PCLEigenmain.cpp
* \brief
*
* \author YZS
* \date   December 2024
*********************************************************************/
#include <iostream>              
#include <string>
#include <Eigen/Dense> //Eigen 头文件
using namespace std;void MatrixVector_AddAndSubtraction()
{Eigen::Matrix2d a;a << 1, 2,3, 4;Eigen::MatrixXd b(2, 2);b << 2, 3,1, 4;std::cout << "a + b =\n" << a + b << std::endl;std::cout << "a - b =\n" << a - b << std::endl;a += b;std::cout << "Now a =\n" << a << std::endl;Eigen::RowVector3d v(1, 2, 3);Eigen::RowVector3d w(1, 0, 0);std::cout << "-v + w - v =\n" << -v + w - v << std::endl;
}void MatrixVectore_ScalarMD()
{Eigen::Matrix2d a;a << 1, 1,1, 1;Eigen::Vector3d v(1, 2, 3);std::cout << "a * 3 =\n" << a * 3 << std::endl;std::cout << "3 * v =\n" << 3 * v << std::endl;v *= 2;std::cout << "Now v =\n" << v << std::endl;Eigen::Matrix2d b;b << 9, 9,9, 9;Eigen::Vector3d v2(2, 4, 6);std::cout << "a / 3 =\n" << (b / 3 )<< std::endl;std::cout << " v/2 =\n" << (v2/2) << std::endl;
}void MatrixVectoreMulti()
{Eigen::Matrix2d a;a << 1, 1,1, 1;Eigen::Matrix2d b;b << 9, 9,9, 9;std::cout << "a *b =\n" << a*b << std::endl;Eigen::Vector3d v(2, 4, 6);Eigen::Matrix3d m = Eigen::Matrix3d::Random();std::cout << "m =\n" <<m << std::endl;std::cout << "v*m=\n" <<m*v << std::endl;}void VectorDotAndCross()
{Eigen::Vector3d v(1, 2, 3);Eigen::Vector3d w(1, 1, 1);cout << "Dot product: " << v.dot(w) << endl;double dp = v.adjoint() * w; cout << "Dot product via a matrix product: " << dp << endl;cout << "Cross product:\n" << v.cross(w) << endl;
}void ReductionOperations()
{Eigen::Matrix2d mat;mat << 4, 5,6, 7;cout << "Matrix is mat.sum():       " << mat.sum() << endl;        cout << "Matrix is mat.prod():      " << mat.prod() << endl;          cout << "Matrix is mat.mean():      " << mat.mean() << endl;       cout << "Matrix is mat.minCoeff():  " << mat.minCoeff() << endl;   cout << "Matrix is mat.maxCoeff():  " << mat.maxCoeff() << endl;   cout << "Matrix is mat.trace():     " << mat.trace() << endl;     
}void BasicOperationBlock()
{Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;cout << m.block<3, 3>(1, 1) << endl << endl;for (int i = 1; i <= 3; ++i){cout << "Block of size " << i << "x" << i << endl;cout << m.block(0, 0, i, i) << endl << endl;}
}void OperationBlockLetfValue()
{Eigen::Array22f m;m << 1, 2,3, 4;Eigen::Array44f a = Eigen::Array44f::Constant(0.6);cout << "Array a:" << endl << a << endl << endl;a.block<2, 2>(1, 1) = m;cout << "Here is now a with m copied into its central 2x2 block:" << endl << a << endl << endl;a.block(0, 0, 2, 3) = a.block(2, 1, 2, 3);cout << "Here is now a with bottom-right 2x3 block copied into top-left 2x3 block:" << endl << a << endl << endl;
}void OperationBlockRowAndCol()
{Eigen::MatrixXf m(3, 3);m << 1, 2, 3,4, 5, 6,7, 8, 9;cout << "M:" << endl << m << endl;cout << "2nd Row: " << m.row(1) << endl;m.col(2) += 3 * m.col(0);cout << "After adding 3 times the first column into the third column, the matrix m is:\n";cout << m << endl;
}void CornerOperationBlock()
{Eigen::Matrix4f m=Eigen::Matrix4f::Random();cout << "m = " << endl << m << endl;cout << "m.leftCols(2) =" << endl << m.leftCols(2) << endl << endl;cout << "m.bottomRows<2>() =" << endl << m.bottomRows<2>() << endl << endl;m.topLeftCorner(1, 3) = m.bottomRightCorner(3, 1).transpose();cout << "After assignment, m = " << endl << m << endl;
}void VectroeOperationBlock()
{Eigen::ArrayXf a(6);a << 1, 2, 3, 4, 5, 6;cout << "a.head(3) =" << endl << a.head(3).transpose() << endl << endl;cout << "a.tail<3>() = " << endl << a.tail<3>().transpose() << endl << endl;a.segment(1, 4) *= 2;cout << "after 'a.segment(1,4) *= 2', a =" << endl << a.transpose() << endl;Eigen::VectorXf v(6);v << 11, 22, 33, 44, 55, 66;cout << "v.head(2) =" << endl << v.head(2).transpose() << endl << endl;cout << "v.tail<2>() = " << endl << v.tail<3>().transpose() << endl << endl;v.segment(1, 4) *= 2;cout << "after 'v.segment(1,4) *= 2', v =" << endl << v.transpose() << endl;}int main(int argc, char* argv[])
{//MatrixVector_AddAndSubtraction();//MatrixVectore_ScalarMD();//MatrixVectoreMulti();//VectorDotAndCross();//ReductionOperations();//BasicOperationBlock();//OperationBlockLetfValue();//OperationBlockRowAndCol();//CornerOperationBlock();VectroeOperationBlock();std::cout << "Hello PCL!" << std::endl;std::system("pause");return 0;
}

至此完成第六节PCL库中Eigen数学工具库简单学习,由于Eigen库涉及的应用较多,后序还会持续更新该库的更多应用。下一节我们将进入《PCL库中点云数据的拓扑关系构建》的学习。   

http://www.lryc.cn/news/505874.html

相关文章:

  • CLion Inlay Hints - 取消 CLion 灰色的参数和类型提示
  • 2025山东科技大学考研专业课复习资料一览
  • vue3 v-model实例之二,tab标签页的实现
  • 东方通TongWeb7.0.4.9M4部署SuperMap iServer 11.2.1
  • QT绘制同心扇形
  • 2012年西部数学奥林匹克试题(几何)
  • 8位移位寄存器的verilog语言
  • 【苍穹外卖】学习心得体会-随笔
  • MySQL学习之表的增删改
  • 电脑excel词典(xllex.dll)文件丢失是或损坏是什么原因?“xllex.dll文件缺失“要怎么解决?
  • 【CSS in Depth 2 精译_084】第 14 章:CSS 蒙版、形状与剪切概述 + 14.1:CSS 滤镜
  • gorm源码解析(四):事务,预编译
  • 前端优雅(装逼)写法(updating····)
  • 黑马Java面试教程_P7_常见集合_P4_HashMap
  • 使用 CFD 加强水资源管理:全面概述
  • XXE练习
  • R语言读取hallmarks的gmt文档的不同姿势整理
  • 【Nginx-4】Nginx负载均衡策略详解
  • Python 的 Decimal的错误计算
  • 【韩顺平 Java满汉楼项目 控制台版】MySQL+JDBC+druid
  • 【HAL库】STM32CubeMX开发----STM32F407----Time定时器中断实验
  • react18+ts 封装图表及词云组件
  • 图像根据mask拼接时,边缘有色差 解决
  • 17、ConvMixer模型原理及其PyTorch逐行实现
  • Spring整合Redis基本操作步骤
  • STM32使用SFUD库驱动W25Q64
  • ArKTS基础组件
  • 如何理解TCP/IP协议?如何理解TCP/IP协议是什么?
  • 如何使用 Python 连接 SQLite 数据库?
  • 【博弈模型】古诺模型、stackelberg博弈模型、伯特兰德模型、价格领导模型