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

 在上一节我们讨论了运用均值插值来对有空洞缺失的点云进行填充,

可以看到,对应缺失坐标的点云都补充出来了。但是后来就有人对这个逻辑的完整性提出了质疑,见下图:

图中通过单轴的插值获得的填充数据虽然在x轴方向上确实接上了,但是在y轴方向上却可以说是毫不相干,一点也不光滑。如何设计一种填充方案,使得两个方向的连接都比较平滑呢?

在这一节,我们将对处理逻辑进行一定的调整,使得填充的点云数据不管在哪个方向看过去都是相对平滑的连接。同时,也将类似下图这种“矩阵型”的列表数据构造方法在代码中用函数的方式表示出来。

“矩阵型”结构构造

我们将一个列表中嵌套多行或者多列的点云数据,用这个新的列表来表示“矩阵型”的方阵点云。在上一节的讨论中,出现了以下新型的按行排列的点云数据形式:

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]]]

由于我们的点云列表数据有的行数据存在缺失,所以其并非真正意义上的矩阵。只能自己手写构造,其方法如下:

1.找到行或者列坐标相同的点。

2.这些点添加进新的空列表。

3.此列表所有点按照另一坐标轴从小到大排列。

4.按这个步骤依次从1到10构造新的行或者列并添加进整体的“矩阵型”。

均值平滑

如图:

在靠近边缘点,可能由于每行每列边界点z轴之间的差值大小变化而产生较大的偏差。由于不是直接拟合曲面函数,这种误差不好避免。为尽量减少这种“锯齿状”的误差,我们可以同时结合x轴方向与y轴方向的插值来实现。

这里我们直接将两个方向的插值数据按照xoy平面坐标做一个z轴的均值计算,以达到尽量平滑连接空洞边缘的效果。

逻辑流

1. 导入原始点云

2. 分别构造x,y方向的新“矩阵型”结构

3. 分别搜索x,y方向的点云空洞

4. 分别插值填充x,y方向的点云空洞

5. 按照坐标对两种方向的插值求均值,平滑填充点云

完整代码

import numpy as np
import matplotlib.pyplot as plt


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]]

# 构造行
def point_data_row(point_data):
    point_row = []
    for i_row in range(10):
        row = []
        for i_column in range(10):
            for i in range(len(point_data)):
                if point_data[i][0] == i_row + 1 and point_data[i][1] == i_column + 1:
                    row.append(point_data[i])
        point_row.append(row)
    return point_row

# 构造列
def point_data_column(point_data):
    point_column = []
    for i_column in range(10):
        column = []
        for i_row in range(10):
            for i in range(len(point_data)):
                if point_data[i][1] == i_column + 1 and point_data[i][0] == i_row + 1:
                    column.append(point_data[i])
        point_column.append(column)
    return point_column


# 行填充
def boundary_row(point_data_line):
    boundary_points_row = []
    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_row.append([boundary_points_first, boundary_points_last])
                break
            num_row_pre += 1
    return boundary_points_row


def fillp_row(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_row = copy_point_data
    return point_data_fill_row

# 列填充
def boundary_column(point_data_line):
    boundary_points_column = []
    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][0]
            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_column.append([boundary_points_first, boundary_points_last])
                break
            num_row_pre += 1
    return boundary_points_column


def fillp_column(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][0] - boundary_points[i][0][0] + 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_column = copy_point_data
    return point_data_fill_column

def mean_fill(point_data_fill_row,point_data_fill_column):
    point_data_fill = []
    for i in range(len(point_data_fill_row)):
        for j in range(len(point_data_fill_column)):
            if point_data_fill_row[i][0] == point_data_fill_column[j][0] and point_data_fill_row[i][1] == point_data_fill_column[j][1]:
                point_data_fill.append([point_data_fill_row[i][0],point_data_fill_row[i][1],(point_data_fill_row[i][2]+point_data_fill_column[j][2])/2])

    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_row = point_data_row(point_data)
    point_data_column = point_data_column(point_data)
    # x,y方向分别插值
    boundary_points_row = boundary_row(point_data_row)
    point_data_fill_row = fillp_row(boundary_points_row)
    boundary_points_column = boundary_column(point_data_column)
    point_data_fill_column = fillp_column(boundary_points_column)
    # 差值均值与绘图
    point_data_fill = mean_fill(point_data_fill_row, point_data_fill_column)
    view(point_data, point_data_fill)

结论:通过双向插值最后均值处理后,可以由图中看到,不仅点云的空洞区域被填充完整,而且不管是x方向还是y方向的边界连接都更加平滑,此补充的方法相对于前一节所提供的思路具有更加完善的填充效果。

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

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

三尺流流

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

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

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

打赏作者

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

抵扣说明:

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

余额充值