您在网上获取的算法在某种程度上是错误的,至少对于您的目的来说是如此。如果我们有以下图像,我们希望它被掩蔽如下:
![Masked image](https://istack.dev59.com/Hcsl9.webp)
创建这样的遮罩最简单的方法是按照你的算法进行操作,但它并没有按照你想要的方式呈现,也不能轻松地进行修改。我们需要查看图像中每个像素的坐标,并获取一个真/假值,以确定该像素是否在半径内。例如,下面是一张放大的图片,显示了圆形半径和严格在该半径内的像素:
![Pixels inside the radius](https://istack.dev59.com/L4ExH.webp)
现在,为了确定哪些像素位于圆内,我们需要知道图像中每个像素的索引。函数
np.ogrid()
提供了两个向量,分别包含列索引和行索引的像素位置(或索引):其中有一个列向量用于列索引,另一个行向量用于行索引:
>>> np.ogrid[:4,:5]
[array([[0],
[1],
[2],
[3]]), array([[0, 1, 2, 3, 4]])]
这种格式对
广播很有用,因为如果我们在某些函数中使用它们,它实际上会创建所有索引的网格,而不仅仅是这两个向量。因此,我们可以使用
np.ogrid()
来创建图像的索引(或像素坐标),然后检查每个像素坐标是否在圆内或圆外。为了判断它是否在中心内部,我们只需找到从中心到每个像素位置的欧几里得距离,然后如果该距离小于圆的半径,我们将把其标记为
包括在掩码中,否则我们将
排除它。
现在我们已经拥有了创建这个掩码的所有必要条件。此外,我们将添加一些好的功能;我们可以发送中心和半径,或者让它自动计算它们。
def create_circular_mask(h, w, center=None, radius=None):
if center is None:
center = (int(w/2), int(h/2))
if radius is None:
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
是一个与指定高度和宽度相同的矩阵。它将列索引向量和行索引向量广播到矩阵中,每个位置的值都是距离中心的距离。如果我们将该矩阵可视化为图像(将其缩放到适当的范围内),那么它将成为从我们指定的中心辐射出的渐变:
![Distance gradient](https://istack.dev59.com/oL7Hy.webp)
因此,当我们将其与半径
进行比较时,它等同于对该梯度图像进行阈值处理。
请注意,最终的掩码是一个布尔矩阵;如果该位置在指定中心点的半径内,则为True
,否则为False
。因此,我们可以将此掩码用作我们关心的像素区域的指示器,或者我们可以取该布尔值的相反值(即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](https://istack.dev59.com/TiMey.webp)
或者我们可以让它计算中心但使用指定的半径:
radius = h/4
mask = create_circular_mask(h, w, radius=radius)
给我们一个居中的圆,半径不会恰好延伸到最小的尺寸:
![Specified radius mask](https://istack.dev59.com/zqfsW.webp)
最后,我们可以指定任何半径和中心点,包括超出图像边界的半径(甚至中心点可以在图像边界之外!):
center = (int(w/4), int(h/4))
radius = h/2
mask = create_circular_mask(h, w, center=center, radius=radius)
你在网上找到的算法相当于将中心设置为
(0, 0)
,半径设置为
h
。
mask = create_circular_mask(h, w, center=(0, 0), radius=h)
![Quarter-circle mask](https://istack.dev59.com/8PPu1.webp)
center_row
和center_col
而不是total...
我认为这段代码会在左上角产生一个四分之一圆形掩模,而不是在你的图像中心的圆形掩模(请注意,在这种情况下,dist_from_center
仍然是错误的)。 - alkasmnp.ogrid
,网上关于np.ogrid
的所有解释都超出了我的理解范围。 - user7469692