【问题标题】:How can I extract this obvious event from this image?如何从这张图片中提取这个明显的事件?
【发布时间】:2015-05-28 17:59:51
【问题描述】:

编辑:我找到了解决方案:D 感谢您的帮助。

我创建了一个图像处理算法,可以从数据中提取该图像。它很复杂,所以我不会详细介绍,但这张图片本质上是一个巨大的 numpy 数组(它可视化对象像素强度的角度依赖性)。

我想编写一个程序来自动确定曲线何时切换方向。我有数据,也有这张图片,但事实证明,用任何一种方法做一些有意义的事情都很棘手。阈值化失败,因为有不同背景颜色的波段。出于同样的原因,Sobel 算子和 Hough 变换也不能很好地工作。

人类很容易看到这种切换何时发生,但告诉计算机却并不容易。有小费吗?谢谢!

编辑:谢谢大家,我现在正在用一般高斯卷积和结果的骨架化后拟合该图像的线条。任何有关这样做的指针将不胜感激:)

【问题讨论】:

  • 您可以使用edge detection algorithm,它由图像与内核的卷积组成。这将类似于局部阈值,避免不同背景的问题。当您拥有边缘时,您可以将点分组到相应的线,并使用样条插值方案找到线的导数。这会给你转折点,因此当曲线切换方向时。
  • 大多数边缘检测算法都依赖于一种阈值处理,使该图像无用。问题是我正在检测曲线,而不仅仅是线条。你怎么看?
  • 据我了解,您遇到的问题是,由于曲线周围的背景强度不同,全局阈值不合适。然而,当执行局部阈值化时,仅比较一个点的最近邻域,从而避免了上述问题。从边缘检测方案中,您将获得与原始图像相同大小的矩阵,该矩阵由检测到边缘的索引处的布尔值组成。从这些点,您可以检索您的线条/曲线。
  • 线条总是大致垂直吗?
  • 你能把图像数组上传到某个地方吗?

标签: python image-processing numpy statistics signal-processing


【解决方案1】:

您可以采用连续列的加权点积来获得更易于处理的一维信号。您或许可以使用此信号提取模式:

import numpy as np
A = np.loadtxt("img.txt")
N = A.shape[0]
L = np.logspace(1,2,N)
X = []
for c0,c1 in zip(A.T, A.T[1:]):
    x = c0.dot(c1*L) / (np.linalg.norm(c0)*np.linalg.norm(c1))
    X.append(x)

X = np.array(X)

import pylab as plt

plt.matshow(A,alpha=.5)
plt.plot(X*3-X.mean(),'k',lw=2)
plt.axis('tight')
plt.show()

这绝对不是对问题的完整答案,而是一个有用的观察,因为太长而无法发表评论。如果有更好的答案,我会删除。

【讨论】:

  • 嗨,我已经考虑了一段时间。你能向我解释一下点积是如何加权的吗?我很高兴我终于有了一个 1D 信号,但我没有在交换机上的任何数据集上看到模式。当然,切换时间隙最大,但这是随机的,因为垂直线可能会变得凹入。
  • @awallllllll “...但这是随机的,因为垂直线可能会变成凹形。”,我同意,这就是为什么它还不是一个有效的答案(也许只是一个线索) .这背后的想法是,当我们移动时,这些列包含空间信息(信号的中心)。加权点积提供了一些方向信息,基本上不会对所有点进行相同的处理。我选择了对数权重,因为我发现它是一条更平滑的曲线,尽管 linspace 也可以。
【解决方案2】:

为了检测尖端位置或转折点,您可以尝试在原始图像(不是骨架化图像)上使用角检测器。作为角点检测器,结构张量可以适用。结构张量对于计算图像中的局部方向也很有用。

【讨论】:

    【解决方案3】:

    在 Mark McCurry 的帮助下,我取得了不错的成绩。

    第 1 步:加载原始图像。通过从自身中减去每个垂直列的中值来去除背景。

    no_background=[]
    for i in range(num_frames):
        no_background.append(orig[:,i]-np.median(orig,1))
    no_background=np.array(no_background).T
    

    第 2 步:将负值更改为 0。

    clipped_background = no_background.clip(min=0)
    

    第 3 步:提取一维信号。取垂直列的加权和,将列中的最大强度与其位置相关联。

    def exp_func(x):
        return np.dot(np.arange(len(x)), np.power(x, 10))/(np.sum(np.power(x, 10)))
    
    weighted_sum = np.apply_along_axis(exp_func,0, clipped_background)
    

    第 4 步:对一维信号求导。

    conv = np.convolve([-1.,1],weighted_sum, mode='same')
    pl.plot(conv)
    

    第 5 步:确定导数何时改变符号。

    signs=np.sign(conv)
    pl.plot(signs)
    pl.ylim(-1.2,1.2)
    

    第 6 步:对上述信号应用中值滤波。

    filtered_signs=median_filter(signs, 5) #pick window size based on result. second arg and odd number.
    pl.plot(filtered_signs)
    pl.ylim(-1.2,1.2)
    

    第 7 步:找到符号切换时的索引(帧位置)。绘制结果。

    def sign_switch(oneDarray):
        inds=[]
        for ind in range(len(oneDarray)-1):
            if (oneDarray[ind]<0 and oneDarray[ind+1]>0) or (oneDarray[ind]>0 and oneDarray[ind+1]<0):
                inds.append(ind)
        return np.array(inds)
    
    switched_frames = sign_switch(filtered_signs)
    

    【讨论】:

    • 这是对您自己问题的一个很好的回答!感谢您与我们其他人分享这个。只要您的中值滤波器信号在您提供的窗口之外变化不大,它似乎就足够强大了。
    • 谢谢,希望对大家有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-29
    • 2020-06-28
    • 2018-12-04
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    相关资源
    最近更新 更多