python - 如何为numpy数组创建圆形蒙版?

标签 python arrays numpy image-processing

我正在尝试在Python中圆形 mask 图像。我在网上找到了一些示例代码,但是我不确定如何更改数学以正确地定位我的圈子。

我有一个类型为image_datanumpy.ndarray类型的图像(3725, 4797, 3):

total_rows, total_cols, total_layers = image_data.shape
X, Y = np.ogrid[:total_rows, :total_cols]
center_row, center_col = total_rows/2, total_cols/2
dist_from_center = (X - total_rows)**2 + (Y - total_cols)**2
radius = (total_rows/2)**2
circular_mask = (dist_from_center > radius)

我看到此代码将欧几里德距离应用于dist_from_center的计算,但是我不理解X - total_rowsY - total_cols部分。这将产生一个四分之一圆的蒙版(以图像的左上角为中心)。

圈子中的XY扮演什么角色?以及如何修改此代码以产生一个在图像中其他位置居中的蒙版?

最佳答案

您上网的算法部分错误,至少出于您的目的。如果我们有以下图像,我们希望将其屏蔽为:

Image to mask Masked image

创建这样的掩码的最简单方法是算法的运行方式,但是它并未以您想要的方式呈现,也没有使您能够以简单的方式对其进行修改。我们需要做的是查看图像中每个像素的坐标,并获取该像素是否在半径之内的真/假值。例如,这是一张放大的图片,显示了圆半径和严格位于该半径内的像素:

Pixels inside the radius

现在,要弄清楚哪些像素位于圆内,我们需要图像中每个像素的索引。函数 np.ogrid() 提供两个 vector ,每个 vector 包含像素位置(或索引):有一个列 vector 用于列索引,行 vector 用于行索引:

>>> np.ogrid[:4,:5]
[array([[0],
       [1],
       [2],
       [3]]), array([[0, 1, 2, 3, 4]])]

这种格式对broadcasting很有用,因此,如果我们在某些函数中使用它们,它将实际上创建一个包含所有索引的网格,而不仅仅是两个 vector 。因此,我们可以使用np.ogrid()创建图像的索引(或像素坐标),然后检查每个像素坐标以查看其在圆内还是圆外。为了判断它是否在中心内,我们可以简单地找到从中心到每个像素位置的欧几里得距离,然后,如果该距离小于圆半径,我们将其标记为蒙版中的大于此值,我们将其从 mask 中排除。

现在,我们已经具备了创建此蒙版的函数所需的一切。此外,我们将为其添加一些不错的功能;我们可以输入中心和半径,或者让它自动计算它们。

def create_circular_mask(h, w, center=None, radius=None):

    if center is None: # use the middle of the image
        center = (int(w/2), int(h/2))
    if radius is None: # use the smallest distance between the center and image walls
        radius = min(center[0], center[1], w-center[0], h-center[1])

    Y, X = np.ogrid[:h, :w]
    dist_from_center = np.sqrt((X - center[0])**2 + (Y-center[1])**2)

    mask = dist_from_center <= radius
    return mask

在这种情况下,dist_from_center是一个与指定高度和宽度相同的矩阵。它将列和行索引 vector 广播到一个矩阵中,其中每个位置的值是距中心的距离。如果我们将此矩阵可视化为图像(将其缩放到适当的范围),那么它将是我们指定的从中心辐射的渐变:

Distance gradient

因此,当我们将其与radius进行比较时,它等于对该梯度图像进行阈值化。

注意,最终的掩码是 bool(boolean) 矩阵; True(如果该位置在距指定中心的半径之内),否则为False。因此,我们可以将该掩码用作我们关注的像素区域的指示符,或者可以采用与该 bool(boolean) 值相反的形式(~中的numpy)来选择该区域之外的像素。因此,像我在本文顶部所做的那样,使用此功能为圆形以外的像素上色很简单:

h, w = img.shape[:2]
mask = create_circular_mask(h, w)
masked_img = img.copy()
masked_img[~mask] = 0

但是,如果我们想在与中心不同的点上创建圆形蒙版,则可以指定它(请注意,该函数期望的中心坐标是x, y顺序,而不是索引row, col = y, x顺序):

center = (int(w/4), int(h/4))
mask = create_circular_mask(h, w, center=center)

由于我们没有给出半径,因此会给我们最大半径,以便圆仍适合图像边界:

Off-center mask

或者我们可以让它计算中心但使用指定的半径:

radius = h/4
mask = create_circular_mask(h, w, radius=radius)

给我们一个半径不精确到最小尺寸的圆心:

Specified radius mask

最后,我们可以指定所需的任何半径和中心,包括延伸到图像边界之外的半径(并且中心甚至可以在图像边界之外!):

center = (int(w/4), int(h/4))
radius = h/2
mask = create_circular_mask(h, w, center=center, radius=radius)

Off-center, larger radius mask

您在网上找到的算法的作用等同于将中心设置为(0, 0)并将半径设置为h:

mask = create_circular_mask(h, w, center=(0, 0), radius=h)

Quarter-circle mask

关于python - 如何为numpy数组创建圆形蒙版?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44865023/

相关文章:

python - "AttributeError: ' SelectorList ' object has no attribute ' 在Scrapy Cloud中获取'"

python - Django /Jinja2 : How to use the index value in a for-loop statement to display two lists?

php - swagger-php 使用属性响应对象数组

arrays - 从数组列表中随机选择 5 个元素,不重复一个元素

python - 分配给 NumPy 中的列

python - 使用一次 `plot` 调用绘制多条曲线时的一个图例条目

java - 创建一个类以从 derby 数据库获取值

python - 转换一个numpy数组

python - 显示一个实时的 numpy 数组

python - 在python中的指定行/列处合并二维数组(不同维度)