我正在尝试检测numpy.ndarray
中的抛物线形点。
我有一个数据集,使用维纳过滤器(使用软件包NIFTy4)对其进行了平滑处理:将其另存为.csv
,可以在here on Google Drive或here on PasteBin中找到。
我正在寻找一种识别阵列中描述向上打开的抛物面的部分的方法。
在提供的样本中,我想检测5种这样的形状。重点主要放在形状的宽度(起点和终点),而不是实际的最小位置。
预先感谢
答案 0 :(得分:3)
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()
答案 1 :(得分:0)
据我所知,曲线平滑且无噪音,因此抛物线的顶点仅与局部最小值相对应。
您没有指定开始和结束的定义方式,因此我假设“直到拐点”。要找到这些位置,您可以计算一阶差异来估计斜率,并检测两侧绝对斜率的第一最大值。
不要期望在这些限制下具有良好的准确性,这是一个不适当地的问题。