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

我为每个爪子制作了一个2D数组,其中包括爪子随时间加载的每个传感器的最大值。这里有一个单爪的例子,我使用Excel绘制我想要“检测”的区域。传感器周围是2 * 2的方框带有局部最大值,它们加起来的和最大。

所以我尝试了一些实验,并决定简单地寻找每一列和每一行的最大值(由于爪子的形状,不能只看一个方向)。这似乎能很好地“检测”到不同脚趾的位置,但也能标记出相邻的传感器。

那么告诉Python哪些最大值是我想要的最好方法是什么呢?

注意:2x2的方块不能重叠,因为它们必须是分开的脚趾!

此外,我选择了2x2作为方便,任何更高级的解决方案都是受欢迎的,但我只是一个人类运动科学家,所以我既不是真正的程序员也不是数学家,所以请保持“简单”。

下面是一个可以用np.loadtxt加载的版本


结果

所以我尝试了@jextee的解决方案(见下面的结果)。正如你所看到的,它对前爪很有效,但对后腿就不那么有效了。

更具体地说,它无法识别第四个脚趾的小峰。这显然是固有的事实,即循环从上向下看最低值,而不考虑它在哪里。

有没有人知道如何调整@jextee的算法,让它也能找到第四个脚趾?

因为我还没有处理其他的试验,所以我无法提供其他的样品。但我之前给出的数据是每个爪子的平均值。这个文件是一个数组,其中包含9只爪子的最大数据,按照它们与盘子接触的顺序排列。

这张照片显示了它们在空间上是如何分布在板块上的。

更新:

我已经为任何感兴趣的人建立了一个博客,我已经设置了一个OneDrive与所有的原始测量。因此,对于任何要求更多数据的人:给你更多力量!


新更新:

所以在我得到关于爪子检测和爪子分类的问题的帮助后,我终于能够检查每个爪子的脚趾检测!事实证明,除了像我自己例子中那样大的爪子,它在其他地方都不太管用。当然,事后看来,是我自己的错,我这么武断地选择了2x2。

这里有一个很好的例子,它错在哪里:指甲被识别为脚趾,而“脚跟”太宽了,它被识别了两次!

爪子太大了,所以采用没有重叠的2x2尺寸,会导致一些脚趾被检测两次。反过来,在小型犬中,它经常找不到第5个脚趾,我怀疑这是由于2x2面积太大造成的。

在对我所有的测量都尝试了当前的解决方案后,我得出了一个惊人的结论,几乎所有的小狗都没有发现第5个脚趾,而在超过50%的大型狗的冲击中,它会发现更多!

显然我需要改变它。我自己的想法是改变社区的大小,让小狗住的地方更小,大狗住的地方更大。但是generate_binary_structure不允许我改变数组的大小。

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


当前回答

我相信你现在已经有足够的信息了,但我忍不住建议使用k-均值聚类方法。k-means是一种无监督聚类算法,它将你的数据(在任何维度上-我碰巧在3D中这样做),并将其排列成k个具有明显边界的聚类。这里很好,因为你确切地知道这些犬齿应该有多少脚趾。

此外,它是在Scipy中实现的,非常好(http://docs.scipy.org/doc/scipy/reference/cluster.vq.html)。

下面是它在空间上解析3D集群的一个例子:

你想要做的有点不同(2D,包括压力值),但我仍然认为你可以尝试一下。

其他回答

只是想告诉你们,有一个很好的选项可以用python在图像中找到局部最大值:

from skimage.feature import peak_local_max

或者对于skimage 0.8.0:

from skimage.feature.peak import peak_local_max

http://scikit-image.org/docs/0.8.0/api/skimage.feature.peak.html

如果你能够创建一些训练数据,那么使用神经网络可能是值得尝试的……但这需要手工标注许多样本。

有趣的问题。我想尝试的解决方案如下。

应用一个低通滤波器,比如用二维高斯掩码卷积。这将给你一堆(可能,但不一定是浮点数)值。 使用每个爪垫(或脚趾)的已知近似半径执行2D非最大抑制。

这将为你提供最大的职位,而不是有多个候选人。澄清一下,第1步中蒙版的半径也应该与第2步中使用的半径相似。这个半径是可以选择的,或者兽医可以事先明确测量它(它会随着年龄/品种等而变化)。

建议的一些解决方案(均值漂移、神经网络等)可能在某种程度上是可行的,但它们过于复杂,可能并不理想。

如果你一步一步地进行:你首先找到全局最大值,如果需要处理周围的点,然后将找到的区域设置为零,然后对下一个重复。

使用持久同源分析你的数据集,我得到了以下结果(点击放大):

这是这个SO答案中描述的峰值检测方法的2d版本。上图仅显示了按持久性排序的0维持久性同源类。

我确实使用scipy.misc.imresize()将原始数据集提升了2倍。但是,请注意,我确实将四个爪子视为一个数据集;把它分成四份会使问题更简单。

方法。 这背后的思想非常简单:考虑函数的函数图,该函数为每个像素分配其级别。它是这样的:

现在考虑高度为255的水位不断下降到较低的水位。在局部极大值时,岛屿弹出(出生)。两个岛屿在鞍点合并;我们认为低岛与高岛合并(死亡)。所谓的持久性图(0维同调类,我们的岛屿)描述了所有岛屿的死亡-出生值:

岛屿的持续存在就是出生水平和死亡水平之间的差异;点到灰色主对角线的垂直距离。这个数字通过减少持久性来标记岛屿。

第一张图片显示了这些岛屿的诞生地点。该方法不仅给出了局部极大值,而且通过上述持久性量化了它们的“意义”。这样就会过滤掉所有持久性过低的岛屿。但是,在您的示例中,每个岛(即每个局部最大值)都是您要寻找的峰值。

Python代码可以在这里找到。