从skimage轮廓创建掩模

7
我有一张图片,使用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()

这里是红色轮廓:

enter image description here

但如果你放大看,就会发现轮廓不在像素的分辨率上。

enter image description here

我该如何创建一个与原始图像具有相同尺寸的图像,并将完全位于轮廓线外(即未被轮廓线穿过)的像素蒙版?例如:

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

谢谢!

3个回答

5
有点晚了,但你知道那句话。我会这样实现它。
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

enter image description here


4

如果你仍在寻找更快的方法来实现这个目标,我建议使用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 - 形状中。


1

好的,我通过将轮廓转换为路径然后选择内部像素来使其工作:

# 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]个像素是否包含在内。有没有更快的算法?谢谢!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接