【问题标题】:Correctly closing of polygons generated using skimage.measure.find_contours()正确关闭使用 skimage.measure.find_contours() 生成的多边形
【发布时间】:2018-04-23 02:52:42
【问题描述】:

我目前正在使用skimage.measure.find_contours() 在表面上查找轮廓。现在我已经找到了我需要能够找到包含在其中的区域的轮廓。

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

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

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

def find_area(array):
    a = 0
    ox,oy = array[0]
    for x,y in array[1:]:
        a += (x*oy-y*ox)
        ox,oy = x,y
    return -a/2

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

谢谢

更新:

应用@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

【问题讨论】:

    标签: python scikit-image


    【解决方案1】:

    如果有人需要通过图像边缘关闭开放轮廓(并制作多边形),这里是:

    import shapely.geometry as sgeo
    import shapely.ops as sops
    
    
    def close_contour_with_image_edge(contour, image_shape):
        """
        this function uses shapely because its easiest way to do that
        :param contour: contour generated by skimage.measure.find_contours()
        :param image_shape: tuple (row, cols), standard return of numpy shape()
        :return:
        """
        # make contour linestring
        contour_line = sgeo.LineString(contour)
    
        # make image box linestring
        box_rows, box_cols = image_shape[0], image_shape[1]
        img_box = sgeo.LineString(coordinates=(
            (0, 0),
            (0, box_cols-1),
            (box_rows-1, box_cols-1),
            (box_rows-1, 0),
            (0, 0)
        ))
    
        # intersect box with non-closed contour and get shortest line which touch both of contour ends
        edge_points = img_box.intersection(contour_line)
        edge_parts = sops.split(img_box, edge_points)
        edge_parts = list(part for part in edge_parts.geoms if part.touches(edge_points.geoms[0]) and part.touches(edge_points.geoms[1]))
        edge_parts.sort(reverse=False, key=lambda x: x.length)
        contour_edge = edge_parts[0]
    
        # weld it
        contour_line = contour_line.union(contour_edge)
        contour_line = sops.linemerge(contour_line)
        contour_polygon = sgeo.Polygon(contour_line.coords)
    
        return contour_polygon
    
    

    【讨论】:

      【解决方案2】:

      如果需要测量不同区域的属性,则开始查找区域(不是轮廓)是自然的。

      算法将是以下内容,在这种情况下:

      1. 准备标记图像:

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

        1.b或应用一些图像阈值函数,然后运行@ 987654323(http://scikit-image.org/docs/dev/api/skimage.measure.html#skimage.measure.label);

      2. 执行regionprops使用非常标记的图像作为输入(http://scikit-image.org/docs/dev/api/skimage.measure.html#skimage.measure.regionprops);

      3. regionprops中迭代区域,并计算所需的参数(区域,周长等)。

      一旦通过regionprops,您可以通过regionprops,您可以调用.coords,每个人都可以获得封闭的轮廓。

      【讨论】:

      • 感谢您的回答。我试过阅读你的建议,但我变得困惑。我只是对图像中显示的轮廓括起来的区域。我将如何用不同的颜色和b)填写这些区域,b)确定所有图像的区域,所有图像都被分成区域吗?谢谢
      • 好的,我想现在得到你的意思。我的担忧是测量.RegionProps只占用了符合标准的完整像素,而Measure.Find_Contours似乎做了一些插值,因此允许给定较大区域的区域内像素。有没有办法弥补这个? span>
      • @ jlt199关于您的第一个注释:(a)其中一种方式是到for i, c in enumerate(contours): rr, cc = skimage.draw.polygon(c[:, 0], c[:, 1], shape=img.shape); img_filled[rr, cc] = i。这不会适当地对角轮廓。更好的方法是使用称为“洪水填充”的算法,但不幸的是,我们在skimage到目前为止,我们没有它。 span>
      • (b)这是另一个复杂的问题,这就是阈值+分割方法的原因,通常是更好的拟合。在这种情况下,基本上,您基本上,通过强度水平识别ROI(高强度区域是感兴趣的,其他是背景)。在您的示例中,您在底部的高(青色和蓝色轮廓)和低强度(红色和紫色)​​区域,以及您将这款的对待作为rois,这非常令人困惑。 span>
      • 我用这个数据设置为例,并且没有意识到轮廓封闭高幅度和低幅度的区域。我的实际数据不显示此行为。因此,我现在使用使用您描述的阈值和标记技术以及regionprops测量区域。我也使用插值函数来应用线性插值以减少像素大小以获得均匀像素尺寸和更大的分辨率。到目前为止,这似乎正在运作良好。谢谢你的帮助。我会尽快使用我的解决方案代码更新线程。 span>
      猜你喜欢
      • 1970-01-01
      • 2012-12-30
      • 1970-01-01
      • 1970-01-01
      • 2020-08-30
      • 2013-02-20
      • 1970-01-01
      • 2010-12-19
      • 2020-01-16
      相关资源
      最近更新 更多