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() 拆向量 高效

相关推荐
米小虾3 小时前
Loop Engineering —— 循环的设计与自主执行
人工智能·agent
米小虾3 小时前
Harness Engineering —— 系统的安全护栏
人工智能·agent
火山引擎开发者社区3 小时前
积分当钱花,火山引擎开发者激励计划首月消费双倍回馈
人工智能
aqi004 小时前
15天学会AI应用开发(十)把文本嵌入模型换成国产模型
人工智能·python·ai编程
MobotStone4 小时前
为什么在AI时代,“好奇心”成了最值钱的能力?
人工智能
武子康5 小时前
调查研究-200 llama.cpp b9754:一次很小但很关键的 Agent 工具调用修复
人工智能·agent·llama
Ralph_Salar5 小时前
从0到1搭建AI智能支付风控助手Stage1-RAG知识库升级 — 元数据让检索更精准
人工智能
武子康5 小时前
调查研究-199 MCP Zero-Touch OAuth:为什么它是 MCP 进入企业生产的关键门槛?
人工智能·agent·mcp