python - 如何估计分段平滑拟合到嘈杂的面具?
问题描述
我有一个源自分段平滑曲线的二进制掩码。每个底层曲线段都是平滑的,但段之间的连接可能是平滑的,也可能不是平滑的。蒙版嘈杂,因此它可能包含基础曲线周围的几个像素。下图显示了此类输入的示例:
我想估计对基础曲线的拟合,给定此输入而无需任何其他先验知识,它将能够提供平滑和非平滑连接。
我在 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 实现,那将是一个加号。
解决方案
这可能接近你想要的。诀窍是首先将掩码骨架化(请参阅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()
推荐阅读
- java - “未解决的参考:http”Kotlin。为什么会这样?
- spring - Kotlin + Spring Boot - 将 TTL 添加到您的地图
- javascript - Webpack:动态依赖加载
- c# - XML 使用 SelectNodes 来获取具有空值子节点的节点
- sql - SQL 根据不同列中的值选择行
- sql - 根据其他列的最大值选择值
- python - 在同一进程中使用 Gstreamer 和 multiprocessing.Manager().Namespace() 时发生内存泄漏
- artifactory - Artifactory OSS:元数据服务日志项目更新错误
- spring - JPA:如何读取实体的特定字段?
- react-hook-form - 反应钩子形式:as vs render:无法理解语法以及它们有何相同之处