我正在尝试在Python中圆形 mask 图像。我在网上找到了一些示例代码,但是我不确定如何更改数学以正确地定位我的圈子。
我有一个类型为image_data
的numpy.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_rows
和Y - total_cols
部分。这将产生一个四分之一圆的蒙版(以图像的左上角为中心)。圈子中的
X
和Y
扮演什么角色?以及如何修改此代码以产生一个在图像中其他位置居中的蒙版?
最佳答案
您上网的算法部分错误,至少出于您的目的。如果我们有以下图像,我们希望将其屏蔽为:
创建这样的掩码的最简单方法是算法的运行方式,但是它并未以您想要的方式呈现,也没有使您能够以简单的方式对其进行修改。我们需要做的是查看图像中每个像素的坐标,并获取该像素是否在半径之内的真/假值。例如,这是一张放大的图片,显示了圆半径和严格位于该半径内的像素:
现在,要弄清楚哪些像素位于圆内,我们需要图像中每个像素的索引。函数 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 广播到一个矩阵中,其中每个位置的值是距中心的距离。如果我们将此矩阵可视化为图像(将其缩放到适当的范围),那么它将是我们指定的从中心辐射的渐变:因此,当我们将其与
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)
由于我们没有给出半径,因此会给我们最大半径,以便圆仍适合图像边界:
或者我们可以让它计算中心但使用指定的半径:
radius = h/4
mask = create_circular_mask(h, w, radius=radius)
给我们一个半径不精确到最小尺寸的圆心:
最后,我们可以指定所需的任何半径和中心,包括延伸到图像边界之外的半径(并且中心甚至可以在图像边界之外!):
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)
关于python - 如何为numpy数组创建圆形蒙版?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44865023/