简体   繁体   English

从 skimage 轮廓创建蒙版

[英]Create mask from skimage contour

I have an image that I found contours on with skimage.measure.find_contours() but now I want to create a mask for the pixels fully outside the largest closed contour.我有一个图像,我在skimage.measure.find_contours()上找到了轮廓,但现在我想为完全在最大闭合轮廓之外的像素创建一个蒙版。 Any idea how to do this?知道如何做到这一点吗?

Modifying the example in the documentation:修改文档中的示例:

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()

Here is the contour in red:这是红色的轮廓:

在此处输入图片说明

But if you zoom in, notice the contour is not at the resolution of the pixels.但是如果放大,请注意轮廓不是像素的分辨率。

在此处输入图片说明

How can I create an image of the same dimensions as the original with the pixels fully outside (ie not crossed by the contour line) masked?如何创建与原始图像尺寸相同且像素完全在外部(即没有与轮廓线交叉)被屏蔽的图像? Eg例如

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

Thanks!谢谢!

A bit late but you know the saying.有点晚了,但你知道这句话。 Here is how I would accomplish this.这是我将如何实现这一点。

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

在此处输入图片说明

If you're still looking for a faster way to achieve that, I would recommend using skimage.draw.polygon , I'm kind of new to this but it seems to be built in to do exactly what you are trying to accomplish:如果您仍在寻找更快的方法来实现这一点,我建议使用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

So in your case, a 'closed contour' is a 'poly', we are creating a blank image with the shape of your contours filled with the value 1:因此,在您的情况下,“闭合轮廓”是“多边形”,我们正在创建一个空白图像,其轮廓形状填充值 1:

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

And now you can apply your mask to the original image to mask out everything outside the contours:现在您可以将您的蒙版应用到原始图像上,以掩盖轮廓之外的所有内容:

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

Documented in scikit image - Shapes记录在scikit 图像中 - 形状

Ok, I was able to make this work by converting the contour to a path and then selecting the pixels inside:好的,我能够通过将轮廓转换为路径然后选择里面的像素来完成这项工作:

# 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)

However, this is kind of slow testing N = r.shape[0]*r.shape[1] pixels for containment.然而,这是一种缓慢测试N = r.shape[0]*r.shape[1]像素的遏制。 Anyone have a faster algorithm?有人有更快的算法吗? Thanks!谢谢!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM