高效创建抗锯齿圆形掩模

2024-10-05 10:46:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试创建反走样(加权而非布尔)的圆形掩模,以制作用于卷积的圆形核。在

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)

输出是

^{pr2}$

那我们就可以了

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固定和{}变化的情况下,至少生成一百万个这样的,那么有没有更好或更有效的方法来实现这一点?(可能没有昂贵的操作,如sqrt,仍然保持足够精确的弧积分,即曲线在特定像素覆盖的面积?)在


Tags: ofthesizedistmask圆形bearray
2条回答

如果你想建立数百万个掩模,你应该预先计算一次从未改变过的东西,并且只计算每个半径所需的严格值。在

你可以试试这样的方法:

class Circle:
    def __init__(self, kernel_size):
        self._kernel_size = kernel_size
        self._kernel_radius = (self._kernel_size - 1) // 2

        x, y = np.ogrid[
            -self._kernel_radius:self._kernel_radius+1,
            -self._kernel_radius:self._kernel_radius+1]
        self._dist = np.sqrt(x**2 + y**2)

    def __call__(self, radius):
        mask = self._dist - radius
        mask = np.clip(mask, 0, 1, out=mask)
        mask *= -1
        mask += 1
        return mask


circle = Circle(kernel_size=9)
for radius in range(1, 4, 0.2):
    mask = circle(radius)  
    print(mask)

我尽可能地在适当的地方进行了操作,以优化速度和内存,但对于小数组来说,这并不重要。在

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

您只需更改一个半径数组(而不是标量半径),并注入两个尾随的单例维度,以便您的掩码创建触发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,...]和{}分别包含半径3.5和{}的内核。在

相关问题 更多 >

    热门问题