检测(x,y)数据中的区域

时间:2013-08-12 19:38:28

标签: python .net image-processing scientific-computing edge-detection

我需要能够根据数据的特征检测(x,y)数据列表的区域。一些示例数据显示在第一张图像中。现在,我需要能够找到黑色标记之间的区域(抱歉质量很差,imgur的编辑器不是很准确)。不幸的是,每次收集这些数据时,由于具有不同的长度和形状,问题变得复杂,如第二图像所示。从~98到~85的急剧下降是一致的,~1e-9和~1.5e-9之间的两个倾角/两个峰值特征应该是相当一致的。

我的问题是,根据信号的特征,检测信号中事件的最佳方法是什么?如果我可以将这个切成标记的三个区域(从第一个开始标记,第一个到第二个标记,第二个标记到结束),那么我相信我可以扩展该方法来处理我更复杂的情况。

之前我已经解决了类似的问题,但是这个问题在从一组数据到另一组数据的变化量方面是独一无二的。上次我只是编写了一个手工制作的算法来找到一个局部极值并用它来定位边缘,但我觉得这是一个相当难看且效率低下的解决方案,不容易重复使用。

我正在使用Python 2.7.5,但理想情况下,这应该是一种与语言无关的解决方案,以便我可以在其他环境中实现它,如VB.NET。

img1

img2

2 个答案:

答案 0 :(得分:3)

基于您发布的两个示例,我有几个不同的建议:阈值处理或模板匹配。

阈值

因为你提到信号中的垂直下降是相对恒定的,特别是对于你正在检测的第一个事件,似乎你可以使用阈值方法,在第一次出现信号交叉时放置事件一些感兴趣的门槛。例如,放置第一个事件(在Python中,并假设您的测量数据存在于包含x-y对的元组序列中):

def detect_onset_event(measurements):
    armed = False
    for offset, (timestamp, value) in enumerate(measurements):
        if value > 90:
            armed = True
        if armed and value < 85:
            return offset
    return -1  # failure condition, might want to raise ValueError()

所以这里我们触发第一个样本偏移,在信号超过90后降至85以下。

你可以为第二个事件做类似的事情,但看起来对于那个事件重要的信号水平可能不那么明确。取决于您的应用和测量数据。这是使阈值处理方法不那么好的一个很好的例子 - 它们可以很脆弱并且依赖于硬编码值。但是,如果您的测量结果非常规则,那么这可以很好地工作,只需很少的编码工作。

模板

在此方法中,您可以为每个感兴趣的信号事​​件创建模板,然后convolve信号上的模板,以识别信号的相似区域。

import numpy

def detect_twopeak_event(measurements, template):
    data = numpy.asarray(measurements) # convert to numpy array
    activations = numpy.convolve(
        data[:, 1],  # convolve over all "value" elements
        template)
    return activations.argmax()

在这里,您需要创建一个样本测量列表,构成您要检测的事件 - 例如,您可以从示例信号的双峰区域中提取测量结果,以用作模板。然后,通过将此模板卷积在测量数据上,您将获得测量值与模板相似程度的指标。您可以返回最佳匹配的索引(如上面的代码中所示)或将这些相似性估计值传递给其他一些过程以选择“最佳匹配”。

有很多方法可以创建模板,但我认为最有希望的方法之一是使用标记的训练事件中的一堆邻域的平均值。也就是说,假设您有一个信号数据库,该数据库与发生给定事件的样本偏移量配对。您可以通过平均这些标记事件周围的窗口区域来创建模板:

def create_mean_template(signals, offsets, radius=20):
    w = numpy.hanning(2 * radius)
    return numpy.mean(
        [s[o-radius:o+radius] * w for s, o in zip(signals, offsets)],
        axis=0)

这已成功用于许多信号处理领域,如人脸识别(例如,您可以通过平均一堆标记眼睛周围的像素来为眼睛创建模板)。

模板方法开始失败的一个地方是,如果您的信号有很多看起来像模板的区域,但这些区域与您要检测的事件不对应。处理这个问题很棘手,因此如果事件附近出现明显的信号模式,模板方法效果最好。

模板方法失败的另一种方法是,如果您的测量数据包含一个双峰区域,这个区域很有趣,但频率与您用作模板的样本不同。在这种情况下,您可以通过在时频域而不是时间幅度域中工作,使模板对于轻微的频率变化更加稳健。在那里,您可以在测量中运行窗口FFT,而不是制作与您感兴趣的幅度变化的时间模式相对应的1D模板,然后提出与k维频率变化相对应的kD模板。您感兴趣的活动周边地区。

希望其中一些建议有所帮助!

答案 1 :(得分:1)

你可能会使用一个有6个以上状态的隐马尔可夫模型,我不是数学天才所以我会使用一个具有离散状态并将数据四舍五入到最接近的整数,我的模型会看起来很相似:

状态1:开始blob(排放在97左右) 状态2:'下降'(排放在83和100之间) 状态3:有趣的东西(排放在82-86之间) 州4:高峰期(80-88) 国家5:最后一个高峰(80-94) 状态6:基线(87-85)

HMM不是一个完美的工具,因为它们主要捕获每个州的排放范围,但是它们能够很好地容忍早期或晚期出现的东西,因为它们只关心状态之间的p值,因此

我希望这有帮助并且有意义

如果你是超级懒人,你可以手工标记6个光谱然后相应地切割数据并计算每个状态的每个发射的p值。

#pseudo code
emissions = defaultdict(int) # with relevant labels initialized to 0
for state_lable, value in data:
    emissions[state_lable][value] += 1
# then normalize all states to 1 and voila you have a HMM

以上是超简化的,但应该比你通常做的if语句更好,更强大:)... ... HMM通常也有一个转换矩阵,但因为你的数据信号太强了你可以“跳过”那个,然后我的实用解决方案:)

然后使用维特比路径标记您未来的所有实验