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

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

一、问题本质

已知:

一个点: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 ]
相关推荐
棒球1号位19 小时前
全球赋能:中国棒球联盟矩阵的国际化人才培养路径·棒球1号位
线性代数·矩阵
梅梅绵绵冰1 天前
算法题-矩阵
数据结构·算法·矩阵
郝学胜-神的一滴2 天前
中级OpenGL教程 022:探秘三维世界的血脉传承——物体父子关系与矩阵递归奥义
c++·线性代数·unity·矩阵·游戏引擎·unreal engine·opengl
luoganttcc3 天前
指数分布的完整推导
线性代数·机器学习·概率论
爱刷碗的苏泓舒4 天前
平方根信息滤波:矩阵推导及 GNSS 参数估计应用
线性代数·算法·矩阵·gnss·参数估计·测量平差·平方根信息滤波
智灵鸟科技4 天前
封闭网络怎么安全地接外部能力:三条通道穷举、威胁封堵矩阵与残余风险
网络·安全·矩阵
zandy10114 天前
企业级BI平台选型指南:评估框架与核心能力矩阵
大数据·人工智能·矩阵
AI科技星4 天前
光速螺旋时空曲率挠率拓扑统一场论——四大力全域闭环求导、精算验证与第一性原理完备证明
线性代数·算法·决策树·机器学习·常温超导·ai科技星
棒球1号位4 天前
中国棒球联盟矩阵建设白皮书:解码本土化创新与国际接轨路径·棒球1号位
大数据·人工智能·矩阵
一个小猴子`4 天前
Triton实现矩阵乘法
矩阵·cuda·triton