【问题标题】:Detect paraboloid shaped sections of an array检测阵列的抛物面形部分
【发布时间】:2018-07-13 19:33:22
【问题描述】:

我正在尝试检测numpy.ndarray 内的抛物线形点。

我有一个数据集,使用维纳滤波器(使用包 NIFTy4)对其进行平滑处理:它保存为.csv,可以在here on Google Drivehere on PasteBin 中找到。

我正在寻找一种方法来识别我的数组中描述向上打开的抛物面的部分。

在提供的示例中,我想检测 5 个这样的形状。重点主要是形状的宽度(开始和结束),而不是实际的最小位置。

提前致谢

【问题讨论】:

  • 您是否已经有了此类曲线的生成器?如果是这样,您可以将其添加到问题中吗?对于那些试图回答的人来说,它可能会派上用场。
  • 我没有发电机。我从测量中提取它们并将它们平滑。但由于原始数据的形状相当混乱,而且只是一个嘈杂的版本,我刚刚附上了最终的数据向量。 (感谢您在手续方面的帮助,这很有帮助:))
  • 找到这种平滑图的局部最小值对您来说足够了吗?
  • @Phteven 计算线在每个点的斜率。您要寻找的点是斜率从负到正的位置。这会经常发生,但您可以比较每个实例的面积。或者寻找曲线下面积的波动。
  • @zch :这是我目前正在研究的一点,但还不够。比“平均位置”更重要的是抛物线的宽度

标签: python numpy pattern-matching


【解决方案1】:

使用numpy的解决方案

对于这个解决方案,我将使用numpy

import numpy as np

数据集

创建数据集

OP Phteven 非常友好地提供了可以使用的数据集,但由于与数据集的链接往往会消失,我还创建了一个函数来生成相似曲线。

def polyval_points(n):
    """Return random points generated from polyval."""
    x = np.linspace(-20, 20, num=n)
    coef = np.random.normal(-3, 3, size=(5))
    y = np.polyval(coef, x) * np.sin(x)
    return x, y

加载数据集

def dataset_points():
    """Return points loaded from dataset."""
    y = np.loadtxt("data.csv", delimiter=',')
    x = np.linspace(0, 1, num=len(y))
    return x, y

阐述要点

斜率卷积

由于点是离散的,我们必须表示斜率。一种这样的方法是通过统一内核。

def convolute_slopes(y, k=3):
    """Return slopes convoluted with an uniform kernel of size k."""
    d2y = np.gradient(np.gradient(y))
    return np.convolve(d2y, np.ones(k)/k, mode="same")

获得抛物面

现在我们可以计算卷积斜率,确定它切换方向的位置并选择平均斜率大于绝对平均乘以描述抛物面必须有多“倾斜”的系数的那些区间。

def get_paraboloids(x, y, c=0.2):
    """Return list of points (x,y) that are part of paraboloids in given set.
        x: np.ndarray of floats
        y: np.ndarray of floats
        c: slopyness coefficient
    """
    slopes = convolute_slopes(y)
    mean = np.mean(np.abs(slopes))
    w = np.where(np.diff(slopes > 0) > 0)[0] + 1
    w = np.insert(w, [0, len(w)], [0, len(x)])
    return [(x[lower:upper], y[lower:upper])
            for lower, upper in zip(w[:-1], w[1:])
            if np.mean(slopes[lower:upper]) > mean * c]

如何使用这个和可视化

首先我们加载数据集并生成更多数据:

datasets = [dataset_points(), polyval_points(10000), polyval_points(10000)]

然后,迭代每个数据集:

from matplotlib import pyplot as plt

plt.figure(figsize=(10 * len(datasets), 10))
for i, points in enumerate(datasets):
    x, y = points
    plt.subplot(1, len(datasets), i + 1)
    plt.plot(x, y, linewidth=1)
    for gx, gy in get_paraboloids(x, y):
        plt.plot(gx, gy, linewidth=3)
plt.show()

结果

【讨论】:

  • 只是:哇。我昨天加入并给了它 20% 左右的机会,12 小时后我有一些工作要做。谢谢你。我会尝试再调整一下,然后回复你
  • 更新:您可以使用二阶导数的最大值进一步改进结果
  • 用平滑卷积还是原始数据?
【解决方案2】:

据我所见,曲线平滑且无噪声,因此抛物线顶点恰好对应于局部最小值。

您没有指定如何定义开头和结尾,因此我将假设“直到拐点”。为了找到这些,您可以计算一阶差分来估计斜率,并检测两侧绝对斜率的第一个最大值。

不要期望在这些限制上有很好的准确性,这是一个不适定问题。

【讨论】:

  • 位置是通过局部最小值找到的
  • 宽度不是通过拐点而是通过找到它“下降”的点。我找不到更好的数学公式的原因是因为它是一个测量量而不是已知的函数关系
  • @Phteven:你怎么称呼“掉线”?使用有意义且明确的描述很重要,否则我们会浪费时间提出不相关的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-03
  • 2011-03-09
  • 1970-01-01
  • 2020-05-03
  • 1970-01-01
  • 2013-01-28
  • 1970-01-01
相关资源
最近更新 更多