python实现插值填充有序均匀点云空洞(1/2)

重建精度

在我们将多图像三维重建为模型时,会产生一张xoy平面的网格

如图,这样的网格就是有序点云模型的基础。有序点云为了还原实际物体的表面形态,将其重建为了一种“点阵”的形式。我们向z轴的负方向看去,如图:

可以看到有序点云就像下棋一样,是呈一行一行,或是一列一列这样排列的。这表明,模型即使是有的地方有点,有的地方没有点,有序点云的每个点依然可以垂直投影到xoy平面精度网格的交点上。

这里的表面有序点云的重建方式其实可以联想到一个surface函数。

[X,Y] = meshgrid(1:0.5:10,1:20);
Z = sin(X) + cos(Y);
surf(X,Y,Z)

其与MATLAB中函数surface()的绘制方法类似,这种三维函数不过是将平面的精度网格直接绘制在了曲面函数上。我们在对三维函数限制一定的网格采样精度后也是可以直接转化为三维点云模型的。

可惜很多实际复杂物体并非能够使用简单的三维函数表示。

有序点云与无序点云

有有序点云自然也存在无序点云,这两类都有典型代表:

有序点云主要是的是现实实物扫描或者图像重建出来的现实表面点云,为了表现物体的表面特征其通常为均匀的一层。无序点云主要是某些数据的特征点集合,这些点云“有聚有散”,多数区域之间的密度差别较大。

拉伸与空洞

在实际的三维重建中,很可能在图像拍摄时由于光照变化:如玻璃平面,水面的反射,和摄像头的像控点不稳定造成图片位置出错。这些情景的图像特征点变少,给空间三维计算照成了困难,最终在三维模型上出现模型的拉伸与空洞。

现有一块有序点云如图所示:

图中红点表示此处平面坐标存在一枚点云,其数字表示此点云z轴的高度。这块点云中间有一个大洞,如何能够通过一种方法能够将表面点云中间的缺失点云补全,使得填充的点云能够和空洞周围的点云平滑的连接在一起。

此点云数据的格式应该如下:

point_data = [[1, 1, 2],[1, 2, 1],[1, 3, 2],[1, 4, 3],[1, 5, 2],[1, 6, 1],[1, 7, 2],[1, 8, 3],[1, 9, 5],[1, 10, 7],
              [2, 1, 1],[2, 2, 1],[2, 3, 2],[2, 4, 4],[2, 5, 3],[2, 6, 3],[2, 7, 4],[2, 8, 2],[2, 9, 4],[2, 10, 6],
              [3, 1, 1],[3, 2, 2],[3, 3, 3],[3, 4, 3],[3, 8, 1],[3, 9, 2],[3, 10, 5],
              [4, 1, 2],[4, 2, 3],[4, 3, 2],[4, 9, 6],[4, 10, 4],
              [5, 1, 4],[5, 2, 5],[5, 9, 2],[5, 10, 4],
              [6, 1, 6],[6, 2, 7],[6, 9, 4],[6, 10, 5],
              [7, 1, 5],[7, 2, 6],[7, 9, 3],[7, 10, 7],
              [8, 1, 5],[8, 2, 7],[8, 3, 5],[8, 9, 5],[8, 10, 7],
              [9, 1, 3],[9, 2, 4],[9, 3, 6],[9, 4, 7],[9, 5, 8],[9, 6, 6],[9, 7, 8],[9, 8, 7],[9, 9, 6],[9, 10, 8],
              [10, 1, 5],[10, 2, 5],[10, 3, 7],[10, 4, 6],[10, 5, 4],[10, 6, 5],[10, 7, 6],[10, 8, 8],[10, 9, 7],[10, 10, 9]]

空洞判断

由图中的空洞可知,空洞的特征为两侧有点, 而中间行或者列存在空洞。

如图,在某行或者某一列中,存在两端不为空但是中间为空(存在红色箭头)时,认定其为需要填充的行或者列。

插值法

插值在离散数据的基础上补插连续函数,使得这条连续曲线通过全部给定的离散数据点。可以看出,插值本质可能是一种曲线拟合,然后根据曲线来预测确定某个坐标处可能的值。在某些像素精度不太高的图片中,插值也可以用来提升图像的清晰度。

本例中,由于空洞并非离散点稀疏。直接应用均值进行填充,整行或者整列的填充均值数据仅与缺失两端点的数值有关。

逻辑流

1. 导入存在空洞的有序点云

2. 空洞按行或者检测并插值

3. 完成插值空洞填充

完整代码

import numpy as np
import matplotlib.pyplot as plt

def boundary(point_data_line):
    boundary_points = []
    for i in range(len(point_data_line)):
        num_row_pre = 1
        for i_row in range(len(point_data_line[i])):
            num_row = point_data_line[i][i_row][1]
            if num_row != num_row_pre:
                boundary_points_first = point_data_line[i][i_row - 1]
                boundary_points_last= point_data_line[i][i_row]
                boundary_points.append([boundary_points_first,boundary_points_last])
                break
            num_row_pre += 1
    return boundary_points

def fillp(boundary_points):
    copy_point_data = []
    for i in point_data:
        copy_point_data.append(i)
    for i in range(len(boundary_points)):
        numpoints = boundary_points[i][1][1] - boundary_points[i][0][1] + 1
        fill_points = np.linspace(boundary_points[i][0], boundary_points[i][1], numpoints)
        for p in fill_points:
            copy_point_data.append(list(p))
    point_data_fill = copy_point_data
    return point_data_fill

def view(point_data,point_data_fill):
    fig1 = plt.figure()
    ax1 = fig1.add_subplot(111, projection='3d')
    ax1.set_xlabel("x")
    ax1.set_ylabel("y")
    ax1.set_zlabel("z")
    for i in range(len(point_data_fill)):
        xf = point_data_fill[i][0]
        yf = point_data_fill[i][1]
        zf = point_data_fill[i][2]
        ax1.scatter(xf, yf, zf, color='b', marker='.')
    for i in range(len(point_data)):
        x = point_data[i][0]
        y = point_data[i][1]
        z = point_data[i][2]
        ax1.scatter(x, y, z, color='gray', marker='o')
    plt.show()
    return None

if __name__ == '__main__':
    point_data = [[1, 1, 2], [1, 2, 1], [1, 3, 2], [1, 4, 3], [1, 5, 2], [1, 6, 1], [1, 7, 2], [1, 8, 3], [1, 9, 5], [1, 10, 7],
        [2, 1, 1], [2, 2, 1], [2, 3, 2], [2, 4, 4], [2, 5, 3], [2, 6, 3], [2, 7, 4], [2, 8, 2], [2, 9, 4], [2, 10, 6],
        [3, 1, 1], [3, 2, 2], [3, 3, 3], [3, 4, 3], [3, 8, 1], [3, 9, 2], [3, 10, 5],
        [4, 1, 2], [4, 2, 3], [4, 3, 2], [4, 9, 6], [4, 10, 4],
        [5, 1, 4], [5, 2, 5], [5, 9, 2], [5, 10, 4],
        [6, 1, 6], [6, 2, 7], [6, 9, 4], [6, 10, 5],
        [7, 1, 5], [7, 2, 6], [7, 9, 3], [7, 10, 7],
        [8, 1, 5], [8, 2, 7], [8, 3, 5], [8, 9, 5], [8, 10, 7],
        [9, 1, 3], [9, 2, 4], [9, 3, 6], [9, 4, 7], [9, 5, 8], [9, 6, 6], [9, 7, 8], [9, 8, 7], [9, 9, 6], [9, 10, 8],
        [10, 1, 5], [10, 2, 5], [10, 3, 7], [10, 4, 6], [10, 5, 4], [10, 6, 5], [10, 7, 6], [10, 8, 8], [10, 9, 7],[10, 10, 9]]
    point_data_line = [[[1, 1, 2],[1, 2, 1],[1, 3, 2],[1, 4, 3],[1, 5, 2],[1, 6, 1],[1, 7, 2],[1, 8, 3],[1, 9, 5],[1, 10, 7]],
              [[2, 1, 1],[2, 2, 1],[2, 3, 2],[2, 4, 4],[2, 5, 3],[2, 6, 3],[2, 7, 4],[2, 8, 2],[2, 9, 4],[2, 10, 6]],
              [[3, 1, 1],[3, 2, 2],[3, 3, 3],[3, 4, 3],[3, 8, 1],[3, 9, 2],[3, 10, 5]],
              [[4, 1, 2],[4, 2, 3],[4, 3, 2],[4, 9, 6],[4, 10, 4]],
              [[5, 1, 4],[5, 2, 5],[5, 9, 2],[5, 10, 4]],
              [[6, 1, 6],[6, 2, 7],[6, 9, 4],[6, 10, 5]],
              [[7, 1, 5],[7, 2, 6],[7, 9, 3],[7, 10, 7]],
              [[8, 1, 5],[8, 2, 7],[8, 3, 5],[8, 9, 5],[8, 10, 7]],
              [[9, 1, 3],[9, 2, 4],[9, 3, 6],[9, 4, 7],[9, 5, 8],[9, 6, 6],[9, 7, 8],[9, 8, 7],[9, 9, 6],[9, 10, 8]],
              [[10, 1, 5],[10, 2, 5],[10, 3, 7],[10, 4, 6],[10, 5, 4],[10, 6, 5],[10, 7, 6],[10, 8, 8],[10, 9, 7],[10, 10, 9]]]
    boundary_points = boundary(point_data_line)
    point_data_fill = fillp( boundary_points)
    view(point_data,point_data_fill)

基于横向x轴的均值插值空洞填充如图所示蓝色的点为填补点,灰色的点为原始的点云。

注意:本文仅仅对于此类特定特征点云空洞填补的思路做一个提供,想要套用此思路在其他形式点云的空洞填补上还需要对适应性做出对应的优化。

  • 5
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
拉格朗日插值是一种常用的数据填充方法,可以通过已知数据点来估计缺失值。下面给出一个使用 Python 实现拉格朗日插值填充空值的示例代码: ```python import numpy as np def lagrange_interpolation(x, y, x_pred): """ 使用拉格朗日插值法计算 x_pred 对应的 y_pred :param x: 已知点的横坐标列表 :param y: 已知点的纵坐标列表 :param x_pred: 需要预测的点的横坐标 :return: 预测点的纵坐标 """ n = len(x) y_pred = 0 for i in range(n): p = 1 for j in range(n): if j != i: p *= (x_pred - x[j]) / (x[i] - x[j]) y_pred += p * y[i] return y_pred def fill_missing_values_lagrange_interpolation(data): """ 使用拉格朗日插值填充 data 中的空值 :param data: 带有空值的数据,格式为 numpy 数组 :return: 填充空值后的数据 """ n, m = data.shape for j in range(m): mask = np.isnan(data[:, j]) if np.all(mask): # 如果该列全部为 NaN,则不填充 continue x = np.arange(n)[~mask] y = data[:, j][~mask] for i in range(n): if np.isnan(data[i, j]): # 如果该点是 NaN,则进行插值 data[i, j] = lagrange_interpolation(x, y, i) return data ``` 使用示例: ```python import numpy as np data = np.array([[1, 2, 3], [4, np.nan, 6], [7, 8, np.nan]]) print(fill_missing_values_lagrange_interpolation(data)) ``` 输出结果: ``` [[1. 2. 3. ] [4. 5. 6. ] [7. 8. 7.33333333]] ``` 注意,拉格朗日插值法虽然简单易用,但是可能会产生过拟合的问题。在实际使用中,需要根据具体情况选择合适的插值方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三尺流流

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值