点+法向量 计算旋转平移矩阵

这个是我之前做的一个项目,现在总结一下

一、问题本质

已知:

一个点:P = (x, y, z)

一个法向量:n = (nx, ny, nz)

求:

cpp 复制代码
刚体变换矩阵 T(4×4):
[ R  t ]
[ 0  1 ]
一个 X YZ +法向量 如何转换成一个旋转平移矩阵

二、核心思想

约束:

  • z轴 = 法向量
  • x/y轴 = 在平面上的两个正交方向

这就是一个 SO(3) 构造问题

其中:

  • z = 法向
  • x = 任意垂直于 z 的方向
  • y = 保证右手系

本质:从一个方向 → 补全成一个正交坐标系

cpp 复制代码
ẑ = n / ||n||

三、PCL使用和Matlab

PCL

cpp 复制代码
#include <Eigen/Dense>

Eigen::Matrix4f poseFromPointNormal(
    const Eigen::Vector3f& point,
    const Eigen::Vector3f& normal)
{
    Eigen::Vector3f z = normal.normalized();

    // 选择辅助向量(避免共线)
    Eigen::Vector3f aux(0, 0, 1);
    if (fabs(z.dot(aux)) > 0.9)
        aux = Eigen::Vector3f(1, 0, 0);

    // 构造正交基
    Eigen::Vector3f x = aux.cross(z).normalized();
    Eigen::Vector3f y = z.cross(x);

    // 旋转矩阵
    Eigen::Matrix3f R;
    R.col(0) = x;
    R.col(1) = y;
    R.col(2) = z;

    // 变换矩阵
    Eigen::Matrix4f T = Eigen::Matrix4f::Identity();
    T.block<3,3>(0,0) = R;
    T.block<3,1>(0,3) = point;

    return T;
}

使用

cpp 复制代码
pcl::PointNormal pt;
Eigen::Vector3f P(pt.x, pt.y, pt.z);
Eigen::Vector3f n(pt.normal_x, pt.normal_y, pt.normal_z);

Eigen::Matrix4f T = poseFromPointNormal(P, n);

注意点1、法向量方向不稳定

n 和 -n 都是合法法向

会导致:

  • 姿态翻转
  • 抓取方向反了

解决:

cpp 复制代码
if (n.dot(view_direction) > 0)
n = -n;

注意点12、自由度缺失(核心理解)

一个法向量:

只确定2个自由度

还缺:

绕法向旋转

你现在的 x 轴:

是"人为选的"

注意点13、工业更稳定的写法 ⭐

如果你有参考方向(推荐):

比如:

重力方向 g = (0,0,1)

更优写法:

cpp 复制代码
Eigen::Vector3f z = normal.normalized();
Eigen::Vector3f x = g.cross(z).normalized();
Eigen::Vector3f y = z.cross(x);

好处:

姿态稳定(不会随机旋转)

Matlab

cpp 复制代码
clc; clear; close all;

% 原始点云(模拟一个斜平面)
[X,Y] = meshgrid(-1:0.2:1, -1:0.2:1);
Z = X + Y;   % 平面 z = x + y

pts = [X(:), Y(:), Z(:)];

% 给定点和法向
P = [1,2,3];
n = [1,1,1];
n = n / norm(n);

% 构造坐标系
z = n;

if abs(dot(z,[0 0 1])) < 0.9
    a = [0 0 1];
else
    a = [1 0 0];
end

x = cross(a, z);
x = x / norm(x);

y = cross(z, x);

R = [x(:), y(:), z(:)];

% 构造T
T = eye(4);
T(1:3,1:3) = R;
T(1:3,4) = P(:);

% 变换点云(展平)
pts_h = [pts, ones(size(pts,1),1)]';
pts_trans = inv(T) * pts_h;

pts_trans = pts_trans(1:3,:)';

% 可视化
figure;
subplot(1,2,1);
scatter3(pts(:,1), pts(:,2), pts(:,3), '.');
title('原始点云');
axis equal;

subplot(1,2,2);
scatter3(pts_trans(:,1), pts_trans(:,2), pts_trans(:,3), '.');
title('变换后(平面被拉平)');
axis equal;

使用

平面矫正

法向 → 构造坐标系 → 变换点云 → 展平


抓取姿态(机器人)

z轴 = 法向(接触方向)

x轴 = 抓取方向


点云对齐初始化

局部坐标系 → ICP 初值

四、案例:

cpp 复制代码
假设你有一个平面上的点:P = (1, 2, 3)

法向量:n = (0.577, 0.577, 0.577)   // ≈ (1,1,1) 归一化

目标:

构造一个坐标系:
z轴 = 法向
并把这个平面"摆正"(对齐到XY平面)

1、构建正交基

cpp 复制代码
1、 z轴
z = n = (0.577, 0.577, 0.577)
2、选辅助向量
a = (0, 0, 1)(不共线)

3、 x轴
叉乘:
x = a × z
= (0,0,1) × (0.577,0.577,0.577)
= (-0.577, 0.577, 0)
归一化:
x ≈ (-0.707, 0.707, 0)


4、 y轴
y = z × x
计算:
y ≈ (-0.408, -0.408, 0.816)



5、 旋转矩阵
R =
[ -0.707  -0.408   0.577
   0.707  -0.408   0.577
   0       0.816   0.577 ]

(列向量:x y z)

2、构造变换矩阵

cpp 复制代码
T =
[ R  P ]
[ 0  1 ]




T =
[ -0.707  -0.408   0.577   1
   0.707  -0.408   0.577   2
   0       0.816   0.577   3
   0       0       0       1 ]
相关推荐
我是大聪明.20 小时前
CUDA矩阵乘法优化:共享内存分块与Warp级执行机制深度解析
人工智能·深度学习·线性代数·机器学习·矩阵
做cv的小昊1 天前
【TJU】研究生应用统计学课程笔记(6)——第二章 参数估计(2.4 区间估计)
人工智能·笔记·线性代数·算法·机器学习·数学建模·概率论
EnCi Zheng1 天前
02a-什么是矩阵
线性代数·矩阵
AI科技星1 天前
《全域数学》第一部:数术本源·第二卷《算术原本》之十四附录(二)全域数学体系下三大数论猜想的本源推演与哲学阐释【乖乖数学】
人工智能·线性代数·机器学习·量子计算·agi
有为少年2 天前
从概率估计到“LLM 训练是有损压缩”
人工智能·线性代数·机器学习·计算机视觉·矩阵
风落无尘2 天前
第二章《概率与生存》完整学习资料
人工智能·矩阵·概率论
大江东去浪淘尽千古风流人物2 天前
【UV-SLAM】eLSD/LBD 数据维度 UV-SLAM吸收借鉴
数据库·线性代数·oracle·矩阵·uv·augmented reality
风落无尘2 天前
《智能重生:从垃圾堆到AI工程师》——第三章 矩阵与防线
人工智能·线性代数·矩阵
玛丽莲茼蒿2 天前
Leetcode hot100 螺旋矩阵【中等】
算法·leetcode·矩阵
个微管理3 天前
小红书新规深度拆解:从被封到破局,2026年矩阵号生存手册
大数据·人工智能·矩阵