【问题标题】:Create mask from skimage contour从 skimage 轮廓创建蒙版
【发布时间】:2025-12-02 00:15:01
【问题描述】:

我有一张图像,我在skimage.measure.find_contours() 上找到了轮廓,但现在我想为完全超出最大闭合轮廓的像素创建一个蒙版。知道怎么做吗?

修改文档中的示例:

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)**2 + np.cos(y)**2)))

# Find contours at a constant value of 0.8
contours = measure.find_contours(r, 0.8)

# Select the largest contiguous contour
contour = sorted(contours, key=lambda x: len(x))[-1]

# Display the image and plot the contour
fig, ax = plt.subplots()
ax.imshow(r, interpolation='nearest', cmap=plt.cm.gray)
X, Y = ax.get_xlim(), ax.get_ylim()
ax.step(contour.T[1], contour.T[0], linewidth=2, c='r')
ax.set_xlim(X), ax.set_ylim(Y)
plt.show()

这是红色的轮廓:

但是如果你放大,注意轮廓不是像素的分辨率。

如何创建与原始图像尺寸相同且像素完全位于外部(即未与轮廓线相交)被遮盖的图像?例如

from numpy import ma
masked_image = ma.array(r.copy(), mask=False)
masked_image.mask[pixels_outside_contour] = True

谢谢!

【问题讨论】:

    标签: python contour scikit-image masked-array


    【解决方案1】:

    有点晚了,但你知道这句话。以下是我将如何做到这一点。

    import scipy.ndimage as ndimage    
    
    # Create an empty image to store the masked array
    r_mask = np.zeros_like(r, dtype='bool')
    
    # Create a contour image by using the contour coordinates rounded to their nearest integer value
    r_mask[np.round(contour[:, 0]).astype('int'), np.round(contour[:, 1]).astype('int')] = 1
    
    # Fill in the hole created by the contour boundary
    r_mask = ndimage.binary_fill_holes(r_mask)
    
    # Invert the mask since you want pixels outside of the region
    r_mask = ~r_mask
    

    【讨论】:

      【解决方案2】:

      如果您仍在寻找更快的方法来实现这一目标,我建议您使用 skimage.draw.polygon,我对此有点陌生,但它似乎内置于做你想做的事:

      import numpy as np
      from skimage.draw import polygon
      
      # fill polygon
      poly = np.array((
          (300, 300),
          (480, 320),
          (380, 430),
          (220, 590),
          (300, 300),
      ))
      rr, cc = polygon(poly[:, 0], poly[:, 1], img.shape)
      img[rr, cc, 1] = 1
      

      因此,在您的情况下,“闭合轮廓”是“多边形”,我们正在创建一个空白图像,轮廓的形状填充值 1:

      mask = np.zeros(r.shape)
      rr, cc = polygon(contour[:, 0], contour[:, 1], mask.shape)
      mask[rr, cc] = 1
      

      现在你可以将你的蒙版应用到原始图像上,以掩盖轮廓之外的所有内容:

      masked = ma.array(r.copy(), mask=mask)
      

      记录在scikit image - Shapes

      【讨论】:

        【解决方案3】:

        好的,我可以通过将轮廓转换为路径然后选择里面的像素来完成这项工作:

        # Convert the contour into a closed path
        from matplotlib import path
        closed_path = path.Path(contour.T)
        
        # Get the points that lie within the closed path
        idx = np.array([[(i,j) for i in range(r.shape[0])] for j in range(r.shape[1])]).reshape(np.prod(r.shape),2)
        mask = closed_path.contains_points(idx).reshape(r.shape)
        
        # Invert the mask and apply to the image
        mask = np.invert(mask)
        masked_data = ma.array(r.copy(), mask=mask)
        

        但是,这是一种缓慢的测试N = r.shape[0]*r.shape[1] 像素的收容措施。谁有更快的算法?谢谢!

        【讨论】: