Eigen 中矩阵的拼接(Concatenation)与 分块(Block Access)操作使用详解和示例演示

一、矩阵分块访问(Block)

Eigen 使用 .block().topLeftCorner().row().col() 等函数进行矩阵子块访问:

1.1 block(i, j, rows, cols) --- 访问子块

cpp 复制代码
MatrixXd mat(4, 4);
mat << 1, 2, 3, 4,
       5, 6, 7, 8,
       9,10,11,12,
      13,14,15,16;

MatrixXd sub = mat.block(1, 1, 2, 2); // 从(1,1)取2x2子矩阵

1.2 快捷方式访问角落区域

cpp 复制代码
mat.topLeftCorner(2, 2);
mat.bottomRightCorner(2, 2);
mat.topRows(2);
mat.leftCols(3);

1.3 修改子块

cpp 复制代码
mat.block(0, 0, 2, 2) = Matrix2d::Ones();

二、矩阵拼接(Concatenation)

2.1 横向拼接(水平拼接)

cpp 复制代码
MatrixXd A(2, 2), B(2, 3);
A << 1, 2, 3, 4;
B << 5, 6, 7, 8, 9, 10;

MatrixXd C(A.rows(), A.cols() + B.cols());
C << A, B;  // 水平拼接

2.2 纵向拼接(垂直拼接)

cpp 复制代码
MatrixXd D(3, 2);
D << 11, 12,
     13, 14,
     15, 16;

MatrixXd E(A.rows() + D.rows(), A.cols());
E << A,
     D;  // 垂直拼接

三、动态拼接(适用于未知大小)

Eigen 不直接支持 push_back,可通过 resize + block 实现:

cpp 复制代码
MatrixXd total(0, 2);  // 初始空矩阵,列数固定为2
MatrixXd row(1, 2);
row << 1, 2;

total.conservativeResize(total.rows() + 1, NoChange);  // 保持列数不变
total.bottomRows(1) = row;

四、行列访问与赋值

cpp 复制代码
Matrix3d A;
A.row(0) = RowVector3d(1, 2, 3);    // 设置第1行
A.col(1) = Vector3d(4, 5, 6);       // 设置第2列

五、分块迭代

可用于滑动窗口、图块处理等:

cpp 复制代码
MatrixXd big = MatrixXd::Random(6, 6);
for (int i = 0; i < big.rows(); i += 3) {
    for (int j = 0; j < big.cols(); j += 3) {
        MatrixXd block = big.block(i, j, 3, 3);
        std::cout << "Block at (" << i << "," << j << "):\n" << block << std::endl;
    }
}

六、拼接 Vector(向量拼接)

Eigen 无直接 append 接口,可手动拼接:

cpp 复制代码
Vector3d a(1, 2, 3);
Vector2d b(4, 5);

VectorXd c(a.size() + b.size());
c << a, b;   // 拼接为5维向量

七、矩阵拼接的注意事项

操作方式 是否推荐 原因说明
conservativeResize() + 赋值 ✅ 推荐 动态拼接、可扩展
std::vector<MatrixXd> 后合并 ✅ 推荐 适合收集多个块再整体合并
STL push_back 模拟拼接 ❌ 不推荐 Eigen 矩阵不是 STL 容器,效率低

八、示例演示

1、信息矩阵拼接示例

图优化中常构建如下稀疏结构矩阵:

H=H11H120H12TH22H230H23TH33 H = \begin{bmatrix} H_{11} & H_{12} & 0 \\ H_{12}^T & H_{22} & H_{23} \\ 0 & H_{23}^T & H_{33} \end{bmatrix} H= H11H12T0H12H22H23T0H23H33

cpp 复制代码
MatrixXd H(9, 9);
H.setZero();

MatrixXd H11 = MatrixXd::Identity(3, 3);
MatrixXd H12 = MatrixXd::Constant(3, 3, 0.5);
MatrixXd H22 = MatrixXd::Identity(3, 3) * 2;
MatrixXd H23 = MatrixXd::Constant(3, 3, 1.0);
MatrixXd H33 = MatrixXd::Identity(3, 3) * 3;

H.block(0, 0, 3, 3) = H11;
H.block(0, 3, 3, 3) = H12;
H.block(3, 0, 3, 3) = H12.transpose();
H.block(3, 3, 3, 3) = H22;
H.block(3, 6, 3, 3) = H23;
H.block(6, 3, 3, 3) = H23.transpose();
H.block(6, 6, 3, 3) = H33;

2、矩阵合并示例

处理多个点云帧时,常需将坐标矩阵拼接成大块矩阵以用于 SVD 或最小二乘:

cpp 复制代码
std::vector<Vector3d> cloudA = { Vector3d(1,2,3), Vector3d(4,5,6) };
std::vector<Vector3d> cloudB = { Vector3d(7,8,9), Vector3d(10,11,12) };

MatrixXd matA(3, cloudA.size());
MatrixXd matB(3, cloudB.size());
for (size_t i = 0; i < cloudA.size(); ++i) {
    matA.col(i) = cloudA[i];
    matB.col(i) = cloudB[i];
}

// 拼接为 6xN 点对矩阵
MatrixXd combined(6, cloudA.size());
combined << matA,
            matB;

3、使用 SparseMatrix 进行分块拼接(稀疏构图)示例

对于大规模问题,更推荐使用稀疏矩阵拼接:

cpp 复制代码
#include <Eigen/Sparse>
using namespace Eigen;

typedef SparseMatrix<double> SpMat;
std::vector<Triplet<double>> triplets;

int block_size = 3;

// 插入块 (i,j)
Matrix3d block = Matrix3d::Identity();
for (int i = 0; i < block_size; ++i)
    for (int j = 0; j < block_size; ++j)
        triplets.emplace_back(i + 3, j + 3, block(i,j));  // 插入到 H(3:6, 3:6)

SpMat H_sparse(9, 9);
H_sparse.setFromTriplets(triplets.begin(), triplets.end());

4、构建动态扩展矩阵队列(如 sliding window)示例

可维护多帧 pose 或 observation:

cpp 复制代码
std::vector<MatrixXd> pose_blocks;

// 每次新状态加入
MatrixXd new_pose(6, 1); // 6 DOF
new_pose.setRandom();
pose_blocks.push_back(new_pose);

// 拼接为整体大矩阵
MatrixXd all_pose(6, pose_blocks.size());
for (size_t i = 0; i < pose_blocks.size(); ++i)
    all_pose.col(i) = pose_blocks[i];

5、拆分一个大矩阵为多个子块示例

例如将优化后的状态拆成多个节点:

cpp 复制代码
VectorXd x = VectorXd::LinSpaced(18, 1, 18);  // 假设每 6 为一帧状态
int n = x.size() / 6;

std::vector<VectorXd> frames;
for (int i = 0; i < n; ++i)
    frames.push_back(x.segment(i * 6, 6));  // 拆成多个6维状态

九、总结-拼接与分块方法对比

方法 用途 是否动态 备注
.block(i,j,r,c) 任意子块读写 高效
conservativeResize() + bottomRows() 逐行拼接 常用于采样/流式输入
std::vector<MatrixXd> 先收集后合并 推荐
稀疏矩阵 Triplet 方式 大规模稀疏拼接 图优化必备
.segment() 拆向量 高效

相关推荐
田里的水稻几秒前
OE_永久配置网络_linux系统终端命令行ip_setting
人工智能·网络协议·机器人·运维开发
独隅4 分钟前
Android Studio 接入多种不同 AI 大模型进行开发的全面详细指南(Android Studio+AI)
android·人工智能·android studio
暴躁小师兄数据学院6 分钟前
【AI大数据工程师特训笔记】第02讲:PostgreSQL数据库生态全景
大数据·数据库·人工智能·postgresql
暴躁小师兄数据学院8 分钟前
【AI大模型应用开发工程师特训笔记】第04讲(第9章):文件目录操作
人工智能·笔记·python
天天讯通8 分钟前
机器人外呼行业适用性分析
人工智能·机器人
sheeta19988 分钟前
LeetCode 每日一题笔记 日期:2026.05.27 题目:3121. 统计特殊字母的数量 II
笔记·算法·leetcode
wechat_Neal9 分钟前
Google AAOS 2026发布深度解析与对中国车企出海的战略启示
人工智能·microsoft·华为·汽车
Cosolar11 分钟前
QwenPaw 源码学习指南
人工智能·架构·github
ST——Jess18 分钟前
年度行业趋势研究报告:泛心理数字化赛道“流日推演”的算法困境与高保真交互范式重构
人工智能·算法·架构
Tisfy20 分钟前
LeetCode 3300.替换为数位和以后的最小元素:一次遍历
数学·算法·leetcode·模拟