Python-二维阵列中的峰值检测

发布于 2021-02-02 23:13:33

我正在帮助兽医诊所测量狗爪下的压力。我使用Python进行数据分析,现在我被困在试图将爪子分成(解剖)子区域。

我制作了每个爪子的2D数组,其中包含爪子随时间推移已加载的每个传感器的最大值。这是一个爪子的示例,我使用Excel绘制了要“检测”的区域。这些是传感器周围具有最大最大值的2 x 2框,它们的总和最大。
BuUbq.png

因此,我尝试了一些实验,并决定只寻找每一列和每一行的最大值(由于爪子的形状而无法朝一个方向看)。这似乎可以很好地“检测”到各个脚趾的位置,但是它也标记了相邻的传感器。

UyNRU.png

那么,告诉Python我想要的最大最大值是什么?

注意:2x2的正方形不能重叠,因为它们必须是单独的脚趾!

同样我以2x2为方便,欢迎使用任何更高级的解决方案,但我只是人类运动的科学家,所以我既不是真正的程序员也不是数学家,所以请保持“简单”。

这是可以加载的版本np.loadtxt

结果
因此,我尝试了@jextee的解决方案(请参见下面的结果)。如您所见,它在前爪上非常有效,但在后腿上效果较差。

更具体地说,它无法识别出第四脚趾的小峰。显然,这是回路从上向下朝着最低值而不考虑这在哪里的事实所固有的。

谁会知道如何调整@jextee的算法,以便它也能够找到第四个脚趾?

FFX0x.png

由于我尚未处理其他任何试验,因此无法提供任何其他样品。但是我之前提供的数据是每只爪子的平均值。该文件是一个数组,其中最大9爪的数据按它们与板接触的顺序排列。

此图显示了它们如何在空间上分布在板上。

iPXEv.png

新更新:
因此,在获得有关爪子检测和爪子分类的问题的帮助后,我终于能够检查每个爪子的脚趾检测!事实证明,除了爪子大小像我自己的示例中的爪子一样,它在任何情况下都无法正常工作。事后看来,如此随意地选择2x2是我自己的错。

这是一个出问题的好例子:指甲被识别为脚趾,而“脚跟”是如此之宽,被识别两次!
JEpIa.png

脚掌太大,因此采用2x2大小且没有重叠的脚掌会使两次脚趾被检测到两次。相反,在小型犬中,它通常找不到第5个脚趾,我怀疑这是2x2区域太大造成的。

在尝试了所有解决方案的最新解决方案后,我得出了一个惊人的结论:几乎对我所有的小型犬来说,它都找不到第五个脚趾,而在大型犬的50%以上的撞击中,它会发现更多!

所以很明显我需要更改它。我自己的猜测是将大小更改neighborhood为小型犬较小,大型犬较大。但是generate_binary_structure不允许我更改数组的大小。

因此,我希望其他人对脚趾的定位有更好的建议,也许脚趾的面积与爪子的大小成正比?

关注者
0
被浏览
84
1 个回答
  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。

    我使用局部最大滤波器检测到峰值。这是第一个4个爪子的数据集的结果:

    Kgt4H.png

    我还在9个爪子的第二个数据集上运行了它,效果也很好。

    这是你的操作方式:

    import numpy as np
    from scipy.ndimage.filters import maximum_filter
    from scipy.ndimage.morphology import generate_binary_structure, binary_erosion
    import matplotlib.pyplot as pp
    
    #for some reason I had to reshape. Numpy ignored the shape header.
    paws_data = np.loadtxt("paws.txt").reshape(4,11,14)
    
    #getting a list of images
    paws = [p.squeeze() for p in np.vsplit(paws_data,4)]
    
    
    def detect_peaks(image):
        """
        Takes an image and detect the peaks usingthe local maximum filter.
        Returns a boolean mask of the peaks (i.e. 1 when
        the pixel's value is the neighborhood maximum, 0 otherwise)
        """
    
        # define an 8-connected neighborhood
        neighborhood = generate_binary_structure(2,2)
    
        #apply the local maximum filter; all pixel of maximal value 
        #in their neighborhood are set to 1
        local_max = maximum_filter(image, footprint=neighborhood)==image
        #local_max is a mask that contains the peaks we are 
        #looking for, but also the background.
        #In order to isolate the peaks we must remove the background from the mask.
    
        #we create the mask of the background
        background = (image==0)
    
        #a little technicality: we must erode the background in order to 
        #successfully subtract it form local_max, otherwise a line will 
        #appear along the background border (artifact of the local maximum filter)
        eroded_background = binary_erosion(background, structure=neighborhood, border_value=1)
    
        #we obtain the final mask, containing only peaks, 
        #by removing the background from the local_max mask (xor operation)
        detected_peaks = local_max ^ eroded_background
    
        return detected_peaks
    
    
    #applying the detection and plotting results
    for i, paw in enumerate(paws):
        detected_peaks = detect_peaks(paw)
        pp.subplot(4,2,(2*i+1))
        pp.imshow(paw)
        pp.subplot(4,2,(2*i+2) )
        pp.imshow(detected_peaks)
    
    pp.show()
    

    你需要做的就是scipy.ndimage.measurements.label在蒙版上使用以标记所有不同的对象。这样你就可以分别与他们一起玩了。

    请注意,该方法效果很好,因为背景不嘈杂。如果是这样,你将在背景中检测到许多其他不需要的峰。另一个重要因素是邻里的大小。如果峰大小发生变化,则需要对其进行调整(应保持大致成比例)。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看