【问题标题】:How to estimate piece-wise smooth fit to a noisy mask?如何估计分段平滑拟合到嘈杂的面具?
【发布时间】:2019-05-31 12:10:06
【问题描述】:

我有一个源自分段平滑曲线的二进制掩码。每个底层曲线段都是平滑的,但段之间的连接可能是平滑的,也可能不是平滑的。 蒙版嘈杂,因此它可能包含基础曲线周围的几个像素。下图显示了此类输入的示例:

在没有任何其他先验知识的情况下,我想估计对基础曲线的拟合,这将能够提供平滑和非平滑连接。

我在 python 中工作,所以我尝试了几种可用的方法,例如 numpy 的多项式拟合、scipy 的样条平滑和 pyqt-fit 的非参数回归,但无法获得所需的输出。这是一个代码示例:

    from imageio import imread
    import random
    import numpy as np
    from scipy.interpolate import UnivariateSpline
    import pyqt_fit.nonparam_regression as smooth
    from pyqt_fit import npr_methods
    from matplotlib import pyplot as plt

    mask = imread(r'C:\mask.bmp')
    ys, xs = np.where(mask)
    # add tiny noise and sort - silly way to comply to UnivariateSpline's requirement of "x must be strictly increasing"
    xs = np.array([x + random.random() * 1e-4 for x in xs])
    sorter = np.argsort(xs)
    xs = xs[sorter]
    ys = ys[sorter]
    # polynomial fit
    p = np.poly1d(np.polyfit(xs, ys, 5))
    # spline smoothing
    spl = UnivariateSpline(xs, ys, k=3, s=1e9)
    # non-parameteric regression
    k = smooth.NonParamRegression(xs, ys, method=npr_methods.LocalPolynomialKernel(q=3))
    k.fit()

    plt.figure()
    plt.imshow(mask, cmap='gray')
    linexs = np.array(range(mask.shape[1]))
    plt.plot(linexs, k(linexs), 'y', lw=1)
    plt.plot(linexs, spl(linexs), 'g', lw=1)
    plt.plot(linexs, p(linexs), 'b', lw=1)
    plt.show()

对于本例中显示的参数,这些拟合既无法捕获左侧的非平滑连接,也无法为右侧的“尾部”提供良好的拟合:
预期的结果应该像下图中的红色曲线一样,我希望位置 1 的曲线不平滑,而位置 2 的曲线是平滑的。

我很乐意获得对合适算法的参考。如果还有一个 python 实现,那将是一个加号。

【问题讨论】:

  • 由于您要求的是算法,它似乎更像是更适合Computer Science 社区的稍微理论的计算机科学问题。
  • 任何形式为 "y = f(x)" 的解对于 x 的任何单个值都会产生一个 y 值,因此右侧的“尾巴” - 看起来同一个 x 需要两个不同的 y 值 - 不能是这种形式。
  • @sophros 谢谢,也将在此处发布。
  • @JamesPhillips 对,我正在寻找另一种解决方案。

标签: python regression curve-fitting spline data-fitting


【解决方案1】:

这可能接近您想要的。诀窍是首先骨架化蒙版(请参阅https://scikit-image.org/docs/dev/auto_examples/edges/plot_skeleton.html)以提取要估计的曲线所沿的点。

from skimage.morphology import skeletonize
import matplotlib.pyplot as plt
import cv2
import numpy as np
from scipy.interpolate import interp1d

img = cv2.imread("./data/bAiew.png", 0)
img = cv2.medianBlur(img, 11)
img = img//255

# Sparse skeleton
skeleton = skeletonize(img, method='lee')

# Into dense
contours, _ = cv2.findContours(skeleton, 0,cv2.CHAIN_APPROX_NONE)
arch = contours[0]
x,y = arch[...,0].squeeze(), arch[...,1].squeeze()

# Fitting a curve
xx, yy = x[0::15], y[0::15] #<- sample every 15th element to see that the interpolate really works
f = interp1d(xx, yy)

plt.figure(figsize=(16,9))
plt.subplot(221)
plt.imshow(img)
plt.title('original mask')

plt.subplot(222)
plt.imshow(skeleton)
plt.title('skeleton')

plt.subplot(223)
plt.scatter(xx,yy)
plt.ylim([img.shape[0],0])
plt.xlim([0, img.shape[1]])
plt.title('sampled points')

plt.subplot(224)
plt.plot(xx,f(xx))
plt.ylim([img.shape[0],0])
plt.xlim([0, img.shape[1]])
plt.title('interpolate')
plt.show()

输出:

【讨论】:

    猜你喜欢
    • 2019-11-04
    • 2019-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-06
    • 2021-06-29
    • 2019-05-21
    相关资源
    最近更新 更多