Python 正确闭合使用skimage.measure.find_等高线()生成的多边形

Python 正确闭合使用skimage.measure.find_等高线()生成的多边形,python,scikit-image,Python,Scikit Image,我目前正在使用skimage.measure.find_outlows()查找曲面上的轮廓。现在我已经找到了轮廓,我需要能够找到包围在轮廓内的区域 当所有顶点都在数据集中时,就可以使用完全封闭的多边形。 但是,如果轮廓在边缘或拐角处超出曲面的边缘,如何确保多边形完全封闭?发生这种情况时,我希望使用曲面的边作为附加顶点来关闭多边形。例如,在下图中,显示了轮廓,您可以看到轮廓结束于图像的边缘,如何将其闭合?同样在棕色等高线的例子中,它只是一条直线,我不想返回一个区域,我该如何挑出这种情况 我知道我

我目前正在使用
skimage.measure.find_outlows()
查找曲面上的轮廓。现在我已经找到了轮廓,我需要能够找到包围在轮廓内的区域

当所有顶点都在数据集中时,就可以使用完全封闭的多边形。 但是,如果轮廓在边缘或拐角处超出曲面的边缘,如何确保多边形完全封闭?发生这种情况时,我希望使用曲面的边作为附加顶点来关闭多边形。例如,在下图中,显示了轮廓,您可以看到轮廓结束于图像的边缘,如何将其闭合?同样在棕色等高线的例子中,它只是一条直线,我不想返回一个区域,我该如何挑出这种情况

我知道我可以通过检查多边形的最后一个顶点是否与第一个顶点相同来检查封闭轮廓/多边形

我有计算多边形内部面积的代码,取自

我只是需要帮助来关闭多边形。并检查可能发生的不同情况

谢谢

更新: 应用@soupault建议的解决方案后,我得到以下代码:

import numpy as np
import matplotlib.pyplot as plt

from skimage import measure


# Construct some test data
x, y = np.ogrid[-np.pi:np.pi:100j, -np.pi:np.pi:100j]
r = np.sin(np.exp((np.sin(x)**3 + np.cos(y)**2)))

# Coordinates of point of interest
pt = [(49,75)]

# Apply thresholding to the surface
threshold = 0.8
blobs = r > threshold

# Make a labelled image based on the thresholding regions
blobs_labels = measure.label(blobs, background = 0)

# Show the thresholded regions
plt.figure()
plt.imshow(blobs_labels, cmap='spectral')

# Apply regionprops to charactersie each of the regions
props = measure.regionprops(blobs_labels, intensity_image = r)

# Loop through each region in regionprops, identify if the point of interest is
# in that region. If so, plot the region and print it's area.
plt.figure()
plt.imshow(r, cmap='Greys')
plt.plot(pt[0][0], pt[0][1],'rx')
for prop in props:
    coords = prop.coords
    if np.sum(np.all(coords[:,[1,0]] == pt[0], axis=1)):
        plt.plot(coords[:,1],coords[:,0],'r.')
        print(prop.area)
此解决方案假定每个像素的大小为1x1。在我的真实数据解决方案中,情况并非如此,因此我还应用了以下函数对数据应用线性插值。我相信您也可以应用类似的功能,使每个像素的面积更小,并提高数据的分辨率

import numpy as np
from scipy import interpolate

def interpolate_patch(x,y,patch):
    x_interp = np.arange(np.ceil(x[0]), x[-1], 1)
    y_interp = np.arange(np.ceil(y[0]), y[-1], 1)

    f = interpolate.interp2d(x, y, patch, kind='linear')

    patch_interp = f(x_interp, y_interp)

    return x_interp, y_interp, patch_interp

如果需要测量不同区域的属性,那么很自然地从查找区域(而不是轮廓)开始

在这种情况下,算法如下所示:

  • 准备带标签的图像:

    1.a用不同的颜色填充不同轮廓线之间的区域

    1.b或应用一些图像阈值功能,然后运行
    skimage.measure.label
    ()

  • 使用非常贴有标签的图像作为输入()执行
    regionprops

  • 迭代
    regionprops
    中的区域,并计算所需的参数(面积、周长等)


  • 一旦您通过
    regionprops
    识别了图像中的区域,您可以调用
    .coords
    获取每个区域的轮廓。

    谢谢您的回答。我试着仔细阅读你的建议,但我弄糊涂了。我只对图中显示的轮廓所包围的区域感兴趣。I)如何用不同的颜色填充这些区域,以及b)在将所有图像分割成多个区域后,如何识别感兴趣的区域?谢谢,我想我现在明白你的意思了。我担心的是,measure.regionprops只获取满足标准的完整像素,而measure.find_轮廓似乎会进行一些插值,因此允许部分像素位于区域内(给定更大的区域)。有什么方法可以弥补这一点吗?@jlt199关于你的第一条评论:(a)其中一种方法是对枚举(等高线)中的i,c进行
    :rr,cc=skimage.draw.polygon(c[:,0],c[:,1],shape=img.shape);img_填充[rr,cc]=i
    。但这对于拐角轮廓来说并不合适。更好的方法是使用名为“洪水填充”的算法,但不幸的是,到目前为止,
    skimage
    中还没有。(b)这是另一个复杂的问题,这就是为什么阈值+分割方法通常更适合。在这种情况下,您基本上可以通过强度级别识别ROI(高强度区域是感兴趣的,其他区域是背景)。在您的示例中,您同时拥有高(底部为青色和蓝色轮廓)和低强度(红色和紫色)区域,并且您将这两个集合都视为ROI,这非常令人困惑。我将此数据集用作示例,但没有意识到轮廓包含高振幅和低振幅区域。我的实际数据没有显示这种行为。因此,我现在使用您描述的阈值和标签技术,以及测量区域的
    regionprops
    。我还使用插值函数应用线性插值来减小像素大小,以获得均匀的像素大小和更高的分辨率。到目前为止,这似乎运作良好。谢谢你的帮助。我将很快用我的解决方案代码更新线程。
    import numpy as np
    from scipy import interpolate
    
    def interpolate_patch(x,y,patch):
        x_interp = np.arange(np.ceil(x[0]), x[-1], 1)
        y_interp = np.arange(np.ceil(y[0]), y[-1], 1)
    
        f = interpolate.interp2d(x, y, patch, kind='linear')
    
        patch_interp = f(x_interp, y_interp)
    
        return x_interp, y_interp, patch_interp