python - 高效创建抗锯齿圆形蒙版

标签 python arrays numpy mask

我正在尝试创建抗锯齿(加权而非 bool 值)圆形掩码以制作用于卷积的圆形内核。

radius = 3  # no. of pixels to be 1 on either side of the center pixel
            # shall be decimal as well; not the real radius
kernel_size = 9                
kernel_radius = (kernel_size - 1) // 2
x, y = np.ogrid[-kernel_radius:kernel_radius+1, -kernel_radius:kernel_radius+1]
dist = ((x**2+y**2)**0.5)
mask = (dist-radius).clip(0,1)
print(mask)

输出是

array([[1.  , 1.  , 1.  , 1.  , 1.  , 1.  , 1.  , 1.  , 1.  ],
       [1.  , 1.  , 0.61, 0.16, 0.  , 0.16, 0.61, 1.  , 1.  ],
       [1.  , 0.61, 0.  , 0.  , 0.  , 0.  , 0.  , 0.61, 1.  ],
       [1.  , 0.16, 0.  , 0.  , 0.  , 0.  , 0.  , 0.16, 1.  ],
       [1.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 1.  ],
       [1.  , 0.16, 0.  , 0.  , 0.  , 0.  , 0.  , 0.16, 1.  ],
       [1.  , 0.61, 0.  , 0.  , 0.  , 0.  , 0.  , 0.61, 1.  ],
       [1.  , 1.  , 0.61, 0.16, 0.  , 0.16, 0.61, 1.  , 1.  ],
       [1.  , 1.  , 1.  , 1.  , 1.  , 1.  , 1.  , 1.  , 1.  ]])

然后我们可以做

mask = 1 - mask
print(mask)

得到

array([[0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  ],
       [0.  , 0.  , 0.39, 0.84, 1.  , 0.84, 0.39, 0.  , 0.  ],
       [0.  , 0.39, 1.  , 1.  , 1.  , 1.  , 1.  , 0.39, 0.  ],
       [0.  , 0.84, 1.  , 1.  , 1.  , 1.  , 1.  , 0.84, 0.  ],
       [0.  , 1.  , 1.  , 1.  , 1.  , 1.  , 1.  , 1.  , 0.  ],
       [0.  , 0.84, 1.  , 1.  , 1.  , 1.  , 1.  , 0.84, 0.  ],
       [0.  , 0.39, 1.  , 1.  , 1.  , 1.  , 1.  , 0.39, 0.  ],
       [0.  , 0.  , 0.39, 0.84, 1.  , 0.84, 0.39, 0.  , 0.  ],
       [0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  ]])

我现在可以对其进行归一化并将其用作卷积运算中的圆形过滤器(内核)。

注意:半径可以是小数。例如:get_circular_kernel(0.5,(5,5)) 应该给出

array([[0.        , 0.        , 0.        , 0.        , 0.        ],
       [0.        , 0.08578644, 0.5       , 0.08578644, 0.        ],
       [0.        , 0.5       , 1.        , 0.5       , 0.        ],
       [0.        , 0.08578644, 0.5       , 0.08578644, 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ]])

我想至少生成一百万个,固定kernel_size,改变radius,有没有更好的或更有效的方法来做到这一点? (也许没有像 sqrt 这样的昂贵操作,并且仍然保持足够精确以进行弧积分,即特定像素中曲线覆盖的区域?)

最佳答案

由于您想要生成大量具有相同大小的内核,您可以通过一步构建每个内核而不是在循环中一个接一个地构建内核来大大提高性能。给定每个内核的 num_radii 值,您可以创建一个形状为 (num_radii, kernel_size, kernel_size) 的数组。这种矢量化的代价是内存:您必须将所有这些值放入 RAM 中,否则您应该将数百万个半径分成几个较小的批处理,然后分别再次生成每个批处理。

您唯一需要更改的是获取一个半径数组(而不是标量半径),并注入(inject)两个尾随的单一维度,以便您的掩码创建触发 broadcasting :

import numpy as np 

kernel_size = 9
kernel_radius = (kernel_size - 1) // 2
x, y = np.ogrid[-kernel_radius:kernel_radius+1, -kernel_radius:kernel_radius+1]
dist = (x**2 + y**2)**0.5 # shape (kernel_size, kernel_size)

# let's create three kernels for the sake of example
radii = np.array([3, 3.5, 4])[...,None,None] # shape (num_radii, 1, 1)
# using ... allows compatibility with arbitrarily-shaped radius arrays

masks = 1 - (dist - radii).clip(0,1) # shape (num_radii, kernel_size, kernel_size)

现在 masks[0,...](或简称 masks[0],但我更喜欢显式版本)包含您问题中的示例掩码,和 masks[1,...]masks[2,...] 包含半径 3.54 的内核,分别。

关于python - 高效创建抗锯齿圆形蒙版,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51002815/

相关文章:

python - 当我在 python 中的匹配对象上执行 dir() 时,为什么没有列出 re 属性?

python - 了解 PATH 中的 Python 版本以及如何更改它

python - "Expand" Pandas 数据框按列中的值

python - numpy 1.9.2+MKL 与 py2exe 打包时出现 OMP 警告

python - 改进我的椭圆拟合算法

python - 如何避免 Pandas 直方图子图中的图标题和轴标题重叠?

c# - 使用 byte[] 和 varbinary(max) 时图像在 NHibernate 中损坏或截断

java - 检查数组中是否存在字符串

c++ - 使用常量变量声明对象数组

python - 如何在 python 中绘制 3D 数据的核密度估计 (KDE) 和零交叉?