圆形掩盖使用numpy数组在python中的图像

10 python arrays numpy image-processing matrix

我试图通过在Web上阅读代码来使用Python修改圆形图像,但在数学中完全丢失了:

我得到的图像(image_data中)type = numpy.ndarrayshape = (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)
Run Code Online (Sandbox Code Playgroud)

我知道他申请euclidean distance计算,dist_from_center但我没有得到X - total_rowsY - total_cols分开

XY在圈子上扮演什么角色?

alk*_*asm 27

您上网的算法部分错误,至少对您而言.如果我们有以下图像,我们希望它像这样掩盖:

图像来掩盖 蒙面图像

创建这样的掩码的最简单方法是你的算法如何处理它,但它不是以你想要的方式呈现,也不能让你以简单的方式修改它.我们需要做的是查看图像中每个像素的坐标,并获得该像素是否在半径范围内的真/假值.例如,这是放大的图片,显示圆半径和严格在该半径范围内的像素:

半径内的像素

现在,为了确定哪些像素位于圆内,我们需要图像中每个像素的索引.该函数np.ogrid()给出两个向量,每个向量包含像素位置(或索引):列索引的列向量和行索引的行向量:

>>> np.ogrid[:4,:5]
[array([[0],
       [1],
       [2],
       [3]]), array([[0, 1, 2, 3, 4]])]
Run Code Online (Sandbox Code Playgroud)

这种格式对于广播非常有用,因此如果我们在某些函数中使用它们,它实际上会创建所有索引的网格,而不仅仅是这两个向量.因此,我们可以使用np.ogrid()创建图像的索引(或像素坐标),然后检查每个像素坐标以查看它是在圆圈内部还是外部.为了判断它是否在中心内,我们可以简单地找到从中心到每个像素位置的欧几里德距离,然后如果该距离小于圆半径,我们将标记为包含在掩模中,如果它比那更大,我们将它从面具中排除.

现在我们已经拥有了创建这个掩码的函数所需的一切.此外,我们将为它添加一些不错的功能; 我们可以发送中心和半径,或者自动计算它们.

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
Run Code Online (Sandbox Code Playgroud)

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

距离渐变

因此,当我们将其与之进行比较时radius,它与对此渐变图像进行阈值处理相同.

请注意,最终的掩模是布尔矩阵; True如果该位置在指定中心的半径范围内,False否则.因此,我们可以使用此蒙版作为我们关注的像素区域的指示器,或者我们可以采用与该布尔(~in numpy)相反的方法来选择该区域之外的像素.因此,使用此功能为黑色圆圈外的像素着色,就像我在本文顶部所做的那样,就像下面这样简单:

h, w = img.shape[:2]
mask = create_circular_mask(h, w)
masked_img = img.copy()
masked_img[~mask] = 0
Run Code Online (Sandbox Code Playgroud)

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

center = [int(w/4), int(h/4)]
mask = create_circular_mask(h, w, center=center)
Run Code Online (Sandbox Code Playgroud)

因为我们没有给出半径,所以会给我们最小的半径,这样圆圈仍然适合图像边界:

偏心面具

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

radius = h/4
mask = create_circular_mask(h, w, radius=radius)
Run Code Online (Sandbox Code Playgroud)

给我们一个中心圆,其半径不能完全延伸到最小尺寸:

指定的半径掩码

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

center = [int(w/4), int(h/4)]
radius = h/2
mask = create_circular_mask(h, w, center=center, radius=radius)
Run Code Online (Sandbox Code Playgroud)

偏心,半径较大的面罩

您在网上找到的算法相当于将中心[0,0]设置为并将半径设置为h:

mask = create_circular_mask(h, w, center=[0,0], radius=h)
Run Code Online (Sandbox Code Playgroud)

四分之一圈面具


She*_*yan 7

其他答案有效,但速度很慢,因此我将使用skimage.draw.disk提出一个答案。使用它速度更快,而且我发现它使用起来很简单。只需指定圆心和半径,然后使用输出创建蒙版

import numpy as np
from skimage.draw import disk
mask = np.zeros((10, 10), dtype=np.uint8)
row = 4
col = 5
radius = 5
# modern scikit uses a tuple for center
rr, cc = disk((row, col), radius)
mask[rr, cc] = 1
Run Code Online (Sandbox Code Playgroud)