You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Numpy SVD对完全共面的三维点集返回非标准法向量?

用NumPy SVD拟合平面的异常问题分析

测试背景

尝试用np.linalg.svd()拟合R³中完全处于Z=100平面的点集,预期结果:

  • 第三个奇异值在机器精度范围内为0;
  • vh的第三列近似为[0, 0, 1](机器精度范围内)。

点集1测试

点集部分点的前两维度数值远大于第三维度:

import numpy as np
pts = [[2345,-124, 100], [981, -123, 100], [4987,12345, 100], [-1324, 0, 100]]
svd = np.linalg.svd(pts)

结果大致符合预期:

  • svd[1]为array([13349.56221861, 2705.21722461, 158.26983058]),第三奇异值虽未接近0,但svd[2]第三列前两维接近0,可作为平面法向量满足拟合需求。

点集2测试

点集所有点的前两维度数值均小于第三维度:

import numpy as np
pts = [[57, 37, 100], [34, 37, 100], [11, -37, 100], [-11, 38, 100]]
svd = np.linalg.svd(pts)

结果异常:

  • svd[1]为array([209.35774076, 64.78329726, 46.58820429]),第三奇异值未接近0;
  • svd[2]的第三列与[0, 0, 1]偏差极大,更接近[1, 0, 0]。

原因分析

问题核心是未对原始点集做中心化处理,这是SVD拟合平面的关键前提:

  1. 拟合平面的本质是寻找包含点集的最小方差平面,需要先消除点集的整体平移分量——即计算点集均值,用每个点减去均值得到中心化后的点矩阵centered_pts = pts - np.mean(pts, axis=0)。
  2. 原始点集所有点Z值均为100,均值的Z分量也是100,此时原始点矩阵的列向量包含指向[0,0,100]方向的强分量。当XY方向的点分布范围远小于Z值(如点集2),SVD会优先捕捉这个整体偏移方向作为主分量,平面法向量对应的分量被掩盖,导致结果偏离预期。
  3. 点集1中XY方向数值远大于Z值,整体偏移分量相对较弱,SVD仍能捕捉到平面法向量对应的分量,结果接近预期。

修正后的验证

对两组点集做中心化后再执行SVD:

import numpy as np

# 点集1中心化处理
pts1 = np.array([[2345,-124, 100], [981, -123, 100], [4987,12345, 100], [-1324, 0, 100]])
centered_pts1 = pts1 - np.mean(pts1, axis=0)
svd1 = np.linalg.svd(centered_pts1)
print("点集1中心化后的奇异值:", svd1[1])
print("点集1中心化后的vh第三列:", svd1[2][2])

# 点集2中心化处理
pts2 = np.array([[57, 37, 100], [34, 37, 100], [11, -37, 100], [-11, 38, 100]])
centered_pts2 = pts2 - np.mean(pts2, axis=0)
svd2 = np.linalg.svd(centered_pts2)
print("点集2中心化后的奇异值:", svd2[1])
print("点集2中心化后的vh第三列:", svd2[2][2])

执行结果会符合预期:

  • 第三奇异值趋近于机器精度下的0;
  • vh的第三列近似为[0, 0, 1](或其负方向,SVD的符号不影响法向量有效性)。

内容的提问来源于stack exchange,提问作者sjohns

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 22:03:38