在公差范围内对间隔较近的点进行平均处理¶
让我们来看看如何减少图形上的点数,只留下那些与其他点之间存在某种标准差异的点。
初始数据¶
让我们使用文件peaks.jl
中的函数,它将创建一个在区间 [-3,3]、[-3,3] 内有几个突起的光滑表面。让我们沿 Z 轴为数据添加一些噪声。现在,点云不再位于一个曲面上,而是分散在曲面周围。
In [ ]:
Pkg.add(["Statistics", "GroupSlices"])
In [ ]:
gr( format=:png ) # Обратите внимание, теперь все графики, в рамках
# текущей рабочей сессии, будут выводиться в PNG
include( "$(@__DIR__)/peaks.jl" );
xy = rand(10000, 2) .* 6 .- 3;
z = peaks.( xy[:,1], xy[:,2] ) .+ 0.5 .- rand(10000,1);
A = [xy z]
scatter( A[:,1], A[:,2], A[:,3], camera=(45, 20), ms=2, markerstrokewidth=0.1, leg=false )
Out[0]:
恢复光滑表面¶
在这个点云中,我们将根据以下特征寻找可以组合的点:
- 点之间的距离不超过
tol
、 - 我们对 Z 轴不感兴趣,只比较 X 轴和 Y 轴。
In [ ]:
tol = 0.33;
为了突出相同区域,我们对原始数据集进行粗略处理,将每个点的所有坐标四舍五入为整数,然后乘以1/tol
。
In [ ]:
aA = round.( (1/tol) .* A[:,1:2], digits=0);
现在,我们的矩阵由大量具有相同值的向量组组成。如何对它们进行分组呢?我们可以将这些向量逐个元素进行比较,但还有一种更简便的方法。
可以使用GroupSlices
库中的函数groupslices
来执行这一操作(如有必要,请取消注释并执行下一个单元格):
In [ ]:
#]add GroupSlices
In [ ]:
using GroupSlices
C = groupslices( aA, dims=1 );
对于矩阵的每一行 r ,函数groupslices
将返回与 r 相同的第 * 行的索引。
让我们求每个子群中点的平均值。
In [ ]:
using Statistics
avgA = [ mean( A[C .== c, :], dims=1) for c in unique( C ) ]
avgA = vcat( avgA... ); # Мы получили матрицу из матриц; осуществим вертикальную конкатенацию строчек
现在我们可以绘制平均后的点,注意虽然数据集没有变得结构化,但我们消除了沿 Z 轴的变化,保留了原始数据的总体外观。
In [ ]:
scatter( A[:,1], A[:,2], A[:,3], camera=(45, 20), ms=2, markerstrokewidth=0.1, leg=false )
scatter!( avgA[:,1], avgA[:,2], avgA[:,3], color=:red, ms=3, legend=false )
Out[0]:
单个区域可以通过如下着色方法看出:
In [ ]:
scatter( A[:,1], A[:,2], A[:,3], camera=(45, 20), ms=2, markerstrokewidth=0.1, leg=false, zcolor=C./maximum(C), c=:prism )
scatter!( avgA[:,1], avgA[:,2], avgA[:,3], color=:white, ms=3, legend=false, camera=(0,90) )
Out[0]:
结论¶
我们通过选择一些独特的点来过滤噪声函数。在选择这些点时,我们依赖于 X 轴和 Y 轴上参考点之间可接受的接近程度。