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

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

一、问题本质

已知:

一个点: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 ]
相关推荐
莱茶荼菜3 天前
【slam公式】
人工智能·线性代数·机器学习
吴名氏.3 天前
Java转AI Agent教程(第九周)错误矩阵
java·人工智能·矩阵·ai agent
伯奥克客服4 天前
2026年视频矩阵厂家技术评估:从EDID到控制协议开放度的六维筛选法
线性代数·矩阵·音视频
释厄6235 天前
三角基底律——矩阵3x6 是所有三角形的基底·3D中高就是边
线性代数·3d·矩阵
桑年6 天前
四、Pandas数据处理
人工智能·python·线性代数·pandas·数据可视化·数据处理
Kobebryant-Manba7 天前
IEKT向量矩阵流程&评估
人工智能·算法·矩阵
学习论之费曼学习法9 天前
无人值守AI内容矩阵实战(10):Windows 上让 Python 进程 7×24 活着
人工智能·windows·python·矩阵·powershell·进程守护
zhongben_keji9 天前
家政小程序开发全解:经营模式、品类矩阵、派单约束与信用核验
线性代数·矩阵·apache
silvamux_9 天前
微头条爆款体平台适配实测:把交付要求变成可计算的指标
java·线性代数·算法·决策树·矩阵
zyseo89 天前
谷歌SEO 关键词研究完整方法论:从种子词到优先级矩阵
数据库·人工智能·矩阵