如何比较两个轮廓路径在视觉上是否相似--Python / Matplotlib

时间:2014-09-23 12:13:57

标签: python matplotlib comparison contour

我想知道如果两个路径的轮廓重叠,如果它们相似则如何比较。

更具体地说,我有一组 n 实现,每个实现都有其轮廓级别。我需要在 l 级别验证每个轮廓的稳定性。要做到这一点,我必须计算它通过偶然发生的次数。

到目前为止,我正在研究这段代码:

def iso_contours(scalar_fields):

    #TODO : access the paths by level (0, 1, 2 ...)
    default = 0
    contours = {}
    contours_number = 0
    for scalar_field in scalar_fields:
        cs = plt.contour(scalar_field)
        for collection in cs.collections:
            paths = collection.get_paths()
            for path in paths:
                num = contours.get(path, default)
                contours[path] = num + 1
                contours_number += 1

    contours.update((x, y/float(contours_number)) for x, y in contours.items())
    return contours

然而,即使有两条相同的路径,它们也被视为不同。

所以,我想知道如果给出两条路径,我可以确定它们是否在视觉上相似。 正如@unutbu提醒我的那样,我不能只比较顶点,因为顶点可能有不同的顺序,或者一条路径中可能有1000个顶点而另一条路径中可能有100个顶点...

2 个答案:

答案 0 :(得分:2)

首先,我假设你知道你的轮廓被绘制成相同的比例并且没有被翻译,所以这不是图像匹配的问题,因为试图找到两个笨拙的形状之间的差异。

有几种方法可以做到这一点,两者都应该给出大致相同的结果。最准确的方法是在两条曲线之间取内积,但这需要将曲线对齐并将其描述为相同的分辨率。例如,这可以通过插值来完成,但这是一个很大的麻烦。

我在这里尝试的方法是一种捷径,但它应该给出一个合理的估计,即绘制两条曲线之间的区域并从图中求和该区域。面积越小,曲线越相似。 (也就是说,总而言之,使用内部产品的曲线,使用差异区域的图像)。

例如,从这些轮廓开始:

enter image description here

我们以这个情节结束,差异是标题中的总和:

enter image description here

这里是代码(它有点复杂,因为我不认为有一种方法可以简单地填充两条任意参数化曲线,所以我从每个填充的单曲中制作图像轮廓然后减去它们):

import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import matplotlib.cm as cm
import numpy as np
import io
import Image

xmin, xmax, ymin, ymax = -3, 6, -2, 3
delta = 0.025
x = np.arange(xmin, xmax, delta)
y = np.arange(ymin, ymax, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)

def f(a, b):
    return 10.*(a*Z2 - b*Z1)

def fill_contour(cs):
    v = cs.collections[0].get_paths()[0].vertices
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.fill(v[:,0], v[:,1], 'k')
    ax.set_xlim(xmin, xmax)
    ax.set_ylim(ymin, ymax)
    buf = io.BytesIO()
    fig.savefig(buf, format = 'png')
    buf.seek(0)
    im = Image.open(buf).convert('L')
    r = np.asarray(im).astype(np.int)
    r/=max(r.flat)
    return r

figc = plt.figure()
axc = figc.add_subplot(111)
c0 = .07
cs1 = axc.contour(X, Y, f(.6 ,.7), [c0], colors='r')
cs2 = axc.contour(X, Y, f(.8, 1.2), [c0], colors='g')


figd = plt.figure()
axd = figd.add_subplot(111)
d1 = fill_contour(cs1)
d2 = fill_contour(cs2)
d = abs(d1-d2)
im = axd.imshow(d, cmap=cm.gray)
figd.colorbar(im)
axd.set_title( "sum = %i" % np.sum(d.flat))

figc.show()
figd.show()

答案 1 :(得分:0)

添加:

ax.set_position([0, 0, 1, 1])
ax.axis('off')

到fill_contour()回调将改善结果,因为轴和"死"从fig.savefig(buf, format = 'png')收集的数据中删除了空格。我试图使用这种方法来获得两个轮廓或轮廓f的重叠区域,而不是d = abs(d1+d2),但我没有那么高兴,因为我丢失了X和Y信息。